From 6913cd9dd4a2486104369b84c424eb15f2015327 Mon Sep 17 00:00:00 2001 From: Jaapio Date: Sun, 24 Mar 2019 11:38:38 +0100 Subject: [PATCH 1/2] Add php 7.3 and 7.4 build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4824118c..07d32346 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: php -php: [ 7.1, 7.2, nightly ] +php: [ 7.1, 7.2, 7.3, 7.4 nightly ] sudo: false env: From 703581584ca53c00f421f2a39ec177ff2c11919a Mon Sep 17 00:00:00 2001 From: Jaapio Date: Sun, 24 Mar 2019 21:19:47 +0100 Subject: [PATCH 2/2] Improve speed by using parsed nodes Before we used the phpdoc context factory to create docblock context. But since this was parsing the code over any over again it was very slow. By using the nodes from the php-parser we are way faster. Thanks to @Ocramius who implemented this in Roave/BetterReflection. --- .travis.yml | 2 +- composer.json | 4 +- composer.lock | 141 +- phive.xml | 3 +- phpbench.json | 7 + .../Reflection/Php/Factory/File.php | 21 +- .../Types/NamespaceNodeToContext.php | 63 + tests/assets/phpunit_assert.php | 3255 +++++++++++++++++ tests/bench/ProjectFactoryBench.php | 29 + .../Types/NamespaceNodeToContextTest.php | 93 + 10 files changed, 3562 insertions(+), 56 deletions(-) create mode 100644 phpbench.json create mode 100644 src/phpDocumentor/Reflection/Types/NamespaceNodeToContext.php create mode 100644 tests/assets/phpunit_assert.php create mode 100644 tests/bench/ProjectFactoryBench.php create mode 100644 tests/unit/phpDocumentor/Reflection/Types/NamespaceNodeToContextTest.php diff --git a/.travis.yml b/.travis.yml index 07d32346..d2e62fe4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: php -php: [ 7.1, 7.2, 7.3, 7.4 nightly ] +php: [ 7.1, 7.2, 7.3, nightly ] sudo: false env: diff --git a/composer.json b/composer.json index 319cbada..a4a443ae 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "phpDocumentor\\": [ "tests/component/", "tests/unit/phpDocumentor", - "tests/mocks/" + "tests/bench/" ] } }, @@ -27,7 +27,7 @@ }, "require-dev": { "mockery/mockery": "~1.0", - "mikey179/vfsStream": "~1.2" + "mikey179/vfsstream": "~1.2" }, "extra": { "branch-alias": { diff --git a/composer.lock b/composer.lock index 550a1146..6b1bee98 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0c0b750e577c44ab31fe983b3d28c8aa", + "content-hash": "ae7e684c7c19ad6defcfa2c3b7dd8847", "packages": [ { "name": "nikic/php-parser", - "version": "v4.0.3", + "version": "v4.2.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "bd088dc940a418f09cda079a9b5c7c478890fb8d" + "reference": "5221f49a608808c1e4d436df32884cbc1b821ac0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bd088dc940a418f09cda079a9b5c7c478890fb8d", - "reference": "bd088dc940a418f09cda079a9b5c7c478890fb8d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/5221f49a608808c1e4d436df32884cbc1b821ac0", + "reference": "5221f49a608808c1e4d436df32884cbc1b821ac0", "shasum": "" }, "require": { @@ -33,7 +33,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -55,27 +55,27 @@ "parser", "php" ], - "time": "2018-07-15T17:25:16+00:00" + "time": "2019-02-16T20:54:15+00:00" }, { "name": "phpdocumentor/reflection-common", - "version": "2.0.0-alpha3", + "version": "2.0.0-beta1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "eedd98e8bc9cfd924f056b4b5847066d4a250d2f" + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/eedd98e8bc9cfd924f056b4b5847066d4a250d2f", - "reference": "eedd98e8bc9cfd924f056b4b5847066d4a250d2f", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", "shasum": "" }, "require": { "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^6" + "phpunit/phpunit": "~6" }, "type": "library", "extra": { @@ -85,9 +85,7 @@ }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -109,7 +107,7 @@ "reflection", "static analysis" ], - "time": "2018-06-13T21:44:20+00:00" + "time": "2018-08-07T13:53:10+00:00" }, { "name": "phpdocumentor/reflection-docblock", @@ -160,25 +158,25 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "0.6.2", + "version": "0.7.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "e81ce9e82df06b49b2d0e0a2393a08955aeda05b" + "reference": "9c0562f9af69b06b002b017a3f0672bbfaba349f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e81ce9e82df06b49b2d0e0a2393a08955aeda05b", - "reference": "e81ce9e82df06b49b2d0e0a2393a08955aeda05b", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c0562f9af69b06b002b017a3f0672bbfaba349f", + "reference": "9c0562f9af69b06b002b017a3f0672bbfaba349f", "shasum": "" }, "require": { "php": ">=7.1", - "phpdocumentor/reflection-common": "^2" + "phpdocumentor/reflection-common": "~2.0.0-beta1" }, "require-dev": { - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.5" + "mockery/mockery": "~1", + "phpunit/phpunit": "~6" }, "type": "library", "extra": { @@ -201,20 +199,21 @@ "email": "me@mikevanriel.com" } ], - "time": "2018-06-14T12:29:58+00:00" + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2018-09-25T05:46:06+00:00" }, { "name": "psr/log", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", "shasum": "" }, "require": { @@ -248,24 +247,83 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2018-11-20T15:27:04+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.11.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "82ebae02209c21113908c229e9883c419720738a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", + "reference": "82ebae02209c21113908c229e9883c419720738a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Gert de Pagter", + "email": "backendtea@gmail.com" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2019-02-06T07:57:58+00:00" }, { "name": "webmozart/assert", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", + "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" }, "require-dev": { "phpunit/phpunit": "^4.6", @@ -298,7 +356,7 @@ "check", "validate" ], - "time": "2018-01-29T19:49:41+00:00" + "time": "2018-12-25T11:19:39+00:00" } ], "packages-dev": [ @@ -398,16 +456,16 @@ }, { "name": "mockery/mockery", - "version": "1.1.0", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "99e29d3596b16dabe4982548527d5ddf90232e99" + "reference": "0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/99e29d3596b16dabe4982548527d5ddf90232e99", - "reference": "99e29d3596b16dabe4982548527d5ddf90232e99", + "url": "https://api.github.com/repos/mockery/mockery/zipball/0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2", + "reference": "0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2", "shasum": "" }, "require": { @@ -416,8 +474,7 @@ "php": ">=5.6.0" }, "require-dev": { - "phpdocumentor/phpdocumentor": "^2.9", - "phpunit/phpunit": "~5.7.10|~6.5" + "phpunit/phpunit": "~5.7.10|~6.5|~7.0|~8.0" }, "type": "library", "extra": { @@ -460,7 +517,7 @@ "test double", "testing" ], - "time": "2018-05-08T08:54:48+00:00" + "time": "2019-02-13T09:37:52+00:00" } ], "aliases": [], diff --git a/phive.xml b/phive.xml index d3b65c11..879855f9 100644 --- a/phive.xml +++ b/phive.xml @@ -1,5 +1,6 @@ - + + diff --git a/phpbench.json b/phpbench.json new file mode 100644 index 00000000..8049a251 --- /dev/null +++ b/phpbench.json @@ -0,0 +1,7 @@ +{ + "bootstrap": "vendor/autoload.php", + "path": "tests/bench", + "extensions": [ + "PhpBench\\Extensions\\XDebug\\XDebugExtension" + ] +} diff --git a/src/phpDocumentor/Reflection/Php/Factory/File.php b/src/phpDocumentor/Reflection/Php/Factory/File.php index ae35de05..adf9283b 100644 --- a/src/phpDocumentor/Reflection/Php/Factory/File.php +++ b/src/phpDocumentor/Reflection/Php/Factory/File.php @@ -26,6 +26,7 @@ use phpDocumentor\Reflection\Php\StrategyContainer; use phpDocumentor\Reflection\Types\Context; use phpDocumentor\Reflection\Types\ContextFactory; +use phpDocumentor\Reflection\Types\NamespaceNodeToContext; use PhpParser\Comment\Doc; use PhpParser\Node; use PhpParser\Node\Stmt\Class_ as ClassNode; @@ -98,10 +99,7 @@ private function createFile(CreateCommand $command) $code = $file->getContents(); $nodes = $this->nodesFactory->create($code); - $contextFactory = new ContextFactory(); - $context = $contextFactory->createForNamespace('\\', $code); - - $docBlock = $this->createFileDocBlock(null, $command->getStrategies(), $context, $nodes); + $docBlock = $this->createFileDocBlock(null, $command->getStrategies(), null, $nodes); $result = new FileElement( $file->md5(), @@ -110,7 +108,7 @@ private function createFile(CreateCommand $command) $docBlock ); - $this->createElements(new Fqsen('\\'), $nodes, $result, $command->getStrategies()); + $this->createElements($nodes, $result, $command->getStrategies(), null); return $result; } @@ -118,10 +116,12 @@ private function createFile(CreateCommand $command) /** * @param Node[] $nodes */ - private function createElements(Fqsen $namespace, array $nodes, FileElement $file, StrategyContainer $strategies): void - { - $contextFactory = new ContextFactory(); - $context = $contextFactory->createForNamespace((string) $namespace, $file->getSource()); + private function createElements( + array $nodes, + FileElement $file, + StrategyContainer $strategies, + ?Context $context + ): void { foreach ($nodes as $node) { switch (get_class($node)) { case ClassNode::class: @@ -140,8 +140,9 @@ private function createElements(Fqsen $namespace, array $nodes, FileElement $fil $file->addInterface($interface); break; case NamespaceNode::class: + $context = (new NamespaceNodeToContext())($node); $file->addNamespace($node->fqsen); - $this->createElements($node->fqsen, $node->stmts, $file, $strategies); + $this->createElements($node->stmts, $file, $strategies, $context); break; case TraitNode::class: $strategy = $strategies->findMatching($node); diff --git a/src/phpDocumentor/Reflection/Types/NamespaceNodeToContext.php b/src/phpDocumentor/Reflection/Types/NamespaceNodeToContext.php new file mode 100644 index 00000000..9c2271d0 --- /dev/null +++ b/src/phpDocumentor/Reflection/Types/NamespaceNodeToContext.php @@ -0,0 +1,63 @@ +name ? $namespace->name->toString() : '', + $this->aliasesToFullyQualifiedNames($namespace) + ); + } + + /** + * @return string[] indexed by alias + */ + private function aliasesToFullyQualifiedNames(Namespace_ $namespace) : array + { + // flatten(flatten(map(stuff))) + return \array_merge([], ...\array_merge([], ...\array_map(function ($use) : array { + /** @var $use Use_|GroupUse */ + + return \array_map(function (UseUse $useUse) use ($use) : array { + + if ($use instanceof GroupUse) { + return [(string) $useUse->getAlias() => $use->prefix->toString() . '\\' . $useUse->name->toString()]; + } + + return [(string) $useUse->getAlias() => $useUse->name->toString()]; + }, $use->uses); + }, $this->classAlikeUses($namespace)))); + } + + /** + * @param null|Namespace_ $namespace + * + * @return Use_[]|GroupUse[] + */ + private function classAlikeUses(Namespace_ $namespace) : array + { + return \array_filter( + $namespace->stmts ?? [], + function (Node $node) : bool { + return ( + $node instanceof Use_ + || $node instanceof GroupUse + ) && \in_array($node->type, [Use_::TYPE_UNKNOWN, Use_::TYPE_NORMAL], true); + } + ); + } +} diff --git a/tests/assets/phpunit_assert.php b/tests/assets/phpunit_assert.php new file mode 100644 index 00000000..2dff5c52 --- /dev/null +++ b/tests/assets/phpunit_assert.php @@ -0,0 +1,3255 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + * This file is added for benchmark purposes only!!! + */ +namespace PHPUnit\Framework; + +use ArrayAccess; +use Countable; +use DOMDocument; +use DOMElement; +use PHPUnit\Framework\Constraint\ArrayHasKey; +use PHPUnit\Framework\Constraint\ArraySubset; +use PHPUnit\Framework\Constraint\Attribute; +use PHPUnit\Framework\Constraint\Callback; +use PHPUnit\Framework\Constraint\ClassHasAttribute; +use PHPUnit\Framework\Constraint\ClassHasStaticAttribute; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\Constraint\Count; +use PHPUnit\Framework\Constraint\DirectoryExists; +use PHPUnit\Framework\Constraint\FileExists; +use PHPUnit\Framework\Constraint\GreaterThan; +use PHPUnit\Framework\Constraint\IsAnything; +use PHPUnit\Framework\Constraint\IsEmpty; +use PHPUnit\Framework\Constraint\IsEqual; +use PHPUnit\Framework\Constraint\IsFalse; +use PHPUnit\Framework\Constraint\IsFinite; +use PHPUnit\Framework\Constraint\IsIdentical; +use PHPUnit\Framework\Constraint\IsInfinite; +use PHPUnit\Framework\Constraint\IsInstanceOf; +use PHPUnit\Framework\Constraint\IsJson; +use PHPUnit\Framework\Constraint\IsNan; +use PHPUnit\Framework\Constraint\IsNull; +use PHPUnit\Framework\Constraint\IsReadable; +use PHPUnit\Framework\Constraint\IsTrue; +use PHPUnit\Framework\Constraint\IsType; +use PHPUnit\Framework\Constraint\IsWritable; +use PHPUnit\Framework\Constraint\JsonMatches; +use PHPUnit\Framework\Constraint\LessThan; +use PHPUnit\Framework\Constraint\LogicalAnd; +use PHPUnit\Framework\Constraint\LogicalNot; +use PHPUnit\Framework\Constraint\LogicalOr; +use PHPUnit\Framework\Constraint\LogicalXor; +use PHPUnit\Framework\Constraint\ObjectHasAttribute; +use PHPUnit\Framework\Constraint\RegularExpression; +use PHPUnit\Framework\Constraint\SameSize; +use PHPUnit\Framework\Constraint\StringContains; +use PHPUnit\Framework\Constraint\StringEndsWith; +use PHPUnit\Framework\Constraint\StringMatchesFormatDescription; +use PHPUnit\Framework\Constraint\StringStartsWith; +use PHPUnit\Framework\Constraint\TraversableContains; +use PHPUnit\Framework\Constraint\TraversableContainsOnly; +use PHPUnit\Util\InvalidArgumentHelper; +use PHPUnit\Util\Type; +use PHPUnit\Util\Xml; +use ReflectionClass; +use ReflectionException; +use ReflectionObject; +use Traversable; + +/** + * A set of assertion methods. + */ +abstract class Assert +{ + /** + * @var int + */ + private static $count = 0; + + /** + * Asserts that an array has a specified key. + * + * @param int|string $key + * @param array|ArrayAccess $array + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertArrayHasKey($key, $array, string $message = ''): void + { + if (!(\is_int($key) || \is_string($key))) { + throw InvalidArgumentHelper::factory( + 1, + 'integer or string' + ); + } + + if (!(\is_array($array) || $array instanceof ArrayAccess)) { + throw InvalidArgumentHelper::factory( + 2, + 'array or ArrayAccess' + ); + } + + $constraint = new ArrayHasKey($key); + + static::assertThat($array, $constraint, $message); + } + + /** + * Asserts that an array has a specified subset. + * + * @param array|ArrayAccess $subset + * @param array|ArrayAccess $array + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + * + * @codeCoverageIgnore + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3494 + */ + public static function assertArraySubset($subset, $array, bool $checkForObjectIdentity = false, string $message = ''): void + { + self::createWarning('assertArraySubset() is deprecated and will be removed in PHPUnit 9.'); + + if (!(\is_array($subset) || $subset instanceof ArrayAccess)) { + throw InvalidArgumentHelper::factory( + 1, + 'array or ArrayAccess' + ); + } + + if (!(\is_array($array) || $array instanceof ArrayAccess)) { + throw InvalidArgumentHelper::factory( + 2, + 'array or ArrayAccess' + ); + } + + $constraint = new ArraySubset($subset, $checkForObjectIdentity); + + static::assertThat($array, $constraint, $message); + } + + /** + * Asserts that an array does not have a specified key. + * + * @param int|string $key + * @param array|ArrayAccess $array + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertArrayNotHasKey($key, $array, string $message = ''): void + { + if (!(\is_int($key) || \is_string($key))) { + throw InvalidArgumentHelper::factory( + 1, + 'integer or string' + ); + } + + if (!(\is_array($array) || $array instanceof ArrayAccess)) { + throw InvalidArgumentHelper::factory( + 2, + 'array or ArrayAccess' + ); + } + + $constraint = new LogicalNot( + new ArrayHasKey($key) + ); + + static::assertThat($array, $constraint, $message); + } + + /** + * Asserts that a haystack contains a needle. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertContains($needle, $haystack, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void + { + // @codeCoverageIgnoreStart + if (\is_string($haystack)) { + self::createWarning('Using assertContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. Refactor your test to use assertStringContainsString() or assertStringContainsStringIgnoringCase() instead.'); + } + + if (!$checkForObjectIdentity) { + self::createWarning('The optional $checkForObjectIdentity parameter of assertContains() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertContainsEquals() instead.'); + } + + if ($checkForNonObjectIdentity) { + self::createWarning('The optional $checkForNonObjectIdentity parameter of assertContains() is deprecated and will be removed in PHPUnit 9.'); + } + + if ($ignoreCase) { + self::createWarning('The optional $ignoreCase parameter of assertContains() is deprecated and will be removed in PHPUnit 9.'); + } + // @codeCoverageIgnoreEnd + + if (\is_array($haystack) || + (\is_object($haystack) && $haystack instanceof Traversable)) { + $constraint = new TraversableContains( + $needle, + $checkForObjectIdentity, + $checkForNonObjectIdentity + ); + } elseif (\is_string($haystack)) { + if (!\is_string($needle)) { + throw InvalidArgumentHelper::factory( + 1, + 'string' + ); + } + + $constraint = new StringContains( + $needle, + $ignoreCase + ); + } else { + throw InvalidArgumentHelper::factory( + 2, + 'array, traversable or string' + ); + } + + static::assertThat($haystack, $constraint, $message); + } + + public static function assertContainsEquals($needle, iterable $haystack, string $message = ''): void + { + $constraint = new TraversableContains($needle, false, false); + + static::assertThat($haystack, $constraint, $message); + } + + /** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object contains a needle. + * + * @param object|string $haystackClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeContains($needle, string $haystackAttributeName, $haystackClassOrObject, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void + { + self::createWarning('assertAttributeContains() is deprecated and will be removed in PHPUnit 9.'); + + static::assertContains( + $needle, + static::readAttribute($haystackClassOrObject, $haystackAttributeName), + $message, + $ignoreCase, + $checkForObjectIdentity, + $checkForNonObjectIdentity + ); + } + + /** + * Asserts that a haystack does not contain a needle. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertNotContains($needle, $haystack, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void + { + // @codeCoverageIgnoreStart + if (\is_string($haystack)) { + self::createWarning('Using assertNotContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. Refactor your test to use assertStringNotContainsString() or assertStringNotContainsStringIgnoringCase() instead.'); + } + + if (!$checkForObjectIdentity) { + self::createWarning('The optional $checkForObjectIdentity parameter of assertNotContains() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertNotContainsEquals() instead.'); + } + + if ($checkForNonObjectIdentity) { + self::createWarning('The optional $checkForNonObjectIdentity parameter of assertNotContains() is deprecated and will be removed in PHPUnit 9.'); + } + + if ($ignoreCase) { + self::createWarning('The optional $ignoreCase parameter of assertNotContains() is deprecated and will be removed in PHPUnit 9.'); + } + // @codeCoverageIgnoreEnd + + if (\is_array($haystack) || + (\is_object($haystack) && $haystack instanceof Traversable)) { + $constraint = new LogicalNot( + new TraversableContains( + $needle, + $checkForObjectIdentity, + $checkForNonObjectIdentity + ) + ); + } elseif (\is_string($haystack)) { + if (!\is_string($needle)) { + throw InvalidArgumentHelper::factory( + 1, + 'string' + ); + } + + $constraint = new LogicalNot( + new StringContains( + $needle, + $ignoreCase + ) + ); + } else { + throw InvalidArgumentHelper::factory( + 2, + 'array, traversable or string' + ); + } + + static::assertThat($haystack, $constraint, $message); + } + + public static function assertNotContainsEquals($needle, iterable $haystack, string $message = ''): void + { + $constraint = new LogicalNot(new TraversableContains($needle, false, false)); + + static::assertThat($haystack, $constraint, $message); + } + + /** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object does not contain a needle. + * + * @param object|string $haystackClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeNotContains($needle, string $haystackAttributeName, $haystackClassOrObject, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): void + { + self::createWarning('assertAttributeNotContains() is deprecated and will be removed in PHPUnit 9.'); + + static::assertNotContains( + $needle, + static::readAttribute($haystackClassOrObject, $haystackAttributeName), + $message, + $ignoreCase, + $checkForObjectIdentity, + $checkForNonObjectIdentity + ); + } + + /** + * Asserts that a haystack contains only values of a given type. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertContainsOnly(string $type, iterable $haystack, ?bool $isNativeType = null, string $message = ''): void + { + if ($isNativeType === null) { + $isNativeType = Type::isType($type); + } + + static::assertThat( + $haystack, + new TraversableContainsOnly( + $type, + $isNativeType + ), + $message + ); + } + + /** + * Asserts that a haystack contains only instances of a given class name. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertContainsOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void + { + static::assertThat( + $haystack, + new TraversableContainsOnly( + $className, + false + ), + $message + ); + } + + /** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object contains only values of a given type. + * + * @param object|string $haystackClassOrObject + * @param bool $isNativeType + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeContainsOnly(string $type, string $haystackAttributeName, $haystackClassOrObject, ?bool $isNativeType = null, string $message = ''): void + { + self::createWarning('assertAttributeContainsOnly() is deprecated and will be removed in PHPUnit 9.'); + + static::assertContainsOnly( + $type, + static::readAttribute($haystackClassOrObject, $haystackAttributeName), + $isNativeType, + $message + ); + } + + /** + * Asserts that a haystack does not contain only values of a given type. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotContainsOnly(string $type, iterable $haystack, ?bool $isNativeType = null, string $message = ''): void + { + if ($isNativeType === null) { + $isNativeType = Type::isType($type); + } + + static::assertThat( + $haystack, + new LogicalNot( + new TraversableContainsOnly( + $type, + $isNativeType + ) + ), + $message + ); + } + + /** + * Asserts that a haystack that is stored in a static attribute of a class + * or an attribute of an object does not contain only values of a given + * type. + * + * @param object|string $haystackClassOrObject + * @param bool $isNativeType + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeNotContainsOnly(string $type, string $haystackAttributeName, $haystackClassOrObject, ?bool $isNativeType = null, string $message = ''): void + { + self::createWarning('assertAttributeNotContainsOnly() is deprecated and will be removed in PHPUnit 9.'); + + static::assertNotContainsOnly( + $type, + static::readAttribute($haystackClassOrObject, $haystackAttributeName), + $isNativeType, + $message + ); + } + + /** + * Asserts the number of elements of an array, Countable or Traversable. + * + * @param Countable|iterable $haystack + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertCount(int $expectedCount, $haystack, string $message = ''): void + { + if (!$haystack instanceof Countable && !\is_iterable($haystack)) { + throw InvalidArgumentHelper::factory(2, 'countable or iterable'); + } + + static::assertThat( + $haystack, + new Count($expectedCount), + $message + ); + } + + /** + * Asserts the number of elements of an array, Countable or Traversable + * that is stored in an attribute. + * + * @param object|string $haystackClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeCount(int $expectedCount, string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void + { + self::createWarning('assertAttributeCount() is deprecated and will be removed in PHPUnit 9.'); + + static::assertCount( + $expectedCount, + static::readAttribute($haystackClassOrObject, $haystackAttributeName), + $message + ); + } + + /** + * Asserts the number of elements of an array, Countable or Traversable. + * + * @param Countable|iterable $haystack + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertNotCount(int $expectedCount, $haystack, string $message = ''): void + { + if (!$haystack instanceof Countable && !\is_iterable($haystack)) { + throw InvalidArgumentHelper::factory(2, 'countable or iterable'); + } + + $constraint = new LogicalNot( + new Count($expectedCount) + ); + + static::assertThat($haystack, $constraint, $message); + } + + /** + * Asserts the number of elements of an array, Countable or Traversable + * that is stored in an attribute. + * + * @param object|string $haystackClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeNotCount(int $expectedCount, string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void + { + self::createWarning('assertAttributeNotCount() is deprecated and will be removed in PHPUnit 9.'); + + static::assertNotCount( + $expectedCount, + static::readAttribute($haystackClassOrObject, $haystackAttributeName), + $message + ); + } + + /** + * Asserts that two variables are equal. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertEquals($expected, $actual, string $message = '', float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void + { + // @codeCoverageIgnoreStart + if ($delta !== 0.0) { + self::createWarning('The optional $delta parameter of assertEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertEqualsWithDelta() instead.'); + } + + if ($maxDepth !== 10) { + self::createWarning('The optional $maxDepth parameter of assertEquals() is deprecated and will be removed in PHPUnit 9.'); + } + + if ($canonicalize) { + self::createWarning('The optional $canonicalize parameter of assertEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertEqualsCanonicalizing() instead.'); + } + + if ($ignoreCase) { + self::createWarning('The optional $ignoreCase parameter of assertEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertEqualsIgnoringCase() instead.'); + } + // @codeCoverageIgnoreEnd + + $constraint = new IsEqual( + $expected, + $delta, + $maxDepth, + $canonicalize, + $ignoreCase + ); + + static::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are equal (canonicalizing). + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertEqualsCanonicalizing($expected, $actual, string $message = ''): void + { + $constraint = new IsEqual( + $expected, + 0.0, + 10, + true, + false + ); + + static::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are equal (ignoring case). + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertEqualsIgnoringCase($expected, $actual, string $message = ''): void + { + $constraint = new IsEqual( + $expected, + 0.0, + 10, + false, + true + ); + + static::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are equal (with delta). + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertEqualsWithDelta($expected, $actual, float $delta, string $message = ''): void + { + $constraint = new IsEqual( + $expected, + $delta + ); + + static::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that a variable is equal to an attribute of an object. + * + * @param object|string $actualClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeEquals($expected, string $actualAttributeName, $actualClassOrObject, string $message = '', float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void + { + self::createWarning('assertAttributeEquals() is deprecated and will be removed in PHPUnit 9.'); + + static::assertEquals( + $expected, + static::readAttribute($actualClassOrObject, $actualAttributeName), + $message, + $delta, + $maxDepth, + $canonicalize, + $ignoreCase + ); + } + + /** + * Asserts that two variables are not equal. + * + * @param float $delta + * @param int $maxDepth + * @param bool $canonicalize + * @param bool $ignoreCase + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotEquals($expected, $actual, string $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false): void + { + // @codeCoverageIgnoreStart + if ($delta !== 0.0) { + self::createWarning('The optional $delta parameter of assertNotEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertNotEqualsWithDelta() instead.'); + } + + if ($maxDepth !== 10) { + self::createWarning('The optional $maxDepth parameter of assertNotEquals() is deprecated and will be removed in PHPUnit 9.'); + } + + if ($canonicalize) { + self::createWarning('The optional $canonicalize parameter of assertNotEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertNotEqualsCanonicalizing() instead.'); + } + + if ($ignoreCase) { + self::createWarning('The optional $ignoreCase parameter of assertNotEquals() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertNotEqualsIgnoringCase() instead.'); + } + // @codeCoverageIgnoreEnd + + $constraint = new LogicalNot( + new IsEqual( + $expected, + $delta, + $maxDepth, + $canonicalize, + $ignoreCase + ) + ); + + static::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are not equal (canonicalizing). + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotEqualsCanonicalizing($expected, $actual, string $message = ''): void + { + $constraint = new LogicalNot( + new IsEqual( + $expected, + 0.0, + 10, + true, + false + ) + ); + + static::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are not equal (ignoring case). + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotEqualsIgnoringCase($expected, $actual, string $message = ''): void + { + $constraint = new LogicalNot( + new IsEqual( + $expected, + 0.0, + 10, + false, + true + ) + ); + + static::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are not equal (with delta). + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotEqualsWithDelta($expected, $actual, float $delta, string $message = ''): void + { + $constraint = new LogicalNot( + new IsEqual( + $expected, + $delta + ) + ); + + static::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that a variable is not equal to an attribute of an object. + * + * @param object|string $actualClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeNotEquals($expected, string $actualAttributeName, $actualClassOrObject, string $message = '', float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void + { + self::createWarning('assertAttributeNotEquals() is deprecated and will be removed in PHPUnit 9.'); + + static::assertNotEquals( + $expected, + static::readAttribute($actualClassOrObject, $actualAttributeName), + $message, + $delta, + $maxDepth, + $canonicalize, + $ignoreCase + ); + } + + /** + * Asserts that a variable is empty. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertEmpty($actual, string $message = ''): void + { + static::assertThat($actual, static::isEmpty(), $message); + } + + /** + * Asserts that a static attribute of a class or an attribute of an object + * is empty. + * + * @param object|string $haystackClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeEmpty(string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void + { + self::createWarning('assertAttributeEmpty() is deprecated and will be removed in PHPUnit 9.'); + + static::assertEmpty( + static::readAttribute($haystackClassOrObject, $haystackAttributeName), + $message + ); + } + + /** + * Asserts that a variable is not empty. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotEmpty($actual, string $message = ''): void + { + static::assertThat($actual, static::logicalNot(static::isEmpty()), $message); + } + + /** + * Asserts that a static attribute of a class or an attribute of an object + * is not empty. + * + * @param object|string $haystackClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeNotEmpty(string $haystackAttributeName, $haystackClassOrObject, string $message = ''): void + { + self::createWarning('assertAttributeNotEmpty() is deprecated and will be removed in PHPUnit 9.'); + + static::assertNotEmpty( + static::readAttribute($haystackClassOrObject, $haystackAttributeName), + $message + ); + } + + /** + * Asserts that a value is greater than another value. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertGreaterThan($expected, $actual, string $message = ''): void + { + static::assertThat($actual, static::greaterThan($expected), $message); + } + + /** + * Asserts that an attribute is greater than another value. + * + * @param object|string $actualClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeGreaterThan($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void + { + self::createWarning('assertAttributeGreaterThan() is deprecated and will be removed in PHPUnit 9.'); + + static::assertGreaterThan( + $expected, + static::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that a value is greater than or equal to another value. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertGreaterThanOrEqual($expected, $actual, string $message = ''): void + { + static::assertThat( + $actual, + static::greaterThanOrEqual($expected), + $message + ); + } + + /** + * Asserts that an attribute is greater than or equal to another value. + * + * @param object|string $actualClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeGreaterThanOrEqual($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void + { + self::createWarning('assertAttributeGreaterThanOrEqual() is deprecated and will be removed in PHPUnit 9.'); + + static::assertGreaterThanOrEqual( + $expected, + static::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that a value is smaller than another value. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertLessThan($expected, $actual, string $message = ''): void + { + static::assertThat($actual, static::lessThan($expected), $message); + } + + /** + * Asserts that an attribute is smaller than another value. + * + * @param object|string $actualClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeLessThan($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void + { + self::createWarning('assertAttributeLessThan() is deprecated and will be removed in PHPUnit 9.'); + + static::assertLessThan( + $expected, + static::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that a value is smaller than or equal to another value. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertLessThanOrEqual($expected, $actual, string $message = ''): void + { + static::assertThat($actual, static::lessThanOrEqual($expected), $message); + } + + /** + * Asserts that an attribute is smaller than or equal to another value. + * + * @param object|string $actualClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeLessThanOrEqual($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void + { + self::createWarning('assertAttributeLessThanOrEqual() is deprecated and will be removed in PHPUnit 9.'); + + static::assertLessThanOrEqual( + $expected, + static::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that the contents of one file is equal to the contents of another + * file. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertFileEquals(string $expected, string $actual, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void + { + static::assertFileExists($expected, $message); + static::assertFileExists($actual, $message); + + $constraint = new IsEqual( + \file_get_contents($expected), + 0.0, + 10, + $canonicalize, + $ignoreCase + ); + + static::assertThat(\file_get_contents($actual), $constraint, $message); + } + + /** + * Asserts that the contents of one file is not equal to the contents of + * another file. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertFileNotEquals(string $expected, string $actual, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void + { + static::assertFileExists($expected, $message); + static::assertFileExists($actual, $message); + + $constraint = new LogicalNot( + new IsEqual( + \file_get_contents($expected), + 0.0, + 10, + $canonicalize, + $ignoreCase + ) + ); + + static::assertThat(\file_get_contents($actual), $constraint, $message); + } + + /** + * Asserts that the contents of a string is equal + * to the contents of a file. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringEqualsFile(string $expectedFile, string $actualString, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void + { + static::assertFileExists($expectedFile, $message); + + $constraint = new IsEqual( + \file_get_contents($expectedFile), + 0.0, + 10, + $canonicalize, + $ignoreCase + ); + + static::assertThat($actualString, $constraint, $message); + } + + /** + * Asserts that the contents of a string is not equal + * to the contents of a file. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringNotEqualsFile(string $expectedFile, string $actualString, string $message = '', bool $canonicalize = false, bool $ignoreCase = false): void + { + static::assertFileExists($expectedFile, $message); + + $constraint = new LogicalNot( + new IsEqual( + \file_get_contents($expectedFile), + 0.0, + 10, + $canonicalize, + $ignoreCase + ) + ); + + static::assertThat($actualString, $constraint, $message); + } + + /** + * Asserts that a file/dir is readable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsReadable(string $filename, string $message = ''): void + { + static::assertThat($filename, new IsReadable, $message); + } + + /** + * Asserts that a file/dir exists and is not readable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotIsReadable(string $filename, string $message = ''): void + { + static::assertThat($filename, new LogicalNot(new IsReadable), $message); + } + + /** + * Asserts that a file/dir exists and is writable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsWritable(string $filename, string $message = ''): void + { + static::assertThat($filename, new IsWritable, $message); + } + + /** + * Asserts that a file/dir exists and is not writable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotIsWritable(string $filename, string $message = ''): void + { + static::assertThat($filename, new LogicalNot(new IsWritable), $message); + } + + /** + * Asserts that a directory exists. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertDirectoryExists(string $directory, string $message = ''): void + { + static::assertThat($directory, new DirectoryExists, $message); + } + + /** + * Asserts that a directory does not exist. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertDirectoryNotExists(string $directory, string $message = ''): void + { + static::assertThat($directory, new LogicalNot(new DirectoryExists), $message); + } + + /** + * Asserts that a directory exists and is readable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertDirectoryIsReadable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertIsReadable($directory, $message); + } + + /** + * Asserts that a directory exists and is not readable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertDirectoryNotIsReadable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertNotIsReadable($directory, $message); + } + + /** + * Asserts that a directory exists and is writable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertDirectoryIsWritable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertIsWritable($directory, $message); + } + + /** + * Asserts that a directory exists and is not writable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertDirectoryNotIsWritable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertNotIsWritable($directory, $message); + } + + /** + * Asserts that a file exists. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertFileExists(string $filename, string $message = ''): void + { + static::assertThat($filename, new FileExists, $message); + } + + /** + * Asserts that a file does not exist. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertFileNotExists(string $filename, string $message = ''): void + { + static::assertThat($filename, new LogicalNot(new FileExists), $message); + } + + /** + * Asserts that a file exists and is readable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertFileIsReadable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertIsReadable($file, $message); + } + + /** + * Asserts that a file exists and is not readable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertFileNotIsReadable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertNotIsReadable($file, $message); + } + + /** + * Asserts that a file exists and is writable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertFileIsWritable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertIsWritable($file, $message); + } + + /** + * Asserts that a file exists and is not writable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertFileNotIsWritable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertNotIsWritable($file, $message); + } + + /** + * Asserts that a condition is true. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertTrue($condition, string $message = ''): void + { + static::assertThat($condition, static::isTrue(), $message); + } + + /** + * Asserts that a condition is not true. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotTrue($condition, string $message = ''): void + { + static::assertThat($condition, static::logicalNot(static::isTrue()), $message); + } + + /** + * Asserts that a condition is false. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertFalse($condition, string $message = ''): void + { + static::assertThat($condition, static::isFalse(), $message); + } + + /** + * Asserts that a condition is not false. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotFalse($condition, string $message = ''): void + { + static::assertThat($condition, static::logicalNot(static::isFalse()), $message); + } + + /** + * Asserts that a variable is null. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNull($actual, string $message = ''): void + { + static::assertThat($actual, static::isNull(), $message); + } + + /** + * Asserts that a variable is not null. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotNull($actual, string $message = ''): void + { + static::assertThat($actual, static::logicalNot(static::isNull()), $message); + } + + /** + * Asserts that a variable is finite. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertFinite($actual, string $message = ''): void + { + static::assertThat($actual, static::isFinite(), $message); + } + + /** + * Asserts that a variable is infinite. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertInfinite($actual, string $message = ''): void + { + static::assertThat($actual, static::isInfinite(), $message); + } + + /** + * Asserts that a variable is nan. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNan($actual, string $message = ''): void + { + static::assertThat($actual, static::isNan(), $message); + } + + /** + * Asserts that a class has a specified attribute. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertClassHasAttribute(string $attributeName, string $className, string $message = ''): void + { + if (!self::isValidClassAttributeName($attributeName)) { + throw InvalidArgumentHelper::factory(1, 'valid attribute name'); + } + + if (!\class_exists($className)) { + throw InvalidArgumentHelper::factory(2, 'class name', $className); + } + + static::assertThat($className, new ClassHasAttribute($attributeName), $message); + } + + /** + * Asserts that a class does not have a specified attribute. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertClassNotHasAttribute(string $attributeName, string $className, string $message = ''): void + { + if (!self::isValidClassAttributeName($attributeName)) { + throw InvalidArgumentHelper::factory(1, 'valid attribute name'); + } + + if (!\class_exists($className)) { + throw InvalidArgumentHelper::factory(2, 'class name', $className); + } + + static::assertThat( + $className, + new LogicalNot( + new ClassHasAttribute($attributeName) + ), + $message + ); + } + + /** + * Asserts that a class has a specified static attribute. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertClassHasStaticAttribute(string $attributeName, string $className, string $message = ''): void + { + if (!self::isValidClassAttributeName($attributeName)) { + throw InvalidArgumentHelper::factory(1, 'valid attribute name'); + } + + if (!\class_exists($className)) { + throw InvalidArgumentHelper::factory(2, 'class name', $className); + } + + static::assertThat( + $className, + new ClassHasStaticAttribute($attributeName), + $message + ); + } + + /** + * Asserts that a class does not have a specified static attribute. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertClassNotHasStaticAttribute(string $attributeName, string $className, string $message = ''): void + { + if (!self::isValidClassAttributeName($attributeName)) { + throw InvalidArgumentHelper::factory(1, 'valid attribute name'); + } + + if (!\class_exists($className)) { + throw InvalidArgumentHelper::factory(2, 'class name', $className); + } + + static::assertThat( + $className, + new LogicalNot( + new ClassHasStaticAttribute($attributeName) + ), + $message + ); + } + + /** + * Asserts that an object has a specified attribute. + * + * @param object $object + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertObjectHasAttribute(string $attributeName, $object, string $message = ''): void + { + if (!self::isValidObjectAttributeName($attributeName)) { + throw InvalidArgumentHelper::factory(1, 'valid attribute name'); + } + + if (!\is_object($object)) { + throw InvalidArgumentHelper::factory(2, 'object'); + } + + static::assertThat( + $object, + new ObjectHasAttribute($attributeName), + $message + ); + } + + /** + * Asserts that an object does not have a specified attribute. + * + * @param object $object + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertObjectNotHasAttribute(string $attributeName, $object, string $message = ''): void + { + if (!self::isValidObjectAttributeName($attributeName)) { + throw InvalidArgumentHelper::factory(1, 'valid attribute name'); + } + + if (!\is_object($object)) { + throw InvalidArgumentHelper::factory(2, 'object'); + } + + static::assertThat( + $object, + new LogicalNot( + new ObjectHasAttribute($attributeName) + ), + $message + ); + } + + /** + * Asserts that two variables have the same type and value. + * Used on objects, it asserts that two variables reference + * the same object. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertSame($expected, $actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsIdentical($expected), + $message + ); + } + + /** + * Asserts that a variable and an attribute of an object have the same type + * and value. + * + * @param object|string $actualClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeSame($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void + { + self::createWarning('assertAttributeSame() is deprecated and will be removed in PHPUnit 9.'); + + static::assertSame( + $expected, + static::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that two variables do not have the same type and value. + * Used on objects, it asserts that two variables do not reference + * the same object. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotSame($expected, $actual, string $message = ''): void + { + if (\is_bool($expected) && \is_bool($actual)) { + static::assertNotEquals($expected, $actual, $message); + } + + static::assertThat( + $actual, + new LogicalNot( + new IsIdentical($expected) + ), + $message + ); + } + + /** + * Asserts that a variable and an attribute of an object do not have the + * same type and value. + * + * @param object|string $actualClassOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeNotSame($expected, string $actualAttributeName, $actualClassOrObject, string $message = ''): void + { + self::createWarning('assertAttributeNotSame() is deprecated and will be removed in PHPUnit 9.'); + + static::assertNotSame( + $expected, + static::readAttribute($actualClassOrObject, $actualAttributeName), + $message + ); + } + + /** + * Asserts that a variable is of a given type. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertInstanceOf(string $expected, $actual, string $message = ''): void + { + if (!\class_exists($expected) && !\interface_exists($expected)) { + throw InvalidArgumentHelper::factory(1, 'class or interface name'); + } + + static::assertThat( + $actual, + new IsInstanceOf($expected), + $message + ); + } + + /** + * Asserts that an attribute is of a given type. + * + * @param object|string $classOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeInstanceOf(string $expected, string $attributeName, $classOrObject, string $message = ''): void + { + self::createWarning('assertAttributeInstanceOf() is deprecated and will be removed in PHPUnit 9.'); + + static::assertInstanceOf( + $expected, + static::readAttribute($classOrObject, $attributeName), + $message + ); + } + + /** + * Asserts that a variable is not of a given type. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertNotInstanceOf(string $expected, $actual, string $message = ''): void + { + if (!\class_exists($expected) && !\interface_exists($expected)) { + throw InvalidArgumentHelper::factory(1, 'class or interface name'); + } + + static::assertThat( + $actual, + new LogicalNot( + new IsInstanceOf($expected) + ), + $message + ); + } + + /** + * Asserts that an attribute is of a given type. + * + * @param object|string $classOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeNotInstanceOf(string $expected, string $attributeName, $classOrObject, string $message = ''): void + { + self::createWarning('assertAttributeNotInstanceOf() is deprecated and will be removed in PHPUnit 9.'); + + static::assertNotInstanceOf( + $expected, + static::readAttribute($classOrObject, $attributeName), + $message + ); + } + + /** + * Asserts that a variable is of a given type. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3369 + * @codeCoverageIgnore + */ + public static function assertInternalType(string $expected, $actual, string $message = ''): void + { + self::createWarning('assertInternalType() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertIsArray(), assertIsBool(), assertIsFloat(), assertIsInt(), assertIsNumeric(), assertIsObject(), assertIsResource(), assertIsString(), assertIsScalar(), assertIsCallable(), or assertIsIterable() instead.'); + + static::assertThat( + $actual, + new IsType($expected), + $message + ); + } + + /** + * Asserts that an attribute is of a given type. + * + * @param object|string $classOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeInternalType(string $expected, string $attributeName, $classOrObject, string $message = ''): void + { + self::createWarning('assertAttributeInternalType() is deprecated and will be removed in PHPUnit 9.'); + + static::assertInternalType( + $expected, + static::readAttribute($classOrObject, $attributeName), + $message + ); + } + + /** + * Asserts that a variable is of type array. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsArray($actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsType(IsType::TYPE_ARRAY), + $message + ); + } + + /** + * Asserts that a variable is of type bool. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsBool($actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsType(IsType::TYPE_BOOL), + $message + ); + } + + /** + * Asserts that a variable is of type float. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsFloat($actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsType(IsType::TYPE_FLOAT), + $message + ); + } + + /** + * Asserts that a variable is of type int. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsInt($actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsType(IsType::TYPE_INT), + $message + ); + } + + /** + * Asserts that a variable is of type numeric. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNumeric($actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsType(IsType::TYPE_NUMERIC), + $message + ); + } + + /** + * Asserts that a variable is of type object. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsObject($actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsType(IsType::TYPE_OBJECT), + $message + ); + } + + /** + * Asserts that a variable is of type resource. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsResource($actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsType(IsType::TYPE_RESOURCE), + $message + ); + } + + /** + * Asserts that a variable is of type string. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsString($actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsType(IsType::TYPE_STRING), + $message + ); + } + + /** + * Asserts that a variable is of type scalar. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsScalar($actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsType(IsType::TYPE_SCALAR), + $message + ); + } + + /** + * Asserts that a variable is of type callable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsCallable($actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsType(IsType::TYPE_CALLABLE), + $message + ); + } + + /** + * Asserts that a variable is of type iterable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsIterable($actual, string $message = ''): void + { + static::assertThat( + $actual, + new IsType(IsType::TYPE_ITERABLE), + $message + ); + } + + /** + * Asserts that a variable is not of a given type. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3369 + * @codeCoverageIgnore + */ + public static function assertNotInternalType(string $expected, $actual, string $message = ''): void + { + self::createWarning('assertNotInternalType() is deprecated and will be removed in PHPUnit 9. Refactor your test to use assertIsNotArray(), assertIsNotBool(), assertIsNotFloat(), assertIsNotInt(), assertIsNotNumeric(), assertIsNotObject(), assertIsNotResource(), assertIsNotString(), assertIsNotScalar(), assertIsNotCallable(), or assertIsNotIterable() instead.'); + + static::assertThat( + $actual, + new LogicalNot( + new IsType($expected) + ), + $message + ); + } + + /** + * Asserts that a variable is not of type array. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNotArray($actual, string $message = ''): void + { + static::assertThat( + $actual, + new LogicalNot(new IsType(IsType::TYPE_ARRAY)), + $message + ); + } + + /** + * Asserts that a variable is not of type bool. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNotBool($actual, string $message = ''): void + { + static::assertThat( + $actual, + new LogicalNot(new IsType(IsType::TYPE_BOOL)), + $message + ); + } + + /** + * Asserts that a variable is not of type float. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNotFloat($actual, string $message = ''): void + { + static::assertThat( + $actual, + new LogicalNot(new IsType(IsType::TYPE_FLOAT)), + $message + ); + } + + /** + * Asserts that a variable is not of type int. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNotInt($actual, string $message = ''): void + { + static::assertThat( + $actual, + new LogicalNot(new IsType(IsType::TYPE_INT)), + $message + ); + } + + /** + * Asserts that a variable is not of type numeric. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNotNumeric($actual, string $message = ''): void + { + static::assertThat( + $actual, + new LogicalNot(new IsType(IsType::TYPE_NUMERIC)), + $message + ); + } + + /** + * Asserts that a variable is not of type object. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNotObject($actual, string $message = ''): void + { + static::assertThat( + $actual, + new LogicalNot(new IsType(IsType::TYPE_OBJECT)), + $message + ); + } + + /** + * Asserts that a variable is not of type resource. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNotResource($actual, string $message = ''): void + { + static::assertThat( + $actual, + new LogicalNot(new IsType(IsType::TYPE_RESOURCE)), + $message + ); + } + + /** + * Asserts that a variable is not of type string. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNotString($actual, string $message = ''): void + { + static::assertThat( + $actual, + new LogicalNot(new IsType(IsType::TYPE_STRING)), + $message + ); + } + + /** + * Asserts that a variable is not of type scalar. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNotScalar($actual, string $message = ''): void + { + static::assertThat( + $actual, + new LogicalNot(new IsType(IsType::TYPE_SCALAR)), + $message + ); + } + + /** + * Asserts that a variable is not of type callable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNotCallable($actual, string $message = ''): void + { + static::assertThat( + $actual, + new LogicalNot(new IsType(IsType::TYPE_CALLABLE)), + $message + ); + } + + /** + * Asserts that a variable is not of type iterable. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertIsNotIterable($actual, string $message = ''): void + { + static::assertThat( + $actual, + new LogicalNot(new IsType(IsType::TYPE_ITERABLE)), + $message + ); + } + + /** + * Asserts that an attribute is of a given type. + * + * @param object|string $classOrObject + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws ReflectionException + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function assertAttributeNotInternalType(string $expected, string $attributeName, $classOrObject, string $message = ''): void + { + self::createWarning('assertAttributeNotInternalType() is deprecated and will be removed in PHPUnit 9.'); + + static::assertNotInternalType( + $expected, + static::readAttribute($classOrObject, $attributeName), + $message + ); + } + + /** + * Asserts that a string matches a given regular expression. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertRegExp(string $pattern, string $string, string $message = ''): void + { + static::assertThat($string, new RegularExpression($pattern), $message); + } + + /** + * Asserts that a string does not match a given regular expression. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertNotRegExp(string $pattern, string $string, string $message = ''): void + { + static::assertThat( + $string, + new LogicalNot( + new RegularExpression($pattern) + ), + $message + ); + } + + /** + * Assert that the size of two arrays (or `Countable` or `Traversable` objects) + * is the same. + * + * @param Countable|iterable $expected + * @param Countable|iterable $actual + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertSameSize($expected, $actual, string $message = ''): void + { + if (!$expected instanceof Countable && !\is_iterable($expected)) { + throw InvalidArgumentHelper::factory(1, 'countable or iterable'); + } + + if (!$actual instanceof Countable && !\is_iterable($actual)) { + throw InvalidArgumentHelper::factory(2, 'countable or iterable'); + } + + static::assertThat( + $actual, + new SameSize($expected), + $message + ); + } + + /** + * Assert that the size of two arrays (or `Countable` or `Traversable` objects) + * is not the same. + * + * @param Countable|iterable $expected + * @param Countable|iterable $actual + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertNotSameSize($expected, $actual, string $message = ''): void + { + if (!$expected instanceof Countable && !\is_iterable($expected)) { + throw InvalidArgumentHelper::factory(1, 'countable or iterable'); + } + + if (!$actual instanceof Countable && !\is_iterable($actual)) { + throw InvalidArgumentHelper::factory(2, 'countable or iterable'); + } + + static::assertThat( + $actual, + new LogicalNot( + new SameSize($expected) + ), + $message + ); + } + + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringMatchesFormat(string $format, string $string, string $message = ''): void + { + static::assertThat($string, new StringMatchesFormatDescription($format), $message); + } + + /** + * Asserts that a string does not match a given format string. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringNotMatchesFormat(string $format, string $string, string $message = ''): void + { + static::assertThat( + $string, + new LogicalNot( + new StringMatchesFormatDescription($format) + ), + $message + ); + } + + /** + * Asserts that a string matches a given format file. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringMatchesFormatFile(string $formatFile, string $string, string $message = ''): void + { + static::assertFileExists($formatFile, $message); + + static::assertThat( + $string, + new StringMatchesFormatDescription( + \file_get_contents($formatFile) + ), + $message + ); + } + + /** + * Asserts that a string does not match a given format string. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringNotMatchesFormatFile(string $formatFile, string $string, string $message = ''): void + { + static::assertFileExists($formatFile, $message); + + static::assertThat( + $string, + new LogicalNot( + new StringMatchesFormatDescription( + \file_get_contents($formatFile) + ) + ), + $message + ); + } + + /** + * Asserts that a string starts with a given prefix. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringStartsWith(string $prefix, string $string, string $message = ''): void + { + static::assertThat($string, new StringStartsWith($prefix), $message); + } + + /** + * Asserts that a string starts not with a given prefix. + * + * @param string $prefix + * @param string $string + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringStartsNotWith($prefix, $string, string $message = ''): void + { + static::assertThat( + $string, + new LogicalNot( + new StringStartsWith($prefix) + ), + $message + ); + } + + /** + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringContainsString(string $needle, string $haystack, string $message = ''): void + { + $constraint = new StringContains($needle, false); + + static::assertThat($haystack, $constraint, $message); + } + + /** + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void + { + $constraint = new StringContains($needle, true); + + static::assertThat($haystack, $constraint, $message); + } + + /** + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringNotContainsString(string $needle, string $haystack, string $message = ''): void + { + $constraint = new LogicalNot(new StringContains($needle)); + + static::assertThat($haystack, $constraint, $message); + } + + /** + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringNotContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void + { + $constraint = new LogicalNot(new StringContains($needle, true)); + + static::assertThat($haystack, $constraint, $message); + } + + /** + * Asserts that a string ends with a given suffix. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringEndsWith(string $suffix, string $string, string $message = ''): void + { + static::assertThat($string, new StringEndsWith($suffix), $message); + } + + /** + * Asserts that a string ends not with a given suffix. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertStringEndsNotWith(string $suffix, string $string, string $message = ''): void + { + static::assertThat( + $string, + new LogicalNot( + new StringEndsWith($suffix) + ), + $message + ); + } + + /** + * Asserts that two XML files are equal. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void + { + $expected = Xml::loadFile($expectedFile); + $actual = Xml::loadFile($actualFile); + + static::assertEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML files are not equal. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void + { + $expected = Xml::loadFile($expectedFile); + $actual = Xml::loadFile($actualFile); + + static::assertNotEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are equal. + * + * @param DOMDocument|string $actualXml + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertXmlStringEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void + { + $expected = Xml::loadFile($expectedFile); + $actual = Xml::load($actualXml); + + static::assertEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are not equal. + * + * @param DOMDocument|string $actualXml + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertXmlStringNotEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void + { + $expected = Xml::loadFile($expectedFile); + $actual = Xml::load($actualXml); + + static::assertNotEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are equal. + * + * @param DOMDocument|string $expectedXml + * @param DOMDocument|string $actualXml + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertXmlStringEqualsXmlString($expectedXml, $actualXml, string $message = ''): void + { + $expected = Xml::load($expectedXml); + $actual = Xml::load($actualXml); + + static::assertEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are not equal. + * + * @param DOMDocument|string $expectedXml + * @param DOMDocument|string $actualXml + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + * @throws Exception + */ + public static function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, string $message = ''): void + { + $expected = Xml::load($expectedXml); + $actual = Xml::load($actualXml); + + static::assertNotEquals($expected, $actual, $message); + } + + /** + * Asserts that a hierarchy of DOMElements matches. + * + * @throws AssertionFailedError + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement, bool $checkAttributes = false, string $message = ''): void + { + $expectedElement = Xml::import($expectedElement); + $actualElement = Xml::import($actualElement); + + static::assertSame( + $expectedElement->tagName, + $actualElement->tagName, + $message + ); + + if ($checkAttributes) { + static::assertSame( + $expectedElement->attributes->length, + $actualElement->attributes->length, + \sprintf( + '%s%sNumber of attributes on node "%s" does not match', + $message, + !empty($message) ? "\n" : '', + $expectedElement->tagName + ) + ); + + for ($i = 0; $i < $expectedElement->attributes->length; $i++) { + $expectedAttribute = $expectedElement->attributes->item($i); + $actualAttribute = $actualElement->attributes->getNamedItem($expectedAttribute->name); + + \assert($expectedAttribute instanceof \DOMAttr); + + if (!$actualAttribute) { + static::fail( + \sprintf( + '%s%sCould not find attribute "%s" on node "%s"', + $message, + !empty($message) ? "\n" : '', + $expectedAttribute->name, + $expectedElement->tagName + ) + ); + } + } + } + + Xml::removeCharacterDataNodes($expectedElement); + Xml::removeCharacterDataNodes($actualElement); + + static::assertSame( + $expectedElement->childNodes->length, + $actualElement->childNodes->length, + \sprintf( + '%s%sNumber of child nodes of "%s" differs', + $message, + !empty($message) ? "\n" : '', + $expectedElement->tagName + ) + ); + + for ($i = 0; $i < $expectedElement->childNodes->length; $i++) { + static::assertEqualXMLStructure( + $expectedElement->childNodes->item($i), + $actualElement->childNodes->item($i), + $checkAttributes, + $message + ); + } + } + + /** + * Evaluates a PHPUnit\Framework\Constraint matcher object. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertThat($value, Constraint $constraint, string $message = ''): void + { + self::$count += \count($constraint); + + $constraint->evaluate($value, $message); + } + + /** + * Asserts that a string is a valid JSON string. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertJson(string $actualJson, string $message = ''): void + { + static::assertThat($actualJson, static::isJson(), $message); + } + + /** + * Asserts that two given JSON encoded objects or arrays are equal. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void + { + static::assertJson($expectedJson, $message); + static::assertJson($actualJson, $message); + + static::assertThat($actualJson, new JsonMatches($expectedJson), $message); + } + + /** + * Asserts that two given JSON encoded objects or arrays are not equal. + * + * @param string $expectedJson + * @param string $actualJson + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, string $message = ''): void + { + static::assertJson($expectedJson, $message); + static::assertJson($actualJson, $message); + + static::assertThat( + $actualJson, + new LogicalNot( + new JsonMatches($expectedJson) + ), + $message + ); + } + + /** + * Asserts that the generated JSON encoded object and the content of the given file are equal. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void + { + static::assertFileExists($expectedFile, $message); + $expectedJson = \file_get_contents($expectedFile); + + static::assertJson($expectedJson, $message); + static::assertJson($actualJson, $message); + + static::assertThat($actualJson, new JsonMatches($expectedJson), $message); + } + + /** + * Asserts that the generated JSON encoded object and the content of the given file are not equal. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void + { + static::assertFileExists($expectedFile, $message); + $expectedJson = \file_get_contents($expectedFile); + + static::assertJson($expectedJson, $message); + static::assertJson($actualJson, $message); + + static::assertThat( + $actualJson, + new LogicalNot( + new JsonMatches($expectedJson) + ), + $message + ); + } + + /** + * Asserts that two JSON files are equal. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void + { + static::assertFileExists($expectedFile, $message); + static::assertFileExists($actualFile, $message); + + $actualJson = \file_get_contents($actualFile); + $expectedJson = \file_get_contents($expectedFile); + + static::assertJson($expectedJson, $message); + static::assertJson($actualJson, $message); + + $constraintExpected = new JsonMatches( + $expectedJson + ); + + $constraintActual = new JsonMatches($actualJson); + + static::assertThat($expectedJson, $constraintActual, $message); + static::assertThat($actualJson, $constraintExpected, $message); + } + + /** + * Asserts that two JSON files are not equal. + * + * @throws ExpectationFailedException + * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException + */ + public static function assertJsonFileNotEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void + { + static::assertFileExists($expectedFile, $message); + static::assertFileExists($actualFile, $message); + + $actualJson = \file_get_contents($actualFile); + $expectedJson = \file_get_contents($expectedFile); + + static::assertJson($expectedJson, $message); + static::assertJson($actualJson, $message); + + $constraintExpected = new JsonMatches( + $expectedJson + ); + + $constraintActual = new JsonMatches($actualJson); + + static::assertThat($expectedJson, new LogicalNot($constraintActual), $message); + static::assertThat($actualJson, new LogicalNot($constraintExpected), $message); + } + + /** + * @throws Exception + */ + public static function logicalAnd(): LogicalAnd + { + $constraints = \func_get_args(); + + $constraint = new LogicalAnd; + $constraint->setConstraints($constraints); + + return $constraint; + } + + public static function logicalOr(): LogicalOr + { + $constraints = \func_get_args(); + + $constraint = new LogicalOr; + $constraint->setConstraints($constraints); + + return $constraint; + } + + public static function logicalNot(Constraint $constraint): LogicalNot + { + return new LogicalNot($constraint); + } + + public static function logicalXor(): LogicalXor + { + $constraints = \func_get_args(); + + $constraint = new LogicalXor; + $constraint->setConstraints($constraints); + + return $constraint; + } + + public static function anything(): IsAnything + { + return new IsAnything; + } + + public static function isTrue(): IsTrue + { + return new IsTrue; + } + + public static function callback(callable $callback): Callback + { + return new Callback($callback); + } + + public static function isFalse(): IsFalse + { + return new IsFalse; + } + + public static function isJson(): IsJson + { + return new IsJson; + } + + public static function isNull(): IsNull + { + return new IsNull; + } + + public static function isFinite(): IsFinite + { + return new IsFinite; + } + + public static function isInfinite(): IsInfinite + { + return new IsInfinite; + } + + public static function isNan(): IsNan + { + return new IsNan; + } + + /** + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function attribute(Constraint $constraint, string $attributeName): Attribute + { + self::createWarning('attribute() is deprecated and will be removed in PHPUnit 9.'); + + return new Attribute($constraint, $attributeName); + } + + public static function contains($value, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false): TraversableContains + { + return new TraversableContains($value, $checkForObjectIdentity, $checkForNonObjectIdentity); + } + + public static function containsOnly(string $type): TraversableContainsOnly + { + return new TraversableContainsOnly($type); + } + + public static function containsOnlyInstancesOf(string $className): TraversableContainsOnly + { + return new TraversableContainsOnly($className, false); + } + + /** + * @param int|string $key + */ + public static function arrayHasKey($key): ArrayHasKey + { + return new ArrayHasKey($key); + } + + public static function equalTo($value, float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): IsEqual + { + return new IsEqual($value, $delta, $maxDepth, $canonicalize, $ignoreCase); + } + + /** + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function attributeEqualTo(string $attributeName, $value, float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): Attribute + { + self::createWarning('attributeEqualTo() is deprecated and will be removed in PHPUnit 9.'); + + return static::attribute( + static::equalTo( + $value, + $delta, + $maxDepth, + $canonicalize, + $ignoreCase + ), + $attributeName + ); + } + + public static function isEmpty(): IsEmpty + { + return new IsEmpty; + } + + public static function isWritable(): IsWritable + { + return new IsWritable; + } + + public static function isReadable(): IsReadable + { + return new IsReadable; + } + + public static function directoryExists(): DirectoryExists + { + return new DirectoryExists; + } + + public static function fileExists(): FileExists + { + return new FileExists; + } + + public static function greaterThan($value): GreaterThan + { + return new GreaterThan($value); + } + + public static function greaterThanOrEqual($value): LogicalOr + { + return static::logicalOr( + new IsEqual($value), + new GreaterThan($value) + ); + } + + public static function classHasAttribute(string $attributeName): ClassHasAttribute + { + return new ClassHasAttribute($attributeName); + } + + public static function classHasStaticAttribute(string $attributeName): ClassHasStaticAttribute + { + return new ClassHasStaticAttribute($attributeName); + } + + public static function objectHasAttribute($attributeName): ObjectHasAttribute + { + return new ObjectHasAttribute($attributeName); + } + + public static function identicalTo($value): IsIdentical + { + return new IsIdentical($value); + } + + public static function isInstanceOf(string $className): IsInstanceOf + { + return new IsInstanceOf($className); + } + + public static function isType(string $type): IsType + { + return new IsType($type); + } + + public static function lessThan($value): LessThan + { + return new LessThan($value); + } + + public static function lessThanOrEqual($value): LogicalOr + { + return static::logicalOr( + new IsEqual($value), + new LessThan($value) + ); + } + + public static function matchesRegularExpression(string $pattern): RegularExpression + { + return new RegularExpression($pattern); + } + + public static function matches(string $string): StringMatchesFormatDescription + { + return new StringMatchesFormatDescription($string); + } + + public static function stringStartsWith($prefix): StringStartsWith + { + return new StringStartsWith($prefix); + } + + public static function stringContains(string $string, bool $case = true): StringContains + { + return new StringContains($string, $case); + } + + public static function stringEndsWith(string $suffix): StringEndsWith + { + return new StringEndsWith($suffix); + } + + public static function countOf(int $count): Count + { + return new Count($count); + } + + /** + * Fails a test with the given message. + * + * @throws AssertionFailedError + */ + public static function fail(string $message = ''): void + { + self::$count++; + + throw new AssertionFailedError($message); + } + + /** + * Returns the value of an attribute of a class or an object. + * This also works for attributes that are declared protected or private. + * + * @param object|string $classOrObject + * + * @throws Exception + * @throws ReflectionException + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function readAttribute($classOrObject, string $attributeName) + { + self::createWarning('readAttribute() is deprecated and will be removed in PHPUnit 9.'); + + if (!self::isValidClassAttributeName($attributeName)) { + throw InvalidArgumentHelper::factory(2, 'valid attribute name'); + } + + if (\is_string($classOrObject)) { + if (!\class_exists($classOrObject)) { + throw InvalidArgumentHelper::factory( + 1, + 'class name' + ); + } + + return static::getStaticAttribute( + $classOrObject, + $attributeName + ); + } + + if (\is_object($classOrObject)) { + return static::getObjectAttribute( + $classOrObject, + $attributeName + ); + } + + throw InvalidArgumentHelper::factory( + 1, + 'class name or object' + ); + } + + /** + * Returns the value of a static attribute. + * This also works for attributes that are declared protected or private. + * + * @throws Exception + * @throws ReflectionException + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function getStaticAttribute(string $className, string $attributeName) + { + self::createWarning('getStaticAttribute() is deprecated and will be removed in PHPUnit 9.'); + + if (!\class_exists($className)) { + throw InvalidArgumentHelper::factory(1, 'class name'); + } + + if (!self::isValidClassAttributeName($attributeName)) { + throw InvalidArgumentHelper::factory(2, 'valid attribute name'); + } + + $class = new ReflectionClass($className); + + while ($class) { + $attributes = $class->getStaticProperties(); + + if (\array_key_exists($attributeName, $attributes)) { + return $attributes[$attributeName]; + } + + $class = $class->getParentClass(); + } + + throw new Exception( + \sprintf( + 'Attribute "%s" not found in class.', + $attributeName + ) + ); + } + + /** + * Returns the value of an object's attribute. + * This also works for attributes that are declared protected or private. + * + * @param object $object + * + * @throws Exception + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/3338 + * @codeCoverageIgnore + */ + public static function getObjectAttribute($object, string $attributeName) + { + self::createWarning('getObjectAttribute() is deprecated and will be removed in PHPUnit 9.'); + + if (!\is_object($object)) { + throw InvalidArgumentHelper::factory(1, 'object'); + } + + if (!self::isValidClassAttributeName($attributeName)) { + throw InvalidArgumentHelper::factory(2, 'valid attribute name'); + } + + try { + $reflector = new ReflectionObject($object); + + do { + try { + $attribute = $reflector->getProperty($attributeName); + + if (!$attribute || $attribute->isPublic()) { + return $object->$attributeName; + } + + $attribute->setAccessible(true); + $value = $attribute->getValue($object); + $attribute->setAccessible(false); + + return $value; + } catch (ReflectionException $e) { + } + } while ($reflector = $reflector->getParentClass()); + } catch (ReflectionException $e) { + } + + throw new Exception( + \sprintf( + 'Attribute "%s" not found in object.', + $attributeName + ) + ); + } + + /** + * Mark the test as incomplete. + * + * @throws IncompleteTestError + */ + public static function markTestIncomplete(string $message = ''): void + { + throw new IncompleteTestError($message); + } + + /** + * Mark the test as skipped. + * + * @throws SkippedTestError + * @throws SyntheticSkippedError + */ + public static function markTestSkipped(string $message = ''): void + { + if ($hint = self::detectLocationHint($message)) { + $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); + \array_unshift($trace, $hint); + + throw new SyntheticSkippedError($hint['message'], 0, $hint['file'], (int) $hint['line'], $trace); + } + + throw new SkippedTestError($message); + } + + /** + * Return the current assertion count. + */ + public static function getCount(): int + { + return self::$count; + } + + /** + * Reset the assertion counter. + */ + public static function resetCount(): void + { + self::$count = 0; + } + + private static function detectLocationHint(string $message): ?array + { + $hint = null; + $lines = \preg_split('/\r\n|\r|\n/', $message); + + while (\strpos($lines[0], '__OFFSET') !== false) { + $offset = \explode('=', \array_shift($lines)); + + if ($offset[0] === '__OFFSET_FILE') { + $hint['file'] = $offset[1]; + } + + if ($offset[0] === '__OFFSET_LINE') { + $hint['line'] = $offset[1]; + } + } + + if ($hint) { + $hint['message'] = \implode(\PHP_EOL, $lines); + } + + return $hint; + } + + private static function isValidObjectAttributeName(string $attributeName): bool + { + return (bool) \preg_match('/[^\x00-\x1f\x7f-\x9f]+/', $attributeName); + } + + private static function isValidClassAttributeName(string $attributeName): bool + { + return (bool) \preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName); + } + + /** + * @codeCoverageIgnore + */ + private static function createWarning(string $warning): void + { + foreach (\debug_backtrace() as $step) { + if (isset($step['object']) && $step['object'] instanceof TestCase) { + \assert($step['object'] instanceof TestCase); + + $step['object']->addWarning($warning); + + break; + } + } + } +} diff --git a/tests/bench/ProjectFactoryBench.php b/tests/bench/ProjectFactoryBench.php new file mode 100644 index 00000000..df55a218 --- /dev/null +++ b/tests/bench/ProjectFactoryBench.php @@ -0,0 +1,29 @@ +factory = \phpDocumentor\Reflection\Php\ProjectFactory::createInstance(); + } + + /** + * @Revs({1, 8, 64, 1024}) + */ + public function benchCreateSingleFileProject() + { + $this->factory->create('myProject', [new LocalFile(__DIR__ . '/../assets/phpunit_assert.php')]); + } +} diff --git a/tests/unit/phpDocumentor/Reflection/Types/NamespaceNodeToContextTest.php b/tests/unit/phpDocumentor/Reflection/Types/NamespaceNodeToContextTest.php new file mode 100644 index 00000000..f7a9146f --- /dev/null +++ b/tests/unit/phpDocumentor/Reflection/Types/NamespaceNodeToContextTest.php @@ -0,0 +1,93 @@ +__invoke($namespace)); + } + + public function expectedContextsProvider() + { + $namespaceWithImports = new Namespace_( + new Name('With\\Imports'), + [ + (new Use_('ClassName', UseStatement::TYPE_NORMAL))->getNode(), + (new Use_('ConstantName', UseStatement::TYPE_CONSTANT))->getNode(), + (new Use_('FunctionName', UseStatement::TYPE_FUNCTION))->getNode(), + (new Use_('UnknownName', UseStatement::TYPE_UNKNOWN))->getNode(), + (new Use_('AAA\\BBB', UseStatement::TYPE_NORMAL))->getNode(), + (new Use_('BBB\\CCC\\DDD', UseStatement::TYPE_NORMAL))->getNode(), + (new Use_('Foo\\EEE\\FFF', UseStatement::TYPE_NORMAL))->getNode(), + (new Use_('Foo', UseStatement::TYPE_NORMAL))->getNode(), + (new Use_('GGG', UseStatement::TYPE_NORMAL))->as('HHH')->getNode(), + (new Use_('III', UseStatement::TYPE_NORMAL))->as('JJJ')->getNode(), + new GroupUse( + new Name('LLL'), + [ + new UseUse(new Name('MMM')), + new UseUse(new Name('NNN'), 'OOO'), + ] + ), + (new Use_('\\PPP', UseStatement::TYPE_NORMAL))->getNode(), + new Class_('ClassNode'), // class node, should be ignored + ] + ); + + return [ + 'No namespace' => [ + null, + new Context(''), + ], + 'Empty namespace' => [ + new Namespace_(), + new Context(''), + ], + 'Actual namespace' => [ + new Namespace_(new Name('Foo\\Bar')), + new Context('Foo\\Bar'), + ], + 'Actual namespace prefixed with \\' => [ + new Namespace_(new Name('\\Foo\\Bar')), + new Context('Foo\\Bar'), + ], + 'Complex use statement' => [ + $namespaceWithImports, + new Context( + 'With\\Imports', + [ + 'ClassName' => 'ClassName', + 'UnknownName' => 'UnknownName', + 'BBB' => 'AAA\\BBB', + 'DDD' => 'BBB\\CCC\\DDD', + 'FFF' => 'Foo\\EEE\\FFF', + 'Foo' => 'Foo', + 'HHH' => 'GGG', + 'JJJ' => 'III', + 'MMM' => 'LLL\\MMM', + 'OOO' => 'LLL\\NNN', + 'PPP' => 'PPP', + ] + ), + ], + ]; + } +}