implement JS password scoring, td_stock approve logicc

This commit is contained in:
Thanakorn S
2026-04-30 15:14:42 +07:00
parent db5c47b6ca
commit ac4fd9a5ad
3147 changed files with 1298 additions and 343 deletions
@@ -0,0 +1,33 @@
<?php
namespace PHPSTORM_META {
override(
\PHPUnit\Framework\TestCase::createMock(0),
map([""=>"$0"])
);
override(
\PHPUnit\Framework\TestCase::createStub(0),
map([""=>"$0"])
);
override(
\PHPUnit\Framework\TestCase::createConfiguredMock(0),
map([""=>"$0"])
);
override(
\PHPUnit\Framework\TestCase::createPartialMock(0),
map([""=>"$0"])
);
override(
\PHPUnit\Framework\TestCase::createTestProxy(0),
map([""=>"$0"])
);
override(
\PHPUnit\Framework\TestCase::getMockForAbstractClass(0),
map([""=>"$0"])
);
}
@@ -0,0 +1,311 @@
# 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.34] - 2023-09-19
### Changed
* The child processes used for process isolation now use temporary files to communicate their result to the parent process
## [8.5.33] - 2023-02-27
### Fixed
* [#5186](https://github.com/sebastianbergmann/phpunit/issues/5186): SBOM does not validate
## [8.5.32] - 2023-01-26
### Fixed
* [#5120](https://github.com/sebastianbergmann/phpunit/issues/5120): Test Runner incorrectly treats `--testsuite` and `--list-tests` as not combinable options
## [8.5.31] - 2022-10-28
### Fixed
* [#5076](https://github.com/sebastianbergmann/phpunit/issues/5076): Test Runner does not warn about conflicting options
## [8.5.30] - 2022-09-25
### Changed
* The configuration generator now asks for a cache directory
### Fixed
* [#4913](https://github.com/sebastianbergmann/phpunit/issues/4913): Failed `assert()` should show a backtrace
* [#4966](https://github.com/sebastianbergmann/phpunit/issues/4966): `TestCase::assertSame()` (and related exact comparisons) must compare `float` exactly
## [8.5.29] - 2022-08-22
### Changed
* [#5033](https://github.com/sebastianbergmann/phpunit/issues/5033): Do not depend on phpspec/prophecy
## [8.5.28] - 2022-07-29
### Fixed
* [#5015](https://github.com/sebastianbergmann/phpunit/pull/5015): Ukraine banner unreadable on black background
* [#5016](https://github.com/sebastianbergmann/phpunit/issues/5016): PHPUnit 8.5.27 does not work on PHP 7.2.0-7.2.18 and PHP 7.3.0-7.3.5
## [8.5.27] - 2022-06-19
### Fixed
* [#4950](https://github.com/sebastianbergmann/phpunit/issues/4950): False error on `atMost()` invocation rule without call
* [#4962](https://github.com/sebastianbergmann/phpunit/issues/4962): Ukraine banner unreadable on white background
## [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.34]: https://github.com/sebastianbergmann/phpunit/compare/8.5.33...8.5.34
[8.5.33]: https://github.com/sebastianbergmann/phpunit/compare/8.5.32...8.5.33
[8.5.32]: https://github.com/sebastianbergmann/phpunit/compare/8.5.31...8.5.32
[8.5.31]: https://github.com/sebastianbergmann/phpunit/compare/8.5.30...8.5.31
[8.5.30]: https://github.com/sebastianbergmann/phpunit/compare/8.5.29...8.5.30
[8.5.29]: https://github.com/sebastianbergmann/phpunit/compare/8.5.28...8.5.29
[8.5.28]: https://github.com/sebastianbergmann/phpunit/compare/8.5.27...8.5.28
[8.5.27]: https://github.com/sebastianbergmann/phpunit/compare/8.5.26...8.5.27
[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
+29
View File
@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2001-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:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
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.
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 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.
+38
View File
@@ -0,0 +1,38 @@
<h1 align="center">🇺🇦 <a href="https://phpunit.de/stand-with-ukraine.html">UKRAINE NEEDS YOUR HELP NOW!</a></h1>
# PHPUnit
[![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/8.5/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
We distribute a [PHP Archive (PHAR)](https://php.net/phar) that has all required (as well as some optional) dependencies of PHPUnit bundled in a single file:
```bash
$ wget https://phar.phpunit.de/phpunit-X.Y.phar
$ php phpunit-X.Y.phar --version
```
Please replace `X.Y` with the version of PHPUnit you are interested in.
Alternatively, you may use [Composer](https://getcomposer.org/) to download and install PHPUnit as well as its dependencies. Please refer to the "[Getting Started](https://phpunit.de/getting-started-with-phpunit.html)" guide for details on how to install PHPUnit.
## Contribute
Please refer to [CONTRIBUTING.md](https://github.com/sebastianbergmann/phpunit/blob/main/.github/CONTRIBUTING.md) for information on how to contribute to PHPUnit and its related projects.
## List of Contributors
Thanks to everyone who has contributed to PHPUnit! You can find a detailed list of contributors on every PHPUnit related package on GitHub. This list shows only the major components:
* [PHPUnit](https://github.com/sebastianbergmann/phpunit/graphs/contributors)
* [php-code-coverage](https://github.com/sebastianbergmann/php-code-coverage/graphs/contributors)
A very special thanks to everyone who has contributed to the [documentation](https://github.com/sebastianbergmann/phpunit-documentation-english/graphs/contributors).
@@ -0,0 +1,33 @@
# Security Policy
If you believe you have found a security vulnerability in PHPUnit, please report it to us through coordinated disclosure.
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
Instead, please email `sebastian@phpunit.de`.
Please include as much of the information listed below as you can to help us better understand and resolve the issue:
* The type of issue
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
## Web Context
PHPUnit is a framework for writing as well as a command-line tool for running tests. Writing and running tests is a development-time activity. There is no reason why PHPUnit should be installed on a webserver and/or in a production environment.
**If you upload PHPUnit to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.**
Please note that if you upload PHPUnit to a webserver "bad things" may happen. [You have been warned.](https://thephp.cc/articles/phpunit-a-security-risk)
PHPUnit is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using PHPUnit in an HTTP or web context or with untrusted input data is performed. PHPUnit might also contain functionality that intentionally exposes internal application data for debugging purposes.
If PHPUnit is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context.
Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes.
@@ -0,0 +1,86 @@
{
"name": "phpunit/phpunit",
"description": "The PHP Unit Testing framework.",
"type": "library",
"keywords": [
"phpunit",
"xunit",
"testing"
],
"homepage": "https://phpunit.de/",
"license": "BSD-3-Clause",
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy"
},
"prefer-stable": true,
"require": {
"php": ">=7.2",
"ext-dom": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"doctrine/instantiator": "^1.3.1",
"myclabs/deep-copy": "^1.10.0",
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"phpunit/php-code-coverage": "^7.0.12",
"phpunit/php-file-iterator": "^2.0.4",
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-timer": "^2.1.2",
"sebastian/comparator": "^3.0.5",
"sebastian/diff": "^3.0.2",
"sebastian/environment": "^4.2.3",
"sebastian/exporter": "^3.1.5",
"sebastian/global-state": "^3.0.0",
"sebastian/object-enumerator": "^3.0.3",
"sebastian/resource-operations": "^2.0.1",
"sebastian/type": "^1.1.3",
"sebastian/version": "^2.0.1"
},
"config": {
"platform": {
"php": "7.2.0"
},
"optimize-autoloader": true,
"sort-packages": true
},
"suggest": {
"phpunit/php-invoker": "To allow enforcing time limits",
"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"
],
"autoload": {
"classmap": [
"src/"
]
},
"autoload-dev": {
"classmap": [
"tests/"
],
"files": [
"src/Framework/Assert/Functions.php",
"tests/_files/CoverageNamespacedFunctionTest.php",
"tests/_files/CoveredFunction.php",
"tests/_files/NamespaceCoveredFunction.php"
]
},
"extra": {
"branch-alias": {
"dev-master": "8.5-dev"
}
}
}
+98
View File
@@ -0,0 +1,98 @@
#!/usr/bin/env php
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (!version_compare(PHP_VERSION, PHP_VERSION, '=')) {
fwrite(
STDERR,
sprintf(
'%s declares an invalid value for PHP_VERSION.' . PHP_EOL .
'This breaks fundamental functionality such as version_compare().' . PHP_EOL .
'Please use a different PHP interpreter.' . PHP_EOL,
PHP_BINARY
)
);
die(1);
}
if (version_compare('7.2.0', PHP_VERSION, '>')) {
fwrite(
STDERR,
sprintf(
'This version of PHPUnit requires PHP >= 7.2.' . PHP_EOL .
'You are using PHP %s (%s).' . PHP_EOL,
PHP_VERSION,
PHP_BINARY
)
);
die(1);
}
foreach (['dom', 'json', 'libxml', 'mbstring', 'tokenizer', 'xml', 'xmlwriter'] as $extension) {
if (extension_loaded($extension)) {
continue;
}
fwrite(
STDERR,
sprintf(
'PHPUnit requires the "%s" extension.' . PHP_EOL,
$extension
)
);
die(1);
}
if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}
if (isset($GLOBALS['_composer_autoload_path'])) {
define('PHPUNIT_COMPOSER_INSTALL', $GLOBALS['_composer_autoload_path']);
unset($GLOBALS['_composer_autoload_path']);
} else {
foreach (array(__DIR__ . '/../../autoload.php', __DIR__ . '/../vendor/autoload.php', __DIR__ . '/vendor/autoload.php') as $file) {
if (file_exists($file)) {
define('PHPUNIT_COMPOSER_INSTALL', $file);
break;
}
}
unset($file);
}
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
fwrite(
STDERR,
'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL .
' composer install' . PHP_EOL . PHP_EOL .
'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL
);
die(1);
}
$options = getopt('', array('prepend:'));
if (isset($options['prepend'])) {
require $options['prepend'];
}
unset($options);
require PHPUNIT_COMPOSER_INSTALL;
PHPUnit\TextUI\Command::main();
+319
View File
@@ -0,0 +1,319 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 8.5 may be structured.
</xs:documentation>
<xs:appinfo source="https://phpunit.de/documentation.html"/>
</xs:annotation>
<xs:element name="phpunit" type="phpUnitType">
<xs:annotation>
<xs:documentation>Root Element</xs:documentation>
</xs:annotation>
</xs:element>
<xs:complexType name="filtersType">
<xs:sequence>
<xs:element name="whitelist" type="whiteListType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="filterType">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:group ref="pathGroup"/>
<xs:element name="exclude">
<xs:complexType>
<xs:group ref="pathGroup"/>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:sequence>
</xs:complexType>
<xs:complexType name="whiteListType">
<xs:complexContent>
<xs:extension base="filterType">
<xs:attribute name="addUncoveredFilesFromWhitelist" default="true" type="xs:boolean"/>
<xs:attribute name="processUncoveredFilesFromWhitelist" default="false" type="xs:boolean"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="groupsType">
<xs:choice>
<xs:sequence>
<xs:element name="include" type="groupType"/>
<xs:element name="exclude" type="groupType" minOccurs="0"/>
</xs:sequence>
<xs:sequence>
<xs:element name="exclude" type="groupType"/>
</xs:sequence>
</xs:choice>
</xs:complexType>
<xs:complexType name="groupType">
<xs:sequence>
<xs:element name="group" type="xs:string" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="extensionsType">
<xs:sequence>
<xs:element name="extension" type="objectType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="listenersType">
<xs:sequence>
<xs:element name="listener" type="objectType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="objectType">
<xs:sequence>
<xs:element name="arguments" minOccurs="0">
<xs:complexType>
<xs:group ref="argumentsGroup"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="class" type="xs:string" use="required"/>
<xs:attribute name="file" type="xs:anyURI"/>
</xs:complexType>
<xs:complexType name="arrayType">
<xs:sequence>
<xs:element name="element" type="argumentType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="argumentType">
<xs:group ref="argumentChoice"/>
<xs:attribute name="key" use="required"/>
</xs:complexType>
<xs:group name="argumentsGroup">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="array" type="arrayType" />
<xs:element name="integer" type="xs:integer" />
<xs:element name="string" type="xs:string" />
<xs:element name="double" type="xs:double" />
<xs:element name="null" />
<xs:element name="object" type="objectType" />
<xs:element name="file" type="xs:anyURI" />
<xs:element name="directory" type="xs:anyURI" />
<xs:element name="boolean" type="xs:boolean" />
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="argumentChoice">
<xs:choice>
<xs:element name="array" type="arrayType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="integer" type="xs:integer" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="string" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="double" type="xs:double" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="null" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="object" type="objectType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="file" type="xs:anyURI" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="directory" type="xs:anyURI" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="boolean" type="xs:boolean" minOccurs="0" maxOccurs="unbounded"/>
</xs:choice>
</xs:group>
<xs:simpleType name="columnsType">
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:integer"/>
</xs:simpleType>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="max"/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
<xs:complexType name="loggersType">
<xs:sequence>
<xs:element name="log" type="loggerType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="loggerType">
<xs:attribute name="type">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="coverage-html"/>
<xs:enumeration value="coverage-text"/>
<xs:enumeration value="coverage-clover"/>
<xs:enumeration value="coverage-crap4j"/>
<xs:enumeration value="coverage-xml"/>
<xs:enumeration value="coverage-php"/>
<xs:enumeration value="json"/>
<xs:enumeration value="plain"/>
<xs:enumeration value="tap"/>
<xs:enumeration value="teamcity"/>
<xs:enumeration value="junit"/>
<xs:enumeration value="testdox-html"/>
<xs:enumeration value="testdox-text"/>
<xs:enumeration value="testdox-xml"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="target" type="xs:anyURI"/>
<xs:attribute name="lowUpperBound" type="xs:nonNegativeInteger" default="50"/>
<xs:attribute name="highLowerBound" type="xs:nonNegativeInteger" default="90"/>
<xs:attribute name="showUncoveredFiles" type="xs:boolean" default="false"/>
<xs:attribute name="showOnlySummary" type="xs:boolean" default="false"/>
<xs:attribute name="threshold" type="xs:nonNegativeInteger" default="30"/>
</xs:complexType>
<xs:group name="pathGroup">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="directory" type="directoryFilterType"/>
<xs:element name="file" type="fileFilterType"/>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:complexType name="directoryFilterType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="prefix" default=""/>
<xs:attribute type="xs:string" name="suffix" default="Test.php"/>
<xs:attributeGroup ref="phpVersionGroup"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="executionOrderType">
<xs:restriction base="xs:string">
<xs:enumeration value="default"/>
<xs:enumeration value="defects"/>
<xs:enumeration value="depends"/>
<xs:enumeration value="depends,defects"/>
<xs:enumeration value="depends,duration"/>
<xs:enumeration value="depends,random"/>
<xs:enumeration value="depends,reverse"/>
<xs:enumeration value="depends,size"/>
<xs:enumeration value="duration"/>
<xs:enumeration value="no-depends"/>
<xs:enumeration value="no-depends,defects"/>
<xs:enumeration value="no-depends,duration"/>
<xs:enumeration value="no-depends,random"/>
<xs:enumeration value="no-depends,reverse"/>
<xs:enumeration value="no-depends,size"/>
<xs:enumeration value="random"/>
<xs:enumeration value="reverse"/>
<xs:enumeration value="size"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="fileFilterType">
<xs:simpleContent>
<xs:extension base="xs:anyURI">
<xs:attributeGroup ref="phpVersionGroup"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:attributeGroup name="phpVersionGroup">
<xs:attribute name="phpVersion" type="xs:string" default="5.3.0"/>
<xs:attribute name="phpVersionOperator" type="xs:string" default="&gt;="/>
</xs:attributeGroup>
<xs:complexType name="phpType">
<xs:sequence>
<xs:choice maxOccurs="unbounded">
<xs:element name="includePath" type="xs:anyURI" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="ini" type="namedValueType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="const" type="namedValueType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="var" type="namedValueType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="env" type="namedValueType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="post" type="namedValueType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="get" type="namedValueType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="cookie" type="namedValueType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="server" type="namedValueType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="files" type="namedValueType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="request" type="namedValueType" minOccurs="0" maxOccurs="unbounded"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
<xs:complexType name="namedValueType">
<xs:attribute name="name" use="required" type="xs:string"/>
<xs:attribute name="value" use="required" type="xs:anySimpleType"/>
<xs:attribute name="verbatim" use="optional" type="xs:boolean"/>
<xs:attribute name="force" use="optional" type="xs:boolean"/>
</xs:complexType>
<xs:complexType name="phpUnitType">
<xs:annotation>
<xs:documentation>The main type specifying the document structure</xs:documentation>
</xs:annotation>
<xs:group ref="configGroup"/>
<xs:attributeGroup ref="configAttributeGroup"/>
</xs:complexType>
<xs:attributeGroup name="configAttributeGroup">
<xs:attribute name="backupGlobals" type="xs:boolean" default="false"/>
<xs:attribute name="backupStaticAttributes" type="xs:boolean" default="false"/>
<xs:attribute name="bootstrap" type="xs:anyURI"/>
<xs:attribute name="cacheResult" type="xs:boolean" default="true"/>
<xs:attribute name="cacheResultFile" type="xs:anyURI"/>
<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="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"/>
<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="printerFile" type="xs:anyURI"/>
<xs:attribute name="processIsolation" type="xs:boolean" default="false"/>
<xs:attribute name="stopOnDefect" type="xs:boolean" default="false"/>
<xs:attribute name="stopOnError" type="xs:boolean" default="false"/>
<xs:attribute name="stopOnFailure" type="xs:boolean" default="false"/>
<xs:attribute name="stopOnWarning" type="xs:boolean" default="false"/>
<xs:attribute name="stopOnIncomplete" type="xs:boolean" default="false"/>
<xs:attribute name="stopOnRisky" type="xs:boolean" default="false"/>
<xs:attribute name="stopOnSkipped" type="xs:boolean" default="false"/>
<xs:attribute name="failOnRisky" type="xs:boolean" default="false"/>
<xs:attribute name="failOnWarning" type="xs:boolean" default="false"/>
<xs:attribute name="beStrictAboutChangesToGlobalState" type="xs:boolean" default="false"/>
<xs:attribute name="beStrictAboutOutputDuringTests" type="xs:boolean" default="false"/>
<xs:attribute name="beStrictAboutResourceUsageDuringSmallTests" type="xs:boolean" default="false"/>
<xs:attribute name="beStrictAboutTestsThatDoNotTestAnything" type="xs:boolean" default="true"/>
<xs:attribute name="beStrictAboutTodoAnnotatedTests" type="xs:boolean" default="false"/>
<xs:attribute name="beStrictAboutCoversAnnotation" type="xs:boolean" default="false"/>
<xs:attribute name="defaultTimeLimit" type="xs:integer" default="0"/>
<xs:attribute name="enforceTimeLimit" type="xs:boolean" default="false"/>
<xs:attribute name="ignoreDeprecatedCodeUnitsFromCodeCoverage" type="xs:boolean" default="false"/>
<xs:attribute name="timeoutForSmallTests" type="xs:integer" default="1"/>
<xs:attribute name="timeoutForMediumTests" type="xs:integer" default="10"/>
<xs:attribute name="timeoutForLargeTests" type="xs:integer" default="60"/>
<xs:attribute name="testSuiteLoaderClass" type="xs:string" default="PHPUnit\Runner\StandardTestSuiteLoader"/>
<xs:attribute name="testSuiteLoaderFile" type="xs:anyURI"/>
<xs:attribute name="defaultTestSuite" type="xs:string" default=""/>
<xs:attribute name="verbose" type="xs:boolean" default="false"/>
<xs:attribute name="testdox" type="xs:boolean" default="false"/>
<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="executionOrder" type="executionOrderType" default="default"/>
<xs:attribute name="resolveDependencies" type="xs:boolean" default="true"/>
<xs:attribute name="noInteraction" type="xs:boolean" default="false"/>
</xs:attributeGroup>
<xs:group name="configGroup">
<xs:all>
<xs:element ref="testSuiteFacet" minOccurs="0"/>
<xs:element name="groups" type="groupsType" minOccurs="0"/>
<xs:element name="testdoxGroups" type="groupsType" minOccurs="0"/>
<xs:element name="filter" type="filtersType" minOccurs="0"/>
<xs:element name="logging" type="loggersType" minOccurs="0"/>
<xs:element name="extensions" type="extensionsType" minOccurs="0"/>
<xs:element name="listeners" type="listenersType" minOccurs="0"/>
<xs:element name="php" type="phpType" minOccurs="0"/>
</xs:all>
</xs:group>
<xs:element name="testSuiteFacet" abstract="true"/>
<xs:element name="testsuite" type="testSuiteType" substitutionGroup="testSuiteFacet"/>
<xs:element name="testsuites" type="testSuitesType" substitutionGroup="testSuiteFacet"/>
<xs:complexType name="testSuitesType">
<xs:sequence>
<xs:element name="testsuite" type="testSuiteType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="testSuiteType">
<xs:sequence>
<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>
</xs:schema>
@@ -0,0 +1,19 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit;
use Throwable;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
interface Exception extends Throwable
{
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,82 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function array_key_exists;
use function is_array;
use ArrayAccess;
/**
* Constraint that asserts that the array it is evaluated for has a given key.
*
* Uses array_key_exists() to check if the key is found in the input array, if
* not found the evaluation fails.
*
* The array key is passed in the constructor.
*/
final class ArrayHasKey extends Constraint
{
/**
* @var int|string
*/
private $key;
/**
* @param int|string $key
*/
public function __construct($key)
{
$this->key = $key;
}
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function toString(): string
{
return 'has the key ' . $this->exporter()->export($this->key);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
if (is_array($other)) {
return array_key_exists($this->key, $other);
}
if ($other instanceof ArrayAccess) {
return $other->offsetExists($this->key);
}
return false;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
return 'an array ' . $this->toString();
}
}
@@ -0,0 +1,135 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function array_replace_recursive;
use function is_array;
use function iterator_to_array;
use function var_export;
use ArrayObject;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\Comparator\ComparisonFailure;
use Traversable;
/**
* Constraint that asserts that the array it is evaluated for has a specified subset.
*
* Uses array_replace_recursive() to check if a key value subset is part of the
* subject array.
*
* @codeCoverageIgnore
*
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/3494
*/
final class ArraySubset extends Constraint
{
/**
* @var iterable
*/
private $subset;
/**
* @var bool
*/
private $strict;
public function __construct(iterable $subset, bool $strict = false)
{
$this->strict = $strict;
$this->subset = $subset;
}
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
// type cast $other & $this->subset as an array to allow
// support in standard array functions.
$other = $this->toArray($other);
$this->subset = $this->toArray($this->subset);
$patched = array_replace_recursive($other, $this->subset);
if ($this->strict) {
$result = $other === $patched;
} else {
$result = $other == $patched;
}
if ($returnResult) {
return $result;
}
if (!$result) {
$f = new ComparisonFailure(
$patched,
$other,
var_export($patched, true),
var_export($other, true)
);
$this->fail($other, $description, $f);
}
}
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function toString(): string
{
return 'has the subset ' . $this->exporter()->export($this->subset);
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
return 'an array ' . $this->toString();
}
private function toArray(iterable $other): array
{
if (is_array($other)) {
return $other;
}
if ($other instanceof ArrayObject) {
return $other->getArrayCopy();
}
if ($other instanceof Traversable) {
return iterator_to_array($other);
}
// Keep BC even if we know that array would not be the expected one
return (array) $other;
}
}
@@ -0,0 +1,80 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\ExpectationFailedException;
/**
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338
*
* @codeCoverageIgnore
*/
final class Attribute extends Composite
{
/**
* @var string
*/
private $attributeName;
public function __construct(Constraint $constraint, string $attributeName)
{
parent::__construct($constraint);
$this->attributeName = $attributeName;
}
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \PHPUnit\Framework\Exception
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
return parent::evaluate(
Assert::readAttribute(
$other,
$this->attributeName
),
$description,
$returnResult
);
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'attribute "' . $this->attributeName . '" ' . $this->innerConstraint()->toString();
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
return $this->toString();
}
}
@@ -0,0 +1,52 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
/**
* Constraint that evaluates against a specified closure.
*
* @psalm-template CallbackInput of mixed
*/
final class Callback extends Constraint
{
/**
* @var callable
*
* @psalm-var callable(CallbackInput $input): bool
*/
private $callback;
/** @psalm-param callable(CallbackInput $input): bool $callback */
public function __construct(callable $callback)
{
$this->callback = $callback;
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is accepted by specified callback';
}
/**
* Evaluates the constraint for parameter $value. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*
* @psalm-param CallbackInput $other
*/
protected function matches($other): bool
{
return ($this->callback)($other);
}
}
@@ -0,0 +1,91 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function get_class;
use function is_object;
use function sprintf;
use PHPUnit\Framework\Exception;
use ReflectionClass;
use ReflectionException;
/**
* Constraint that asserts that the class it is evaluated for has a given
* attribute.
*
* The attribute name is passed in the constructor.
*/
class ClassHasAttribute extends Constraint
{
/**
* @var string
*/
private $attributeName;
public function __construct(string $attributeName)
{
$this->attributeName = $attributeName;
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return sprintf(
'has attribute "%s"',
$this->attributeName
);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
try {
return (new ReflectionClass($other))->hasProperty($this->attributeName);
// @codeCoverageIgnoreStart
} catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
$e->getCode(),
$e
);
}
// @codeCoverageIgnoreEnd
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
return sprintf(
'%sclass "%s" %s',
is_object($other) ? 'object of ' : '',
is_object($other) ? get_class($other) : $other,
$this->toString()
);
}
protected function attributeName(): string
{
return $this->attributeName;
}
}
@@ -0,0 +1,62 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function sprintf;
use PHPUnit\Framework\Exception;
use ReflectionClass;
use ReflectionException;
/**
* Constraint that asserts that the class it is evaluated for has a given
* static attribute.
*
* The attribute name is passed in the constructor.
*/
final class ClassHasStaticAttribute extends ClassHasAttribute
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return sprintf(
'has static attribute "%s"',
$this->attributeName()
);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
try {
$class = new ReflectionClass($other);
if ($class->hasProperty($this->attributeName())) {
return $class->getProperty($this->attributeName())->isStatic();
}
// @codeCoverageIgnoreStart
} catch (ReflectionException $e) {
throw new Exception(
$e->getMessage(),
$e->getCode(),
$e
);
}
// @codeCoverageIgnoreEnd
return false;
}
}
@@ -0,0 +1,70 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function count;
use PHPUnit\Framework\ExpectationFailedException;
/**
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338
*
* @codeCoverageIgnore
*/
abstract class Composite extends Constraint
{
/**
* @var Constraint
*/
private $innerConstraint;
public function __construct(Constraint $innerConstraint)
{
$this->innerConstraint = $innerConstraint;
}
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
try {
return $this->innerConstraint->evaluate(
$other,
$description,
$returnResult
);
} catch (ExpectationFailedException $e) {
$this->fail($other, $description, $e->getComparisonFailure());
}
}
/**
* Counts the number of constraint elements.
*/
public function count(): int
{
return count($this->innerConstraint);
}
protected function innerConstraint(): Constraint
{
return $this->innerConstraint;
}
}
@@ -0,0 +1,155 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function sprintf;
use Countable;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\SelfDescribing;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Exporter\Exporter;
/**
* Abstract base class for constraints which can be applied to any value.
*/
abstract class Constraint implements Countable, SelfDescribing
{
/**
* @var Exporter
*/
private $exporter;
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = false;
if ($this->matches($other)) {
$success = true;
}
if ($returnResult) {
return $success;
}
if (!$success) {
$this->fail($other, $description);
}
}
/**
* Counts the number of constraint elements.
*/
public function count(): int
{
return 1;
}
protected function exporter(): Exporter
{
if ($this->exporter === null) {
$this->exporter = new Exporter;
}
return $this->exporter;
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* This method can be overridden to implement the evaluation algorithm.
*
* @param mixed $other value or object to evaluate
*
* @codeCoverageIgnore
*/
protected function matches($other): bool
{
return false;
}
/**
* 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
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*
* @psalm-return never-return
*/
protected function fail($other, $description, ComparisonFailure $comparisonFailure = null): void
{
$failureDescription = sprintf(
'Failed asserting that %s.',
$this->failureDescription($other)
);
$additionalFailureDescription = $this->additionalFailureDescription($other);
if ($additionalFailureDescription) {
$failureDescription .= "\n" . $additionalFailureDescription;
}
if (!empty($description)) {
$failureDescription = $description . "\n" . $failureDescription;
}
throw new ExpectationFailedException(
$failureDescription,
$comparisonFailure
);
}
/**
* Return additional failure description where needed.
*
* The function can be overridden to provide additional failure
* information like a diff
*
* @param mixed $other evaluated value or object
*/
protected function additionalFailureDescription($other): string
{
return '';
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* To provide additional failure information additionalFailureDescription
* can be used.
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
return $this->exporter()->export($other) . ' ' . $this->toString();
}
}
@@ -0,0 +1,128 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function count;
use function is_array;
use function iterator_count;
use function sprintf;
use Countable;
use EmptyIterator;
use Generator;
use Iterator;
use IteratorAggregate;
use Traversable;
class Count extends Constraint
{
/**
* @var int
*/
private $expectedCount;
public function __construct(int $expected)
{
$this->expectedCount = $expected;
}
public function toString(): string
{
return sprintf(
'count matches %d',
$this->expectedCount
);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*/
protected function matches($other): bool
{
return $this->expectedCount === $this->getCountOf($other);
}
/**
* @param iterable $other
*/
protected function getCountOf($other): ?int
{
if ($other instanceof Countable || is_array($other)) {
return count($other);
}
if ($other instanceof EmptyIterator) {
return 0;
}
if ($other instanceof Traversable) {
while ($other instanceof IteratorAggregate) {
$other = $other->getIterator();
}
$iterator = $other;
if ($iterator instanceof Generator) {
return $this->getCountOfGenerator($iterator);
}
if (!$iterator instanceof Iterator) {
return iterator_count($iterator);
}
$key = $iterator->key();
$count = iterator_count($iterator);
// Manually rewind $iterator to previous key, since iterator_count
// moves pointer.
if ($key !== null) {
$iterator->rewind();
while ($iterator->valid() && $key !== $iterator->key()) {
$iterator->next();
}
}
return $count;
}
return null;
}
/**
* Returns the total number of iterations from a generator.
* This will fully exhaust the generator.
*/
protected function getCountOfGenerator(Generator $generator): int
{
for ($count = 0; $generator->valid(); $generator->next()) {
$count++;
}
return $count;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
return sprintf(
'actual size %d matches expected size %d',
$this->getCountOf($other),
$this->expectedCount
);
}
}
@@ -0,0 +1,56 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function is_dir;
use function sprintf;
/**
* Constraint that checks if the directory(name) that it is evaluated for exists.
*
* The file path to check is passed as $other in evaluate().
*/
final class DirectoryExists extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'directory exists';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return is_dir($other);
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
return sprintf(
'directory "%s" exists',
$other
);
}
}
@@ -0,0 +1,82 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function get_class;
use function sprintf;
use PHPUnit\Util\Filter;
use Throwable;
final class Exception extends Constraint
{
/**
* @var string
*/
private $className;
public function __construct(string $className)
{
$this->className = $className;
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return sprintf(
'exception of type "%s"',
$this->className
);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return $other instanceof $this->className;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
if ($other !== null) {
$message = '';
if ($other instanceof Throwable) {
$message = '. Message was: "' . $other->getMessage() . '" at'
. "\n" . Filter::getFilteredStacktrace($other);
}
return sprintf(
'exception of type "%s" matches expected exception "%s"%s',
get_class($other),
$this->className,
$message
);
}
return sprintf(
'exception of type "%s" is thrown',
$this->className
);
}
}
@@ -0,0 +1,64 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function sprintf;
use Throwable;
final class ExceptionCode extends Constraint
{
/**
* @var int|string
*/
private $expectedCode;
/**
* @param int|string $expected
*/
public function __construct($expected)
{
$this->expectedCode = $expected;
}
public function toString(): string
{
return 'exception code is ';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param Throwable $other
*/
protected function matches($other): bool
{
return (string) $other->getCode() === (string) $this->expectedCode;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\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)
);
}
}
@@ -0,0 +1,75 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function sprintf;
use function strpos;
use Throwable;
final class ExceptionMessage extends Constraint
{
/**
* @var string
*/
private $expectedMessage;
public function __construct(string $expected)
{
$this->expectedMessage = $expected;
}
public function toString(): string
{
if ($this->expectedMessage === '') {
return 'exception message is empty';
}
return 'exception message contains ';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param Throwable $other
*/
protected function matches($other): bool
{
if ($this->expectedMessage === '') {
return $other->getMessage() === '';
}
return strpos((string) $other->getMessage(), $this->expectedMessage) !== false;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
if ($this->expectedMessage === '') {
return sprintf(
"exception message is empty but is '%s'",
$other->getMessage()
);
}
return sprintf(
"exception message '%s' contains '%s'",
$other->getMessage(),
$this->expectedMessage
);
}
}
@@ -0,0 +1,71 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function sprintf;
use Exception;
use PHPUnit\Util\RegularExpression as RegularExpressionUtil;
final class ExceptionMessageRegularExpression extends Constraint
{
/**
* @var string
*/
private $expectedMessageRegExp;
public function __construct(string $expected)
{
$this->expectedMessageRegExp = $expected;
}
public function toString(): string
{
return 'exception message matches ';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param \PHPUnit\Framework\Exception $other
*
* @throws \PHPUnit\Framework\Exception
* @throws Exception
*/
protected function matches($other): bool
{
$match = RegularExpressionUtil::safeMatch($this->expectedMessageRegExp, $other->getMessage());
if ($match === false) {
throw new \PHPUnit\Framework\Exception(
"Invalid expected exception message regex given: '{$this->expectedMessageRegExp}'"
);
}
return $match === 1;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
return sprintf(
"exception message '%s' matches '%s'",
$other->getMessage(),
$this->expectedMessageRegExp
);
}
}
@@ -0,0 +1,56 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function file_exists;
use function sprintf;
/**
* Constraint that checks if the file(name) that it is evaluated for exists.
*
* The file path to check is passed as $other in evaluate().
*/
final class FileExists extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'file exists';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return file_exists($other);
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
return sprintf(
'file "%s" exists',
$other
);
}
}
@@ -0,0 +1,51 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
/**
* Constraint that asserts that the value it is evaluated for is greater
* than a given value.
*/
final class GreaterThan extends Constraint
{
/**
* @var float|int
*/
private $value;
/**
* @param float|int $value
*/
public function __construct($value)
{
$this->value = $value;
}
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function toString(): string
{
return 'is greater than ' . $this->exporter()->export($this->value);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return $this->value < $other;
}
}
@@ -0,0 +1,51 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use PHPUnit\Framework\ExpectationFailedException;
/**
* Constraint that accepts any input value.
*/
final class IsAnything extends Constraint
{
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
return $returnResult ? true : null;
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is anything';
}
/**
* Counts the number of constraint elements.
*/
public function count(): int
{
return 0;
}
}
@@ -0,0 +1,70 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function count;
use function gettype;
use function sprintf;
use function strpos;
use Countable;
use EmptyIterator;
/**
* Constraint that checks whether a variable is empty().
*/
final class IsEmpty extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is empty';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
if ($other instanceof EmptyIterator) {
return true;
}
if ($other instanceof Countable) {
return count($other) === 0;
}
return empty($other);
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
$type = gettype($other);
return sprintf(
'%s %s %s',
strpos($type, 'a') === 0 || strpos($type, 'o') === 0 ? 'an' : 'a',
$type,
$this->toString()
);
}
}
@@ -0,0 +1,142 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function is_string;
use function sprintf;
use function strpos;
use function trim;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Comparator\Factory as ComparatorFactory;
/**
* Constraint that checks if one value is equal to another.
*
* Equality is checked with PHP's == operator, the operator is explained in
* detail at {@url https://php.net/manual/en/types.comparisons.php}.
* Two values are equal if they have the same value disregarding type.
*
* The expected value is passed in the constructor.
*/
final class IsEqual extends Constraint
{
/**
* @var mixed
*/
private $value;
/**
* @var float
*/
private $delta;
/**
* @var bool
*/
private $canonicalize;
/**
* @var bool
*/
private $ignoreCase;
public function __construct($value, float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false)
{
$this->value = $value;
$this->delta = $delta;
$this->canonicalize = $canonicalize;
$this->ignoreCase = $ignoreCase;
}
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
// If $this->value and $other are identical, they are also equal.
// This is the most common path and will allow us to skip
// initialization of all the comparators.
if ($this->value === $other) {
return true;
}
$comparatorFactory = ComparatorFactory::getInstance();
try {
$comparator = $comparatorFactory->getComparatorFor(
$this->value,
$other
);
$comparator->assertEquals(
$this->value,
$other,
$this->delta,
$this->canonicalize,
$this->ignoreCase
);
} catch (ComparisonFailure $f) {
if ($returnResult) {
return false;
}
throw new ExpectationFailedException(
trim($description . "\n" . $f->getMessage()),
$f
);
}
return true;
}
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function toString(): string
{
$delta = '';
if (is_string($this->value)) {
if (strpos($this->value, "\n") !== false) {
return 'is equal to <text>';
}
return sprintf(
"is equal to '%s'",
$this->value
);
}
if ($this->delta != 0) {
$delta = sprintf(
' with delta <%F>',
$this->delta
);
}
return sprintf(
'is equal to %s%s',
$this->exporter()->export($this->value),
$delta
);
}
}
@@ -0,0 +1,35 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
/**
* Constraint that accepts false.
*/
final class IsFalse extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is false';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return $other === false;
}
}
@@ -0,0 +1,37 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function is_finite;
/**
* Constraint that accepts finite.
*/
final class IsFinite extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is finite';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return is_finite($other);
}
}
@@ -0,0 +1,132 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function get_class;
use function is_array;
use function is_object;
use function is_string;
use function sprintf;
use PHPUnit\Framework\ExpectationFailedException;
use SebastianBergmann\Comparator\ComparisonFailure;
/**
* Constraint that asserts that one value is identical to another.
*
* Identical check is performed with PHP's === operator, the operator is
* explained in detail at
* {@url https://php.net/manual/en/types.comparisons.php}.
* Two values are identical if they have the same value and are of the same
* type.
*
* The expected value is passed in the constructor.
*/
final class IsIdentical extends Constraint
{
/**
* @var mixed
*/
private $value;
public function __construct($value)
{
$this->value = $value;
}
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = $this->value === $other;
if ($returnResult) {
return $success;
}
if (!$success) {
$f = null;
// if both values are strings, make sure a diff is generated
if (is_string($this->value) && is_string($other)) {
$f = new ComparisonFailure(
$this->value,
$other,
sprintf("'%s'", $this->value),
sprintf("'%s'", $other)
);
}
// if both values are array, make sure a diff is generated
if (is_array($this->value) && is_array($other)) {
$f = new ComparisonFailure(
$this->value,
$other,
$this->exporter()->export($this->value),
$this->exporter()->export($other)
);
}
$this->fail($other, $description, $f);
}
}
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function toString(): string
{
if (is_object($this->value)) {
return 'is identical to an object of class "' .
get_class($this->value) . '"';
}
return 'is identical to ' . $this->exporter()->export($this->value);
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
if (is_object($this->value) && is_object($other)) {
return 'two variables reference the same object';
}
if (is_string($this->value) && is_string($other)) {
return 'two strings are identical';
}
if (is_array($this->value) && is_array($other)) {
return 'two arrays are identical';
}
return parent::failureDescription($other);
}
}
@@ -0,0 +1,37 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function is_infinite;
/**
* Constraint that accepts infinite.
*/
final class IsInfinite extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is infinite';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return is_infinite($other);
}
}
@@ -0,0 +1,90 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function sprintf;
use ReflectionClass;
use ReflectionException;
/**
* Constraint that asserts that the object it is evaluated for is an instance
* of a given class.
*
* The expected class name is passed in the constructor.
*/
final class IsInstanceOf extends Constraint
{
/**
* @var string
*/
private $className;
public function __construct(string $className)
{
$this->className = $className;
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return sprintf(
'is instance of %s "%s"',
$this->getType(),
$this->className
);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return $other instanceof $this->className;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
return sprintf(
'%s is an instance of %s "%s"',
$this->exporter()->shortenedExport($other),
$this->getType(),
$this->className
);
}
private function getType(): string
{
try {
$reflection = new ReflectionClass($this->className);
if ($reflection->isInterface()) {
return 'interface';
}
} catch (ReflectionException $e) {
}
return 'class';
}
}
@@ -0,0 +1,77 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function json_decode;
use function json_last_error;
use function sprintf;
/**
* Constraint that asserts that a string is valid JSON.
*/
final class IsJson extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is valid JSON';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
if ($other === '') {
return false;
}
json_decode($other);
if (json_last_error()) {
return false;
}
return true;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
if ($other === '') {
return 'an empty string is valid JSON';
}
json_decode($other);
$error = JsonMatchesErrorMessageProvider::determineJsonError(
(string) json_last_error()
);
return sprintf(
'%s is valid JSON (%s)',
$this->exporter()->shortenedExport($other),
$error
);
}
}
@@ -0,0 +1,37 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function is_nan;
/**
* Constraint that accepts nan.
*/
final class IsNan extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is nan';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return is_nan($other);
}
}
@@ -0,0 +1,35 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
/**
* Constraint that accepts null.
*/
final class IsNull extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is null';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return $other === null;
}
}
@@ -0,0 +1,56 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function is_readable;
use function sprintf;
/**
* Constraint that checks if the file/dir(name) that it is evaluated for is readable.
*
* The file path to check is passed as $other in evaluate().
*/
final class IsReadable extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is readable';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return is_readable($other);
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
return sprintf(
'"%s" is readable',
$other
);
}
}
@@ -0,0 +1,35 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
/**
* Constraint that accepts true.
*/
final class IsTrue extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is true';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return $other === true;
}
}
@@ -0,0 +1,214 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function get_resource_type;
use function is_array;
use function is_bool;
use function is_callable;
use function is_float;
use function is_int;
use function is_iterable;
use function is_numeric;
use function is_object;
use function is_resource;
use function is_scalar;
use function is_string;
use function sprintf;
use TypeError;
/**
* Constraint that asserts that the value it is evaluated for is of a
* specified type.
*
* The expected value is passed in the constructor.
*/
final class IsType extends Constraint
{
/**
* @var string
*/
public const TYPE_ARRAY = 'array';
/**
* @var string
*/
public const TYPE_BOOL = 'bool';
/**
* @var string
*/
public const TYPE_FLOAT = 'float';
/**
* @var string
*/
public const TYPE_INT = 'int';
/**
* @var string
*/
public const TYPE_NULL = 'null';
/**
* @var string
*/
public const TYPE_NUMERIC = 'numeric';
/**
* @var string
*/
public const TYPE_OBJECT = 'object';
/**
* @var string
*/
public const TYPE_RESOURCE = 'resource';
/**
* @var string
*/
public const TYPE_STRING = 'string';
/**
* @var string
*/
public const TYPE_SCALAR = 'scalar';
/**
* @var string
*/
public const TYPE_CALLABLE = 'callable';
/**
* @var string
*/
public const TYPE_ITERABLE = 'iterable';
/**
* @var array<string,bool>
*/
private const KNOWN_TYPES = [
'array' => true,
'boolean' => true,
'bool' => true,
'double' => true,
'float' => true,
'integer' => true,
'int' => true,
'null' => true,
'numeric' => true,
'object' => true,
'real' => true,
'resource' => true,
'string' => true,
'scalar' => true,
'callable' => true,
'iterable' => true,
];
/**
* @var string
*/
private $type;
/**
* @throws \PHPUnit\Framework\Exception
*/
public function __construct(string $type)
{
if (!isset(self::KNOWN_TYPES[$type])) {
throw new \PHPUnit\Framework\Exception(
sprintf(
'Type specified for PHPUnit\Framework\Constraint\IsType <%s> ' .
'is not a valid type.',
$type
)
);
}
$this->type = $type;
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return sprintf(
'is of type "%s"',
$this->type
);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
switch ($this->type) {
case 'numeric':
return is_numeric($other);
case 'integer':
case 'int':
return is_int($other);
case 'double':
case 'float':
case 'real':
return is_float($other);
case 'string':
return is_string($other);
case 'boolean':
case 'bool':
return is_bool($other);
case 'null':
return null === $other;
case 'array':
return is_array($other);
case 'object':
return is_object($other);
case 'resource':
if (is_resource($other)) {
return true;
}
try {
$resource = @get_resource_type($other);
if (is_string($resource)) {
return true;
}
} catch (TypeError $e) {
}
return false;
case 'scalar':
return is_scalar($other);
case 'callable':
return is_callable($other);
case 'iterable':
return is_iterable($other);
}
}
}
@@ -0,0 +1,56 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function is_writable;
use function sprintf;
/**
* Constraint that checks if the file/dir(name) that it is evaluated for is writable.
*
* The file path to check is passed as $other in evaluate().
*/
final class IsWritable extends Constraint
{
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'is writable';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return is_writable($other);
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*/
protected function failureDescription($other): string
{
return sprintf(
'"%s" is writable',
$other
);
}
}
@@ -0,0 +1,108 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function json_decode;
use function sprintf;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Util\Json;
use SebastianBergmann\Comparator\ComparisonFailure;
/**
* Asserts whether or not two JSON objects are equal.
*/
final class JsonMatches extends Constraint
{
/**
* @var string
*/
private $value;
public function __construct(string $value)
{
$this->value = $value;
}
/**
* Returns a string representation of the object.
*/
public function toString(): string
{
return sprintf(
'matches JSON string "%s"',
$this->value
);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* This method can be overridden to implement the evaluation algorithm.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
[$error, $recodedOther] = Json::canonicalize($other);
if ($error) {
return false;
}
[$error, $recodedValue] = Json::canonicalize($this->value);
if ($error) {
return false;
}
return $recodedOther == $recodedValue;
}
/**
* Throws an exception for the given compared value and test description.
*
* @param mixed $other evaluated value or object
* @param string $description Additional information about the test
*
* @throws \PHPUnit\Framework\Exception
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*
* @psalm-return never-return
*/
protected function fail($other, $description, ComparisonFailure $comparisonFailure = null): void
{
if ($comparisonFailure === null) {
[$error, $recodedOther] = Json::canonicalize($other);
if ($error) {
parent::fail($other, $description);
}
[$error, $recodedValue] = Json::canonicalize($this->value);
if ($error) {
parent::fail($other, $description);
}
$comparisonFailure = new ComparisonFailure(
json_decode($this->value),
json_decode($other),
Json::prettify($recodedValue),
Json::prettify($recodedOther),
false,
'Failed asserting that two json values are equal.'
);
}
parent::fail($other, $description, $comparisonFailure);
}
}
@@ -0,0 +1,78 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use const JSON_ERROR_CTRL_CHAR;
use const JSON_ERROR_DEPTH;
use const JSON_ERROR_NONE;
use const JSON_ERROR_STATE_MISMATCH;
use const JSON_ERROR_SYNTAX;
use const JSON_ERROR_UTF8;
use function strtolower;
/**
* Provides human readable messages for each JSON error.
*/
final class JsonMatchesErrorMessageProvider
{
/**
* Translates JSON error to a human readable string.
*/
public static function determineJsonError(string $error, string $prefix = ''): ?string
{
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';
default:
return $prefix . 'Unknown error';
}
}
/**
* Translates a given type to a human readable message prefix.
*/
public static function translateTypeToPrefix(string $type): string
{
switch (strtolower($type)) {
case 'expected':
$prefix = 'Expected value JSON decode error - ';
break;
case 'actual':
$prefix = 'Actual value JSON decode error - ';
break;
default:
$prefix = '';
break;
}
return $prefix;
}
}
@@ -0,0 +1,51 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
/**
* Constraint that asserts that the value it is evaluated for is less than
* a given value.
*/
final class LessThan extends Constraint
{
/**
* @var float|int
*/
private $value;
/**
* @param float|int $value
*/
public function __construct($value)
{
$this->value = $value;
}
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function toString(): string
{
return 'is less than ' . $this->exporter()->export($this->value);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return $this->value > $other;
}
}
@@ -0,0 +1,121 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function array_values;
use function count;
use PHPUnit\Framework\ExpectationFailedException;
/**
* Logical AND.
*/
final class LogicalAnd extends Constraint
{
/**
* @var Constraint[]
*/
private $constraints = [];
public static function fromConstraints(Constraint ...$constraints): self
{
$constraint = new self;
$constraint->constraints = array_values($constraints);
return $constraint;
}
/**
* @param Constraint[] $constraints
*
* @throws \PHPUnit\Framework\Exception
*/
public function setConstraints(array $constraints): void
{
$this->constraints = [];
foreach ($constraints as $constraint) {
if (!($constraint instanceof Constraint)) {
throw new \PHPUnit\Framework\Exception(
'All parameters to ' . __CLASS__ .
' must be a constraint object.'
);
}
$this->constraints[] = $constraint;
}
}
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = true;
foreach ($this->constraints as $constraint) {
if (!$constraint->evaluate($other, $description, true)) {
$success = false;
break;
}
}
if ($returnResult) {
return $success;
}
if (!$success) {
$this->fail($other, $description);
}
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
$text = '';
foreach ($this->constraints as $key => $constraint) {
if ($key > 0) {
$text .= ' and ';
}
$text .= $constraint->toString();
}
return $text;
}
/**
* Counts the number of constraint elements.
*/
public function count(): int
{
$count = 0;
foreach ($this->constraints as $constraint) {
$count += count($constraint);
}
return $count;
}
}
@@ -0,0 +1,169 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function count;
use function get_class;
use function preg_match;
use function str_replace;
use PHPUnit\Framework\ExpectationFailedException;
/**
* Logical NOT.
*/
final class LogicalNot extends Constraint
{
/**
* @var Constraint
*/
private $constraint;
public static function negate(string $string): string
{
$positives = [
'contains ',
'exists',
'has ',
'is ',
'are ',
'matches ',
'starts with ',
'ends with ',
'reference ',
'not not ',
];
$negatives = [
'does not contain ',
'does not exist',
'does not have ',
'is not ',
'are not ',
'does not match ',
'starts not with ',
'ends not with ',
'don\'t reference ',
'not ',
];
preg_match('/(\'[\w\W]*\')([\w\W]*)("[\w\W]*")/i', $string, $matches);
if (count($matches) > 0) {
$nonInput = $matches[2];
$negatedString = str_replace(
$nonInput,
str_replace(
$positives,
$negatives,
$nonInput
),
$string
);
} else {
$negatedString = str_replace(
$positives,
$negatives,
$string
);
}
return $negatedString;
}
/**
* @param Constraint|mixed $constraint
*/
public function __construct($constraint)
{
if (!($constraint instanceof Constraint)) {
$constraint = new IsEqual($constraint);
}
$this->constraint = $constraint;
}
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = !$this->constraint->evaluate($other, $description, true);
if ($returnResult) {
return $success;
}
if (!$success) {
$this->fail($other, $description);
}
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
switch (get_class($this->constraint)) {
case LogicalAnd::class:
case self::class:
case LogicalOr::class:
return 'not( ' . $this->constraint->toString() . ' )';
default:
return self::negate(
$this->constraint->toString()
);
}
}
/**
* Counts the number of constraint elements.
*/
public function count(): int
{
return count($this->constraint);
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
switch (get_class($this->constraint)) {
case LogicalAnd::class:
case self::class:
case LogicalOr::class:
return 'not( ' . $this->constraint->failureDescription($other) . ' )';
default:
return self::negate(
$this->constraint->failureDescription($other)
);
}
}
}
@@ -0,0 +1,118 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function array_values;
use function count;
use PHPUnit\Framework\ExpectationFailedException;
/**
* Logical OR.
*/
final class LogicalOr extends Constraint
{
/**
* @var Constraint[]
*/
private $constraints = [];
public static function fromConstraints(Constraint ...$constraints): self
{
$constraint = new self;
$constraint->constraints = array_values($constraints);
return $constraint;
}
/**
* @param Constraint[] $constraints
*/
public function setConstraints(array $constraints): void
{
$this->constraints = [];
foreach ($constraints as $constraint) {
if (!($constraint instanceof Constraint)) {
$constraint = new IsEqual(
$constraint
);
}
$this->constraints[] = $constraint;
}
}
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = false;
foreach ($this->constraints as $constraint) {
if ($constraint->evaluate($other, $description, true)) {
$success = true;
break;
}
}
if ($returnResult) {
return $success;
}
if (!$success) {
$this->fail($other, $description);
}
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
$text = '';
foreach ($this->constraints as $key => $constraint) {
if ($key > 0) {
$text .= ' or ';
}
$text .= $constraint->toString();
}
return $text;
}
/**
* Counts the number of constraint elements.
*/
public function count(): int
{
$count = 0;
foreach ($this->constraints as $constraint) {
$count += count($constraint);
}
return $count;
}
}
@@ -0,0 +1,123 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function array_values;
use function count;
use PHPUnit\Framework\ExpectationFailedException;
/**
* Logical XOR.
*/
final class LogicalXor extends Constraint
{
/**
* @var Constraint[]
*/
private $constraints = [];
public static function fromConstraints(Constraint ...$constraints): self
{
$constraint = new self;
$constraint->constraints = array_values($constraints);
return $constraint;
}
/**
* @param Constraint[] $constraints
*/
public function setConstraints(array $constraints): void
{
$this->constraints = [];
foreach ($constraints as $constraint) {
if (!($constraint instanceof Constraint)) {
$constraint = new IsEqual(
$constraint
);
}
$this->constraints[] = $constraint;
}
}
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = true;
$lastResult = null;
foreach ($this->constraints as $constraint) {
$result = $constraint->evaluate($other, $description, true);
if ($result === $lastResult) {
$success = false;
break;
}
$lastResult = $result;
}
if ($returnResult) {
return $success;
}
if (!$success) {
$this->fail($other, $description);
}
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
$text = '';
foreach ($this->constraints as $key => $constraint) {
if ($key > 0) {
$text .= ' xor ';
}
$text .= $constraint->toString();
}
return $text;
}
/**
* Counts the number of constraint elements.
*/
public function count(): int
{
$count = 0;
foreach ($this->constraints as $constraint) {
$count += count($constraint);
}
return $count;
}
}
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use ReflectionObject;
/**
* Constraint that asserts that the object it is evaluated for has a given
* attribute.
*
* The attribute name is passed in the constructor.
*/
final class ObjectHasAttribute extends ClassHasAttribute
{
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return (new ReflectionObject($other))->hasProperty($this->attributeName());
}
}
@@ -0,0 +1,57 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function preg_match;
use function sprintf;
/**
* Constraint that asserts that the string it is evaluated for matches
* a regular expression.
*
* Checks a given value using the Perl Compatible Regular Expression extension
* in PHP. The pattern is matched by executing preg_match().
*
* The pattern string passed in the constructor.
*/
class RegularExpression extends Constraint
{
/**
* @var string
*/
private $pattern;
public function __construct(string $pattern)
{
$this->pattern = $pattern;
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return sprintf(
'matches PCRE pattern "%s"',
$this->pattern
);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return preg_match($this->pattern, $other) > 0;
}
}
@@ -0,0 +1,18 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
final class SameSize extends Count
{
public function __construct(iterable $expected)
{
parent::__construct($this->getCountOf($expected));
}
}
@@ -0,0 +1,79 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function mb_stripos;
use function mb_strpos;
use function mb_strtolower;
use function sprintf;
/**
* Constraint that asserts that the string it is evaluated for contains
* a given string.
*
* Uses mb_strpos() to find the position of the string in the input, if not
* found the evaluation fails.
*
* The sub-string is passed in the constructor.
*/
final class StringContains extends Constraint
{
/**
* @var string
*/
private $string;
/**
* @var bool
*/
private $ignoreCase;
public function __construct(string $string, bool $ignoreCase = false)
{
$this->string = $string;
$this->ignoreCase = $ignoreCase;
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
if ($this->ignoreCase) {
$string = mb_strtolower($this->string);
} else {
$string = $this->string;
}
return sprintf(
'contains "%s"',
$string
);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
if ('' === $this->string) {
return true;
}
if ($this->ignoreCase) {
return mb_stripos($other, $this->string) !== false;
}
return mb_strpos($other, $this->string) !== false;
}
}
@@ -0,0 +1,49 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function strlen;
use function substr;
/**
* Constraint that asserts that the string it is evaluated for ends with a given
* suffix.
*/
final class StringEndsWith extends Constraint
{
/**
* @var string
*/
private $suffix;
public function __construct(string $suffix)
{
$this->suffix = $suffix;
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'ends with "' . $this->suffix . '"';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return substr($other, 0 - strlen($this->suffix)) === $this->suffix;
}
}
@@ -0,0 +1,108 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use const DIRECTORY_SEPARATOR;
use function explode;
use function implode;
use function preg_match;
use function preg_quote;
use function preg_replace;
use function strtr;
use SebastianBergmann\Diff\Differ;
/**
* ...
*/
final class StringMatchesFormatDescription extends RegularExpression
{
/**
* @var string
*/
private $string;
public function __construct(string $string)
{
parent::__construct(
$this->createPatternFromFormat(
$this->convertNewlines($string)
)
);
$this->string = $string;
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return parent::matches(
$this->convertNewlines($other)
);
}
protected function failureDescription($other): string
{
return 'string matches format description';
}
protected function additionalFailureDescription($other): string
{
$from = explode("\n", $this->string);
$to = explode("\n", $this->convertNewlines($other));
foreach ($from as $index => $line) {
if (isset($to[$index]) && $line !== $to[$index]) {
$line = $this->createPatternFromFormat($line);
if (preg_match($line, $to[$index]) > 0) {
$from[$index] = $to[$index];
}
}
}
$this->string = implode("\n", $from);
$other = implode("\n", $to);
return (new Differ("--- Expected\n+++ Actual\n"))->diff($this->string, $other);
}
private function createPatternFromFormat(string $string): string
{
$string = strtr(
preg_quote($string, '/'),
[
'%%' => '%',
'%e' => '\\' . DIRECTORY_SEPARATOR,
'%s' => '[^\r\n]+',
'%S' => '[^\r\n]*',
'%a' => '.+',
'%A' => '.*',
'%w' => '\s*',
'%i' => '[+-]?\d+',
'%d' => '\d+',
'%x' => '[0-9a-fA-F]+',
'%f' => '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?',
'%c' => '.',
]
);
return '/^' . $string . '$/s';
}
private function convertNewlines($text): string
{
return preg_replace('/\r\n/', "\n", $text);
}
}
@@ -0,0 +1,53 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function strpos;
use PHPUnit\Framework\InvalidArgumentException;
/**
* Constraint that asserts that the string it is evaluated for begins with a
* given prefix.
*/
final class StringStartsWith extends Constraint
{
/**
* @var string
*/
private $prefix;
public function __construct(string $prefix)
{
if ($prefix === '') {
throw InvalidArgumentException::create(1, 'non-empty string');
}
$this->prefix = $prefix;
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'starts with "' . $this->prefix . '"';
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
return strpos((string) $other, $this->prefix) === 0;
}
}
@@ -0,0 +1,120 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function is_array;
use function is_object;
use function is_string;
use function sprintf;
use function strpos;
use SplObjectStorage;
/**
* Constraint that asserts that the Traversable it is applied to contains
* a given value.
*
* @deprecated Use TraversableContainsEqual or TraversableContainsIdentical instead
*/
final class TraversableContains extends Constraint
{
/**
* @var bool
*/
private $checkForObjectIdentity;
/**
* @var bool
*/
private $checkForNonObjectIdentity;
/**
* @var mixed
*/
private $value;
public function __construct($value, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false)
{
$this->checkForObjectIdentity = $checkForObjectIdentity;
$this->checkForNonObjectIdentity = $checkForNonObjectIdentity;
$this->value = $value;
}
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function toString(): string
{
if (is_string($this->value) && strpos($this->value, "\n") !== false) {
return 'contains "' . $this->value . '"';
}
return 'contains ' . $this->exporter()->export($this->value);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
if ($other instanceof SplObjectStorage) {
return $other->contains($this->value);
}
if (is_object($this->value)) {
foreach ($other as $element) {
if ($this->checkForObjectIdentity && $element === $this->value) {
return true;
}
/* @noinspection TypeUnsafeComparisonInspection */
if (!$this->checkForObjectIdentity && $element == $this->value) {
return true;
}
}
} else {
foreach ($other as $element) {
if ($this->checkForNonObjectIdentity && $element === $this->value) {
return true;
}
/* @noinspection TypeUnsafeComparisonInspection */
if (!$this->checkForNonObjectIdentity && $element == $this->value) {
return true;
}
}
}
return false;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
return sprintf(
'%s %s',
is_array($other) ? 'an array' : 'a traversable',
$this->toString()
);
}
}
@@ -0,0 +1,88 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function is_array;
use function is_string;
use function sprintf;
use function strpos;
use SplObjectStorage;
/**
* Constraint that asserts that the Traversable it is applied to contains
* a given value (using non-strict comparison).
*/
final class TraversableContainsEqual extends Constraint
{
/**
* @var mixed
*/
private $value;
public function __construct($value)
{
$this->value = $value;
}
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function toString(): string
{
if (is_string($this->value) && strpos($this->value, "\n") !== false) {
return 'contains "' . $this->value . '"';
}
return 'contains ' . $this->exporter()->export($this->value);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
if ($other instanceof SplObjectStorage) {
return $other->contains($this->value);
}
foreach ($other as $element) {
/* @noinspection TypeUnsafeComparisonInspection */
if ($this->value == $element) {
return true;
}
}
return false;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
return sprintf(
'%s %s',
is_array($other) ? 'an array' : 'a traversable',
$this->toString()
);
}
}
@@ -0,0 +1,87 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use function is_array;
use function is_string;
use function sprintf;
use function strpos;
use SplObjectStorage;
/**
* Constraint that asserts that the Traversable it is applied to contains
* a given value (using strict comparison).
*/
final class TraversableContainsIdentical extends Constraint
{
/**
* @var mixed
*/
private $value;
public function __construct($value)
{
$this->value = $value;
}
/**
* Returns a string representation of the constraint.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function toString(): string
{
if (is_string($this->value) && strpos($this->value, "\n") !== false) {
return 'contains "' . $this->value . '"';
}
return 'contains ' . $this->exporter()->export($this->value);
}
/**
* Evaluates the constraint for parameter $other. Returns true if the
* constraint is met, false otherwise.
*
* @param mixed $other value or object to evaluate
*/
protected function matches($other): bool
{
if ($other instanceof SplObjectStorage) {
return $other->contains($this->value);
}
foreach ($other as $element) {
if ($this->value === $element) {
return true;
}
}
return false;
}
/**
* Returns the description of the failure.
*
* The beginning of failure messages is "Failed asserting that" in most
* cases. This method should return the second part of that sentence.
*
* @param mixed $other evaluated value or object
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
protected function failureDescription($other): string
{
return sprintf(
'%s %s',
is_array($other) ? 'an array' : 'a traversable',
$this->toString()
);
}
}
@@ -0,0 +1,87 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Constraint;
use PHPUnit\Framework\ExpectationFailedException;
/**
* Constraint that asserts that the Traversable it is applied to contains
* only values of a given type.
*/
final class TraversableContainsOnly extends Constraint
{
/**
* @var Constraint
*/
private $constraint;
/**
* @var string
*/
private $type;
/**
* @throws \PHPUnit\Framework\Exception
*/
public function __construct(string $type, bool $isNativeType = true)
{
if ($isNativeType) {
$this->constraint = new IsType($type);
} else {
$this->constraint = new IsInstanceOf(
$type
);
}
$this->type = $type;
}
/**
* Evaluates the constraint for parameter $other.
*
* If $returnResult is set to false (the default), an exception is thrown
* in case of a failure. null is returned otherwise.
*
* If $returnResult is true, the result of the evaluation is returned as
* a boolean value instead: true in case of success, false in case of a
* failure.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
* @throws ExpectationFailedException
*/
public function evaluate($other, string $description = '', bool $returnResult = false)
{
$success = true;
foreach ($other as $item) {
if (!$this->constraint->evaluate($item, '', true)) {
$success = false;
break;
}
}
if ($returnResult) {
return $success;
}
if (!$success) {
$this->fail($other, $description);
}
}
/**
* Returns a string representation of the constraint.
*/
public function toString(): string
{
return 'contains only values of type "' . $this->type . '"';
}
}
@@ -0,0 +1,63 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
use function count;
use function explode;
use PHPUnit\Util\Test as TestUtil;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class DataProviderTestSuite extends TestSuite
{
/**
* @var string[]
*/
private $dependencies = [];
/**
* @param string[] $dependencies
*/
public function setDependencies(array $dependencies): void
{
$this->dependencies = $dependencies;
foreach ($this->tests as $test) {
if (!$test instanceof TestCase) {
continue;
}
$test->setDependencies($dependencies);
}
}
public function getDependencies(): array
{
return $this->dependencies;
}
public function hasDependencies(): bool
{
return count($this->dependencies) > 0;
}
/**
* Returns the size of the each test created using the data provider(s).
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function getSize(): int
{
[$className, $methodName] = explode('::', $this->getName());
return TestUtil::getSize($className, $methodName);
}
}
@@ -0,0 +1,14 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Error;
final class Deprecated extends Error
{
}
@@ -0,0 +1,23 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Error;
use PHPUnit\Framework\Exception;
class Error extends Exception
{
public function __construct(string $message, int $code, string $file, int $line, \Exception $previous = null)
{
parent::__construct($message, $code, $previous);
$this->file = $file;
$this->line = $line;
}
}
@@ -0,0 +1,14 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Error;
final class Notice extends Error
{
}
@@ -0,0 +1,14 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\Error;
final class Warning extends Error
{
}
@@ -0,0 +1,24 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
class AssertionFailedError extends Exception implements SelfDescribing
{
/**
* Wrapper for getMessage() which is declared as final.
*/
public function toString(): string
{
return $this->getMessage();
}
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
class CodeCoverageException extends Exception
{
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class CoveredCodeNotExecutedException extends RiskyTestError
{
}
@@ -0,0 +1,81 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
use function array_keys;
use function get_object_vars;
use PHPUnit\Util\Filter;
use RuntimeException;
use Throwable;
/**
* Base class for all PHPUnit Framework exceptions.
*
* Ensures that exceptions thrown during a test run do not leave stray
* references behind.
*
* Every Exception contains a stack trace. Each stack frame contains the 'args'
* of the called function. The function arguments can contain references to
* instantiated objects. The references prevent the objects from being
* destructed (until test results are eventually printed), so memory cannot be
* freed up.
*
* With enabled process isolation, test results are serialized in the child
* process and unserialized in the parent process. The stack trace of Exceptions
* may contain objects that cannot be serialized or unserialized (e.g., PDO
* connections). Unserializing user-space objects from the child process into
* the parent would break the intended encapsulation of process isolation.
*
* @see http://fabien.potencier.org/article/9/php-serialization-stack-traces-and-exceptions
*
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
class Exception extends RuntimeException implements \PHPUnit\Exception
{
/**
* @var array
*/
protected $serializableTrace;
public function __construct($message = '', $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->serializableTrace = $this->getTrace();
foreach (array_keys($this->serializableTrace) as $key) {
unset($this->serializableTrace[$key]['args']);
}
}
public function __toString(): string
{
$string = TestFailure::exceptionToString($this);
if ($trace = Filter::getFilteredStacktrace($this)) {
$string .= "\n" . $trace;
}
return $string;
}
public function __sleep(): array
{
return array_keys(get_object_vars($this));
}
/**
* Returns the serializable trace (without 'args').
*/
public function getSerializableTrace(): array
{
return $this->serializableTrace;
}
}
@@ -0,0 +1,42 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
use Exception;
use SebastianBergmann\Comparator\ComparisonFailure;
/**
* Exception for expectations which failed their check.
*
* The exception contains the error message and optionally a
* SebastianBergmann\Comparator\ComparisonFailure which is used to
* generate diff output of the failed expectations.
*
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class ExpectationFailedException extends AssertionFailedError
{
/**
* @var ComparisonFailure
*/
protected $comparisonFailure;
public function __construct(string $message, ComparisonFailure $comparisonFailure = null, Exception $previous = null)
{
$this->comparisonFailure = $comparisonFailure;
parent::__construct($message, 0, $previous);
}
public function getComparisonFailure(): ?ComparisonFailure
{
return $this->comparisonFailure;
}
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class IncompleteTestError extends AssertionFailedError implements IncompleteTest
{
}
@@ -0,0 +1,46 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
use function debug_backtrace;
use function in_array;
use function lcfirst;
use function sprintf;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class InvalidArgumentException extends Exception
{
public static function create(int $argument, string $type): self
{
$stack = debug_backtrace();
$function = $stack[1]['function'];
if (isset($stack[1]['class'])) {
$function = sprintf('%s::%s', $stack[1]['class'], $stack[1]['function']);
}
return new self(
sprintf(
'Argument #%d of %s() must be %s %s',
$argument,
$function,
in_array(lcfirst($type)[0], ['a', 'e', 'i', 'o', 'u'], true) ? 'an' : 'a',
$type
)
);
}
private function __construct(string $message = '', int $code = 0, \Exception $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class InvalidCoversTargetException extends CodeCoverageException
{
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class InvalidDataProviderException extends Exception
{
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class MissingCoversAnnotationException extends RiskyTestError
{
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class NoChildTestSuiteException extends Exception
{
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class OutputError extends AssertionFailedError
{
}
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class PHPTAssertionFailedError extends SyntheticError
{
/**
* @var string
*/
private $diff;
public function __construct(string $message, int $code, string $file, int $line, array $trace, string $diff)
{
parent::__construct($message, $code, $file, $line, $trace);
$this->diff = $diff;
}
public function getDiff(): string
{
return $this->diff;
}
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
class RiskyTestError extends AssertionFailedError
{
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class SkippedTestError extends AssertionFailedError implements SkippedTest
{
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class SkippedTestSuiteError extends AssertionFailedError implements SkippedTest
{
}
@@ -0,0 +1,61 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
class SyntheticError extends AssertionFailedError
{
/**
* The synthetic file.
*
* @var string
*/
protected $syntheticFile = '';
/**
* The synthetic line number.
*
* @var int
*/
protected $syntheticLine = 0;
/**
* The synthetic trace.
*
* @var array
*/
protected $syntheticTrace = [];
public function __construct(string $message, int $code, string $file, int $line, array $trace)
{
parent::__construct($message, $code);
$this->syntheticFile = $file;
$this->syntheticLine = $line;
$this->syntheticTrace = $trace;
}
public function getSyntheticFile(): string
{
return $this->syntheticFile;
}
public function getSyntheticLine(): int
{
return $this->syntheticLine;
}
public function getSyntheticTrace(): array
{
return $this->syntheticTrace;
}
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class SyntheticSkippedError extends SyntheticError implements SkippedTest
{
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class UnintentionallyCoveredCodeError extends RiskyTestError
{
}
@@ -0,0 +1,24 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class Warning extends Exception implements SelfDescribing
{
/**
* Wrapper for getMessage() which is declared as final.
*/
public function toString(): string
{
return $this->getMessage();
}
}
@@ -0,0 +1,120 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
use function array_keys;
use function get_class;
use function spl_object_hash;
use PHPUnit\Util\Filter;
use Throwable;
/**
* Wraps Exceptions thrown by code under test.
*
* Re-instantiates Exceptions thrown by user-space code to retain their original
* class names, properties, and stack traces (but without arguments).
*
* Unlike PHPUnit\Framework_\Exception, the complete stack of previous Exceptions
* is processed.
*
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class ExceptionWrapper extends Exception
{
/**
* @var string
*/
protected $className;
/**
* @var null|ExceptionWrapper
*/
protected $previous;
public function __construct(Throwable $t)
{
// PDOException::getCode() is a string.
// @see https://php.net/manual/en/class.pdoexception.php#95812
parent::__construct($t->getMessage(), (int) $t->getCode());
$this->setOriginalException($t);
}
public function __toString(): string
{
$string = TestFailure::exceptionToString($this);
if ($trace = Filter::getFilteredStacktrace($this)) {
$string .= "\n" . $trace;
}
if ($this->previous) {
$string .= "\nCaused by\n" . $this->previous;
}
return $string;
}
public function getClassName(): string
{
return $this->className;
}
public function getPreviousWrapped(): ?self
{
return $this->previous;
}
public function setClassName(string $className): void
{
$this->className = $className;
}
public function setOriginalException(Throwable $t): void
{
$this->originalException($t);
$this->className = get_class($t);
$this->file = $t->getFile();
$this->line = $t->getLine();
$this->serializableTrace = $t->getTrace();
foreach (array_keys($this->serializableTrace) as $key) {
unset($this->serializableTrace[$key]['args']);
}
if ($t->getPrevious()) {
$this->previous = new self($t->getPrevious());
}
}
public function getOriginalException(): ?Throwable
{
return $this->originalException();
}
/**
* Method to contain static originalException to exclude it from stacktrace to prevent the stacktrace contents,
* which can be quite big, from being garbage-collected, thus blocking memory until shutdown.
* Approach works both for var_dump() and var_export() and print_r().
*/
private function originalException(Throwable $exceptionToStore = null): ?Throwable
{
static $originalExceptions;
$instanceId = spl_object_hash($this);
if ($exceptionToStore) {
$originalExceptions[$instanceId] = $exceptionToStore;
}
return $originalExceptions[$instanceId] ?? null;
}
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
interface IncompleteTest
{
}
@@ -0,0 +1,66 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class IncompleteTestCase extends TestCase
{
/**
* @var ?bool
*/
protected $backupGlobals = false;
/**
* @var ?bool
*/
protected $backupStaticAttributes = false;
/**
* @var ?bool
*/
protected $runTestInSeparateProcess = false;
/**
* @var string
*/
private $message;
public function __construct(string $className, string $methodName, string $message = '')
{
parent::__construct($className . '::' . $methodName);
$this->message = $message;
}
public function getMessage(): string
{
return $this->message;
}
/**
* Returns a string representation of the test case.
*
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function toString(): string
{
return $this->getName();
}
/**
* @throws Exception
*/
protected function runTest(): void
{
$this->markTestIncomplete($this->message);
}
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class InvalidParameterGroupException extends Exception
{
}
@@ -0,0 +1,97 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject;
use PHPUnit\Framework\MockObject\Builder\InvocationMocker as InvocationMockerBuilder;
use PHPUnit\Framework\MockObject\Rule\InvocationOrder;
/**
* @internal This trait is not covered by the backward compatibility promise for PHPUnit
*/
trait Api
{
/**
* @var ConfigurableMethod[]
*/
private static $__phpunit_configurableMethods;
/**
* @var object
*/
private $__phpunit_originalObject;
/**
* @var bool
*/
private $__phpunit_returnValueGeneration = true;
/**
* @var InvocationHandler
*/
private $__phpunit_invocationMocker;
/** @noinspection MagicMethodsValidityInspection */
public static function __phpunit_initConfigurableMethods(ConfigurableMethod ...$configurableMethods): void
{
if (isset(static::$__phpunit_configurableMethods)) {
throw new ConfigurableMethodsAlreadyInitializedException(
'Configurable methods is already initialized and can not be reinitialized'
);
}
static::$__phpunit_configurableMethods = $configurableMethods;
}
/** @noinspection MagicMethodsValidityInspection */
public function __phpunit_setOriginalObject($originalObject): void
{
$this->__phpunit_originalObject = $originalObject;
}
/** @noinspection MagicMethodsValidityInspection */
public function __phpunit_setReturnValueGeneration(bool $returnValueGeneration): void
{
$this->__phpunit_returnValueGeneration = $returnValueGeneration;
}
/** @noinspection MagicMethodsValidityInspection */
public function __phpunit_getInvocationHandler(): InvocationHandler
{
if ($this->__phpunit_invocationMocker === null) {
$this->__phpunit_invocationMocker = new InvocationHandler(
static::$__phpunit_configurableMethods,
$this->__phpunit_returnValueGeneration
);
}
return $this->__phpunit_invocationMocker;
}
/** @noinspection MagicMethodsValidityInspection */
public function __phpunit_hasMatchers(): bool
{
return $this->__phpunit_getInvocationHandler()->hasMatchers();
}
/** @noinspection MagicMethodsValidityInspection */
public function __phpunit_verify(bool $unsetInvocationMocker = true): void
{
$this->__phpunit_getInvocationHandler()->verify();
if ($unsetInvocationMocker) {
$this->__phpunit_invocationMocker = null;
}
}
public function expects(InvocationOrder $matcher): InvocationMockerBuilder
{
return $this->__phpunit_getInvocationHandler()->expects($matcher);
}
}
@@ -0,0 +1,30 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject;
use function call_user_func_array;
use function func_get_args;
use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount;
/**
* @internal This trait is not covered by the backward compatibility promise for PHPUnit
*/
trait Method
{
public function method()
{
$expects = $this->expects(new AnyInvokedCount);
return call_user_func_array(
[$expects, 'method'],
func_get_args()
);
}
}
@@ -0,0 +1,25 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject\Builder;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
interface Identity
{
/**
* Sets the identification of the expectation to $id.
*
* @note The identifier is unique per mock object.
*
* @param string $id unique identification of expectation
*/
public function id($id);
}
@@ -0,0 +1,300 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject\Builder;
use function array_map;
use function array_merge;
use function count;
use function get_class;
use function gettype;
use function in_array;
use function is_object;
use function is_string;
use function sprintf;
use function strtolower;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\MockObject\ConfigurableMethod;
use PHPUnit\Framework\MockObject\IncompatibleReturnValueException;
use PHPUnit\Framework\MockObject\InvocationHandler;
use PHPUnit\Framework\MockObject\Matcher;
use PHPUnit\Framework\MockObject\Rule;
use PHPUnit\Framework\MockObject\RuntimeException;
use PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls;
use PHPUnit\Framework\MockObject\Stub\Exception;
use PHPUnit\Framework\MockObject\Stub\ReturnArgument;
use PHPUnit\Framework\MockObject\Stub\ReturnCallback;
use PHPUnit\Framework\MockObject\Stub\ReturnReference;
use PHPUnit\Framework\MockObject\Stub\ReturnSelf;
use PHPUnit\Framework\MockObject\Stub\ReturnStub;
use PHPUnit\Framework\MockObject\Stub\ReturnValueMap;
use PHPUnit\Framework\MockObject\Stub\Stub;
use Throwable;
final class InvocationMocker implements InvocationStubber, MethodNameMatch
{
/**
* @var InvocationHandler
*/
private $invocationHandler;
/**
* @var Matcher
*/
private $matcher;
/**
* @var ConfigurableMethod[]
*/
private $configurableMethods;
public function __construct(InvocationHandler $handler, Matcher $matcher, ConfigurableMethod ...$configurableMethods)
{
$this->invocationHandler = $handler;
$this->matcher = $matcher;
$this->configurableMethods = $configurableMethods;
}
/**
* @return $this
*/
public function id($id): self
{
$this->invocationHandler->registerMatcher($id, $this->matcher);
return $this;
}
/**
* @return $this
*/
public function will(Stub $stub): Identity
{
$this->matcher->setStub($stub);
return $this;
}
public function willReturn($value, ...$nextValues): self
{
if (count($nextValues) === 0) {
$this->ensureTypeOfReturnValues([$value]);
$stub = $value instanceof Stub ? $value : new ReturnStub($value);
} else {
$values = array_merge([$value], $nextValues);
$this->ensureTypeOfReturnValues($values);
$stub = new ConsecutiveCalls($values);
}
return $this->will($stub);
}
public function willReturnReference(&$reference): self
{
$stub = new ReturnReference($reference);
return $this->will($stub);
}
public function willReturnMap(array $valueMap): self
{
$stub = new ReturnValueMap($valueMap);
return $this->will($stub);
}
public function willReturnArgument($argumentIndex): self
{
$stub = new ReturnArgument($argumentIndex);
return $this->will($stub);
}
public function willReturnCallback($callback): self
{
$stub = new ReturnCallback($callback);
return $this->will($stub);
}
public function willReturnSelf(): self
{
$stub = new ReturnSelf;
return $this->will($stub);
}
public function willReturnOnConsecutiveCalls(...$values): self
{
$stub = new ConsecutiveCalls($values);
return $this->will($stub);
}
public function willThrowException(Throwable $exception): self
{
$stub = new Exception($exception);
return $this->will($stub);
}
/**
* @return $this
*/
public function after($id): self
{
$this->matcher->setAfterMatchBuilderId($id);
return $this;
}
/**
* @throws RuntimeException
*
* @return $this
*/
public function with(...$arguments): self
{
$this->canDefineParameters();
$this->matcher->setParametersRule(new Rule\Parameters($arguments));
return $this;
}
/**
* @param array ...$arguments
*
* @throws RuntimeException
*
* @return $this
*/
public function withConsecutive(...$arguments): self
{
$this->canDefineParameters();
$this->matcher->setParametersRule(new Rule\ConsecutiveParameters($arguments));
return $this;
}
/**
* @throws RuntimeException
*
* @return $this
*/
public function withAnyParameters(): self
{
$this->canDefineParameters();
$this->matcher->setParametersRule(new Rule\AnyParameters);
return $this;
}
/**
* @param Constraint|string $constraint
*
* @throws RuntimeException
*
* @return $this
*/
public function method($constraint): self
{
if ($this->matcher->hasMethodNameRule()) {
throw new RuntimeException(
'Rule for method name is already defined, cannot redefine'
);
}
$configurableMethodNames = array_map(
static function (ConfigurableMethod $configurable)
{
return strtolower($configurable->getName());
},
$this->configurableMethods
);
if (is_string($constraint) && !in_array(strtolower($constraint), $configurableMethodNames, true)) {
throw new RuntimeException(
sprintf(
'Trying to configure method "%s" which cannot be configured because it does not exist, has not been specified, is final, or is static',
$constraint
)
);
}
$this->matcher->setMethodNameRule(new Rule\MethodName($constraint));
return $this;
}
/**
* Validate that a parameters rule can be defined, throw exceptions otherwise.
*
* @throws RuntimeException
*/
private function canDefineParameters(): void
{
if (!$this->matcher->hasMethodNameRule()) {
throw new RuntimeException(
'Rule for method name is not defined, cannot define rule for parameters ' .
'without one'
);
}
if ($this->matcher->hasParametersRule()) {
throw new RuntimeException(
'Rule for parameters is already defined, cannot redefine'
);
}
}
private function getConfiguredMethod(): ?ConfigurableMethod
{
$configuredMethod = null;
foreach ($this->configurableMethods as $configurableMethod) {
if ($this->matcher->getMethodNameRule()->matchesName($configurableMethod->getName())) {
if ($configuredMethod !== null) {
return null;
}
$configuredMethod = $configurableMethod;
}
}
return $configuredMethod;
}
private function ensureTypeOfReturnValues(array $values): void
{
$configuredMethod = $this->getConfiguredMethod();
if ($configuredMethod === null) {
return;
}
foreach ($values as $value) {
if (!$configuredMethod->mayReturn($value)) {
throw new IncompatibleReturnValueException(
sprintf(
'Method %s may not return value of type %s, its return declaration is "%s"',
$configuredMethod->getName(),
is_object($value) ? get_class($value) : gettype($value),
$configuredMethod->getReturnTypeDeclaration()
)
);
}
}
}
}
@@ -0,0 +1,62 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject\Builder;
use PHPUnit\Framework\MockObject\Stub\Stub;
use Throwable;
interface InvocationStubber
{
public function will(Stub $stub): Identity;
/** @return self */
public function willReturn($value, ...$nextValues)/* : self */;
/**
* @param mixed $reference
*
* @return self
*/
public function willReturnReference(&$reference)/* : self */;
/**
* @param array<int, array<int, mixed>> $valueMap
*
* @return self
*/
public function willReturnMap(array $valueMap)/* : self */;
/**
* @param int $argumentIndex
*
* @return self
*/
public function willReturnArgument($argumentIndex)/* : self */;
/**
* @param callable $callback
*
* @return self
*/
public function willReturnCallback($callback)/* : self */;
/** @return self */
public function willReturnSelf()/* : self */;
/**
* @param mixed $values
*
* @return self
*/
public function willReturnOnConsecutiveCalls(...$values)/* : self */;
/** @return self */
public function willThrowException(Throwable $exception)/* : self */;
}
@@ -0,0 +1,26 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject\Builder;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
interface Match_ extends Stub
{
/**
* Defines the expectation which must occur before the current is valid.
*
* @param string $id the identification of the expectation that should
* occur before this one
*
* @return Stub
*/
public function after($id);
}
@@ -0,0 +1,26 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject\Builder;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
interface MethodNameMatch extends ParametersMatch
{
/**
* Adds a new method name match and returns the parameter match object for
* further matching possibilities.
*
* @param \PHPUnit\Framework\Constraint\Constraint $constraint Constraint for matching method, if a string is passed it will use the PHPUnit_Framework_Constraint_IsEqual
*
* @return ParametersMatch
*/
public function method($constraint);
}
@@ -0,0 +1,48 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject\Builder;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
interface ParametersMatch extends Match_
{
/**
* Sets the parameters to match for, each parameter to this function will
* be part of match. To perform specific matches or constraints create a
* new PHPUnit\Framework\Constraint\Constraint and use it for the parameter.
* If the parameter value is not a constraint it will use the
* PHPUnit\Framework\Constraint\IsEqual for the value.
*
* Some examples:
* <code>
* // match first parameter with value 2
* $b->with(2);
* // match first parameter with value 'smock' and second identical to 42
* $b->with('smock', new PHPUnit\Framework\Constraint\IsEqual(42));
* </code>
*
* @return ParametersMatch
*/
public function with(...$arguments);
/**
* Sets a rule which allows any kind of parameters.
*
* Some examples:
* <code>
* // match any number of parameters
* $b->withAnyParameters();
* </code>
*
* @return ParametersMatch
*/
public function withAnyParameters();
}
@@ -0,0 +1,24 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject\Builder;
use PHPUnit\Framework\MockObject\Stub\Stub as BaseStub;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
interface Stub extends Identity
{
/**
* Stubs the matching method with the stub object $stub. Any invocations of
* the matched method will now be handled by the stub instead.
*/
public function will(BaseStub $stub): Identity;
}
@@ -0,0 +1,53 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject;
use SebastianBergmann\Type\Type;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class ConfigurableMethod
{
/**
* @var string
*/
private $name;
/**
* @var Type
*/
private $returnType;
public function __construct(string $name, Type $returnType)
{
$this->name = $name;
$this->returnType = $returnType;
}
public function getName(): string
{
return $this->name;
}
public function mayReturn($value): bool
{
if ($value === null && $this->returnType->allowsNull()) {
return true;
}
return $this->returnType->isAssignable(Type::fromValue($value, false));
}
public function getReturnTypeDeclaration(): string
{
return $this->returnType->getReturnTypeDeclaration();
}
}
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class BadMethodCallException extends \BadMethodCallException implements Exception
{
}

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