Aggiornato Composer

This commit is contained in:
Paolo A
2024-05-17 12:24:19 +00:00
parent 4ac62108b5
commit ec201d75b2
2238 changed files with 38684 additions and 59785 deletions

View File

@@ -1,448 +0,0 @@
# ChangeLog
All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
## [9.2.15] - 2022-03-07
### Fixed
* [#885](https://github.com/sebastianbergmann/php-code-coverage/issues/885): Files that have only `\r` (CR, 0x0d) EOL characters are not handled correctly
* [#907](https://github.com/sebastianbergmann/php-code-coverage/issues/907): Line with only `return [` is not recognized as executable
## [9.2.14] - 2022-02-28
### Fixed
* [#904](https://github.com/sebastianbergmann/php-code-coverage/issues/904): Lines of code containing the `match` keyword were not recognized as executable correctly
* [#905](https://github.com/sebastianbergmann/php-code-coverage/issues/905): Lines of code in constructors were not recognized as executable correctly when constructor property promotion is used
## [9.2.13] - 2022-02-23
### Changed
* The contents of the static analysis sourcecode files is now used to generate the static analysis cache version identifier
### Fixed
* Reverted rename of `SebastianBergmann\CodeCoverage\ProcessedCodeCoverageData` to `SebastianBergmann\CodeCoverage\Data\ProcessedCodeCoverageData` (this class is marked as `@internal` and not covered by the backward compatibility promise, but it is (still) used directly by PHPUnit)
* Reverted rename of `SebastianBergmann\CodeCoverage\RawCodeCoverageData` to `SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData` (this class is marked as `@internal` and not covered by the backward compatibility promise, but it is (still) used directly by PHPUnit)
* The `ArrayDim`, `Cast`, and `MethodCall` nodes are now considered when determining whether a line of code is executable or not
## [9.2.12] - 2022-02-23 [YANKED]
### Changed
* [#898](https://github.com/sebastianbergmann/php-code-coverage/pull/898): Use content hash instead of `filemtime()` to determine cache hit/miss
### Fixed
* [#736](https://github.com/sebastianbergmann/php-code-coverage/issues/736): HTML report generator allows invalid values for low upper bound and high lower bound
* [#854](https://github.com/sebastianbergmann/php-code-coverage/issues/854): "Class Coverage Distribution" and "Class Complexity" graphs are not displayed at full width
* [#897](https://github.com/sebastianbergmann/php-code-coverage/issues/897): `declare(strict_types=1)` marked as uncovered
## [9.2.11] - 2022-02-18
### Changed
* `CoveredFileAnalyser` and `UncoveredFileAnalyser` have been combined to `FileAnalyser`
* Updated bundled CSS/JavaScript components used for HTML report: Bootstrap 4.6.1, jQuery 3.6.0, and popper.js 1.16.1
### Fixed
* [#889](https://github.com/sebastianbergmann/php-code-coverage/issues/889): Code Coverage depends on autoload order
## [9.2.10] - 2021-12-05
### Fixed
* [#887](https://github.com/sebastianbergmann/php-code-coverage/issues/887): Document return type of `CodeUnitFindingVisitor::enterNode()` so that Symfony's DebugClassLoader does not trigger a deprecation warning
## [9.2.9] - 2021-11-19
### Fixed
* [#882](https://github.com/sebastianbergmann/php-code-coverage/issues/882): PHPUnit 9.2.8 has wrong version number
## [9.2.8] - 2021-10-30
### Fixed
* [#866](https://github.com/sebastianbergmann/php-code-coverage/issues/866): `CodeUnitFindingVisitor` does not handle `enum` type introduced in PHP 8.1
* [#868](https://github.com/sebastianbergmann/php-code-coverage/pull/868): Uncovered files should be ignored unless requested
* [#876](https://github.com/sebastianbergmann/php-code-coverage/issues/876): PCOV driver causes 2x slowdown after upgrade to PHPUnit 9.5
## [9.2.7] - 2021-09-17
### Fixed
* [#860](https://github.com/sebastianbergmann/php-code-coverage/pull/860): Empty value for `XDEBUG_MODE` environment variable is not handled correctly
## [9.2.6] - 2021-03-28
### Fixed
* [#846](https://github.com/sebastianbergmann/php-code-coverage/issues/846): Method name should not appear in the method signature attribute of Cobertura XML
## [9.2.5] - 2020-11-28
### Fixed
* [#831](https://github.com/sebastianbergmann/php-code-coverage/issues/831): Files that do not contain a newline are not handled correctly
## [9.2.4] - 2020-11-27
### Added
* [#834](https://github.com/sebastianbergmann/php-code-coverage/issues/834): Support `XDEBUG_MODE` environment variable
## [9.2.3] - 2020-10-30
### Changed
* Bumped required version of `nikic/php-parser`
## [9.2.2] - 2020-10-28
### Fixed
* [#820](https://github.com/sebastianbergmann/php-code-coverage/issues/820): Hidden dependency on PHPUnit
## [9.2.1] - 2020-10-26
### Fixed
* `SebastianBergmann\CodeCoverage\Exception` now correctly extends `\Throwable`
## [9.2.0] - 2020-10-02
### Added
* [#812](https://github.com/sebastianbergmann/php-code-coverage/pull/812): Support for Cobertura XML report format
### Changed
* Reduced the number of I/O operations performed by the static analysis cache
## [9.1.11] - 2020-09-19
### Fixed
* [#811](https://github.com/sebastianbergmann/php-code-coverage/issues/811): `T_FN` constant is used on PHP 7.3 where it is not available
## [9.1.10] - 2020-09-18
### Added
* `SebastianBergmann\CodeCoverage\Driver\Selector::forLineCoverage()` and `SebastianBergmann\CodeCoverage\Driver\Selector::forLineAndPathCoverage()` have been added
### Fixed
* [#810](https://github.com/sebastianbergmann/php-code-coverage/issues/810): `SebastianBergmann\CodeCoverage\Driver\Driver::forLineCoverage()` and `SebastianBergmann\CodeCoverage\Driver\Driver::forLineAndPathCoverage()` are marked as internal
### Removed
* `SebastianBergmann\CodeCoverage\Driver\Driver::forLineCoverage()` and `SebastianBergmann\CodeCoverage\Driver\Driver::forLineAndPathCoverage()` are now deprecated
## [9.1.9] - 2020-09-15
### Fixed
* [#808](https://github.com/sebastianbergmann/php-code-coverage/issues/808): `PHP Warning: Use of undefined constant T_MATCH`
## [9.1.8] - 2020-09-07
### Changed
* [#800](https://github.com/sebastianbergmann/php-code-coverage/pull/800): All files on the inclusion list are no longer loaded when `SebastianBergmann\CodeCoverage::start()` is called for the first time and `processUncoveredFiles` is set to `true`
### Fixed
* [#799](https://github.com/sebastianbergmann/php-code-coverage/issues/799): Uncovered new line at end of file
## [9.1.7] - 2020-09-03
### Fixed
* Fixed regressions introduced in versions 9.1.5 and 9.1.6
## [9.1.6] - 2020-08-31
### Fixed
* [#799](https://github.com/sebastianbergmann/php-code-coverage/issues/799): Uncovered new line at end of file
* [#803](https://github.com/sebastianbergmann/php-code-coverage/issues/803): HTML report does not sort directories and files anymore
## [9.1.5] - 2020-08-27
### Changed
* [#800](https://github.com/sebastianbergmann/php-code-coverage/pull/800): All files on the inclusion list are no longer loaded when `SebastianBergmann\CodeCoverage::start()` is called for the first time and `processUncoveredFiles` is set to `true`
### Fixed
* [#797](https://github.com/sebastianbergmann/php-code-coverage/pull/797): Class name is wrongly removed from namespace name
## [9.1.4] - 2020-08-13
### Fixed
* [#793](https://github.com/sebastianbergmann/php-code-coverage/issues/793): Lines with `::class` constant are not covered
## [9.1.3] - 2020-08-10
### Changed
* Changed PHP-Parser usage to parse sourcecode according to the PHP version we are currently running on instead of using emulative lexing
## [9.1.2] - 2020-08-10
### Fixed
* [#791](https://github.com/sebastianbergmann/php-code-coverage/pull/791): Cache Warmer does not warm all caches
## [9.1.1] - 2020-08-10
### Added
* Added `SebastianBergmann\CodeCoverage::cacheDirectory()` method for querying where the cache writes its files
## [9.1.0] - 2020-08-10
### Added
* Implemented a persistent cache for information gathered using PHP-Parser based static analysis (hereinafter referred to as "cache")
* Added `SebastianBergmann\CodeCoverage::cacheStaticAnalysis(string $cacheDirectory)` method for enabling the cache; it will write its files to `$directory`
* Added `SebastianBergmann\CodeCoverage::doNotCacheStaticAnalysis` method for disabling the cache
* Added `SebastianBergmann\CodeCoverage::cachesStaticAnalysis()` method for querying whether the cache is enabled
* Added `SebastianBergmann\CodeCoverage\StaticAnalysis\CacheWarmer::warmCache()` method for warming the cache
## [9.0.0] - 2020-08-07
### Added
* [#761](https://github.com/sebastianbergmann/php-code-coverage/pull/761): Support for Branch Coverage and Path Coverage
* Added `SebastianBergmann\CodeCoverage\Driver\Driver::forLineCoverage()` for selecting the best available driver for line coverage
* Added `SebastianBergmann\CodeCoverage\Driver\Driver::forLineAndPathCoverage()` for selecting the best available driver for path coverage
* This component is now supported on PHP 8
* This component now supports Xdebug 3
### Changed
* [#746](https://github.com/sebastianbergmann/php-code-coverage/pull/746): Remove some ancient workarounds for very old Xdebug versions
* [#747](https://github.com/sebastianbergmann/php-code-coverage/pull/747): Use native filtering in PCOV and Xdebug drivers
* [#748](https://github.com/sebastianbergmann/php-code-coverage/pull/748): Store raw code coverage in value objects instead of arrays
* [#749](https://github.com/sebastianbergmann/php-code-coverage/pull/749): Store processed code coverage in value objects instead of arrays
* [#752](https://github.com/sebastianbergmann/php-code-coverage/pull/752): Rework how code coverage settings are propagated to the driver
* [#754](https://github.com/sebastianbergmann/php-code-coverage/pull/754): Implement collection of raw branch and path coverage
* [#755](https://github.com/sebastianbergmann/php-code-coverage/pull/755): Implement processing of raw branch and path coverage
* [#756](https://github.com/sebastianbergmann/php-code-coverage/pull/756): Improve handling of uncovered files
* `SebastianBergmann\CodeCoverage\Filter::addDirectoryToWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::includeDirectory()`
* `SebastianBergmann\CodeCoverage\Filter::addFilesToWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::includeFiles()`
* `SebastianBergmann\CodeCoverage\Filter::addFileToWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::includeFile()`
* `SebastianBergmann\CodeCoverage\Filter::removeDirectoryFromWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::excludeDirectory()`
* `SebastianBergmann\CodeCoverage\Filter::removeFileFromWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::excludeFile()`
* `SebastianBergmann\CodeCoverage\Filter::isFiltered()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::isExcluded()`
* `SebastianBergmann\CodeCoverage\Filter::getWhitelist()` has been renamed to `SebastianBergmann\CodeCoverage\Filter::files()`
* The arguments for `CodeCoverage::__construct()` are no longer optional
### Fixed
* [#700](https://github.com/sebastianbergmann/php-code-coverage/pull/700): Throw an exception if code coverage fails to write to disk
### Removed
* `SebastianBergmann\CodeCoverage\CodeCoverage::setCacheTokens()` and `SebastianBergmann\CodeCoverage\CodeCoverage::getCacheTokens()` have been removed
* `SebastianBergmann\CodeCoverage\CodeCoverage::setCheckForUnintentionallyCoveredCode()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::enableCheckForUnintentionallyCoveredCode()` or `SebastianBergmann\CodeCoverage\CodeCoverage::disableCheckForUnintentionallyCoveredCode()` instead
* `SebastianBergmann\CodeCoverage\CodeCoverage::setSubclassesExcludedFromUnintentionallyCoveredCodeCheck()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::excludeSubclassesOfThisClassFromUnintentionallyCoveredCodeCheck()` instead
* `SebastianBergmann\CodeCoverage\CodeCoverage::setAddUncoveredFilesFromWhitelist()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::includeUncoveredFiles()` or `SebastianBergmann\CodeCoverage\CodeCoverage::excludeUncoveredFiles()` instead
* `SebastianBergmann\CodeCoverage\CodeCoverage::setProcessUncoveredFiles()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::processUncoveredFiles()` or `SebastianBergmann\CodeCoverage\CodeCoverage::doNotProcessUncoveredFiles()` instead
* `SebastianBergmann\CodeCoverage\CodeCoverage::setIgnoreDeprecatedCode()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::ignoreDeprecatedCode()` or `SebastianBergmann\CodeCoverage\CodeCoverage::doNotIgnoreDeprecatedCode()` instead
* `SebastianBergmann\CodeCoverage\CodeCoverage::setDisableIgnoredLines()` has been removed, please use `SebastianBergmann\CodeCoverage\CodeCoverage::enableAnnotationsForIgnoringCode()` or `SebastianBergmann\CodeCoverage\CodeCoverage::disableAnnotationsForIgnoringCode()` instead
* `SebastianBergmann\CodeCoverage\CodeCoverage::setCheckForMissingCoversAnnotation()` has been removed
* `SebastianBergmann\CodeCoverage\CodeCoverage::setCheckForUnexecutedCoveredCode()` has been removed
* `SebastianBergmann\CodeCoverage\CodeCoverage::setForceCoversAnnotation()` has been removed
* `SebastianBergmann\CodeCoverage\Filter::hasWhitelist()` has been removed, please use `SebastianBergmann\CodeCoverage\Filter::isEmpty()` instead
* `SebastianBergmann\CodeCoverage\Filter::getWhitelistedFiles()` has been removed
* `SebastianBergmann\CodeCoverage\Filter::setWhitelistedFiles()` has been removed
## [8.0.2] - 2020-05-23
### Fixed
* [#750](https://github.com/sebastianbergmann/php-code-coverage/pull/750): Inconsistent handling of namespaces
* [#751](https://github.com/sebastianbergmann/php-code-coverage/pull/751): Dead code is not highlighted correctly
* [#753](https://github.com/sebastianbergmann/php-code-coverage/issues/753): Do not use `$_SERVER['REQUEST_TIME']` because the test(ed) code might unset it
## [8.0.1] - 2020-02-19
### Fixed
* [#731](https://github.com/sebastianbergmann/php-code-coverage/pull/731): Confusing footer in the HTML report
## [8.0.0] - 2020-02-07
### Fixed
* [#721](https://github.com/sebastianbergmann/php-code-coverage/pull/721): Workaround for PHP bug [#79191](https://bugs.php.net/bug.php?id=79191)
### Removed
* This component is no longer supported on PHP 7.2
## [7.0.15] - 2021-07-26
### Changed
* Bumped required version of php-token-stream
## [7.0.14] - 2020-12-02
### Changed
* [#837](https://github.com/sebastianbergmann/php-code-coverage/issues/837): Allow version 4 of php-token-stream
## [7.0.13] - 2020-11-30
### Changed
* Changed PHP version constraint in `composer.json` from `^7.2` to `>=7.2` to allow installation of this version of this library on PHP 8. However, this version of this library does not work on PHP 8. PHPUnit 8.5, which uses this version of this library, does not call into this library and instead shows a message that code coverage functionality is not available for PHPUnit 8.5 on PHP 8.
## [7.0.12] - 2020-11-27
### Added
* [#834](https://github.com/sebastianbergmann/php-code-coverage/issues/834): Support `XDEBUG_MODE` environment variable
## [7.0.11] - 2020-11-27
### Added
* Support for Xdebug 3
## [7.0.10] - 2019-11-20
### Fixed
* [#710](https://github.com/sebastianbergmann/php-code-coverage/pull/710): Code Coverage does not work in PhpStorm
## [7.0.9] - 2019-11-20
### Changed
* [#709](https://github.com/sebastianbergmann/php-code-coverage/pull/709): Prioritize PCOV over Xdebug
## [7.0.8] - 2019-09-17
### Changed
* Updated bundled CSS/JavaScript components used for HTML report: Bootstrap 4.3.1, jQuery 3.4.1, and popper.js 1.15.0
## [7.0.7] - 2019-07-25
### Changed
* Bumped required version of php-token-stream
## [7.0.6] - 2019-07-08
### Changed
* Bumped required version of php-token-stream
## [7.0.5] - 2019-06-06
### Fixed
* [#681](https://github.com/sebastianbergmann/php-code-coverage/pull/681): `use function` statements are not ignored
## [7.0.4] - 2019-05-29
### Fixed
* [#682](https://github.com/sebastianbergmann/php-code-coverage/pull/682): Code that is not executed is reported as being executed when using PCOV
## [7.0.3] - 2019-02-26
### Fixed
* [#671](https://github.com/sebastianbergmann/php-code-coverage/issues/671): `TypeError` when directory name is a number
## [7.0.2] - 2019-02-15
### Changed
* Updated bundled CSS/JavaScript components used for HTML report: Bootstrap 4.3.0
### Fixed
* [#667](https://github.com/sebastianbergmann/php-code-coverage/pull/667): `TypeError` in PHP reporter
## [7.0.1] - 2019-02-01
### Fixed
* [#664](https://github.com/sebastianbergmann/php-code-coverage/issues/664): `TypeError` when whitelisted file does not exist
## [7.0.0] - 2019-02-01
### Added
* [#663](https://github.com/sebastianbergmann/php-code-coverage/pull/663): Support for PCOV
### Fixed
* [#654](https://github.com/sebastianbergmann/php-code-coverage/issues/654): HTML report fails to load assets
* [#655](https://github.com/sebastianbergmann/php-code-coverage/issues/655): Popin pops in outside of screen
### Removed
* This component is no longer supported on PHP 7.1
[9.2.15]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.14...9.2.15
[9.2.14]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.13...9.2.14
[9.2.13]: https://github.com/sebastianbergmann/php-code-coverage/compare/c011a0b6aaa4acd2f39b7f51fb4ad4442b6ec631...9.2.13
[9.2.12]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.11...c011a0b6aaa4acd2f39b7f51fb4ad4442b6ec631
[9.2.11]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.10...9.2.11
[9.2.10]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.9...9.2.10
[9.2.9]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.8...9.2.9
[9.2.8]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.7...9.2.8
[9.2.7]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.6...9.2.7
[9.2.6]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.5...9.2.6
[9.2.5]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.4...9.2.5
[9.2.4]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.3...9.2.4
[9.2.3]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.2...9.2.3
[9.2.2]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.1...9.2.2
[9.2.1]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.0...9.2.1
[9.2.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.11...9.2.0
[9.1.11]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.10...9.1.11
[9.1.10]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.9...9.1.10
[9.1.9]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.8...9.1.9
[9.1.8]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.7...9.1.8
[9.1.7]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.6...9.1.7
[9.1.6]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.5...9.1.6
[9.1.5]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.4...9.1.5
[9.1.4]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.3...9.1.4
[9.1.3]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.2...9.1.3
[9.1.2]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.1...9.1.2
[9.1.1]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.1.0...9.1.1
[9.1.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.0.0...9.1.0
[9.0.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/8.0...9.0.0
[8.0.2]: https://github.com/sebastianbergmann/php-code-coverage/compare/8.0.1...8.0.2
[8.0.1]: https://github.com/sebastianbergmann/php-code-coverage/compare/8.0.0...8.0.1
[8.0.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.10...8.0.0
[7.0.15]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.14...7.0.15
[7.0.14]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.13...7.0.14
[7.0.13]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.12...7.0.13
[7.0.12]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.11...7.0.12
[7.0.11]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.10...7.0.11
[7.0.10]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.9...7.0.10
[7.0.9]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.8...7.0.9
[7.0.8]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.7...7.0.8
[7.0.7]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.6...7.0.7
[7.0.6]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.5...7.0.6
[7.0.5]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.4...7.0.5
[7.0.4]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.3...7.0.4
[7.0.3]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.2...7.0.3
[7.0.2]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.1...7.0.2
[7.0.1]: https://github.com/sebastianbergmann/php-code-coverage/compare/7.0.0...7.0.1
[7.0.0]: https://github.com/sebastianbergmann/php-code-coverage/compare/6.1.4...7.0.0

View File

@@ -1,33 +1,29 @@
php-code-coverage
BSD 3-Clause License
Copyright (c) 2009-2022, Sebastian Bergmann <sebastian@phpunit.de>.
Copyright (c) 2009-2023, 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.

View File

@@ -17,7 +17,8 @@
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues"
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy"
},
"config": {
"platform": {
@@ -32,7 +33,7 @@
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
"nikic/php-parser": "^4.13.0",
"nikic/php-parser": "^4.18 || ^5.0",
"phpunit/php-file-iterator": "^3.0.3",
"phpunit/php-text-template": "^2.0.2",
"sebastian/code-unit-reverse-lookup": "^2.0.2",
@@ -46,8 +47,8 @@
"phpunit/phpunit": "^9.3"
},
"suggest": {
"ext-pcov": "*",
"ext-xdebug": "*"
"ext-pcov": "PHP extension that provides line coverage",
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
},
"autoload": {
"classmap": [

View File

@@ -20,7 +20,6 @@ use function count;
use function explode;
use function get_class;
use function is_array;
use function is_file;
use function sort;
use PHPUnit\Framework\TestCase;
use PHPUnit\Runner\PhptTestCase;
@@ -77,7 +76,7 @@ final class CodeCoverage
private $ignoreDeprecatedCode = false;
/**
* @var PhptTestCase|string|TestCase
* @var null|PhptTestCase|string|TestCase
*/
private $currentId;
@@ -115,6 +114,11 @@ final class CodeCoverage
*/
private $cacheDirectory;
/**
* @var ?Directory
*/
private $cachedReport;
public function __construct(Driver $driver, Filter $filter)
{
$this->driver = $driver;
@@ -128,7 +132,11 @@ final class CodeCoverage
*/
public function getReport(): Directory
{
return (new Builder($this->analyser()))->build($this);
if ($this->cachedReport === null) {
$this->cachedReport = (new Builder($this->analyser()))->build($this);
}
return $this->cachedReport;
}
/**
@@ -136,9 +144,18 @@ final class CodeCoverage
*/
public function clear(): void
{
$this->currentId = null;
$this->data = new ProcessedCodeCoverageData;
$this->tests = [];
$this->currentId = null;
$this->data = new ProcessedCodeCoverageData;
$this->tests = [];
$this->cachedReport = null;
}
/**
* @internal
*/
public function clearCache(): void
{
$this->cachedReport = null;
}
/**
@@ -203,6 +220,8 @@ final class CodeCoverage
$this->currentId = $id;
$this->driver->start();
$this->cachedReport = null;
}
/**
@@ -221,7 +240,8 @@ final class CodeCoverage
$data = $this->driver->stop();
$this->append($data, null, $append, $linesToBeCovered, $linesToBeUsed);
$this->currentId = null;
$this->currentId = null;
$this->cachedReport = null;
return $data;
}
@@ -246,6 +266,8 @@ final class CodeCoverage
throw new TestIdMissingException;
}
$this->cachedReport = null;
$this->applyFilter($rawData);
$this->applyExecutableLinesFilter($rawData);
@@ -313,6 +335,8 @@ final class CodeCoverage
$this->data->merge($that->data);
$this->tests = array_merge($this->tests, $that->getTests());
$this->cachedReport = null;
}
public function enableCheckForUnintentionallyCoveredCode(): void
@@ -486,9 +510,16 @@ final class CodeCoverage
continue;
}
$linesToBranchMap = $this->analyser()->executableLinesIn($filename);
$data->keepLineCoverageDataOnlyForLines(
$filename,
$this->analyser()->executableLinesIn($filename)
array_keys($linesToBranchMap)
);
$data->markExecutableLineByBranch(
$filename,
$linesToBranchMap
);
}
}
@@ -518,7 +549,7 @@ final class CodeCoverage
);
foreach ($uncoveredFiles as $uncoveredFile) {
if (is_file($uncoveredFile)) {
if ($this->filter->isFile($uncoveredFile)) {
$this->append(
RawCodeCoverageData::fromUncoveredFile(
$uncoveredFile,
@@ -543,7 +574,7 @@ final class CodeCoverage
$this->driver->start();
foreach ($uncoveredFiles as $uncoveredFile) {
if (is_file($uncoveredFile)) {
if ($this->filter->isFile($uncoveredFile)) {
include_once $uncoveredFile;
}
}
@@ -644,7 +675,7 @@ final class CodeCoverage
} catch (\ReflectionException $e) {
throw new ReflectionException(
$e->getMessage(),
(int) $e->getCode(),
$e->getCode(),
$e
);
}
@@ -667,7 +698,9 @@ final class CodeCoverage
if ($this->cachesStaticAnalysis()) {
$this->analyser = new CachingFileAnalyser(
$this->cacheDirectory,
$this->analyser
$this->analyser,
$this->useAnnotationsForIgnoringCode,
$this->ignoreDeprecatedCode
);
}

View File

@@ -100,11 +100,7 @@ final class Filter
public function isExcluded(string $filename): bool
{
if (!$this->isFile($filename)) {
return true;
}
return !isset($this->files[$filename]);
return !isset($this->files[$filename]) || !$this->isFile($filename);
}
/**

View File

@@ -46,7 +46,7 @@ abstract class AbstractNode implements Countable
*/
private $id;
public function __construct(string $name, self $parent = null)
public function __construct(string $name, ?self $parent = null)
{
if (substr($name, -1) === DIRECTORY_SEPARATOR) {
$name = substr($name, 0, -1);

View File

@@ -74,8 +74,6 @@ final class Iterator implements RecursiveIterator
/**
* Returns the sub iterator for the current element.
*
* @return Iterator
*/
public function getChildren(): self
{

View File

@@ -15,8 +15,12 @@ use function array_flip;
use function array_intersect;
use function array_intersect_key;
use function count;
use function explode;
use function file_get_contents;
use function in_array;
use function is_file;
use function range;
use function trim;
use SebastianBergmann\CodeCoverage\Driver\Driver;
use SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser;
@@ -87,7 +91,7 @@ final class RawCodeCoverageData
{
$lineCoverage = [];
foreach ($analyser->executableLinesIn($filename) as $line) {
foreach ($analyser->executableLinesIn($filename) as $line => $branch) {
$lineCoverage[$line] = Driver::LINE_NOT_EXECUTED;
}
@@ -137,6 +141,42 @@ final class RawCodeCoverageData
);
}
/**
* @param int[] $linesToBranchMap
*/
public function markExecutableLineByBranch(string $filename, array $linesToBranchMap): void
{
if (!isset($this->lineCoverage[$filename])) {
return;
}
$linesByBranch = [];
foreach ($linesToBranchMap as $line => $branch) {
$linesByBranch[$branch][] = $line;
}
foreach ($this->lineCoverage[$filename] as $line => $lineStatus) {
if (!isset($linesToBranchMap[$line])) {
continue;
}
$branch = $linesToBranchMap[$line];
if (!isset($linesByBranch[$branch])) {
continue;
}
foreach ($linesByBranch[$branch] as $lineInBranch) {
$this->lineCoverage[$filename][$lineInBranch] = $lineStatus;
}
if (Driver::LINE_EXECUTED === $lineStatus) {
unset($linesByBranch[$branch]);
}
}
}
/**
* @param int[] $lines
*/

View File

@@ -16,6 +16,7 @@ use function is_string;
use function ksort;
use function max;
use function range;
use function strpos;
use function time;
use DOMDocument;
use SebastianBergmann\CodeCoverage\CodeCoverage;
@@ -243,7 +244,9 @@ final class Clover
$buffer = $xmlDocument->saveXML();
if ($target !== null) {
Filesystem::createDirectory(dirname($target));
if (!strpos($target, '://') !== false) {
Filesystem::createDirectory(dirname($target));
}
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -9,10 +9,14 @@
*/
namespace SebastianBergmann\CodeCoverage\Report;
use function basename;
use function count;
use function dirname;
use function file_put_contents;
use function preg_match;
use function range;
use function str_replace;
use function strpos;
use function time;
use DOMImplementation;
use SebastianBergmann\CodeCoverage\CodeCoverage;
@@ -25,7 +29,7 @@ final class Cobertura
/**
* @throws WriteOperationFailedException
*/
public function process(CodeCoverage $coverage, ?string $target = null, ?string $name = null): string
public function process(CodeCoverage $coverage, ?string $target = null): string
{
$time = (string) time();
@@ -84,9 +88,8 @@ final class Cobertura
$packageElement = $document->createElement('package');
$packageComplexity = 0;
$packageName = $name ?? '';
$packageElement->setAttribute('name', $packageName);
$packageElement->setAttribute('name', str_replace($report->pathAsString() . DIRECTORY_SEPARATOR, '', $item->pathAsString()));
$linesValid = $item->numberOfExecutableLines();
$linesCovered = $item->numberOfExecutedLines();
@@ -191,7 +194,7 @@ final class Cobertura
}
}
if ($report->numberOfFunctions() === 0) {
if ($item->numberOfFunctions() === 0) {
$packageElement->setAttribute('complexity', (string) $packageComplexity);
continue;
@@ -215,7 +218,7 @@ final class Cobertura
$classElement->appendChild($classLinesElement);
$functions = $report->functions();
$functions = $item->functions();
foreach ($functions as $functionName => $function) {
if ($function['executableLines'] === 0) {
@@ -292,7 +295,9 @@ final class Cobertura
$buffer = $document->saveXML();
if ($target !== null) {
Filesystem::createDirectory(dirname($target));
if (!strpos($target, '://') !== false) {
Filesystem::createDirectory(dirname($target));
}
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -15,6 +15,7 @@ use function file_put_contents;
use function htmlspecialchars;
use function is_string;
use function round;
use function strpos;
use DOMDocument;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
@@ -124,7 +125,9 @@ final class Crap4j
$buffer = $document->saveXML();
if ($target !== null) {
Filesystem::createDirectory(dirname($target));
if (!strpos($target, '://') !== false) {
Filesystem::createDirectory(dirname($target));
}
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -80,6 +80,8 @@ use const T_WHILE;
use const T_YIELD;
use const T_YIELD_FROM;
use function array_key_exists;
use function array_keys;
use function array_merge;
use function array_pop;
use function array_unique;
use function constant;
@@ -89,6 +91,9 @@ use function explode;
use function file_get_contents;
use function htmlspecialchars;
use function is_string;
use function ksort;
use function range;
use function sort;
use function sprintf;
use function str_replace;
use function substr;
@@ -129,7 +134,7 @@ final class File extends Renderer
[
'items' => $this->renderItems($node),
'lines' => $this->renderSourceWithLineCoverage($node),
'legend' => '<p><span class="success"><strong>Executed</strong></span><span class="danger"><strong>Not Executed</strong></span><span class="warning"><strong>Dead Code</strong></span></p>',
'legend' => '<p><span class="legend covered-by-small-tests">Covered by small (and larger) tests</span><span class="legend covered-by-medium-tests">Covered by medium (and large) tests</span><span class="legend covered-by-large-tests">Covered by large tests (and tests of unknown size)</span><span class="legend not-covered">Not covered</span><span class="legend not-coverable">Not coverable</span></p>',
'structure' => '',
]
);
@@ -797,8 +802,15 @@ final class File extends Renderer
$singleLineTemplate = new Template($this->templatePath . 'line.html.dist', '{{', '}}');
$lines = '';
$first = true;
foreach ($path['path'] as $branchId) {
if ($first) {
$first = false;
} else {
$lines .= ' <tr><td colspan="2">&nbsp;</td></tr>' . "\n";
}
$branchLines = range($branches[$branchId]['line_start'], $branches[$branchId]['line_end']);
sort($branchLines); // sometimes end_line < start_line
@@ -834,6 +846,7 @@ final class File extends Renderer
$popoverContent .= $this->createPopoverContentForTest($test, $testData[$test]);
}
$trClass = $lineCss . ' popin';
}

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,9 @@
body {
font-family: sans-serif;
font-size: 1em;
font-kerning: normal;
font-variant-ligatures: common-ligatures;
text-rendering: optimizeLegibility;
padding-top: 10px;
}
@@ -8,6 +13,8 @@ body {
.octicon {
margin-right:.25em;
vertical-align: baseline;
width: 0.75em;
}
.table-bordered>thead>tr>td {
@@ -57,6 +64,7 @@ body {
}
td.big {
vertical-align: middle;
width: 117px;
}
@@ -112,7 +120,7 @@ svg text {
.scrollbox {
height:245px;
overflow-x:hidden;
overflow-x:scroll;
overflow-y:scroll;
}
@@ -120,3 +128,31 @@ table + .structure-heading {
border-top: 1px solid lightgrey;
padding-top: 0.5em;
}
.legend {
font-weight: bold;
margin-right: 2px;
padding-left: 10px;
padding-right: 10px;
text-align: center;
}
.covered-by-small-tests {
background-color: #99cb84;
}
.covered-by-medium-tests {
background-color: #c3e3b5;
}
.covered-by-large-tests {
background-color: #dff0d8;
}
.not-covered {
background-color: #f2dede;
}
.not-coverable {
background-color: #fcf8e3;
}

View File

@@ -4,9 +4,9 @@
<meta charset="UTF-8">
<title>Dashboard for {{full_path}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/nv.d3.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/nv.d3.min.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
</head>
<body>
@@ -137,9 +137,9 @@
</p>
</footer>
</div>
<script src="{{path_to_root}}_js/jquery.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/d3.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/nv.d3.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/jquery.min.js?v={{version}}" type="text/javascript"></script>
<script src="{{path_to_root}}_js/d3.min.js?v={{version}}" type="text/javascript"></script>
<script src="{{path_to_root}}_js/nv.d3.min.js?v={{version}}" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
nv.addGraph(function() {

View File

@@ -4,9 +4,9 @@
<meta charset="UTF-8">
<title>Dashboard for {{full_path}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/nv.d3.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/nv.d3.min.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
</head>
<body>
@@ -137,9 +137,9 @@
</p>
</footer>
</div>
<script src="{{path_to_root}}_js/jquery.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/d3.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/nv.d3.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/jquery.min.js?v={{version}}" type="text/javascript"></script>
<script src="{{path_to_root}}_js/d3.min.js?v={{version}}" type="text/javascript"></script>
<script src="{{path_to_root}}_js/nv.d3.min.js?v={{version}}" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
nv.addGraph(function() {

View File

@@ -4,9 +4,9 @@
<meta charset="UTF-8">
<title>Code Coverage for {{full_path}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/octicons.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/octicons.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
</head>
<body>

View File

@@ -4,9 +4,9 @@
<meta charset="UTF-8">
<title>Code Coverage for {{full_path}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/octicons.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/octicons.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
</head>
<body>

View File

@@ -4,9 +4,9 @@
<meta charset="UTF-8">
<title>Code Coverage for {{full_path}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/octicons.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/octicons.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
</head>
<body>
@@ -57,9 +57,9 @@
</a>
</footer>
</div>
<script src="{{path_to_root}}_js/jquery.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/popper.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/bootstrap.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/file.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/jquery.min.js?v={{version}}" type="text/javascript"></script>
<script src="{{path_to_root}}_js/popper.min.js?v={{version}}" type="text/javascript"></script>
<script src="{{path_to_root}}_js/bootstrap.min.js?v={{version}}" type="text/javascript"></script>
<script src="{{path_to_root}}_js/file.js?v={{version}}" type="text/javascript"></script>
</body>
</html>

View File

@@ -4,9 +4,9 @@
<meta charset="UTF-8">
<title>Code Coverage for {{full_path}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="{{path_to_root}}_css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/octicons.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/bootstrap.min.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/octicons.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/style.css?v={{version}}" rel="stylesheet" type="text/css">
<link href="{{path_to_root}}_css/custom.css" rel="stylesheet" type="text/css">
</head>
<body>
@@ -59,9 +59,9 @@
</a>
</footer>
</div>
<script src="{{path_to_root}}_js/jquery.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/popper.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/bootstrap.min.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/file.js" type="text/javascript"></script>
<script src="{{path_to_root}}_js/jquery.min.js?v={{version}}" type="text/javascript"></script>
<script src="{{path_to_root}}_js/popper.min.js?v={{version}}" type="text/javascript"></script>
<script src="{{path_to_root}}_js/bootstrap.min.js?v={{version}}" type="text/javascript"></script>
<script src="{{path_to_root}}_js/file.js?v={{version}}" type="text/javascript"></script>
</body>
</html>

View File

@@ -1,5 +1,5 @@
<tr>
<td class="{{classes_level}}">{{name}}</td>
<td class="{{lines_level}}">{{name}}</td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>

View File

@@ -1,5 +1,5 @@
<tr>
<td class="{{classes_level}}">{{name}}</td>
<td class="{{lines_level}}">{{name}}</td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
<tr>
<td class="{{methods_level}}">{{name}}</td>
<td class="{{lines_level}}">{{name}}</td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>

View File

@@ -1,5 +1,5 @@
<tr>
<td class="{{methods_level}}">{{name}}</td>
<td class="{{lines_level}}">{{name}}</td>
<td class="{{lines_level}} big">{{lines_bar}}</td>
<td class="{{lines_level}} small"><div align="right">{{lines_executed_percent}}</div></td>
<td class="{{lines_level}} small"><div align="right">{{lines_number}}</div></td>

View File

@@ -12,7 +12,7 @@ namespace SebastianBergmann\CodeCoverage\Report;
use function dirname;
use function file_put_contents;
use function serialize;
use function sprintf;
use function strpos;
use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
use SebastianBergmann\CodeCoverage\Util\Filesystem;
@@ -21,17 +21,15 @@ final class PHP
{
public function process(CodeCoverage $coverage, ?string $target = null): string
{
$buffer = sprintf(
"<?php
return \unserialize(<<<'END_OF_COVERAGE_SERIALIZATION'%s%s%sEND_OF_COVERAGE_SERIALIZATION%s);",
PHP_EOL,
serialize($coverage),
PHP_EOL,
PHP_EOL
);
$coverage->clearCache();
$buffer = "<?php
return \unserialize(<<<'END_OF_COVERAGE_SERIALIZATION'" . PHP_EOL . serialize($coverage) . PHP_EOL . 'END_OF_COVERAGE_SERIALIZATION' . PHP_EOL . ');';
if ($target !== null) {
Filesystem::createDirectory(dirname($target));
if (!strpos($target, '://') !== false) {
Filesystem::createDirectory(dirname($target));
}
if (@file_put_contents($target, $buffer) === false) {
throw new WriteOperationFailedException($target);

View File

@@ -37,7 +37,7 @@ final class Coverage
{
$this->contextNode = $context;
$this->writer = new XMLWriter();
$this->writer = new XMLWriter;
$this->writer->openMemory();
$this->writer->startElementNS(null, $context->nodeName, 'https://schema.phpunit.de/coverage/1.0');
$this->writer->writeAttribute('nr', $line);

View File

@@ -20,7 +20,7 @@ final class Report extends File
{
public function __construct(string $name)
{
$dom = new DOMDocument();
$dom = new DOMDocument;
$dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="https://schema.phpunit.de/coverage/1.0"><file /></phpunit>');
$contextNode = $dom->getElementsByTagNameNS(

View File

@@ -31,7 +31,7 @@ final class Source
{
$context = $this->context;
$tokens = (new Tokenizer())->parse($source);
$tokens = (new Tokenizer)->parse($source);
$srcDom = (new XMLSerializer(new NamespaceUri($context->namespaceURI)))->toDom($tokens);
$context->parentNode->replaceChild(

View File

@@ -17,7 +17,6 @@ use DOMElement;
final class Tests
{
private $contextNode;
private $codeMap = [
-1 => 'UNKNOWN', // PHPUnit_Runner_BaseTestRunner::STATUS_UNKNOWN
0 => 'PASSED', // PHPUnit_Runner_BaseTestRunner::STATUS_PASSED

View File

@@ -20,7 +20,9 @@ final class CacheWarmer
new ParsingFileAnalyser(
$useAnnotationsForIgnoringCode,
$ignoreDeprecatedCode
)
),
$useAnnotationsForIgnoringCode,
$ignoreDeprecatedCode,
);
foreach ($filter->files() as $file) {

View File

@@ -9,15 +9,15 @@
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function assert;
use function crc32;
use function file_get_contents;
use function file_put_contents;
use function implode;
use function is_file;
use function md5;
use function serialize;
use GlobIterator;
use function unserialize;
use SebastianBergmann\CodeCoverage\Util\Filesystem;
use SplFileInfo;
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
/**
* @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
@@ -29,31 +29,39 @@ final class CachingFileAnalyser implements FileAnalyser
*/
private static $cacheVersion;
/**
* @var string
*/
private $directory;
/**
* @var FileAnalyser
*/
private $analyser;
/**
* @var bool
*/
private $useAnnotationsForIgnoringCode;
/**
* @var bool
*/
private $ignoreDeprecatedCode;
/**
* @var array
*/
private $cache = [];
/**
* @var string
*/
private $directory;
public function __construct(string $directory, FileAnalyser $analyser)
public function __construct(string $directory, FileAnalyser $analyser, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode)
{
Filesystem::createDirectory($directory);
$this->analyser = $analyser;
$this->directory = $directory;
if (self::$cacheVersion === null) {
$this->calculateCacheVersion();
}
$this->analyser = $analyser;
$this->directory = $directory;
$this->useAnnotationsForIgnoringCode = $useAnnotationsForIgnoringCode;
$this->ignoreDeprecatedCode = $ignoreDeprecatedCode;
}
public function classesIn(string $filename): array
@@ -165,19 +173,37 @@ final class CachingFileAnalyser implements FileAnalyser
private function cacheFile(string $filename): string
{
return $this->directory . DIRECTORY_SEPARATOR . hash('sha256', $filename . crc32(file_get_contents($filename)) . self::$cacheVersion);
$cacheKey = md5(
implode(
"\0",
[
$filename,
file_get_contents($filename),
self::cacheVersion(),
$this->useAnnotationsForIgnoringCode,
$this->ignoreDeprecatedCode,
]
)
);
return $this->directory . DIRECTORY_SEPARATOR . $cacheKey;
}
private function calculateCacheVersion(): void
private static function cacheVersion(): string
{
$buffer = '';
foreach (new GlobIterator(__DIR__ . '/*.php') as $file) {
assert($file instanceof SplFileInfo);
$buffer .= file_get_contents($file->getPathname());
if (self::$cacheVersion !== null) {
return self::$cacheVersion;
}
self::$cacheVersion = (string) crc32($buffer);
$buffer = [];
foreach ((new FileIteratorFacade)->getFilesAsArray(__DIR__, '.php') as $file) {
$buffer[] = $file;
$buffer[] = file_get_contents($file);
}
self::$cacheVersion = md5(implode("\0", $buffer));
return self::$cacheVersion;
}
}

View File

@@ -9,6 +9,7 @@
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function assert;
use function implode;
use function rtrim;
use function trim;
@@ -25,6 +26,7 @@ use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\Node\UnionType;
use PhpParser\NodeAbstract;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
use SebastianBergmann\Complexity\CyclomaticComplexityCalculatingVisitor;
@@ -179,8 +181,12 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
return '?' . $type->type;
}
if ($type instanceof UnionType || $type instanceof IntersectionType) {
return $this->unionOrIntersectionAsString($type);
if ($type instanceof UnionType) {
return $this->unionTypeAsString($type);
}
if ($type instanceof IntersectionType) {
return $this->intersectionTypeAsString($type);
}
return $type->toString();
@@ -297,27 +303,43 @@ final class CodeUnitFindingVisitor extends NodeVisitorAbstract
return trim(rtrim($namespacedName, $name), '\\');
}
/**
* @psalm-param UnionType|IntersectionType $type
*/
private function unionOrIntersectionAsString(ComplexType $type): string
private function unionTypeAsString(UnionType $node): string
{
if ($type instanceof UnionType) {
$separator = '|';
} else {
$separator = '&';
}
$types = [];
foreach ($type->types as $_type) {
if ($_type instanceof Name) {
$types[] = $_type->toCodeString();
} else {
$types[] = $_type->toString();
foreach ($node->types as $type) {
if ($type instanceof IntersectionType) {
$types[] = '(' . $this->intersectionTypeAsString($type) . ')';
continue;
}
$types[] = $this->typeAsString($type);
}
return implode($separator, $types);
return implode('|', $types);
}
private function intersectionTypeAsString(IntersectionType $node): string
{
$types = [];
foreach ($node->types as $type) {
$types[] = $this->typeAsString($type);
}
return implode('&', $types);
}
/**
* @psalm-param Identifier|Name $node $node
*/
private function typeAsString(NodeAbstract $node): string
{
if ($node instanceof Name) {
return $node->toCodeString();
}
return $node->toString();
}
}

View File

@@ -9,46 +9,19 @@
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function array_diff_key;
use function assert;
use function count;
use function current;
use function end;
use function explode;
use function max;
use function preg_match;
use function preg_quote;
use function range;
use function reset;
use function sprintf;
use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\CallLike;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Match_;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\NullsafePropertyFetch;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\MatchArm;
use PhpParser\Node\Scalar\Encapsed;
use PhpParser\Node\Stmt\Break_;
use PhpParser\Node\Stmt\Case_;
use PhpParser\Node\Stmt\Catch_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Continue_;
use PhpParser\Node\Stmt\Do_;
use PhpParser\Node\Stmt\Echo_;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\ElseIf_;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Finally_;
use PhpParser\Node\Stmt\For_;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\Goto_;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Switch_;
use PhpParser\Node\Stmt\Throw_;
use PhpParser\Node\Stmt\TryCatch;
use PhpParser\Node\Stmt\Unset_;
use PhpParser\Node\Stmt\While_;
use PhpParser\NodeVisitorAbstract;
/**
@@ -57,217 +30,361 @@ use PhpParser\NodeVisitorAbstract;
final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
{
/**
* @psalm-var array<int, int>
* @var int
*/
private $executableLines = [];
private $nextBranch = 0;
/**
* @psalm-var array<int, int>
* @var string
*/
private $propertyLines = [];
private $source;
/**
* @psalm-var array<int, Return_>
* @var array<int, int>
*/
private $returns = [];
private $executableLinesGroupedByBranch = [];
/**
* @var array<int, bool>
*/
private $unsets = [];
/**
* @var array<int, string>
*/
private $commentsToCheckForUnset = [];
public function __construct(string $source)
{
$this->source = $source;
}
public function enterNode(Node $node): void
{
$this->savePropertyLines($node);
foreach ($node->getComments() as $comment) {
$commentLine = $comment->getStartLine();
if (!isset($this->executableLinesGroupedByBranch[$commentLine])) {
continue;
}
foreach (explode("\n", $comment->getText()) as $text) {
$this->commentsToCheckForUnset[$commentLine] = $text;
$commentLine++;
}
}
if ($node instanceof Node\Scalar\String_ ||
$node instanceof Node\Scalar\EncapsedStringPart) {
$startLine = $node->getStartLine() + 1;
$endLine = $node->getEndLine() - 1;
if ($startLine <= $endLine) {
foreach (range($startLine, $endLine) as $line) {
unset($this->executableLinesGroupedByBranch[$line]);
}
}
if (!$this->isExecutable($node)) {
return;
}
foreach ($this->getLines($node) as $line) {
if (isset($this->propertyLines[$line])) {
if ($node instanceof Node\Stmt\Interface_) {
foreach (range($node->getStartLine(), $node->getEndLine()) as $line) {
$this->unsets[$line] = true;
}
return;
}
if ($node instanceof Node\Stmt\Declare_ ||
$node instanceof Node\Stmt\DeclareDeclare ||
$node instanceof Node\Stmt\Else_ ||
$node instanceof Node\Stmt\EnumCase ||
$node instanceof Node\Stmt\Finally_ ||
$node instanceof Node\Stmt\GroupUse ||
$node instanceof Node\Stmt\Label ||
$node instanceof Node\Stmt\Namespace_ ||
$node instanceof Node\Stmt\Nop ||
$node instanceof Node\Stmt\Switch_ ||
$node instanceof Node\Stmt\TryCatch ||
$node instanceof Node\Stmt\Use_ ||
$node instanceof Node\Stmt\UseUse ||
$node instanceof Node\Expr\ConstFetch ||
$node instanceof Node\Expr\Match_ ||
$node instanceof Node\Expr\Variable ||
$node instanceof Node\Expr\Throw_ ||
$node instanceof Node\ComplexType ||
$node instanceof Node\Const_ ||
$node instanceof Node\Identifier ||
$node instanceof Node\Name ||
$node instanceof Node\Param ||
$node instanceof Node\Scalar) {
return;
}
/*
* nikic/php-parser ^4.18 represents <code>throw</code> statements
* as <code>Stmt\Throw_</code> objects
*/
if ($node instanceof Node\Stmt\Throw_) {
$this->setLineBranch($node->expr->getEndLine(), $node->expr->getEndLine(), ++$this->nextBranch);
return;
}
/*
* nikic/php-parser ^5 represents <code>throw</code> statements
* as <code>Stmt\Expression</code> objects that contain an
* <code>Expr\Throw_</code> object
*/
if ($node instanceof Node\Stmt\Expression && $node->expr instanceof Node\Expr\Throw_) {
$this->setLineBranch($node->expr->expr->getEndLine(), $node->expr->expr->getEndLine(), ++$this->nextBranch);
return;
}
if ($node instanceof Node\Stmt\Enum_ ||
$node instanceof Node\Stmt\Function_ ||
$node instanceof Node\Stmt\Class_ ||
$node instanceof Node\Stmt\ClassMethod ||
$node instanceof Node\Expr\Closure ||
$node instanceof Node\Stmt\Trait_) {
$isConcreteClassLike = $node instanceof Node\Stmt\Enum_ || $node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Trait_;
if (null !== $node->stmts) {
foreach ($node->stmts as $stmt) {
if ($stmt instanceof Node\Stmt\Nop) {
continue;
}
foreach (range($stmt->getStartLine(), $stmt->getEndLine()) as $line) {
unset($this->executableLinesGroupedByBranch[$line]);
if (
$isConcreteClassLike &&
!$stmt instanceof Node\Stmt\ClassMethod
) {
$this->unsets[$line] = true;
}
}
}
}
if ($isConcreteClassLike) {
return;
}
$this->executableLines[$line] = $line;
}
}
$hasEmptyBody = [] === $node->stmts ||
null === $node->stmts ||
(
1 === count($node->stmts) &&
$node->stmts[0] instanceof Node\Stmt\Nop
);
/**
* @psalm-return array<int, int>
*/
public function executableLines(): array
{
$this->computeReturns();
if ($hasEmptyBody) {
if ($node->getEndLine() === $node->getStartLine()) {
return;
}
sort($this->executableLines);
$this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch);
return $this->executableLines;
}
return;
}
private function savePropertyLines(Node $node): void
{
if (!$node instanceof Property && !$node instanceof Node\Stmt\ClassConst) {
return;
}
foreach (range($node->getStartLine(), $node->getEndLine()) as $index) {
$this->propertyLines[$index] = $index;
}
}
if ($node instanceof Node\Expr\ArrowFunction) {
$startLine = max(
$node->getStartLine() + 1,
$node->expr->getStartLine()
);
private function computeReturns(): void
{
foreach ($this->returns as $return) {
foreach (range($return->getStartLine(), $return->getEndLine()) as $loc) {
if (isset($this->executableLines[$loc])) {
continue 2;
$endLine = $node->expr->getEndLine();
if ($endLine < $startLine) {
return;
}
$this->setLineBranch($startLine, $endLine, ++$this->nextBranch);
return;
}
if ($node instanceof Node\Expr\Ternary) {
if (null !== $node->if &&
$node->getStartLine() !== $node->if->getEndLine()) {
$this->setLineBranch($node->if->getStartLine(), $node->if->getEndLine(), ++$this->nextBranch);
}
if ($node->getStartLine() !== $node->else->getEndLine()) {
$this->setLineBranch($node->else->getStartLine(), $node->else->getEndLine(), ++$this->nextBranch);
}
return;
}
if ($node instanceof Node\Expr\BinaryOp\Coalesce) {
if ($node->getStartLine() !== $node->getEndLine()) {
$this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch);
}
return;
}
if ($node instanceof Node\Stmt\If_ ||
$node instanceof Node\Stmt\ElseIf_ ||
$node instanceof Node\Stmt\Case_) {
if (null === $node->cond) {
return;
}
$this->setLineBranch(
$node->cond->getStartLine(),
$node->cond->getStartLine(),
++$this->nextBranch
);
return;
}
if ($node instanceof Node\Stmt\For_) {
$startLine = null;
$endLine = null;
if ([] !== $node->init) {
$startLine = $node->init[0]->getStartLine();
end($node->init);
$endLine = current($node->init)->getEndLine();
reset($node->init);
}
if ([] !== $node->cond) {
if (null === $startLine) {
$startLine = $node->cond[0]->getStartLine();
}
end($node->cond);
$endLine = current($node->cond)->getEndLine();
reset($node->cond);
}
$line = $return->getEndLine();
if ($return->expr !== null) {
$line = $return->expr->getStartLine();
}
$this->executableLines[$line] = $line;
}
}
/**
* @return int[]
*/
private function getLines(Node $node): array
{
if ($node instanceof Cast ||
$node instanceof PropertyFetch ||
$node instanceof NullsafePropertyFetch ||
$node instanceof StaticPropertyFetch) {
return [$node->getEndLine()];
}
if ($node instanceof ArrayDimFetch) {
if (null === $node->dim) {
return [];
}
return [$node->dim->getStartLine()];
}
if ($node instanceof Array_) {
$startLine = $node->getStartLine();
if (isset($this->executableLines[$startLine])) {
return [];
}
if ([] === $node->items) {
return [$node->getEndLine()];
}
if ($node->items[0] instanceof ArrayItem) {
return [$node->items[0]->getStartLine()];
}
}
if ($node instanceof ClassMethod) {
if ($node->name->name !== '__construct') {
return [];
}
$existsAPromotedProperty = false;
foreach ($node->getParams() as $param) {
if (0 !== ($param->flags & Class_::VISIBILITY_MODIFIER_MASK)) {
$existsAPromotedProperty = true;
break;
if ([] !== $node->loop) {
if (null === $startLine) {
$startLine = $node->loop[0]->getStartLine();
}
end($node->loop);
$endLine = current($node->loop)->getEndLine();
reset($node->loop);
}
if ($existsAPromotedProperty) {
// Only the line with `function` keyword should be listed here
// but `nikic/php-parser` doesn't provide a way to fetch it
return range($node->getStartLine(), $node->name->getEndLine());
if (null === $startLine || null === $endLine) {
return;
}
return [];
$this->setLineBranch(
$startLine,
$endLine,
++$this->nextBranch
);
return;
}
if ($node instanceof MethodCall) {
return [$node->name->getStartLine()];
if ($node instanceof Node\Stmt\Foreach_) {
$this->setLineBranch(
$node->expr->getStartLine(),
$node->valueVar->getEndLine(),
++$this->nextBranch
);
return;
}
if ($node instanceof Ternary) {
$lines = [$node->cond->getStartLine()];
if ($node instanceof Node\Stmt\While_ ||
$node instanceof Node\Stmt\Do_) {
$this->setLineBranch(
$node->cond->getStartLine(),
$node->cond->getEndLine(),
++$this->nextBranch
);
if (null !== $node->if) {
$lines[] = $node->if->getStartLine();
return;
}
if ($node instanceof Node\Stmt\Catch_) {
assert([] !== $node->types);
$startLine = $node->types[0]->getStartLine();
end($node->types);
$endLine = current($node->types)->getEndLine();
$this->setLineBranch(
$startLine,
$endLine,
++$this->nextBranch
);
return;
}
if ($node instanceof Node\Expr\CallLike) {
if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) {
$branch = $this->executableLinesGroupedByBranch[$node->getStartLine()];
} else {
$branch = ++$this->nextBranch;
}
$lines[] = $node->else->getStartLine();
$this->setLineBranch($node->getStartLine(), $node->getEndLine(), $branch);
return $lines;
return;
}
if ($node instanceof Match_) {
return [$node->cond->getStartLine()];
if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) {
return;
}
if ($node instanceof MatchArm) {
return [$node->body->getStartLine()];
}
if ($node instanceof Expression && (
$node->expr instanceof Cast ||
$node->expr instanceof Match_ ||
$node->expr instanceof MethodCall
)) {
return [];
}
if ($node instanceof Return_) {
$this->returns[] = $node;
return [];
}
return [$node->getStartLine()];
$this->setLineBranch($node->getStartLine(), $node->getEndLine(), ++$this->nextBranch);
}
private function isExecutable(Node $node): bool
public function afterTraverse(array $nodes): void
{
return $node instanceof Assign ||
$node instanceof ArrayDimFetch ||
$node instanceof Array_ ||
$node instanceof BinaryOp ||
$node instanceof Break_ ||
$node instanceof CallLike ||
$node instanceof Case_ ||
$node instanceof Cast ||
$node instanceof Catch_ ||
$node instanceof ClassMethod ||
$node instanceof Closure ||
$node instanceof Continue_ ||
$node instanceof Do_ ||
$node instanceof Echo_ ||
$node instanceof ElseIf_ ||
$node instanceof Else_ ||
$node instanceof Encapsed ||
$node instanceof Expression ||
$node instanceof Finally_ ||
$node instanceof For_ ||
$node instanceof Foreach_ ||
$node instanceof Goto_ ||
$node instanceof If_ ||
$node instanceof Match_ ||
$node instanceof MatchArm ||
$node instanceof MethodCall ||
$node instanceof NullsafePropertyFetch ||
$node instanceof PropertyFetch ||
$node instanceof Return_ ||
$node instanceof StaticPropertyFetch ||
$node instanceof Switch_ ||
$node instanceof Ternary ||
$node instanceof Throw_ ||
$node instanceof TryCatch ||
$node instanceof Unset_ ||
$node instanceof While_;
$lines = explode("\n", $this->source);
foreach ($lines as $lineNumber => $line) {
$lineNumber++;
if (1 === preg_match('/^\s*$/', $line) ||
(
isset($this->commentsToCheckForUnset[$lineNumber]) &&
1 === preg_match(sprintf('/^\s*%s\s*$/', preg_quote($this->commentsToCheckForUnset[$lineNumber], '/')), $line)
)) {
unset($this->executableLinesGroupedByBranch[$lineNumber]);
}
}
$this->executableLinesGroupedByBranch = array_diff_key(
$this->executableLinesGroupedByBranch,
$this->unsets
);
}
public function executableLinesGroupedByBranch(): array
{
return $this->executableLinesGroupedByBranch;
}
private function setLineBranch(int $start, int $end, int $branch): void
{
foreach (range($start, $end) as $line) {
$this->executableLinesGroupedByBranch[$line] = $branch;
}
}
}

View File

@@ -10,9 +10,11 @@
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function array_merge;
use function assert;
use function range;
use function strpos;
use PhpParser\Node;
use PhpParser\Node\Attribute;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
@@ -52,7 +54,8 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
!$node instanceof Trait_ &&
!$node instanceof Interface_ &&
!$node instanceof ClassMethod &&
!$node instanceof Function_) {
!$node instanceof Function_ &&
!$node instanceof Attribute) {
return;
}
@@ -60,11 +63,16 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
return;
}
// Workaround for https://bugs.xdebug.org/view.php?id=1798
if ($node instanceof Class_ ||
$node instanceof Trait_ ||
$node instanceof Interface_) {
$node instanceof Interface_ ||
$node instanceof Attribute) {
$this->ignoredLines[] = $node->getStartLine();
assert($node->name !== null);
// Workaround for https://github.com/nikic/PHP-Parser/issues/886
$this->ignoredLines[] = $node->name->getStartLine();
}
if (!$this->useAnnotationsForIgnoringCode) {
@@ -75,6 +83,19 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
return;
}
$this->processDocComment($node);
}
/**
* @psalm-return list<int>
*/
public function ignoredLines(): array
{
return $this->ignoredLines;
}
private function processDocComment(Node $node): void
{
$docComment = $node->getDocComment();
if ($docComment === null) {
@@ -95,12 +116,4 @@ final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract
);
}
}
/**
* @psalm-return list<int>
*/
public function ignoredLines(): array
{
return $this->ignoredLines;
}
}

View File

@@ -9,17 +9,19 @@
*/
namespace SebastianBergmann\CodeCoverage\StaticAnalysis;
use function array_merge;
use function array_unique;
use function assert;
use function file_get_contents;
use function is_array;
use function max;
use function range;
use function sort;
use function sprintf;
use function substr_count;
use function token_get_all;
use function trim;
use PhpParser\Error;
use PhpParser\Lexer;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\NodeVisitor\ParentConnectingVisitor;
@@ -139,10 +141,7 @@ final class ParsingFileAnalyser implements FileAnalyser
$linesOfCode = 1;
}
$parser = (new ParserFactory)->create(
ParserFactory::PREFER_PHP7,
new Lexer
);
$parser = (new ParserFactory)->createForHostVersion();
try {
$nodes = $parser->parse($source);
@@ -153,7 +152,7 @@ final class ParsingFileAnalyser implements FileAnalyser
$codeUnitFindingVisitor = new CodeUnitFindingVisitor;
$lineCountingVisitor = new LineCountingVisitor($linesOfCode);
$ignoredLinesFindingVisitor = new IgnoredLinesFindingVisitor($this->useAnnotationsForIgnoringCode, $this->ignoreDeprecatedCode);
$executableLinesFindingVisitor = new ExecutableLinesFindingVisitor;
$executableLinesFindingVisitor = new ExecutableLinesFindingVisitor($source);
$traverser->addVisitor(new NameResolver);
$traverser->addVisitor(new ParentConnectingVisitor);
@@ -172,7 +171,7 @@ final class ParsingFileAnalyser implements FileAnalyser
$filename,
$error->getMessage()
),
(int) $error->getCode(),
$error->getCode(),
$error
);
}
@@ -181,7 +180,7 @@ final class ParsingFileAnalyser implements FileAnalyser
$this->classes[$filename] = $codeUnitFindingVisitor->classes();
$this->traits[$filename] = $codeUnitFindingVisitor->traits();
$this->functions[$filename] = $codeUnitFindingVisitor->functions();
$this->executableLines[$filename] = $executableLinesFindingVisitor->executableLines();
$this->executableLines[$filename] = $executableLinesFindingVisitor->executableLinesGroupedByBranch();
$this->ignoredLines[$filename] = [];
$this->findLinesIgnoredByLineBasedAnnotations($filename, $source, $this->useAnnotationsForIgnoringCode);
@@ -206,45 +205,44 @@ final class ParsingFileAnalyser implements FileAnalyser
private function findLinesIgnoredByLineBasedAnnotations(string $filename, string $source, bool $useAnnotationsForIgnoringCode): void
{
$ignore = false;
$stop = false;
if (!$useAnnotationsForIgnoringCode) {
return;
}
$start = false;
foreach (token_get_all($source) as $token) {
if (!is_array($token)) {
if (!is_array($token) ||
!(T_COMMENT === $token[0] || T_DOC_COMMENT === $token[0])) {
continue;
}
switch ($token[0]) {
case T_COMMENT:
case T_DOC_COMMENT:
if (!$useAnnotationsForIgnoringCode) {
break;
}
$comment = trim($token[1]);
$comment = trim($token[1]);
if ($comment === '// @codeCoverageIgnore' ||
$comment === '//@codeCoverageIgnore') {
$ignore = true;
$stop = true;
} elseif ($comment === '// @codeCoverageIgnoreStart' ||
$comment === '//@codeCoverageIgnoreStart') {
$ignore = true;
} elseif ($comment === '// @codeCoverageIgnoreEnd' ||
$comment === '//@codeCoverageIgnoreEnd') {
$stop = true;
}
break;
}
if ($ignore) {
if ($comment === '// @codeCoverageIgnore' ||
$comment === '//@codeCoverageIgnore') {
$this->ignoredLines[$filename][] = $token[2];
if ($stop) {
$ignore = false;
$stop = false;
continue;
}
if ($comment === '// @codeCoverageIgnoreStart' ||
$comment === '//@codeCoverageIgnoreStart') {
$start = $token[2];
continue;
}
if ($comment === '// @codeCoverageIgnoreEnd' ||
$comment === '//@codeCoverageIgnoreEnd') {
if (false === $start) {
$start = $token[2];
}
$this->ignoredLines[$filename] = array_merge(
$this->ignoredLines[$filename],
range($start, $token[2])
);
}
}
}

View File

@@ -22,7 +22,7 @@ final class Version
public static function id(): string
{
if (self::$version === null) {
self::$version = (new VersionId('9.2.15', dirname(__DIR__)))->getVersion();
self::$version = (new VersionId('9.2.31', dirname(__DIR__)))->getVersion();
}
return self::$version;

View File

@@ -1,248 +0,0 @@
# Changes in PHPUnit 8.5
All notable changes of the PHPUnit 8.5 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [8.5.26] - 2022-04-01
### Fixed
* [#4938](https://github.com/sebastianbergmann/phpunit/issues/4938): Test Double code generator does not handle `void` return type declaration on `__clone()` methods
## [8.5.25] - 2022-03-16
### Fixed
* [#4934](https://github.com/sebastianbergmann/phpunit/issues/4934): Code Coverage does not work with PHPUnit 8.5.24 PHAR on PHP 7
## [8.5.24] - 2022-03-05 - #StandWithUkraine
### Changed
* [#4874](https://github.com/sebastianbergmann/phpunit/pull/4874): `PHP_FLOAT_EPSILON` is now used instead of hardcoded `0.0000000001` in `PHPUnit\Framework\Constraint\IsIdentical`
### Fixed
* When the HTML code coverage report's configured low upper bound is larger than the high lower bound then the default values are used instead
## [8.5.23] - 2022-01-21
### Fixed
* [#4799](https://github.com/sebastianbergmann/phpunit/pull/4799): Memory leaks in `PHPUnit\Framework\TestSuite` class
* [#4857](https://github.com/sebastianbergmann/phpunit/pull/4857): Result of `debug_backtrace()` is not used correctly
## [8.5.22] - 2021-12-25
### Changed
* [#4812](https://github.com/sebastianbergmann/phpunit/issues/4812): Do not enforce time limits when a debugging session through DBGp is active
* [#4835](https://github.com/sebastianbergmann/phpunit/issues/4835): Support for `$GLOBALS['_composer_autoload_path']` introduced in Composer 2.2
### Fixed
* [#4840](https://github.com/sebastianbergmann/phpunit/pull/4840): TestDox prettifying for class names does not correctly handle diacritics
* [#4846](https://github.com/sebastianbergmann/phpunit/pull/4846): Composer proxy script is not ignored
## [8.5.21] - 2021-09-25
### Changed
* PHPUnit no longer converts PHP deprecations to exceptions by default (configure `convertDeprecationsToExceptions="true"` to enable this)
* The PHPUnit XML configuration file generator now configures `convertDeprecationsToExceptions="true"`
### Fixed
* [#4772](https://github.com/sebastianbergmann/phpunit/pull/4772): TestDox HTML report not displayed correctly when browser has custom colour settings
## [8.5.20] - 2021-08-31
### Fixed
* [#4751](https://github.com/sebastianbergmann/phpunit/issues/4751): Configuration validation fails when using brackets in glob pattern
## [8.5.19] - 2021-07-31
### Fixed
* [#4740](https://github.com/sebastianbergmann/phpunit/issues/4740): `phpunit.phar` does not work with PHP 8.1
## [8.5.18] - 2021-07-19
### Fixed
* [#4720](https://github.com/sebastianbergmann/phpunit/issues/4720): PHPUnit does not verify its own PHP extension requirements
## [8.5.17] - 2021-06-23
### Changed
* PHPUnit now errors out on startup when `PHP_VERSION` contains a value that is not compatible with `version_compare()`, for instance `X.Y.Z-(to be removed in future macOS)`
## [8.5.16] - 2021-06-05
### Changed
* The test result cache (the storage for which is implemented in `PHPUnit\Runner\DefaultTestResultCache`) no longer uses PHP's `serialize()` and `unserialize()` functions for persistence. It now uses a versioned JSON format instead that is independent of PHP implementation details (see [#3581](https://github.com/sebastianbergmann/phpunit/issues/3581) and [#4662](https://github.com/sebastianbergmann/phpunit/pull/4662) for examples why this is a problem). When PHPUnit tries to load the test result cache from a file that does not exist, or from a file that does not contain data in JSON format, or from a file that contains data in a JSON format version other than the one used by the currently running PHPUnit version, then this is considered to be a "cache miss". An empty `DefaultTestResultCache` object is created in this case. This should also prevent PHPUnit from crashing when trying to load a test result cache file created by a different version of PHPUnit (see [#4580](https://github.com/sebastianbergmann/phpunit/issues/4580) for example).
### Fixed
* [#4663](https://github.com/sebastianbergmann/phpunit/issues/4663): `TestCase::expectError()` works on PHP 7.3, but not on PHP >= 7.4
* [#4678](https://github.com/sebastianbergmann/phpunit/pull/4678): Stubbed methods with `iterable` return types should return empty array by default
* [#4692](https://github.com/sebastianbergmann/phpunit/issues/4692): Annotations in single-line doc-comments are not handled correctly
* [#4694](https://github.com/sebastianbergmann/phpunit/issues/4694): `TestCase::getMockFromWsdl()` does not work with PHP 8.1-dev
## [8.5.15] - 2021-03-17
### Fixed
* [#4591](https://github.com/sebastianbergmann/phpunit/issues/4591): TeamCity logger logs warnings as test failures
## [8.5.14] - 2021-01-17
### Fixed
* [#4535](https://github.com/sebastianbergmann/phpunit/issues/4535): `getMockFromWsdl()` does not handle methods that do not have parameters correctly
* [#4572](https://github.com/sebastianbergmann/phpunit/issues/4572): Schema validation does not work with `%xx` sequences in path to `phpunit.xsd`
* [#4575](https://github.com/sebastianbergmann/phpunit/issues/4575): PHPUnit 8.5 incompatibility with PHP 8.1
## [8.5.13] - 2020-12-01
### Fixed
* Running tests in isolated processes did not work with PHP 8 on Windows
## [8.5.12] - 2020-11-30
### Changed
* Changed PHP version constraint in `composer.json` from `^7.2` to `>=7.2` to allow the installation of PHPUnit 8.5 on PHP 8. Please note that the code coverage functionality is not available for PHPUnit 8.5 on PHP 8.
### Fixed
* [#4529](https://github.com/sebastianbergmann/phpunit/issues/4529): Debug mode of Xdebug 2 is not disabled for PHPT tests
## [8.5.11] - 2020-11-27
### Changed
* Bumped required version of `phpunit/php-code-coverage`
## [8.5.10] - 2020-11-27
### Added
* Support for Xdebug 3
### Fixed
* [#4516](https://github.com/sebastianbergmann/phpunit/issues/4516): `phpunit/phpunit-selenium` does not work with PHPUnit 8.5.9
## [8.5.9] - 2020-11-10
### Fixed
* [#3965](https://github.com/sebastianbergmann/phpunit/issues/3965): Process Isolation throws exceptions when PHPDBG is used
* [#4470](https://github.com/sebastianbergmann/phpunit/pull/4470): Infinite recursion when `--static-backup --strict-global-state` is used
## [8.5.8] - 2020-06-22
### Fixed
* [#4312](https://github.com/sebastianbergmann/phpunit/issues/4312): Fix for [#4299](https://github.com/sebastianbergmann/phpunit/issues/4299) breaks backward compatibility
## [8.5.7] - 2020-06-21
### Fixed
* [#4299](https://github.com/sebastianbergmann/phpunit/issues/4299): "No tests executed" does not always result in exit code `1`
* [#4306](https://github.com/sebastianbergmann/phpunit/issues/4306): Exceptions during code coverage driver initialization are not handled correctly
## [8.5.6] - 2020-06-15
### Fixed
* [#4211](https://github.com/sebastianbergmann/phpunit/issues/4211): `phpdbg_*()` functions are scoped to `PHPUnit\phpdbg_*()`
## [8.5.5] - 2020-05-22
### Fixed
* [#4033](https://github.com/sebastianbergmann/phpunit/issues/4033): Unexpected behaviour when `$GLOBALS` is deleted
## [8.5.4] - 2020-04-23
### Changed
* Changed how `PHPUnit\TextUI\Command` passes warnings to `PHPUnit\TextUI\TestRunner`
## [8.5.3] - 2020-03-31
### Fixed
* [#4017](https://github.com/sebastianbergmann/phpunit/issues/4017): Do not suggest refactoring to something that is also deprecated
* [#4133](https://github.com/sebastianbergmann/phpunit/issues/4133): `expectExceptionMessageRegExp()` has been removed in PHPUnit 9 without a deprecation warning being given in PHPUnit 8
* [#4139](https://github.com/sebastianbergmann/phpunit/issues/4139): Cannot double interfaces that declare a constructor with PHP 8
* [#4144](https://github.com/sebastianbergmann/phpunit/issues/4144): Empty objects are converted to empty arrays in JSON comparison failure diff
## [8.5.2] - 2020-01-08
### Removed
* `eval-stdin.php` has been removed, it was not used anymore since PHPUnit 7.2.7
## [8.5.1] - 2019-12-25
### Changed
* `eval-stdin.php` can now only be executed with `cli` and `phpdbg`
### Fixed
* [#3983](https://github.com/sebastianbergmann/phpunit/issues/3983): Deprecation warning given too eagerly
## [8.5.0] - 2019-12-06
### Added
* [#3911](https://github.com/sebastianbergmann/phpunit/issues/3911): Support combined use of `addMethods()` and `onlyMethods()`
* [#3949](https://github.com/sebastianbergmann/phpunit/issues/3949): Introduce specialized assertions `assertFileEqualsCanonicalizing()`, `assertFileEqualsIgnoringCase()`, `assertStringEqualsFileCanonicalizing()`, `assertStringEqualsFileIgnoringCase()`, `assertFileNotEqualsCanonicalizing()`, `assertFileNotEqualsIgnoringCase()`, `assertStringNotEqualsFileCanonicalizing()`, and `assertStringNotEqualsFileIgnoringCase()` as alternative to using `assertFileEquals()` etc. with optional parameters
### Changed
* [#3860](https://github.com/sebastianbergmann/phpunit/pull/3860): Deprecate invoking PHPUnit commandline test runner with just a class name
* [#3950](https://github.com/sebastianbergmann/phpunit/issues/3950): Deprecate optional parameters of `assertFileEquals()` etc.
* [#3955](https://github.com/sebastianbergmann/phpunit/issues/3955): Deprecate support for doubling multiple interfaces
### Fixed
* [#3953](https://github.com/sebastianbergmann/phpunit/issues/3953): Code Coverage for test executed in isolation does not work when the PHAR is used
* [#3967](https://github.com/sebastianbergmann/phpunit/issues/3967): Cannot double interface that extends interface that extends `\Throwable`
* [#3968](https://github.com/sebastianbergmann/phpunit/pull/3968): Test class run in a separate PHP process are passing when `exit` called inside
[8.5.26]: https://github.com/sebastianbergmann/phpunit/compare/8.5.25...8.5.26
[8.5.25]: https://github.com/sebastianbergmann/phpunit/compare/8.5.24...8.5.25
[8.5.24]: https://github.com/sebastianbergmann/phpunit/compare/8.5.23...8.5.24
[8.5.23]: https://github.com/sebastianbergmann/phpunit/compare/8.5.22...8.5.23
[8.5.22]: https://github.com/sebastianbergmann/phpunit/compare/8.5.21...8.5.22
[8.5.21]: https://github.com/sebastianbergmann/phpunit/compare/8.5.20...8.5.21
[8.5.20]: https://github.com/sebastianbergmann/phpunit/compare/8.5.19...8.5.20
[8.5.19]: https://github.com/sebastianbergmann/phpunit/compare/8.5.18...8.5.19
[8.5.18]: https://github.com/sebastianbergmann/phpunit/compare/8.5.17...8.5.18
[8.5.17]: https://github.com/sebastianbergmann/phpunit/compare/8.5.16...8.5.17
[8.5.16]: https://github.com/sebastianbergmann/phpunit/compare/8.5.15...8.5.16
[8.5.15]: https://github.com/sebastianbergmann/phpunit/compare/8.5.14...8.5.15
[8.5.14]: https://github.com/sebastianbergmann/phpunit/compare/8.5.13...8.5.14
[8.5.13]: https://github.com/sebastianbergmann/phpunit/compare/8.5.12...8.5.13
[8.5.12]: https://github.com/sebastianbergmann/phpunit/compare/8.5.11...8.5.12
[8.5.11]: https://github.com/sebastianbergmann/phpunit/compare/8.5.10...8.5.11
[8.5.10]: https://github.com/sebastianbergmann/phpunit/compare/8.5.9...8.5.10
[8.5.9]: https://github.com/sebastianbergmann/phpunit/compare/8.5.8...8.5.9
[8.5.8]: https://github.com/sebastianbergmann/phpunit/compare/8.5.7...8.5.8
[8.5.7]: https://github.com/sebastianbergmann/phpunit/compare/8.5.6...8.5.7
[8.5.6]: https://github.com/sebastianbergmann/phpunit/compare/8.5.5...8.5.6
[8.5.5]: https://github.com/sebastianbergmann/phpunit/compare/8.5.4...8.5.5
[8.5.4]: https://github.com/sebastianbergmann/phpunit/compare/8.5.3...8.5.4
[8.5.3]: https://github.com/sebastianbergmann/phpunit/compare/8.5.2...8.5.3
[8.5.2]: https://github.com/sebastianbergmann/phpunit/compare/8.5.1...8.5.2
[8.5.1]: https://github.com/sebastianbergmann/phpunit/compare/8.5.0...8.5.1
[8.5.0]: https://github.com/sebastianbergmann/phpunit/compare/8.4.3...8.5.0

View File

@@ -1,180 +0,0 @@
# Changes in PHPUnit 9.5
All notable changes of the PHPUnit 9.5 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [9.5.20] - 2022-04-01
### Fixed
* [#4938](https://github.com/sebastianbergmann/phpunit/issues/4938): Test Double code generator does not handle `void` return type declaration on `__clone()` methods
* [#4947](https://github.com/sebastianbergmann/phpunit/issues/4947): Test annotated with `@coversNothing` may lead to files missing from code coverage report
## [9.5.19] - 2022-03-15
### Fixed
* [#4929](https://github.com/sebastianbergmann/phpunit/issues/4929): Test Double code generator does not handle new expressions inside parameter default values
* [#4932](https://github.com/sebastianbergmann/phpunit/issues/4932): Backport support for intersection types from PHPUnit 10 to PHPUnit 9.5
* [#4933](https://github.com/sebastianbergmann/phpunit/issues/4933): Backport support for `never` type from PHPUnit 10 to PHPUnit 9.5
## [9.5.18] - 2022-03-08
### Fixed
* [#4877](https://github.com/sebastianbergmann/phpunit/issues/4877): No stack trace shown when an error occurs during bootstrap
## [9.5.17] - 2022-03-05 - #StandWithUkraine
## [9.5.16] - 2022-02-23
### Changed
* Reverted sync with API change in (now yanked) phpunit/php-code-coverage 9.2.12
## [9.5.15] - 2022-02-23 [YANKED]
### Fixed
* When the HTML code coverage report's configured low upper bound is larger than the high lower bound then the default values are used instead
## [9.5.14] - 2022-02-18
### Changed
* [#4874](https://github.com/sebastianbergmann/phpunit/pull/4874): `PHP_FLOAT_EPSILON` is now used instead of hardcoded `0.0000000001` in `PHPUnit\Framework\Constraint\IsIdentical`
## [9.5.13] - 2022-01-24
### Fixed
* [#4871](https://github.com/sebastianbergmann/phpunit/issues/4871): Class `SebastianBergmann\CodeCoverage\Filter` is not found during PHPT tests when PHPUnit is used from PHAR
## [9.5.12] - 2022-01-21
### Fixed
* [#4799](https://github.com/sebastianbergmann/phpunit/pull/4799): Memory leaks in `PHPUnit\Framework\TestSuite` class
* [#4857](https://github.com/sebastianbergmann/phpunit/pull/4857): Result of `debug_backtrace()` is not used correctly
## [9.5.11] - 2021-12-25
### Changed
* [#4812](https://github.com/sebastianbergmann/phpunit/issues/4812): Do not enforce time limits when a debugging session through DBGp is active
* [#4835](https://github.com/sebastianbergmann/phpunit/issues/4835): Support for `$GLOBALS['_composer_autoload_path']` introduced in Composer 2.2
### Fixed
* [#4840](https://github.com/sebastianbergmann/phpunit/pull/4840): TestDox prettifying for class names does not correctly handle diacritics
* [#4846](https://github.com/sebastianbergmann/phpunit/pull/4846): Composer proxy script is not ignored
## [9.5.10] - 2021-09-25
### Changed
* PHPUnit no longer converts PHP deprecations to exceptions by default (configure `convertDeprecationsToExceptions="true"` to enable this)
* The PHPUnit XML configuration file generator now configures `convertDeprecationsToExceptions="true"`
### Fixed
* [#4772](https://github.com/sebastianbergmann/phpunit/pull/4772): TestDox HTML report not displayed correctly when browser has custom colour settings
## [9.5.9] - 2021-08-31
### Fixed
* [#4750](https://github.com/sebastianbergmann/phpunit/issues/4750): Automatic return value generation leads to invalid (and superfluous) test double code generation when a stubbed method returns `*|false`
* [#4751](https://github.com/sebastianbergmann/phpunit/issues/4751): Configuration validation fails when using brackets in glob pattern
## [9.5.8] - 2021-07-31
### Fixed
* [#4740](https://github.com/sebastianbergmann/phpunit/issues/4740): `phpunit.phar` does not work with PHP 8.1
## [9.5.7] - 2021-07-19
### Fixed
* [#4720](https://github.com/sebastianbergmann/phpunit/issues/4720): PHPUnit does not verify its own PHP extension requirements
* [#4735](https://github.com/sebastianbergmann/phpunit/issues/4735): Automated return value generation does not work for stubbed methods that return `*|false`
## [9.5.6] - 2021-06-23
### Changed
* PHPUnit now errors out on startup when `PHP_VERSION` contains a value that is not compatible with `version_compare()`, for instance `X.Y.Z-(to be removed in future macOS)`
## [9.5.5] - 2021-06-05
### Changed
* The test result cache (the storage for which is implemented in `PHPUnit\Runner\DefaultTestResultCache`) no longer uses PHP's `serialize()` and `unserialize()` functions for persistence. It now uses a versioned JSON format instead that is independent of PHP implementation details (see [#3581](https://github.com/sebastianbergmann/phpunit/issues/3581) and [#4662](https://github.com/sebastianbergmann/phpunit/pull/4662) for examples why this is a problem). When PHPUnit tries to load the test result cache from a file that does not exist, or from a file that does not contain data in JSON format, or from a file that contains data in a JSON format version other than the one used by the currently running PHPUnit version, then this is considered to be a "cache miss". An empty `DefaultTestResultCache` object is created in this case. This should also prevent PHPUnit from crashing when trying to load a test result cache file created by a different version of PHPUnit (see [#4580](https://github.com/sebastianbergmann/phpunit/issues/4580) for example).
### Fixed
* [#4632](https://github.com/sebastianbergmann/phpunit/issues/4632): TestDox result printer does not handle repeated test execution correctly
* [#4678](https://github.com/sebastianbergmann/phpunit/pull/4678): Stubbed methods with `iterable` return types should return empty array by default
* [#4692](https://github.com/sebastianbergmann/phpunit/issues/4692): Annotations in single-line doc-comments are not handled correctly
* [#4694](https://github.com/sebastianbergmann/phpunit/issues/4694): `TestCase::getMockFromWsdl()` does not work with PHP 8.1-dev
## [9.5.4] - 2021-03-23
### Fixed
* [#4630](https://github.com/sebastianbergmann/phpunit/issues/4630): Empty test case class causes error in TestDox XML logger
## [9.5.3] - 2021-03-17
### Fixed
* [#4591](https://github.com/sebastianbergmann/phpunit/issues/4591): TeamCity logger logs warnings as test failures
* [#4620](https://github.com/sebastianbergmann/phpunit/issues/4620): No useful output when an error occurs in the bootstrap script
## [9.5.2] - 2021-02-02
### Fixed
* [#4573](https://github.com/sebastianbergmann/phpunit/issues/4573): No stack trace printed when PHPUnit is used from PHAR
* [#4590](https://github.com/sebastianbergmann/phpunit/issues/4590): `--coverage-text` CLI option is documented wrong
## [9.5.1] - 2021-01-17
### Fixed
* [#4572](https://github.com/sebastianbergmann/phpunit/issues/4572): Schema validation does not work with `%xx` sequences in path to `phpunit.xsd`
## [9.5.0] - 2020-12-04
### Changed
* [#4490](https://github.com/sebastianbergmann/phpunit/issues/4490): Emit Error instead of Warning when test case class cannot be instantiated
* [#4491](https://github.com/sebastianbergmann/phpunit/issues/4491): Emit Error instead of Warning when data provider does not work correctly
* [#4492](https://github.com/sebastianbergmann/phpunit/issues/4492): Emit Error instead of Warning when test double configuration is invalid
* [#4493](https://github.com/sebastianbergmann/phpunit/issues/4493): Emit error when (configured) test directory does not exist
### Fixed
* [#4535](https://github.com/sebastianbergmann/phpunit/issues/4535): `getMockFromWsdl()` does not handle methods that do not have parameters correctly
[9.5.20]: https://github.com/sebastianbergmann/phpunit/compare/9.5.19...9.5.20
[9.5.19]: https://github.com/sebastianbergmann/phpunit/compare/9.5.18...9.5.19
[9.5.18]: https://github.com/sebastianbergmann/phpunit/compare/9.5.17...9.5.18
[9.5.17]: https://github.com/sebastianbergmann/phpunit/compare/9.5.16...9.5.17
[9.5.16]: https://github.com/sebastianbergmann/phpunit/compare/dc738383c519243b0a967f63943a848d3fd861aa...9.5.16
[9.5.15]: https://github.com/sebastianbergmann/phpunit/compare/9.5.14...dc738383c519243b0a967f63943a848d3fd861aa
[9.5.14]: https://github.com/sebastianbergmann/phpunit/compare/9.5.13...9.5.14
[9.5.13]: https://github.com/sebastianbergmann/phpunit/compare/9.5.12...9.5.13
[9.5.12]: https://github.com/sebastianbergmann/phpunit/compare/9.5.11...9.5.12
[9.5.11]: https://github.com/sebastianbergmann/phpunit/compare/9.5.10...9.5.11
[9.5.10]: https://github.com/sebastianbergmann/phpunit/compare/9.5.9...9.5.10
[9.5.9]: https://github.com/sebastianbergmann/phpunit/compare/9.5.8...9.5.9
[9.5.8]: https://github.com/sebastianbergmann/phpunit/compare/9.5.7...9.5.8
[9.5.7]: https://github.com/sebastianbergmann/phpunit/compare/9.5.6...9.5.7
[9.5.6]: https://github.com/sebastianbergmann/phpunit/compare/9.5.5...9.5.6
[9.5.5]: https://github.com/sebastianbergmann/phpunit/compare/9.5.4...9.5.5
[9.5.4]: https://github.com/sebastianbergmann/phpunit/compare/9.5.3...9.5.4
[9.5.3]: https://github.com/sebastianbergmann/phpunit/compare/9.5.2...9.5.3
[9.5.2]: https://github.com/sebastianbergmann/phpunit/compare/9.5.1...9.5.2
[9.5.1]: https://github.com/sebastianbergmann/phpunit/compare/9.5.0...9.5.1
[9.5.0]: https://github.com/sebastianbergmann/phpunit/compare/9.4.4...9.5.0

View File

@@ -1,33 +1,29 @@
PHPUnit
BSD 3-Clause License
Copyright (c) 2001-2022, Sebastian Bergmann <sebastian@phpunit.de>.
Copyright (c) 2001-2024, 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.

View File

@@ -1,11 +1,11 @@
# PHPUnit
PHPUnit is a programmer-oriented testing framework for PHP. It is an instance of the xUnit architecture for unit testing frameworks.
[![Latest Stable Version](https://img.shields.io/packagist/v/phpunit/phpunit.svg?style=flat-square)](https://packagist.org/packages/phpunit/phpunit)
[![Minimum PHP Version](https://img.shields.io/badge/php-%3E%3D%207.3-8892BF.svg?style=flat-square)](https://php.net/)
[![CI Status](https://github.com/sebastianbergmann/phpunit/workflows/CI/badge.svg?branch=9.5&event=push)](https://phpunit.de/build-status.html)
[![Latest Stable Version](https://poser.pugx.org/phpunit/phpunit/v/stable.png)](https://packagist.org/packages/phpunit/phpunit)
[![CI Status](https://github.com/sebastianbergmann/phpunit/workflows/CI/badge.svg)](https://github.com/sebastianbergmann/phpunit/actions)
[![Type Coverage](https://shepherd.dev/github/sebastianbergmann/phpunit/coverage.svg)](https://shepherd.dev/github/sebastianbergmann/phpunit)
[![codecov](https://codecov.io/gh/sebastianbergmann/phpunit/branch/9.6/graph/badge.svg)](https://codecov.io/gh/sebastianbergmann/phpunit)
PHPUnit is a programmer-oriented testing framework for PHP. It is an instance of the xUnit architecture for unit testing frameworks.
## Installation
@@ -19,11 +19,11 @@ $ 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 "[Getting Started](https://phpunit.de/getting-started-with-phpunit.html)" guide for details on how to install PHPUnit.
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) for details on how to install PHPUnit.
## Contribute
Please refer to [CONTRIBUTING.md](https://github.com/sebastianbergmann/phpunit/blob/master/.github/CONTRIBUTING.md) for information on how to contribute to PHPUnit and its related projects.
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.
## List of Contributors
@@ -32,12 +32,5 @@ Thanks to everyone who has contributed to PHPUnit! You can find a detailed list
* [PHPUnit](https://github.com/sebastianbergmann/phpunit/graphs/contributors)
* [php-code-coverage](https://github.com/sebastianbergmann/php-code-coverage/graphs/contributors)
A very special thanks to everyone who has contributed to the documentation and helps maintain the translations:
* [English](https://github.com/sebastianbergmann/phpunit-documentation-english/graphs/contributors)
* [Spanish](https://github.com/sebastianbergmann/phpunit-documentation-spanish/graphs/contributors)
* [French](https://github.com/sebastianbergmann/phpunit-documentation-french/graphs/contributors)
* [Japanese](https://github.com/sebastianbergmann/phpunit-documentation-japanese/graphs/contributors)
* [Brazilian Portuguese](https://github.com/sebastianbergmann/phpunit-documentation-brazilian-portuguese/graphs/contributors)
* [Simplified Chinese](https://github.com/sebastianbergmann/phpunit-documentation-chinese/graphs/contributors)
A very special thanks to everyone who has contributed to the [documentation](https://github.com/sebastianbergmann/phpunit-documentation-english/graphs/contributors).

View File

@@ -17,7 +17,8 @@
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues"
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy"
},
"prefer-stable": true,
"require": {
@@ -28,32 +29,27 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"doctrine/instantiator": "^1.3.1",
"doctrine/instantiator": "^1.3.1 || ^2",
"myclabs/deep-copy": "^1.10.1",
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"phpspec/prophecy": "^1.12.1",
"phpunit/php-code-coverage": "^9.2.13",
"phpunit/php-code-coverage": "^9.2.28",
"phpunit/php-file-iterator": "^3.0.5",
"phpunit/php-invoker": "^3.1.1",
"phpunit/php-text-template": "^2.0.3",
"phpunit/php-timer": "^5.0.2",
"sebastian/cli-parser": "^1.0.1",
"sebastian/code-unit": "^1.0.6",
"sebastian/comparator": "^4.0.5",
"sebastian/comparator": "^4.0.8",
"sebastian/diff": "^4.0.3",
"sebastian/environment": "^5.1.3",
"sebastian/exporter": "^4.0.3",
"sebastian/exporter": "^4.0.5",
"sebastian/global-state": "^5.0.1",
"sebastian/object-enumerator": "^4.0.3",
"sebastian/resource-operations": "^3.0.3",
"sebastian/type": "^3.0",
"sebastian/type": "^3.2",
"sebastian/version": "^3.0.2"
},
"require-dev": {
"ext-PDO": "*",
"phpspec/prophecy-phpunit": "^2.0.1"
},
"config": {
"platform": {
"php": "7.3.0"
@@ -62,8 +58,8 @@
"sort-packages": true
},
"suggest": {
"ext-soap": "*",
"ext-xdebug": "*"
"ext-soap": "To be able to generate mocks based on WSDL files",
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
},
"bin": [
"phpunit"
@@ -88,7 +84,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "9.5-dev"
"dev-master": "9.6-dev"
}
}
}

21
vendor/phpunit/phpunit/phpunit vendored Executable file → Normal file
View File

@@ -38,22 +38,31 @@ if (version_compare('7.3.0', PHP_VERSION, '>')) {
die(1);
}
foreach (['dom', 'json', 'libxml', 'mbstring', 'tokenizer', 'xml', 'xmlwriter'] as $extension) {
if (extension_loaded($extension)) {
continue;
}
$requiredExtensions = ['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" extension.' . PHP_EOL,
$extension
'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 (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}

View File

@@ -2,7 +2,7 @@
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:annotation>
<xs:documentation source="https://phpunit.de/documentation.html">
This Schema file defines the rules by which the XML configuration file of PHPUnit 9.5 may be structured.
This Schema file defines the rules by which the XML configuration file of PHPUnit 9.6 may be structured.
</xs:documentation>
<xs:appinfo source="https://phpunit.de/documentation.html"/>
</xs:annotation>
@@ -57,7 +57,7 @@
</xs:complexType>
<xs:complexType name="extensionsType">
<xs:sequence>
<xs:element name="extension" type="objectType" maxOccurs="unbounded"/>
<xs:element name="extension" type="objectType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="listenersType">
@@ -279,8 +279,10 @@
</xs:complexType>
<xs:complexType name="testSuiteType">
<xs:sequence>
<xs:group ref="pathGroup"/>
<xs:element name="exclude" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:group ref="pathGroup"/>
<xs:element name="exclude" type="xs:string"/>
</xs:choice>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>

View File

@@ -244,7 +244,7 @@
<xs:attribute name="cacheTokens" type="xs:boolean" default="false"/>
<xs:attribute name="colors" type="xs:boolean" default="false"/>
<xs:attribute name="columns" type="columnsType" default="80"/>
<xs:attribute name="convertDeprecationsToExceptions" type="xs:boolean" default="true"/>
<xs:attribute name="convertDeprecationsToExceptions" type="xs:boolean" default="false"/>
<xs:attribute name="convertErrorsToExceptions" type="xs:boolean" default="true"/>
<xs:attribute name="convertNoticesToExceptions" type="xs:boolean" default="true"/>
<xs:attribute name="convertWarningsToExceptions" type="xs:boolean" default="true"/>
@@ -309,8 +309,10 @@
</xs:complexType>
<xs:complexType name="testSuiteType">
<xs:sequence>
<xs:group ref="pathGroup"/>
<xs:element name="exclude" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:group ref="pathGroup"/>
<xs:element name="exclude" type="xs:string"/>
</xs:choice>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>

View File

@@ -163,7 +163,7 @@
</xs:group>
<xs:complexType name="directoryFilterType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:extension base="xs:anyURI">
<xs:attribute type="xs:string" name="prefix" default=""/>
<xs:attribute type="xs:string" name="suffix" default="Test.php"/>
<xs:attributeGroup ref="phpVersionGroup"/>
@@ -248,7 +248,7 @@
<xs:attribute name="convertWarningsToExceptions" type="xs:boolean" default="true"/>
<xs:attribute name="disableCodeCoverageIgnore" type="xs:boolean" default="false"/>
<xs:attribute name="forceCoversAnnotation" type="xs:boolean" default="false"/>
<xs:attribute name="printerClass" type="xs:string" default="PHPUnit\TextUI\ResultPrinter"/>
<xs:attribute name="printerClass" type="xs:string" default="PHPUnit\TextUI\DefaultResultPrinter"/>
<xs:attribute name="printerFile" type="xs:anyURI"/>
<xs:attribute name="processIsolation" type="xs:boolean" default="false"/>
<xs:attribute name="stopOnDefect" type="xs:boolean" default="false"/>
@@ -282,7 +282,7 @@
<xs:attribute name="stderr" type="xs:boolean" default="false"/>
<xs:attribute name="reverseDefectList" type="xs:boolean" default="false"/>
<xs:attribute name="registerMockObjectsFromTestArgumentsRecursively" type="xs:boolean" default="false"/>
<xs:attribute name="extensionsDirectory" type="xs:anyURI"/>
<xs:attribute name="extensionsDirectory" type="xs:string"/>
<xs:attribute name="executionOrder" type="executionOrderType" default="default"/>
<xs:attribute name="resolveDependencies" type="xs:boolean" default="true"/>
<xs:attribute name="noInteraction" type="xs:boolean" default="false"/>
@@ -310,7 +310,7 @@
<xs:complexType name="testSuiteType">
<xs:sequence>
<xs:group ref="pathGroup"/>
<xs:element name="exclude" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="exclude" type="xs:anyURI" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>

View File

@@ -37,6 +37,7 @@ use Countable;
use DOMAttr;
use DOMDocument;
use DOMElement;
use Generator;
use PHPUnit\Framework\Constraint\ArrayHasKey;
use PHPUnit\Framework\Constraint\Callback;
use PHPUnit\Framework\Constraint\ClassHasAttribute;
@@ -72,6 +73,7 @@ use PHPUnit\Framework\Constraint\LogicalOr;
use PHPUnit\Framework\Constraint\LogicalXor;
use PHPUnit\Framework\Constraint\ObjectEquals;
use PHPUnit\Framework\Constraint\ObjectHasAttribute;
use PHPUnit\Framework\Constraint\ObjectHasProperty;
use PHPUnit\Framework\Constraint\RegularExpression;
use PHPUnit\Framework\Constraint\SameSize;
use PHPUnit\Framework\Constraint\StringContains;
@@ -110,14 +112,14 @@ abstract class Assert
if (!(is_int($key) || is_string($key))) {
throw InvalidArgumentException::create(
1,
'integer or string'
'integer or string',
);
}
if (!(is_array($array) || $array instanceof ArrayAccess)) {
throw InvalidArgumentException::create(
2,
'array or ArrayAccess'
'array or ArrayAccess',
);
}
@@ -141,19 +143,19 @@ abstract class Assert
if (!(is_int($key) || is_string($key))) {
throw InvalidArgumentException::create(
1,
'integer or string'
'integer or string',
);
}
if (!(is_array($array) || $array instanceof ArrayAccess)) {
throw InvalidArgumentException::create(
2,
'array or ArrayAccess'
'array or ArrayAccess',
);
}
$constraint = new LogicalNot(
new ArrayHasKey($key)
new ArrayHasKey($key),
);
static::assertThat($array, $constraint, $message);
@@ -190,7 +192,7 @@ abstract class Assert
public static function assertNotContains($needle, iterable $haystack, string $message = ''): void
{
$constraint = new LogicalNot(
new TraversableContainsIdentical($needle)
new TraversableContainsIdentical($needle),
);
static::assertThat($haystack, $constraint, $message);
@@ -219,9 +221,9 @@ abstract class Assert
$haystack,
new TraversableContainsOnly(
$type,
$isNativeType
$isNativeType,
),
$message
$message,
);
}
@@ -237,9 +239,9 @@ abstract class Assert
$haystack,
new TraversableContainsOnly(
$className,
false
false,
),
$message
$message,
);
}
@@ -260,10 +262,10 @@ abstract class Assert
new LogicalNot(
new TraversableContainsOnly(
$type,
$isNativeType
)
$isNativeType,
),
),
$message
$message,
);
}
@@ -278,6 +280,10 @@ abstract class Assert
*/
public static function assertCount(int $expectedCount, $haystack, string $message = ''): void
{
if ($haystack instanceof Generator) {
self::createWarning('Passing an argument of type Generator for the $haystack parameter is deprecated. Support for this will be removed in PHPUnit 10.');
}
if (!$haystack instanceof Countable && !is_iterable($haystack)) {
throw InvalidArgumentException::create(2, 'countable or iterable');
}
@@ -285,7 +291,7 @@ abstract class Assert
static::assertThat(
$haystack,
new Count($expectedCount),
$message
$message,
);
}
@@ -300,12 +306,16 @@ abstract class Assert
*/
public static function assertNotCount(int $expectedCount, $haystack, string $message = ''): void
{
if ($haystack instanceof Generator) {
self::createWarning('Passing an argument of type Generator for the $haystack parameter is deprecated. Support for this will be removed in PHPUnit 10.');
}
if (!$haystack instanceof Countable && !is_iterable($haystack)) {
throw InvalidArgumentException::create(2, 'countable or iterable');
}
$constraint = new LogicalNot(
new Count($expectedCount)
new Count($expectedCount),
);
static::assertThat($haystack, $constraint, $message);
@@ -360,7 +370,7 @@ abstract class Assert
{
$constraint = new IsEqualWithDelta(
$expected,
$delta
$delta,
);
static::assertThat($actual, $constraint, $message);
@@ -375,7 +385,7 @@ abstract class Assert
public static function assertNotEquals($expected, $actual, string $message = ''): void
{
$constraint = new LogicalNot(
new IsEqual($expected)
new IsEqual($expected),
);
static::assertThat($actual, $constraint, $message);
@@ -390,7 +400,7 @@ abstract class Assert
public static function assertNotEqualsCanonicalizing($expected, $actual, string $message = ''): void
{
$constraint = new LogicalNot(
new IsEqualCanonicalizing($expected)
new IsEqualCanonicalizing($expected),
);
static::assertThat($actual, $constraint, $message);
@@ -405,7 +415,7 @@ abstract class Assert
public static function assertNotEqualsIgnoringCase($expected, $actual, string $message = ''): void
{
$constraint = new LogicalNot(
new IsEqualIgnoringCase($expected)
new IsEqualIgnoringCase($expected),
);
static::assertThat($actual, $constraint, $message);
@@ -422,8 +432,8 @@ abstract class Assert
$constraint = new LogicalNot(
new IsEqualWithDelta(
$expected,
$delta
)
$delta,
),
);
static::assertThat($actual, $constraint, $message);
@@ -437,7 +447,7 @@ abstract class Assert
static::assertThat(
$actual,
static::objectEquals($expected, $method),
$message
$message,
);
}
@@ -451,6 +461,10 @@ abstract class Assert
*/
public static function assertEmpty($actual, string $message = ''): void
{
if ($actual instanceof Generator) {
self::createWarning('Passing an argument of type Generator for the $actual parameter is deprecated. Support for this will be removed in PHPUnit 10.');
}
static::assertThat($actual, static::isEmpty(), $message);
}
@@ -464,6 +478,10 @@ abstract class Assert
*/
public static function assertNotEmpty($actual, string $message = ''): void
{
if ($actual instanceof Generator) {
self::createWarning('Passing an argument of type Generator for the $actual parameter is deprecated. Support for this will be removed in PHPUnit 10.');
}
static::assertThat($actual, static::logicalNot(static::isEmpty()), $message);
}
@@ -489,7 +507,7 @@ abstract class Assert
static::assertThat(
$actual,
static::greaterThanOrEqual($expected),
$message
$message,
);
}
@@ -545,7 +563,7 @@ abstract class Assert
static::assertFileExists($actual, $message);
$constraint = new IsEqualCanonicalizing(
file_get_contents($expected)
file_get_contents($expected),
);
static::assertThat(file_get_contents($actual), $constraint, $message);
@@ -581,7 +599,7 @@ abstract class Assert
static::assertFileExists($actual, $message);
$constraint = new LogicalNot(
new IsEqual(file_get_contents($expected))
new IsEqual(file_get_contents($expected)),
);
static::assertThat(file_get_contents($actual), $constraint, $message);
@@ -600,7 +618,7 @@ abstract class Assert
static::assertFileExists($actual, $message);
$constraint = new LogicalNot(
new IsEqualCanonicalizing(file_get_contents($expected))
new IsEqualCanonicalizing(file_get_contents($expected)),
);
static::assertThat(file_get_contents($actual), $constraint, $message);
@@ -619,7 +637,7 @@ abstract class Assert
static::assertFileExists($actual, $message);
$constraint = new LogicalNot(
new IsEqualIgnoringCase(file_get_contents($expected))
new IsEqualIgnoringCase(file_get_contents($expected)),
);
static::assertThat(file_get_contents($actual), $constraint, $message);
@@ -685,7 +703,7 @@ abstract class Assert
static::assertFileExists($expectedFile, $message);
$constraint = new LogicalNot(
new IsEqual(file_get_contents($expectedFile))
new IsEqual(file_get_contents($expectedFile)),
);
static::assertThat($actualString, $constraint, $message);
@@ -703,7 +721,7 @@ abstract class Assert
static::assertFileExists($expectedFile, $message);
$constraint = new LogicalNot(
new IsEqualCanonicalizing(file_get_contents($expectedFile))
new IsEqualCanonicalizing(file_get_contents($expectedFile)),
);
static::assertThat($actualString, $constraint, $message);
@@ -721,7 +739,7 @@ abstract class Assert
static::assertFileExists($expectedFile, $message);
$constraint = new LogicalNot(
new IsEqualIgnoringCase(file_get_contents($expectedFile))
new IsEqualIgnoringCase(file_get_contents($expectedFile)),
);
static::assertThat($actualString, $constraint, $message);
@@ -1168,9 +1186,13 @@ abstract class Assert
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws Exception
* @throws ExpectationFailedException
*
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
public static function assertClassHasAttribute(string $attributeName, string $className, string $message = ''): void
{
self::createWarning('assertClassHasAttribute() is deprecated and will be removed in PHPUnit 10.');
if (!self::isValidClassAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}
@@ -1188,9 +1210,13 @@ abstract class Assert
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws Exception
* @throws ExpectationFailedException
*
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
public static function assertClassNotHasAttribute(string $attributeName, string $className, string $message = ''): void
{
self::createWarning('assertClassNotHasAttribute() is deprecated and will be removed in PHPUnit 10.');
if (!self::isValidClassAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}
@@ -1202,9 +1228,9 @@ abstract class Assert
static::assertThat(
$className,
new LogicalNot(
new ClassHasAttribute($attributeName)
new ClassHasAttribute($attributeName),
),
$message
$message,
);
}
@@ -1214,9 +1240,13 @@ abstract class Assert
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws Exception
* @throws ExpectationFailedException
*
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
public static function assertClassHasStaticAttribute(string $attributeName, string $className, string $message = ''): void
{
self::createWarning('assertClassHasStaticAttribute() is deprecated and will be removed in PHPUnit 10.');
if (!self::isValidClassAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}
@@ -1228,7 +1258,7 @@ abstract class Assert
static::assertThat(
$className,
new ClassHasStaticAttribute($attributeName),
$message
$message,
);
}
@@ -1238,9 +1268,13 @@ abstract class Assert
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws Exception
* @throws ExpectationFailedException
*
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
public static function assertClassNotHasStaticAttribute(string $attributeName, string $className, string $message = ''): void
{
self::createWarning('assertClassNotHasStaticAttribute() is deprecated and will be removed in PHPUnit 10.');
if (!self::isValidClassAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}
@@ -1252,9 +1286,9 @@ abstract class Assert
static::assertThat(
$className,
new LogicalNot(
new ClassHasStaticAttribute($attributeName)
new ClassHasStaticAttribute($attributeName),
),
$message
$message,
);
}
@@ -1266,9 +1300,13 @@ abstract class Assert
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws Exception
* @throws ExpectationFailedException
*
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
public static function assertObjectHasAttribute(string $attributeName, $object, string $message = ''): void
{
self::createWarning('assertObjectHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectHasProperty() instead.');
if (!self::isValidObjectAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}
@@ -1280,7 +1318,7 @@ abstract class Assert
static::assertThat(
$object,
new ObjectHasAttribute($attributeName),
$message
$message,
);
}
@@ -1292,9 +1330,13 @@ abstract class Assert
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws Exception
* @throws ExpectationFailedException
*
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
public static function assertObjectNotHasAttribute(string $attributeName, $object, string $message = ''): void
{
self::createWarning('assertObjectNotHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectNotHasProperty() instead.');
if (!self::isValidObjectAttributeName($attributeName)) {
throw InvalidArgumentException::create(1, 'valid attribute name');
}
@@ -1306,9 +1348,39 @@ abstract class Assert
static::assertThat(
$object,
new LogicalNot(
new ObjectHasAttribute($attributeName)
new ObjectHasAttribute($attributeName),
),
$message
$message,
);
}
/**
* Asserts that an object has a specified property.
*
* @throws ExpectationFailedException
*/
final public static function assertObjectHasProperty(string $propertyName, object $object, string $message = ''): void
{
static::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
{
static::assertThat(
$object,
new LogicalNot(
new ObjectHasProperty($propertyName),
),
$message,
);
}
@@ -1321,7 +1393,9 @@ abstract class Assert
* @throws ExpectationFailedException
*
* @psalm-template ExpectedType
*
* @psalm-param ExpectedType $expected
*
* @psalm-assert =ExpectedType $actual
*/
public static function assertSame($expected, $actual, string $message = ''): void
@@ -1329,7 +1403,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsIdentical($expected),
$message
$message,
);
}
@@ -1350,9 +1424,9 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(
new IsIdentical($expected)
new IsIdentical($expected),
),
$message
$message,
);
}
@@ -1364,7 +1438,9 @@ abstract class Assert
* @throws ExpectationFailedException
*
* @psalm-template ExpectedType of object
*
* @psalm-param class-string<ExpectedType> $expected
*
* @psalm-assert =ExpectedType $actual
*/
public static function assertInstanceOf(string $expected, $actual, string $message = ''): void
@@ -1376,7 +1452,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsInstanceOf($expected),
$message
$message,
);
}
@@ -1388,7 +1464,9 @@ abstract class Assert
* @throws ExpectationFailedException
*
* @psalm-template ExpectedType of object
*
* @psalm-param class-string<ExpectedType> $expected
*
* @psalm-assert !ExpectedType $actual
*/
public static function assertNotInstanceOf(string $expected, $actual, string $message = ''): void
@@ -1400,9 +1478,9 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(
new IsInstanceOf($expected)
new IsInstanceOf($expected),
),
$message
$message,
);
}
@@ -1419,7 +1497,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_ARRAY),
$message
$message,
);
}
@@ -1436,7 +1514,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_BOOL),
$message
$message,
);
}
@@ -1453,7 +1531,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_FLOAT),
$message
$message,
);
}
@@ -1470,7 +1548,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_INT),
$message
$message,
);
}
@@ -1487,7 +1565,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_NUMERIC),
$message
$message,
);
}
@@ -1504,7 +1582,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_OBJECT),
$message
$message,
);
}
@@ -1521,7 +1599,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_RESOURCE),
$message
$message,
);
}
@@ -1538,7 +1616,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_CLOSED_RESOURCE),
$message
$message,
);
}
@@ -1555,7 +1633,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_STRING),
$message
$message,
);
}
@@ -1572,7 +1650,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_SCALAR),
$message
$message,
);
}
@@ -1589,7 +1667,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_CALLABLE),
$message
$message,
);
}
@@ -1606,7 +1684,7 @@ abstract class Assert
static::assertThat(
$actual,
new IsType(IsType::TYPE_ITERABLE),
$message
$message,
);
}
@@ -1623,7 +1701,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_ARRAY)),
$message
$message,
);
}
@@ -1640,7 +1718,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_BOOL)),
$message
$message,
);
}
@@ -1657,7 +1735,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_FLOAT)),
$message
$message,
);
}
@@ -1674,7 +1752,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_INT)),
$message
$message,
);
}
@@ -1691,7 +1769,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_NUMERIC)),
$message
$message,
);
}
@@ -1708,7 +1786,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_OBJECT)),
$message
$message,
);
}
@@ -1725,7 +1803,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_RESOURCE)),
$message
$message,
);
}
@@ -1742,7 +1820,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_CLOSED_RESOURCE)),
$message
$message,
);
}
@@ -1759,7 +1837,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_STRING)),
$message
$message,
);
}
@@ -1776,7 +1854,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_SCALAR)),
$message
$message,
);
}
@@ -1793,7 +1871,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_CALLABLE)),
$message
$message,
);
}
@@ -1810,7 +1888,7 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(new IsType(IsType::TYPE_ITERABLE)),
$message
$message,
);
}
@@ -1853,9 +1931,9 @@ abstract class Assert
static::assertThat(
$string,
new LogicalNot(
new RegularExpression($pattern)
new RegularExpression($pattern),
),
$message
$message,
);
}
@@ -1876,9 +1954,9 @@ abstract class Assert
static::assertThat(
$string,
new LogicalNot(
new RegularExpression($pattern)
new RegularExpression($pattern),
),
$message
$message,
);
}
@@ -1895,6 +1973,14 @@ abstract class Assert
*/
public static function assertSameSize($expected, $actual, string $message = ''): void
{
if ($expected instanceof Generator) {
self::createWarning('Passing an argument of type Generator for the $expected parameter is deprecated. Support for this will be removed in PHPUnit 10.');
}
if ($actual instanceof Generator) {
self::createWarning('Passing an argument of type Generator for the $actual parameter is deprecated. Support for this will be removed in PHPUnit 10.');
}
if (!$expected instanceof Countable && !is_iterable($expected)) {
throw InvalidArgumentException::create(1, 'countable or iterable');
}
@@ -1906,7 +1992,7 @@ abstract class Assert
static::assertThat(
$actual,
new SameSize($expected),
$message
$message,
);
}
@@ -1923,6 +2009,14 @@ abstract class Assert
*/
public static function assertNotSameSize($expected, $actual, string $message = ''): void
{
if ($expected instanceof Generator) {
self::createWarning('Passing an argument of type Generator for the $expected parameter is deprecated. Support for this will be removed in PHPUnit 10.');
}
if ($actual instanceof Generator) {
self::createWarning('Passing an argument of type Generator for the $actual parameter is deprecated. Support for this will be removed in PHPUnit 10.');
}
if (!$expected instanceof Countable && !is_iterable($expected)) {
throw InvalidArgumentException::create(1, 'countable or iterable');
}
@@ -1934,9 +2028,9 @@ abstract class Assert
static::assertThat(
$actual,
new LogicalNot(
new SameSize($expected)
new SameSize($expected),
),
$message
$message,
);
}
@@ -1962,9 +2056,9 @@ abstract class Assert
static::assertThat(
$string,
new LogicalNot(
new StringMatchesFormatDescription($format)
new StringMatchesFormatDescription($format),
),
$message
$message,
);
}
@@ -1981,9 +2075,9 @@ abstract class Assert
static::assertThat(
$string,
new StringMatchesFormatDescription(
file_get_contents($formatFile)
file_get_contents($formatFile),
),
$message
$message,
);
}
@@ -2001,10 +2095,10 @@ abstract class Assert
$string,
new LogicalNot(
new StringMatchesFormatDescription(
file_get_contents($formatFile)
)
file_get_contents($formatFile),
),
),
$message
$message,
);
}
@@ -2033,9 +2127,9 @@ abstract class Assert
static::assertThat(
$string,
new LogicalNot(
new StringStartsWith($prefix)
new StringStartsWith($prefix),
),
$message
$message,
);
}
@@ -2105,9 +2199,9 @@ abstract class Assert
static::assertThat(
$string,
new LogicalNot(
new StringEndsWith($suffix)
new StringEndsWith($suffix),
),
$message
$message,
);
}
@@ -2146,9 +2240,9 @@ abstract class Assert
*
* @param DOMDocument|string $actualXml
*
* @throws \PHPUnit\Util\Xml\Exception
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
* @throws Xml\Exception
*/
public static function assertXmlStringEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void
{
@@ -2170,9 +2264,9 @@ abstract class Assert
*
* @param DOMDocument|string $actualXml
*
* @throws \PHPUnit\Util\Xml\Exception
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
* @throws Xml\Exception
*/
public static function assertXmlStringNotEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void
{
@@ -2195,9 +2289,9 @@ abstract class Assert
* @param DOMDocument|string $expectedXml
* @param DOMDocument|string $actualXml
*
* @throws \PHPUnit\Util\Xml\Exception
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
* @throws Xml\Exception
*/
public static function assertXmlStringEqualsXmlString($expectedXml, $actualXml, string $message = ''): void
{
@@ -2226,9 +2320,9 @@ abstract class Assert
* @param DOMDocument|string $expectedXml
* @param DOMDocument|string $actualXml
*
* @throws \PHPUnit\Util\Xml\Exception
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
* @throws Xml\Exception
*/
public static function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, string $message = ''): void
{
@@ -2272,7 +2366,7 @@ abstract class Assert
static::assertSame(
$expectedElement->tagName,
$actualElement->tagName,
$message
$message,
);
if ($checkAttributes) {
@@ -2283,8 +2377,8 @@ abstract class Assert
'%s%sNumber of attributes on node "%s" does not match',
$message,
!empty($message) ? "\n" : '',
$expectedElement->tagName
)
$expectedElement->tagName,
),
);
for ($i = 0; $i < $expectedElement->attributes->length; $i++) {
@@ -2300,8 +2394,8 @@ abstract class Assert
$message,
!empty($message) ? "\n" : '',
$expectedAttribute->name,
$expectedElement->tagName
)
$expectedElement->tagName,
),
);
}
}
@@ -2317,8 +2411,8 @@ abstract class Assert
'%s%sNumber of child nodes of "%s" differs',
$message,
!empty($message) ? "\n" : '',
$expectedElement->tagName
)
$expectedElement->tagName,
),
);
for ($i = 0; $i < $expectedElement->childNodes->length; $i++) {
@@ -2326,7 +2420,7 @@ abstract class Assert
$expectedElement->childNodes->item($i),
$actualElement->childNodes->item($i),
$checkAttributes,
$message
$message,
);
}
}
@@ -2386,9 +2480,9 @@ abstract class Assert
static::assertThat(
$actualJson,
new LogicalNot(
new JsonMatches($expectedJson)
new JsonMatches($expectedJson),
),
$message
$message,
);
}
@@ -2426,9 +2520,9 @@ abstract class Assert
static::assertThat(
$actualJson,
new LogicalNot(
new JsonMatches($expectedJson)
new JsonMatches($expectedJson),
),
$message
$message,
);
}
@@ -2450,7 +2544,7 @@ abstract class Assert
static::assertJson($actualJson, $message);
$constraintExpected = new JsonMatches(
$expectedJson
$expectedJson,
);
$constraintActual = new JsonMatches($actualJson);
@@ -2477,7 +2571,7 @@ abstract class Assert
static::assertJson($actualJson, $message);
$constraintExpected = new JsonMatches(
$expectedJson
$expectedJson,
);
$constraintActual = new JsonMatches($actualJson);
@@ -2658,22 +2752,37 @@ abstract class Assert
{
return static::logicalOr(
new IsEqual($value),
new GreaterThan($value)
new GreaterThan($value),
);
}
/**
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
public static function classHasAttribute(string $attributeName): ClassHasAttribute
{
self::createWarning('classHasAttribute() is deprecated and will be removed in PHPUnit 10.');
return new ClassHasAttribute($attributeName);
}
/**
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
public static function classHasStaticAttribute(string $attributeName): ClassHasStaticAttribute
{
self::createWarning('classHasStaticAttribute() is deprecated and will be removed in PHPUnit 10.');
return new ClassHasStaticAttribute($attributeName);
}
/**
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
public static function objectHasAttribute($attributeName): ObjectHasAttribute
{
self::createWarning('objectHasAttribute() is deprecated and will be removed in PHPUnit 10.');
return new ObjectHasAttribute($attributeName);
}
@@ -2701,7 +2810,7 @@ abstract class Assert
{
return static::logicalOr(
new IsEqual($value),
new LessThan($value)
new LessThan($value),
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -40,7 +40,7 @@ class Count extends Constraint
{
return sprintf(
'count matches %d',
$this->expectedCount
$this->expectedCount,
);
}
@@ -76,7 +76,7 @@ class Count extends Constraint
throw new Exception(
$e->getMessage(),
$e->getCode(),
$e
$e,
);
}
}
@@ -136,7 +136,7 @@ class Count extends Constraint
return sprintf(
'actual size %d matches expected size %d',
(int) $this->getCountOf($other),
$this->expectedCount
$this->expectedCount,
);
}
}

View File

@@ -9,6 +9,8 @@
*/
namespace PHPUnit\Framework\Constraint;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*/
@@ -30,7 +32,7 @@ final class GreaterThan extends Constraint
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
public function toString(): string
{

View File

@@ -64,7 +64,7 @@ final class IsEmpty extends Constraint
'%s %s %s',
strpos($type, 'a') === 0 || strpos($type, 'o') === 0 ? 'an' : 'a',
$type,
$this->toString()
$this->toString(),
);
}
}

View File

@@ -9,6 +9,8 @@
*/
namespace PHPUnit\Framework\Constraint;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*/
@@ -30,7 +32,7 @@ final class LessThan extends Constraint
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
public function toString(): string
{

View File

@@ -15,6 +15,7 @@ use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\SelfDescribing;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Exporter\Exporter;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -36,8 +37,8 @@ abstract class Constraint implements Countable, SelfDescribing
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
* @throws InvalidArgumentException
*/
public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
{
@@ -82,6 +83,7 @@ abstract class Constraint implements Countable, SelfDescribing
* This method can be overridden to implement the evaluation algorithm.
*
* @param mixed $other value or object to evaluate
*
* @codeCoverageIgnore
*/
protected function matches($other): bool
@@ -92,20 +94,19 @@ abstract class Constraint implements Countable, SelfDescribing
/**
* 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 ComparisonFailure $comparisonFailure
* @param mixed $other evaluated value or object
* @param string $description Additional information about the test
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
* @throws InvalidArgumentException
*
* @psalm-return never-return
*/
protected function fail($other, $description, ComparisonFailure $comparisonFailure = null): void
protected function fail($other, $description, ?ComparisonFailure $comparisonFailure = null): void
{
$failureDescription = sprintf(
'Failed asserting that %s.',
$this->failureDescription($other)
$this->failureDescription($other),
);
$additionalFailureDescription = $this->additionalFailureDescription($other);
@@ -120,7 +121,7 @@ abstract class Constraint implements Countable, SelfDescribing
throw new ExpectationFailedException(
$failureDescription,
$comparisonFailure
$comparisonFailure,
);
}
@@ -148,7 +149,7 @@ abstract class Constraint implements Countable, SelfDescribing
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
protected function failureDescription($other): string
{

View File

@@ -16,6 +16,7 @@ use function trim;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Comparator\Factory as ComparatorFactory;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -61,8 +62,6 @@ final class IsEqual extends Constraint
* failure.
*
* @throws ExpectationFailedException
*
* @return bool
*/
public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
{
@@ -78,7 +77,7 @@ final class IsEqual extends Constraint
try {
$comparator = $comparatorFactory->getComparatorFor(
$this->value,
$other
$other,
);
$comparator->assertEquals(
@@ -86,7 +85,7 @@ final class IsEqual extends Constraint
$other,
$this->delta,
$this->canonicalize,
$this->ignoreCase
$this->ignoreCase,
);
} catch (ComparisonFailure $f) {
if ($returnResult) {
@@ -95,7 +94,7 @@ final class IsEqual extends Constraint
throw new ExpectationFailedException(
trim($description . "\n" . $f->getMessage()),
$f
$f,
);
}
@@ -105,7 +104,7 @@ final class IsEqual extends Constraint
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
public function toString(): string
{
@@ -118,21 +117,21 @@ final class IsEqual extends Constraint
return sprintf(
"is equal to '%s'",
$this->value
$this->value,
);
}
if ($this->delta != 0) {
$delta = sprintf(
' with delta <%F>',
$this->delta
$this->delta,
);
}
return sprintf(
'is equal to %s%s',
$this->exporter()->export($this->value),
$delta
$delta,
);
}
}

View File

@@ -16,6 +16,7 @@ use function trim;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Comparator\Factory as ComparatorFactory;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -58,7 +59,7 @@ final class IsEqualCanonicalizing extends Constraint
try {
$comparator = $comparatorFactory->getComparatorFor(
$this->value,
$other
$other,
);
$comparator->assertEquals(
@@ -66,7 +67,7 @@ final class IsEqualCanonicalizing extends Constraint
$other,
0.0,
true,
false
false,
);
} catch (ComparisonFailure $f) {
if ($returnResult) {
@@ -75,7 +76,7 @@ final class IsEqualCanonicalizing extends Constraint
throw new ExpectationFailedException(
trim($description . "\n" . $f->getMessage()),
$f
$f,
);
}
@@ -85,7 +86,7 @@ final class IsEqualCanonicalizing extends Constraint
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
public function toString(): string
{
@@ -96,13 +97,13 @@ final class IsEqualCanonicalizing extends Constraint
return sprintf(
"is equal to '%s'",
$this->value
$this->value,
);
}
return sprintf(
'is equal to %s',
$this->exporter()->export($this->value)
$this->exporter()->export($this->value),
);
}
}

View File

@@ -16,6 +16,7 @@ use function trim;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Comparator\Factory as ComparatorFactory;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -58,7 +59,7 @@ final class IsEqualIgnoringCase extends Constraint
try {
$comparator = $comparatorFactory->getComparatorFor(
$this->value,
$other
$other,
);
$comparator->assertEquals(
@@ -66,7 +67,7 @@ final class IsEqualIgnoringCase extends Constraint
$other,
0.0,
false,
true
true,
);
} catch (ComparisonFailure $f) {
if ($returnResult) {
@@ -75,7 +76,7 @@ final class IsEqualIgnoringCase extends Constraint
throw new ExpectationFailedException(
trim($description . "\n" . $f->getMessage()),
$f
$f,
);
}
@@ -85,7 +86,7 @@ final class IsEqualIgnoringCase extends Constraint
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
public function toString(): string
{
@@ -96,13 +97,13 @@ final class IsEqualIgnoringCase extends Constraint
return sprintf(
"is equal to '%s'",
$this->value
$this->value,
);
}
return sprintf(
'is equal to %s',
$this->exporter()->export($this->value)
$this->exporter()->export($this->value),
);
}
}

View File

@@ -14,6 +14,7 @@ use function trim;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Comparator\Factory as ComparatorFactory;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -62,13 +63,13 @@ final class IsEqualWithDelta extends Constraint
try {
$comparator = $comparatorFactory->getComparatorFor(
$this->value,
$other
$other,
);
$comparator->assertEquals(
$this->value,
$other,
$this->delta
$this->delta,
);
} catch (ComparisonFailure $f) {
if ($returnResult) {
@@ -77,7 +78,7 @@ final class IsEqualWithDelta extends Constraint
throw new ExpectationFailedException(
trim($description . "\n" . $f->getMessage()),
$f
$f,
);
}
@@ -87,14 +88,14 @@ final class IsEqualWithDelta extends Constraint
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
public function toString(): string
{
return sprintf(
'is equal to %s with delta <%F>>',
'is equal to %s with delta <%F>',
$this->exporter()->export($this->value),
$this->delta
$this->delta,
);
}
}

View File

@@ -36,7 +36,7 @@ final class Exception extends Constraint
{
return sprintf(
'exception of type "%s"',
$this->className
$this->className,
);
}
@@ -73,13 +73,13 @@ final class Exception extends Constraint
'exception of type "%s" matches expected exception "%s"%s',
get_class($other),
$this->className,
$message
$message,
);
}
return sprintf(
'exception of type "%s" is thrown',
$this->className
$this->className,
);
}
}

View File

@@ -10,6 +10,7 @@
namespace PHPUnit\Framework\Constraint;
use function sprintf;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
use Throwable;
/**
@@ -54,14 +55,14 @@ final class ExceptionCode extends Constraint
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
protected function failureDescription($other): string
{
return sprintf(
'%s is equal to expected exception code %s',
$this->exporter()->export($other->getCode()),
$this->exporter()->export($this->expectedCode)
$this->exporter()->export($this->expectedCode),
);
}
}

View File

@@ -65,14 +65,14 @@ final class ExceptionMessage extends Constraint
if ($this->expectedMessage === '') {
return sprintf(
"exception message is empty but is '%s'",
$other->getMessage()
$other->getMessage(),
);
}
return sprintf(
"exception message '%s' contains '%s'",
$other->getMessage(),
$this->expectedMessage
$this->expectedMessage,
);
}
}

View File

@@ -48,7 +48,7 @@ final class ExceptionMessageRegularExpression extends Constraint
if ($match === false) {
throw new \PHPUnit\Framework\Exception(
"Invalid expected exception message regex given: '{$this->expectedMessageRegExp}'"
"Invalid expected exception message regex given: '{$this->expectedMessageRegExp}'",
);
}
@@ -68,7 +68,7 @@ final class ExceptionMessageRegularExpression extends Constraint
return sprintf(
"exception message '%s' matches '%s'",
$other->getMessage(),
$this->expectedMessageRegExp
$this->expectedMessageRegExp,
);
}
}

View File

@@ -48,7 +48,7 @@ final class DirectoryExists extends Constraint
{
return sprintf(
'directory "%s" exists',
$other
$other,
);
}
}

View File

@@ -48,7 +48,7 @@ final class FileExists extends Constraint
{
return sprintf(
'file "%s" exists',
$other
$other,
);
}
}

View File

@@ -48,7 +48,7 @@ final class IsReadable extends Constraint
{
return sprintf(
'"%s" is readable',
$other
$other,
);
}
}

View File

@@ -48,7 +48,7 @@ final class IsWritable extends Constraint
{
return sprintf(
'"%s" is writable',
$other
$other,
);
}
}

View File

@@ -9,18 +9,14 @@
*/
namespace PHPUnit\Framework\Constraint;
use const PHP_FLOAT_EPSILON;
use function abs;
use function get_class;
use function is_array;
use function is_float;
use function is_infinite;
use function is_nan;
use function is_object;
use function is_string;
use function sprintf;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -47,18 +43,12 @@ final class IsIdentical extends Constraint
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
* @throws InvalidArgumentException
*/
public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
{
if (is_float($this->value) && is_float($other) &&
!is_infinite($this->value) && !is_infinite($other) &&
!is_nan($this->value) && !is_nan($other)) {
$success = abs($this->value - $other) < PHP_FLOAT_EPSILON;
} else {
$success = $this->value === $other;
}
$success = $this->value === $other;
if ($returnResult) {
return $success;
@@ -73,7 +63,7 @@ final class IsIdentical extends Constraint
$this->value,
$other,
sprintf("'%s'", $this->value),
sprintf("'%s'", $other)
sprintf("'%s'", $other),
);
}
@@ -83,7 +73,7 @@ final class IsIdentical extends Constraint
$this->value,
$other,
$this->exporter()->export($this->value),
$this->exporter()->export($other)
$this->exporter()->export($other),
);
}
@@ -96,7 +86,7 @@ final class IsIdentical extends Constraint
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
public function toString(): string
{
@@ -116,7 +106,7 @@ final class IsIdentical extends Constraint
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
protected function failureDescription($other): string
{

View File

@@ -11,9 +11,11 @@ namespace PHPUnit\Framework\Constraint;
use function json_decode;
use function sprintf;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Util\Json;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -37,7 +39,7 @@ final class JsonMatches extends Constraint
{
return sprintf(
'matches JSON string "%s"',
$this->value
$this->value,
);
}
@@ -69,17 +71,16 @@ final class JsonMatches extends Constraint
/**
* 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 ComparisonFailure $comparisonFailure
* @param mixed $other evaluated value or object
* @param string $description Additional information about the test
*
* @throws \PHPUnit\Framework\Exception
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws Exception
* @throws ExpectationFailedException
* @throws InvalidArgumentException
*
* @psalm-return never-return
*/
protected function fail($other, $description, ComparisonFailure $comparisonFailure = null): void
protected function fail($other, $description, ?ComparisonFailure $comparisonFailure = null): void
{
if ($comparisonFailure === null) {
[$error, $recodedOther] = Json::canonicalize($other);
@@ -100,7 +101,7 @@ final class JsonMatches extends Constraint
Json::prettify($recodedValue),
Json::prettify($recodedOther),
false,
'Failed asserting that two json values are equal.'
'Failed asserting that two json values are equal.',
);
}

View File

@@ -30,14 +30,19 @@ final class JsonMatchesErrorMessageProvider
switch ($error) {
case JSON_ERROR_NONE:
return null;
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';
@@ -56,6 +61,7 @@ final class JsonMatchesErrorMessageProvider
$prefix = 'Expected value JSON decode error - ';
break;
case 'actual':
$prefix = 'Actual value JSON decode error - ';

View File

@@ -18,6 +18,8 @@ use ReflectionException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
class ClassHasAttribute extends Constraint
{
@@ -38,7 +40,7 @@ class ClassHasAttribute extends Constraint
{
return sprintf(
'has attribute "%s"',
$this->attributeName
$this->attributeName,
);
}
@@ -56,8 +58,8 @@ class ClassHasAttribute extends Constraint
} catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
$e->getCode(),
$e,
);
}
// @codeCoverageIgnoreEnd
@@ -77,7 +79,7 @@ class ClassHasAttribute extends Constraint
'%sclass "%s" %s',
is_object($other) ? 'object of ' : '',
is_object($other) ? get_class($other) : $other,
$this->toString()
$this->toString(),
);
}

View File

@@ -16,6 +16,8 @@ use ReflectionException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
final class ClassHasStaticAttribute extends ClassHasAttribute
{
@@ -26,7 +28,7 @@ final class ClassHasStaticAttribute extends ClassHasAttribute
{
return sprintf(
'has static attribute "%s"',
$this->attributeName()
$this->attributeName(),
);
}
@@ -48,8 +50,8 @@ final class ClassHasStaticAttribute extends ClassHasAttribute
} catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
(int) $e->getCode(),
$e
$e->getCode(),
$e,
);
}
// @codeCoverageIgnoreEnd

View File

@@ -65,7 +65,7 @@ final class ObjectEquals extends Constraint
if (!$object->hasMethod($this->method)) {
throw new ComparisonMethodDoesNotExistException(
get_class($other),
$this->method
$this->method,
);
}
@@ -75,7 +75,7 @@ final class ObjectEquals extends Constraint
if (!$method->hasReturnType()) {
throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
get_class($other),
$this->method
$this->method,
);
}
@@ -84,28 +84,28 @@ final class ObjectEquals extends Constraint
if (!$returnType instanceof ReflectionNamedType) {
throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
get_class($other),
$this->method
$this->method,
);
}
if ($returnType->allowsNull()) {
throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
get_class($other),
$this->method
$this->method,
);
}
if ($returnType->getName() !== 'bool') {
throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
get_class($other),
$this->method
$this->method,
);
}
if ($method->getNumberOfParameters() !== 1 || $method->getNumberOfRequiredParameters() !== 1) {
throw new ComparisonMethodDoesNotDeclareExactlyOneParameterException(
get_class($other),
$this->method
$this->method,
);
}
@@ -114,7 +114,7 @@ final class ObjectEquals extends Constraint
if (!$parameter->hasType()) {
throw new ComparisonMethodDoesNotDeclareParameterTypeException(
get_class($other),
$this->method
$this->method,
);
}
@@ -123,7 +123,7 @@ final class ObjectEquals extends Constraint
if (!$type instanceof ReflectionNamedType) {
throw new ComparisonMethodDoesNotDeclareParameterTypeException(
get_class($other),
$this->method
$this->method,
);
}
@@ -137,7 +137,7 @@ final class ObjectEquals extends Constraint
throw new ComparisonMethodDoesNotAcceptParameterTypeException(
get_class($other),
$this->method,
get_class($this->expected)
get_class($this->expected),
);
}

View File

@@ -13,6 +13,8 @@ use ReflectionObject;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/4601
*/
final class ObjectHasAttribute extends ClassHasAttribute
{

View File

@@ -50,10 +50,17 @@ final class LogicalNot extends UnaryOperator
preg_match('/(\'[\w\W]*\')([\w\W]*)("[\w\W]*")/i', $string, $matches);
$positives = array_map(static function (string $s)
{
return '/\\b' . preg_quote($s, '/') . '/';
}, $positives);
if (count($matches) === 0) {
preg_match('/(\'[\w\W]*\')([\w\W]*)(\'[\w\W]*\')/i', $string, $matches);
}
$positives = array_map(
static function (string $s)
{
return '/\\b' . preg_quote($s, '/') . '/';
},
$positives,
);
if (count($matches) > 0) {
$nonInput = $matches[2];
@@ -63,15 +70,15 @@ final class LogicalNot extends UnaryOperator
preg_replace(
$positives,
$negatives,
$nonInput
$nonInput,
),
$string
$string,
);
} else {
$negatedString = preg_replace(
$positives,
$negatives,
$string
$string,
);
}

View File

@@ -57,7 +57,7 @@ final class LogicalXor extends BinaryOperator
{
return $matches xor $constraint->evaluate($other, '', true);
},
$initial->evaluate($other, '', true)
$initial->evaluate($other, '', true),
);
}
}

View File

@@ -11,6 +11,8 @@ namespace PHPUnit\Framework\Constraint;
use function count;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*/
@@ -79,7 +81,7 @@ abstract class UnaryOperator extends Operator
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
protected function failureDescription($other): string
{

View File

@@ -10,8 +10,10 @@
namespace PHPUnit\Framework\Constraint;
use function json_decode;
use function json_last_error;
use function sprintf;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -55,7 +57,7 @@ final class IsJson extends Constraint
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
protected function failureDescription($other): string
{
@@ -65,13 +67,13 @@ final class IsJson extends Constraint
json_decode($other);
$error = (string) JsonMatchesErrorMessageProvider::determineJsonError(
(string) json_last_error()
(string) json_last_error(),
);
return sprintf(
'%s is valid JSON (%s)',
$this->exporter()->shortenedExport($other),
$error
$error,
);
}
}

View File

@@ -34,7 +34,7 @@ class RegularExpression extends Constraint
{
return sprintf(
'matches PCRE pattern "%s"',
$this->pattern
$this->pattern,
);
}

View File

@@ -48,7 +48,7 @@ final class StringContains extends Constraint
return sprintf(
'contains "%s"',
$string
$string,
);
}

View File

@@ -33,8 +33,8 @@ final class StringMatchesFormatDescription extends RegularExpression
{
parent::__construct(
$this->createPatternFromFormat(
$this->convertNewlines($string)
)
$this->convertNewlines($string),
),
);
$this->string = $string;
@@ -49,7 +49,7 @@ final class StringMatchesFormatDescription extends RegularExpression
protected function matches($other): bool
{
return parent::matches(
$this->convertNewlines($other)
$this->convertNewlines($other),
);
}
@@ -96,7 +96,7 @@ final class StringMatchesFormatDescription extends RegularExpression
'%x' => '[0-9a-fA-F]+',
'%f' => '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?',
'%c' => '.',
]
],
);
return '/^' . $string . '$/s';

View File

@@ -9,7 +9,6 @@
*/
namespace PHPUnit\Framework\Constraint;
use function strlen;
use function strpos;
use PHPUnit\Framework\InvalidArgumentException;
@@ -25,7 +24,7 @@ final class StringStartsWith extends Constraint
public function __construct(string $prefix)
{
if (strlen($prefix) === 0) {
if ($prefix === '') {
throw InvalidArgumentException::create(1, 'non-empty string');
}

View File

@@ -12,6 +12,7 @@ namespace PHPUnit\Framework\Constraint;
use function array_key_exists;
use function is_array;
use ArrayAccess;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -34,7 +35,7 @@ final class ArrayHasKey extends Constraint
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
public function toString(): string
{
@@ -68,7 +69,7 @@ final class ArrayHasKey extends Constraint
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
protected function failureDescription($other): string
{

View File

@@ -10,7 +10,9 @@
namespace PHPUnit\Framework\Constraint;
use function is_array;
use function sprintf;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -30,7 +32,7 @@ abstract class TraversableContains extends Constraint
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
public function toString(): string
{
@@ -45,14 +47,14 @@ abstract class TraversableContains extends Constraint
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
protected function failureDescription($other): string
{
return sprintf(
'%s %s',
is_array($other) ? 'an array' : 'a traversable',
$this->toString()
$this->toString(),
);
}

View File

@@ -9,7 +9,9 @@
*/
namespace PHPUnit\Framework\Constraint;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
use Traversable;
/**
@@ -28,7 +30,7 @@ final class TraversableContainsOnly extends Constraint
private $type;
/**
* @throws \PHPUnit\Framework\Exception
* @throws Exception
*/
public function __construct(string $type, bool $isNativeType = true)
{
@@ -36,7 +38,7 @@ final class TraversableContainsOnly extends Constraint
$this->constraint = new IsType($type);
} else {
$this->constraint = new IsInstanceOf(
$type
$type,
);
}
@@ -55,8 +57,8 @@ final class TraversableContainsOnly extends Constraint
*
* @param mixed|Traversable $other
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
* @throws InvalidArgumentException
*/
public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
{

View File

@@ -12,6 +12,7 @@ namespace PHPUnit\Framework\Constraint;
use function sprintf;
use ReflectionClass;
use ReflectionException;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -36,7 +37,7 @@ final class IsInstanceOf extends Constraint
return sprintf(
'is instance of %s "%s"',
$this->getType(),
$this->className
$this->className,
);
}
@@ -59,7 +60,7 @@ final class IsInstanceOf extends Constraint
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
protected function failureDescription($other): string
{
@@ -67,7 +68,7 @@ final class IsInstanceOf extends Constraint
'%s is an instance of %s "%s"',
$this->exporter()->shortenedExport($other),
$this->getType(),
$this->className
$this->className,
);
}

View File

@@ -10,6 +10,7 @@
namespace PHPUnit\Framework\Constraint;
use function gettype;
use function is_array;
use function is_bool;
use function is_callable;
@@ -21,6 +22,7 @@ use function is_object;
use function is_scalar;
use function is_string;
use function sprintf;
use PHPUnit\Framework\Exception;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -121,17 +123,17 @@ final class IsType extends Constraint
private $type;
/**
* @throws \PHPUnit\Framework\Exception
* @throws Exception
*/
public function __construct(string $type)
{
if (!isset(self::KNOWN_TYPES[$type])) {
throw new \PHPUnit\Framework\Exception(
throw new Exception(
sprintf(
'Type specified for PHPUnit\Framework\Constraint\IsType <%s> ' .
'is not a valid type.',
$type
)
$type,
),
);
}
@@ -145,7 +147,7 @@ final class IsType extends Constraint
{
return sprintf(
'is of type "%s"',
$this->type
$this->type,
);
}

View File

@@ -11,6 +11,7 @@ namespace PHPUnit\Framework;
use function explode;
use PHPUnit\Util\Test as TestUtil;
use SebastianBergmann\RecursionContext\InvalidArgumentException;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -64,7 +65,7 @@ final class DataProviderTestSuite extends TestSuite
/**
* Returns the size of the each test created using the data provider(s).
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws InvalidArgumentException
*/
public function getSize(): int
{

View File

@@ -16,7 +16,7 @@ use PHPUnit\Framework\Exception;
*/
class Error extends Exception
{
public function __construct(string $message, int $code, string $file, int $line, \Exception $previous = null)
public function __construct(string $message, int $code, string $file, int $line, ?\Exception $previous = null)
{
parent::__construct($message, $code, $previous);

View File

@@ -15,17 +15,17 @@ namespace PHPUnit\Framework;
final class ErrorTestCase extends TestCase
{
/**
* @var bool
* @var ?bool
*/
protected $backupGlobals = false;
/**
* @var bool
* @var ?bool
*/
protected $backupStaticAttributes = false;
/**
* @var bool
* @var ?bool
*/
protected $runTestInSeparateProcess = false;

View File

@@ -21,7 +21,7 @@ final class ActualValueIsNotAnObjectException extends Exception
parent::__construct(
'Actual value is not an object',
0,
null
null,
);
}

View File

@@ -24,10 +24,10 @@ final class ComparisonMethodDoesNotAcceptParameterTypeException extends Exceptio
'%s is not an accepted argument type for comparison method %s::%s().',
$type,
$className,
$methodName
$methodName,
),
0,
null
null,
);
}

View File

@@ -23,10 +23,10 @@ final class ComparisonMethodDoesNotDeclareBoolReturnTypeException extends Except
sprintf(
'Comparison method %s::%s() does not declare bool return type.',
$className,
$methodName
$methodName,
),
0,
null
null,
);
}

View File

@@ -23,10 +23,10 @@ final class ComparisonMethodDoesNotDeclareExactlyOneParameterException extends E
sprintf(
'Comparison method %s::%s() does not declare exactly one parameter.',
$className,
$methodName
$methodName,
),
0,
null
null,
);
}

View File

@@ -23,10 +23,10 @@ final class ComparisonMethodDoesNotDeclareParameterTypeException extends Excepti
sprintf(
'Parameter of comparison method %s::%s() does not have a declared type.',
$className,
$methodName
$methodName,
),
0,
null
null,
);
}

View File

@@ -23,10 +23,10 @@ final class ComparisonMethodDoesNotExistException extends Exception
sprintf(
'Comparison method %s::%s() does not exist.',
$className,
$methodName
$methodName,
),
0,
null
null,
);
}

View File

@@ -44,7 +44,7 @@ class Exception extends RuntimeException implements \PHPUnit\Exception
*/
protected $serializableTrace;
public function __construct($message = '', $code = 0, Throwable $previous = null)
public function __construct($message = '', $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);

View File

@@ -28,7 +28,7 @@ final class ExpectationFailedException extends AssertionFailedError
*/
protected $comparisonFailure;
public function __construct(string $message, ComparisonFailure $comparisonFailure = null, Exception $previous = null)
public function __construct(string $message, ?ComparisonFailure $comparisonFailure = null, ?Exception $previous = null)
{
$this->comparisonFailure = $comparisonFailure;

View File

@@ -34,12 +34,12 @@ final class InvalidArgumentException extends Exception
$argument,
$function,
in_array(lcfirst($type)[0], ['a', 'e', 'i', 'o', 'u'], true) ? 'an' : 'a',
$type
)
$type,
),
);
}
private function __construct(string $message = '', int $code = 0, \Exception $previous = null)
private function __construct(string $message = '', int $code = 0, ?\Exception $previous = null)
{
parent::__construct($message, $code, $previous);
}

View File

@@ -9,11 +9,13 @@
*/
namespace PHPUnit\Framework;
use const PHP_VERSION_ID;
use function array_keys;
use function get_class;
use function spl_object_hash;
use PHPUnit\Util\Filter;
use Throwable;
use WeakReference;
/**
* Wraps Exceptions thrown by code under test.
@@ -38,6 +40,11 @@ final class ExceptionWrapper extends Exception
*/
protected $previous;
/**
* @var null|WeakReference<Throwable>
*/
private $originalException;
public function __construct(Throwable $t)
{
// PDOException::getCode() is a string.
@@ -107,16 +114,25 @@ final class ExceptionWrapper extends Exception
*
* Approach works both for var_dump() and var_export() and print_r().
*/
private function originalException(Throwable $exceptionToStore = null): ?Throwable
private function originalException(?Throwable $exceptionToStore = null): ?Throwable
{
static $originalExceptions;
// drop once PHP 7.3 support is removed
if (PHP_VERSION_ID < 70400) {
static $originalExceptions;
$instanceId = spl_object_hash($this);
$instanceId = spl_object_hash($this);
if ($exceptionToStore) {
$originalExceptions[$instanceId] = $exceptionToStore;
if ($exceptionToStore) {
$originalExceptions[$instanceId] = $exceptionToStore;
}
return $originalExceptions[$instanceId] ?? null;
}
return $originalExceptions[$instanceId] ?? null;
if ($exceptionToStore) {
$this->originalException = WeakReference::create($exceptionToStore);
}
return $this->originalException !== null ? $this->originalException->get() : null;
}
}

View File

@@ -77,8 +77,8 @@ final class ExecutionOrderDependency
static function (self $d)
{
return $d->isValid();
}
)
},
),
);
}
@@ -95,7 +95,7 @@ final class ExecutionOrderDependency
{
return $dependency->getTarget();
},
$existing
$existing,
);
foreach ($additional as $dependency) {
@@ -132,7 +132,7 @@ final class ExecutionOrderDependency
{
return $dependency->getTarget();
},
$right
$right,
);
foreach ($left as $dependency) {

Some files were not shown because too many files have changed in this diff Show More