From 1b995233662ff9367e5274e8d1e980be594a4ff5 Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Tue, 2 Jun 2026 17:27:22 +0200 Subject: [PATCH] Enhance self-serve lane functionality with new relay management and configuration updates --- composer_2.phar | Bin 0 -> 3561371 bytes docker-compose.yml | 3 + phpunit.phar | 132545 +++++++++++++++ .../nginx/app/.phpunit.cache/test-results | 2 +- .../nginx/app/build/logs/api-server.err.log | 248 + .../selfserve/classes/selfserve_wash_flow.php | 6 +- .../traits/selfserve_lane_command_t.php | 102 +- ...artmentSelfserveVehicleConditionsRoute.php | 121 +- .../nginx/app/routes/moduleSelfServeRoute.php | 57 +- .../Api/SelfserveCustomerStartApiTest.php | 130 + ...ModuleConfigVariableDatabaseConfigTest.php | 130 + .../SelfserveEligibilityLaneAccessTest.php | 15 +- .../SelfserveLaneStartEntranceTimeoutTest.php | 23 +- .../Selfserve/SelfserveLaneStopFlowTest.php | 27 +- ...lfservePublishedConfigLaneWildcardTest.php | 50 + .../Selfserve/SelfserveRouteWiringTest.php | 3 + .../app/traits/module_config_variable_t.php | 30 +- services/traefik/dynamic.yml | 16 + 18 files changed, 133418 insertions(+), 90 deletions(-) create mode 100644 composer_2.phar create mode 100644 phpunit.phar create mode 100644 services/nginx/app/tests/Api/SelfserveCustomerStartApiTest.php create mode 100644 services/nginx/app/tests/Unit/Selfserve/ModuleConfigVariableDatabaseConfigTest.php create mode 100644 services/nginx/app/tests/Unit/Selfserve/SelfservePublishedConfigLaneWildcardTest.php diff --git a/composer_2.phar b/composer_2.phar new file mode 100644 index 0000000000000000000000000000000000000000..fe03d9b9c28a52eb2d0d33f06f4ffd341e97a6c9 GIT binary patch literal 3561371 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 z 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%0A8!1G2@S%5EWjizqixoN@WXo9S#xMoER6 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 wAwd_>Be-h-)%Xs;`a5Z?y#m!Zc@C*ZG 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

{Ke>luA1#w~y;;YW8~_3i|8x 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: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

|^5|UT=dBu__a9bFT6+ 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')) { + fwrite( + STDERR, + sprintf( + 'PHPUnit 13.1.13 by Sebastian Bergmann and contributors.' . PHP_EOL . PHP_EOL . + 'This version of PHPUnit requires PHP >= 8.4.1.' . PHP_EOL . + 'You are using PHP %s (%s).' . PHP_EOL, + PHP_VERSION, + PHP_BINARY + ) + ); + + die(1); +} + +$requiredExtensions = ['ctype', 'dom', 'json', 'libxml', 'mbstring', 'tokenizer', 'xml', 'xmlwriter']; + +$unavailableExtensions = array_filter( + $requiredExtensions, + static function ($extension) { + return !extension_loaded($extension); + } +); + +if ([] !== $unavailableExtensions) { + fwrite( + STDERR, + sprintf( + 'PHPUnit requires the "%s" extensions, but the "%s" %s not available.' . PHP_EOL, + implode('", "', $requiredExtensions), + implode('", "', $unavailableExtensions), + count($unavailableExtensions) === 1 ? 'extension is' : 'extensions are' + ) + ); + + die(1); +} + +unset($requiredExtensions, $unavailableExtensions); + +if (__FILE__ === realpath($_SERVER['SCRIPT_NAME'])) { + $execute = true; +} else { + $execute = false; +} + +$options = getopt('', array('composer-lock', 'manifest', 'sbom')); + +if (isset($options['composer-lock'])) { + $printComposerLock = true; +} elseif (isset($options['manifest'])) { + $printManifest = true; +} elseif (isset($options['sbom'])) { + $printSbom = true; +} + +unset($options); + +define('__PHPUNIT_PHAR__', str_replace(DIRECTORY_SEPARATOR, '/', __FILE__)); +define('__PHPUNIT_PHAR_ROOT__', 'phar://phpunit-13.1.13.phar'); + +Phar::mapPhar('phpunit-13.1.13.phar'); + +spl_autoload_register( + function ($class) { + static $classes = null; + + if ($classes === null) { + $classes = ['PHPUnitPHAR\\DeepCopy\\DeepCopy' => '/myclabs-deep-copy/DeepCopy/DeepCopy.php', + 'PHPUnitPHAR\\DeepCopy\\Exception\\CloneException' => '/myclabs-deep-copy/DeepCopy/Exception/CloneException.php', + 'PHPUnitPHAR\\DeepCopy\\Exception\\PropertyException' => '/myclabs-deep-copy/DeepCopy/Exception/PropertyException.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\ChainableFilter' => '/myclabs-deep-copy/DeepCopy/Filter/ChainableFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\Doctrine\\DoctrineCollectionFilter' => '/myclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\Doctrine\\DoctrineEmptyCollectionFilter' => '/myclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\Doctrine\\DoctrineProxyFilter' => '/myclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\Filter' => '/myclabs-deep-copy/DeepCopy/Filter/Filter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\KeepFilter' => '/myclabs-deep-copy/DeepCopy/Filter/KeepFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\ReplaceFilter' => '/myclabs-deep-copy/DeepCopy/Filter/ReplaceFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\SetNullFilter' => '/myclabs-deep-copy/DeepCopy/Filter/SetNullFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Matcher\\Doctrine\\DoctrineProxyMatcher' => '/myclabs-deep-copy/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php', + 'PHPUnitPHAR\\DeepCopy\\Matcher\\Matcher' => '/myclabs-deep-copy/DeepCopy/Matcher/Matcher.php', + 'PHPUnitPHAR\\DeepCopy\\Matcher\\PropertyMatcher' => '/myclabs-deep-copy/DeepCopy/Matcher/PropertyMatcher.php', + 'PHPUnitPHAR\\DeepCopy\\Matcher\\PropertyNameMatcher' => '/myclabs-deep-copy/DeepCopy/Matcher/PropertyNameMatcher.php', + 'PHPUnitPHAR\\DeepCopy\\Matcher\\PropertyTypeMatcher' => '/myclabs-deep-copy/DeepCopy/Matcher/PropertyTypeMatcher.php', + 'PHPUnitPHAR\\DeepCopy\\Reflection\\ReflectionHelper' => '/myclabs-deep-copy/DeepCopy/Reflection/ReflectionHelper.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\Date\\DateIntervalFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/Date/DateIntervalFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\Date\\DatePeriodFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/Date/DatePeriodFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\ReplaceFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/ReplaceFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\ShallowCopyFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/ShallowCopyFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\Spl\\ArrayObjectFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/Spl/ArrayObjectFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\Spl\\SplDoublyLinkedList' => '/myclabs-deep-copy/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\Spl\\SplDoublyLinkedListFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\TypeFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/TypeFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeMatcher\\TypeMatcher' => '/myclabs-deep-copy/DeepCopy/TypeMatcher/TypeMatcher.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Application' => '/phar-io-manifest/values/Application.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ApplicationName' => '/phar-io-manifest/values/ApplicationName.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Author' => '/phar-io-manifest/values/Author.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\AuthorCollection' => '/phar-io-manifest/values/AuthorCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\AuthorCollectionIterator' => '/phar-io-manifest/values/AuthorCollectionIterator.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\AuthorElement' => '/phar-io-manifest/xml/AuthorElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\AuthorElementCollection' => '/phar-io-manifest/xml/AuthorElementCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\BundledComponent' => '/phar-io-manifest/values/BundledComponent.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\BundledComponentCollection' => '/phar-io-manifest/values/BundledComponentCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\BundledComponentCollectionIterator' => '/phar-io-manifest/values/BundledComponentCollectionIterator.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\BundlesElement' => '/phar-io-manifest/xml/BundlesElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ComponentElement' => '/phar-io-manifest/xml/ComponentElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ComponentElementCollection' => '/phar-io-manifest/xml/ComponentElementCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ContainsElement' => '/phar-io-manifest/xml/ContainsElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\CopyrightElement' => '/phar-io-manifest/xml/CopyrightElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\CopyrightInformation' => '/phar-io-manifest/values/CopyrightInformation.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ElementCollection' => '/phar-io-manifest/xml/ElementCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ElementCollectionException' => '/phar-io-manifest/exceptions/ElementCollectionException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Email' => '/phar-io-manifest/values/Email.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Exception' => '/phar-io-manifest/exceptions/Exception.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ExtElement' => '/phar-io-manifest/xml/ExtElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ExtElementCollection' => '/phar-io-manifest/xml/ExtElementCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Extension' => '/phar-io-manifest/values/Extension.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ExtensionElement' => '/phar-io-manifest/xml/ExtensionElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\InvalidApplicationNameException' => '/phar-io-manifest/exceptions/InvalidApplicationNameException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\InvalidEmailException' => '/phar-io-manifest/exceptions/InvalidEmailException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\InvalidUrlException' => '/phar-io-manifest/exceptions/InvalidUrlException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Library' => '/phar-io-manifest/values/Library.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\License' => '/phar-io-manifest/values/License.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\LicenseElement' => '/phar-io-manifest/xml/LicenseElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Manifest' => '/phar-io-manifest/values/Manifest.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestDocument' => '/phar-io-manifest/xml/ManifestDocument.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestDocumentException' => '/phar-io-manifest/exceptions/ManifestDocumentException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestDocumentLoadingException' => '/phar-io-manifest/exceptions/ManifestDocumentLoadingException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestDocumentMapper' => '/phar-io-manifest/ManifestDocumentMapper.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestDocumentMapperException' => '/phar-io-manifest/exceptions/ManifestDocumentMapperException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestElement' => '/phar-io-manifest/xml/ManifestElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestElementException' => '/phar-io-manifest/exceptions/ManifestElementException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestLoader' => '/phar-io-manifest/ManifestLoader.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestLoaderException' => '/phar-io-manifest/exceptions/ManifestLoaderException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestSerializer' => '/phar-io-manifest/ManifestSerializer.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\NoEmailAddressException' => '/phar-io-manifest/exceptions/NoEmailAddressException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\PhpElement' => '/phar-io-manifest/xml/PhpElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\PhpExtensionRequirement' => '/phar-io-manifest/values/PhpExtensionRequirement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\PhpVersionRequirement' => '/phar-io-manifest/values/PhpVersionRequirement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Requirement' => '/phar-io-manifest/values/Requirement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\RequirementCollection' => '/phar-io-manifest/values/RequirementCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\RequirementCollectionIterator' => '/phar-io-manifest/values/RequirementCollectionIterator.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\RequiresElement' => '/phar-io-manifest/xml/RequiresElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Type' => '/phar-io-manifest/values/Type.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Url' => '/phar-io-manifest/values/Url.php', + 'PHPUnitPHAR\\PharIo\\Version\\AbstractVersionConstraint' => '/phar-io-version/constraints/AbstractVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\AndVersionConstraintGroup' => '/phar-io-version/constraints/AndVersionConstraintGroup.php', + 'PHPUnitPHAR\\PharIo\\Version\\AnyVersionConstraint' => '/phar-io-version/constraints/AnyVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\BuildMetaData' => '/phar-io-version/BuildMetaData.php', + 'PHPUnitPHAR\\PharIo\\Version\\ExactVersionConstraint' => '/phar-io-version/constraints/ExactVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\Exception' => '/phar-io-version/exceptions/Exception.php', + 'PHPUnitPHAR\\PharIo\\Version\\GreaterThanOrEqualToVersionConstraint' => '/phar-io-version/constraints/GreaterThanOrEqualToVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\InvalidPreReleaseSuffixException' => '/phar-io-version/exceptions/InvalidPreReleaseSuffixException.php', + 'PHPUnitPHAR\\PharIo\\Version\\InvalidVersionException' => '/phar-io-version/exceptions/InvalidVersionException.php', + 'PHPUnitPHAR\\PharIo\\Version\\NoBuildMetaDataException' => '/phar-io-version/exceptions/NoBuildMetaDataException.php', + 'PHPUnitPHAR\\PharIo\\Version\\NoPreReleaseSuffixException' => '/phar-io-version/exceptions/NoPreReleaseSuffixException.php', + 'PHPUnitPHAR\\PharIo\\Version\\OrVersionConstraintGroup' => '/phar-io-version/constraints/OrVersionConstraintGroup.php', + 'PHPUnitPHAR\\PharIo\\Version\\PreReleaseSuffix' => '/phar-io-version/PreReleaseSuffix.php', + 'PHPUnitPHAR\\PharIo\\Version\\SpecificMajorAndMinorVersionConstraint' => '/phar-io-version/constraints/SpecificMajorAndMinorVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\SpecificMajorVersionConstraint' => '/phar-io-version/constraints/SpecificMajorVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\UnsupportedVersionConstraintException' => '/phar-io-version/exceptions/UnsupportedVersionConstraintException.php', + 'PHPUnitPHAR\\PharIo\\Version\\Version' => '/phar-io-version/Version.php', + 'PHPUnitPHAR\\PharIo\\Version\\VersionConstraint' => '/phar-io-version/constraints/VersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\VersionConstraintParser' => '/phar-io-version/VersionConstraintParser.php', + 'PHPUnitPHAR\\PharIo\\Version\\VersionConstraintValue' => '/phar-io-version/VersionConstraintValue.php', + 'PHPUnitPHAR\\PharIo\\Version\\VersionNumber' => '/phar-io-version/VersionNumber.php', + 'PHPUnitPHAR\\PhpParser\\Builder' => '/nikic-php-parser/PhpParser/Builder.php', + 'PHPUnitPHAR\\PhpParser\\BuilderFactory' => '/nikic-php-parser/PhpParser/BuilderFactory.php', + 'PHPUnitPHAR\\PhpParser\\BuilderHelpers' => '/nikic-php-parser/PhpParser/BuilderHelpers.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\ClassConst' => '/nikic-php-parser/PhpParser/Builder/ClassConst.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Class_' => '/nikic-php-parser/PhpParser/Builder/Class_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Declaration' => '/nikic-php-parser/PhpParser/Builder/Declaration.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\EnumCase' => '/nikic-php-parser/PhpParser/Builder/EnumCase.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Enum_' => '/nikic-php-parser/PhpParser/Builder/Enum_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\FunctionLike' => '/nikic-php-parser/PhpParser/Builder/FunctionLike.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Function_' => '/nikic-php-parser/PhpParser/Builder/Function_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Interface_' => '/nikic-php-parser/PhpParser/Builder/Interface_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Method' => '/nikic-php-parser/PhpParser/Builder/Method.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Namespace_' => '/nikic-php-parser/PhpParser/Builder/Namespace_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Param' => '/nikic-php-parser/PhpParser/Builder/Param.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Property' => '/nikic-php-parser/PhpParser/Builder/Property.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\TraitUse' => '/nikic-php-parser/PhpParser/Builder/TraitUse.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\TraitUseAdaptation' => '/nikic-php-parser/PhpParser/Builder/TraitUseAdaptation.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Trait_' => '/nikic-php-parser/PhpParser/Builder/Trait_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Use_' => '/nikic-php-parser/PhpParser/Builder/Use_.php', + 'PHPUnitPHAR\\PhpParser\\Comment' => '/nikic-php-parser/PhpParser/Comment.php', + 'PHPUnitPHAR\\PhpParser\\Comment\\Doc' => '/nikic-php-parser/PhpParser/Comment/Doc.php', + 'PHPUnitPHAR\\PhpParser\\ConstExprEvaluationException' => '/nikic-php-parser/PhpParser/ConstExprEvaluationException.php', + 'PHPUnitPHAR\\PhpParser\\ConstExprEvaluator' => '/nikic-php-parser/PhpParser/ConstExprEvaluator.php', + 'PHPUnitPHAR\\PhpParser\\Error' => '/nikic-php-parser/PhpParser/Error.php', + 'PHPUnitPHAR\\PhpParser\\ErrorHandler' => '/nikic-php-parser/PhpParser/ErrorHandler.php', + 'PHPUnitPHAR\\PhpParser\\ErrorHandler\\Collecting' => '/nikic-php-parser/PhpParser/ErrorHandler/Collecting.php', + 'PHPUnitPHAR\\PhpParser\\ErrorHandler\\Throwing' => '/nikic-php-parser/PhpParser/ErrorHandler/Throwing.php', + 'PHPUnitPHAR\\PhpParser\\Internal\\DiffElem' => '/nikic-php-parser/PhpParser/Internal/DiffElem.php', + 'PHPUnitPHAR\\PhpParser\\Internal\\Differ' => '/nikic-php-parser/PhpParser/Internal/Differ.php', + 'PHPUnitPHAR\\PhpParser\\Internal\\PrintableNewAnonClassNode' => '/nikic-php-parser/PhpParser/Internal/PrintableNewAnonClassNode.php', + 'PHPUnitPHAR\\PhpParser\\Internal\\TokenPolyfill' => '/nikic-php-parser/PhpParser/Internal/TokenPolyfill.php', + 'PHPUnitPHAR\\PhpParser\\Internal\\TokenStream' => '/nikic-php-parser/PhpParser/Internal/TokenStream.php', + 'PHPUnitPHAR\\PhpParser\\JsonDecoder' => '/nikic-php-parser/PhpParser/JsonDecoder.php', + 'PHPUnitPHAR\\PhpParser\\Lexer' => '/nikic-php-parser/PhpParser/Lexer.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\Emulative' => '/nikic-php-parser/PhpParser/Lexer/Emulative.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\AsymmetricVisibilityTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/AsymmetricVisibilityTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\AttributeEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\EnumTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\ExplicitOctalEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\KeywordEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\MatchTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\NullsafeTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\PipeOperatorEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/PipeOperatorEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\PropertyTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/PropertyTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyFunctionTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\ReverseEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\TokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/TokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\VoidCastEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/VoidCastEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Modifiers' => '/nikic-php-parser/PhpParser/Modifiers.php', + 'PHPUnitPHAR\\PhpParser\\NameContext' => '/nikic-php-parser/PhpParser/NameContext.php', + 'PHPUnitPHAR\\PhpParser\\Node' => '/nikic-php-parser/PhpParser/Node.php', + 'PHPUnitPHAR\\PhpParser\\NodeAbstract' => '/nikic-php-parser/PhpParser/NodeAbstract.php', + 'PHPUnitPHAR\\PhpParser\\NodeDumper' => '/nikic-php-parser/PhpParser/NodeDumper.php', + 'PHPUnitPHAR\\PhpParser\\NodeFinder' => '/nikic-php-parser/PhpParser/NodeFinder.php', + 'PHPUnitPHAR\\PhpParser\\NodeTraverser' => '/nikic-php-parser/PhpParser/NodeTraverser.php', + 'PHPUnitPHAR\\PhpParser\\NodeTraverserInterface' => '/nikic-php-parser/PhpParser/NodeTraverserInterface.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitorAbstract' => '/nikic-php-parser/PhpParser/NodeVisitorAbstract.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\CloningVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/CloningVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\CommentAnnotatingVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/CommentAnnotatingVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\FindingVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/FindingVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\FirstFindingVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/FirstFindingVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\NameResolver' => '/nikic-php-parser/PhpParser/NodeVisitor/NameResolver.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\NodeConnectingVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/NodeConnectingVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\ParentConnectingVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/ParentConnectingVisitor.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Arg' => '/nikic-php-parser/PhpParser/Node/Arg.php', + 'PHPUnitPHAR\\PhpParser\\Node\\ArrayItem' => '/nikic-php-parser/PhpParser/Node/ArrayItem.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Attribute' => '/nikic-php-parser/PhpParser/Node/Attribute.php', + 'PHPUnitPHAR\\PhpParser\\Node\\AttributeGroup' => '/nikic-php-parser/PhpParser/Node/AttributeGroup.php', + 'PHPUnitPHAR\\PhpParser\\Node\\ClosureUse' => '/nikic-php-parser/PhpParser/Node/ClosureUse.php', + 'PHPUnitPHAR\\PhpParser\\Node\\ComplexType' => '/nikic-php-parser/PhpParser/Node/ComplexType.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Const_' => '/nikic-php-parser/PhpParser/Node/Const_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\DeclareItem' => '/nikic-php-parser/PhpParser/Node/DeclareItem.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr' => '/nikic-php-parser/PhpParser/Node/Expr.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ArrayDimFetch' => '/nikic-php-parser/PhpParser/Node/Expr/ArrayDimFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Array_' => '/nikic-php-parser/PhpParser/Node/Expr/Array_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ArrowFunction' => '/nikic-php-parser/PhpParser/Node/Expr/ArrowFunction.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Assign' => '/nikic-php-parser/PhpParser/Node/Expr/Assign.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Coalesce.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Concat.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Div' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Div.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Minus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Mod.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Mul.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Plus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Pow.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/ShiftRight.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignRef' => '/nikic-php-parser/PhpParser/Node/Expr/AssignRef.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Coalesce.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Concat.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Div.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Equal.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Greater.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Identical.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Minus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Mod.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Mul.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/NotEqual.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Pipe' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Pipe.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Plus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Pow.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Smaller.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Spaceship.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BitwiseNot' => '/nikic-php-parser/PhpParser/Node/Expr/BitwiseNot.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BooleanNot' => '/nikic-php-parser/PhpParser/Node/Expr/BooleanNot.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\CallLike' => '/nikic-php-parser/PhpParser/Node/Expr/CallLike.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast' => '/nikic-php-parser/PhpParser/Node/Expr/Cast.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Array_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Array_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Bool_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Bool_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Double' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Double.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Int_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Int_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Object_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Object_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\String_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/String_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Unset_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Unset_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Void_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Void_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ClassConstFetch' => '/nikic-php-parser/PhpParser/Node/Expr/ClassConstFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Clone_' => '/nikic-php-parser/PhpParser/Node/Expr/Clone_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Closure' => '/nikic-php-parser/PhpParser/Node/Expr/Closure.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ConstFetch' => '/nikic-php-parser/PhpParser/Node/Expr/ConstFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Empty_' => '/nikic-php-parser/PhpParser/Node/Expr/Empty_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Error' => '/nikic-php-parser/PhpParser/Node/Expr/Error.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ErrorSuppress' => '/nikic-php-parser/PhpParser/Node/Expr/ErrorSuppress.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Eval_' => '/nikic-php-parser/PhpParser/Node/Expr/Eval_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Exit_' => '/nikic-php-parser/PhpParser/Node/Expr/Exit_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\FuncCall' => '/nikic-php-parser/PhpParser/Node/Expr/FuncCall.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Include_' => '/nikic-php-parser/PhpParser/Node/Expr/Include_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Instanceof_' => '/nikic-php-parser/PhpParser/Node/Expr/Instanceof_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Isset_' => '/nikic-php-parser/PhpParser/Node/Expr/Isset_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\List_' => '/nikic-php-parser/PhpParser/Node/Expr/List_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Match_' => '/nikic-php-parser/PhpParser/Node/Expr/Match_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\MethodCall' => '/nikic-php-parser/PhpParser/Node/Expr/MethodCall.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\New_' => '/nikic-php-parser/PhpParser/Node/Expr/New_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\NullsafeMethodCall' => '/nikic-php-parser/PhpParser/Node/Expr/NullsafeMethodCall.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\NullsafePropertyFetch' => '/nikic-php-parser/PhpParser/Node/Expr/NullsafePropertyFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\PostDec' => '/nikic-php-parser/PhpParser/Node/Expr/PostDec.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\PostInc' => '/nikic-php-parser/PhpParser/Node/Expr/PostInc.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\PreDec' => '/nikic-php-parser/PhpParser/Node/Expr/PreDec.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\PreInc' => '/nikic-php-parser/PhpParser/Node/Expr/PreInc.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Print_' => '/nikic-php-parser/PhpParser/Node/Expr/Print_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\PropertyFetch' => '/nikic-php-parser/PhpParser/Node/Expr/PropertyFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ShellExec' => '/nikic-php-parser/PhpParser/Node/Expr/ShellExec.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\StaticCall' => '/nikic-php-parser/PhpParser/Node/Expr/StaticCall.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => '/nikic-php-parser/PhpParser/Node/Expr/StaticPropertyFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Ternary' => '/nikic-php-parser/PhpParser/Node/Expr/Ternary.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Throw_' => '/nikic-php-parser/PhpParser/Node/Expr/Throw_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\UnaryMinus' => '/nikic-php-parser/PhpParser/Node/Expr/UnaryMinus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\UnaryPlus' => '/nikic-php-parser/PhpParser/Node/Expr/UnaryPlus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Variable' => '/nikic-php-parser/PhpParser/Node/Expr/Variable.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\YieldFrom' => '/nikic-php-parser/PhpParser/Node/Expr/YieldFrom.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Yield_' => '/nikic-php-parser/PhpParser/Node/Expr/Yield_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\FunctionLike' => '/nikic-php-parser/PhpParser/Node/FunctionLike.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Identifier' => '/nikic-php-parser/PhpParser/Node/Identifier.php', + 'PHPUnitPHAR\\PhpParser\\Node\\InterpolatedStringPart' => '/nikic-php-parser/PhpParser/Node/InterpolatedStringPart.php', + 'PHPUnitPHAR\\PhpParser\\Node\\IntersectionType' => '/nikic-php-parser/PhpParser/Node/IntersectionType.php', + 'PHPUnitPHAR\\PhpParser\\Node\\MatchArm' => '/nikic-php-parser/PhpParser/Node/MatchArm.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Name' => '/nikic-php-parser/PhpParser/Node/Name.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Name\\FullyQualified' => '/nikic-php-parser/PhpParser/Node/Name/FullyQualified.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Name\\Relative' => '/nikic-php-parser/PhpParser/Node/Name/Relative.php', + 'PHPUnitPHAR\\PhpParser\\Node\\NullableType' => '/nikic-php-parser/PhpParser/Node/NullableType.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Param' => '/nikic-php-parser/PhpParser/Node/Param.php', + 'PHPUnitPHAR\\PhpParser\\Node\\PropertyHook' => '/nikic-php-parser/PhpParser/Node/PropertyHook.php', + 'PHPUnitPHAR\\PhpParser\\Node\\PropertyItem' => '/nikic-php-parser/PhpParser/Node/PropertyItem.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar' => '/nikic-php-parser/PhpParser/Node/Scalar.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\Float_' => '/nikic-php-parser/PhpParser/Node/Scalar/Float_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\Int_' => '/nikic-php-parser/PhpParser/Node/Scalar/Int_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\InterpolatedString' => '/nikic-php-parser/PhpParser/Node/Scalar/InterpolatedString.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Class_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Dir.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\File' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/File.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Function_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Line.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Method.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Namespace_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Property' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Property.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Trait_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\String_' => '/nikic-php-parser/PhpParser/Node/Scalar/String_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\StaticVar' => '/nikic-php-parser/PhpParser/Node/StaticVar.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt' => '/nikic-php-parser/PhpParser/Node/Stmt.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Block' => '/nikic-php-parser/PhpParser/Node/Stmt/Block.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Break_' => '/nikic-php-parser/PhpParser/Node/Stmt/Break_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Case_' => '/nikic-php-parser/PhpParser/Node/Stmt/Case_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Catch_' => '/nikic-php-parser/PhpParser/Node/Stmt/Catch_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\ClassConst' => '/nikic-php-parser/PhpParser/Node/Stmt/ClassConst.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\ClassLike' => '/nikic-php-parser/PhpParser/Node/Stmt/ClassLike.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\ClassMethod' => '/nikic-php-parser/PhpParser/Node/Stmt/ClassMethod.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Class_' => '/nikic-php-parser/PhpParser/Node/Stmt/Class_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Const_' => '/nikic-php-parser/PhpParser/Node/Stmt/Const_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Continue_' => '/nikic-php-parser/PhpParser/Node/Stmt/Continue_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Declare_' => '/nikic-php-parser/PhpParser/Node/Stmt/Declare_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Do_' => '/nikic-php-parser/PhpParser/Node/Stmt/Do_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Echo_' => '/nikic-php-parser/PhpParser/Node/Stmt/Echo_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\ElseIf_' => '/nikic-php-parser/PhpParser/Node/Stmt/ElseIf_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Else_' => '/nikic-php-parser/PhpParser/Node/Stmt/Else_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\EnumCase' => '/nikic-php-parser/PhpParser/Node/Stmt/EnumCase.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Enum_' => '/nikic-php-parser/PhpParser/Node/Stmt/Enum_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Expression' => '/nikic-php-parser/PhpParser/Node/Stmt/Expression.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Finally_' => '/nikic-php-parser/PhpParser/Node/Stmt/Finally_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\For_' => '/nikic-php-parser/PhpParser/Node/Stmt/For_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Foreach_' => '/nikic-php-parser/PhpParser/Node/Stmt/Foreach_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Function_' => '/nikic-php-parser/PhpParser/Node/Stmt/Function_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Global_' => '/nikic-php-parser/PhpParser/Node/Stmt/Global_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Goto_' => '/nikic-php-parser/PhpParser/Node/Stmt/Goto_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\GroupUse' => '/nikic-php-parser/PhpParser/Node/Stmt/GroupUse.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\HaltCompiler' => '/nikic-php-parser/PhpParser/Node/Stmt/HaltCompiler.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\If_' => '/nikic-php-parser/PhpParser/Node/Stmt/If_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\InlineHTML' => '/nikic-php-parser/PhpParser/Node/Stmt/InlineHTML.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Interface_' => '/nikic-php-parser/PhpParser/Node/Stmt/Interface_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Label' => '/nikic-php-parser/PhpParser/Node/Stmt/Label.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Namespace_' => '/nikic-php-parser/PhpParser/Node/Stmt/Namespace_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Nop' => '/nikic-php-parser/PhpParser/Node/Stmt/Nop.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Property' => '/nikic-php-parser/PhpParser/Node/Stmt/Property.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Return_' => '/nikic-php-parser/PhpParser/Node/Stmt/Return_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Static_' => '/nikic-php-parser/PhpParser/Node/Stmt/Static_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Switch_' => '/nikic-php-parser/PhpParser/Node/Stmt/Switch_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\TraitUse' => '/nikic-php-parser/PhpParser/Node/Stmt/TraitUse.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\TraitUseAdaptation' => '/nikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Alias' => '/nikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Precedence' => '/nikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Trait_' => '/nikic-php-parser/PhpParser/Node/Stmt/Trait_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\TryCatch' => '/nikic-php-parser/PhpParser/Node/Stmt/TryCatch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Unset_' => '/nikic-php-parser/PhpParser/Node/Stmt/Unset_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Use_' => '/nikic-php-parser/PhpParser/Node/Stmt/Use_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\While_' => '/nikic-php-parser/PhpParser/Node/Stmt/While_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\UnionType' => '/nikic-php-parser/PhpParser/Node/UnionType.php', + 'PHPUnitPHAR\\PhpParser\\Node\\UseItem' => '/nikic-php-parser/PhpParser/Node/UseItem.php', + 'PHPUnitPHAR\\PhpParser\\Node\\VarLikeIdentifier' => '/nikic-php-parser/PhpParser/Node/VarLikeIdentifier.php', + 'PHPUnitPHAR\\PhpParser\\Node\\VariadicPlaceholder' => '/nikic-php-parser/PhpParser/Node/VariadicPlaceholder.php', + 'PHPUnitPHAR\\PhpParser\\Parser' => '/nikic-php-parser/PhpParser/Parser.php', + 'PHPUnitPHAR\\PhpParser\\ParserAbstract' => '/nikic-php-parser/PhpParser/ParserAbstract.php', + 'PHPUnitPHAR\\PhpParser\\ParserFactory' => '/nikic-php-parser/PhpParser/ParserFactory.php', + 'PHPUnitPHAR\\PhpParser\\Parser\\Php7' => '/nikic-php-parser/PhpParser/Parser/Php7.php', + 'PHPUnitPHAR\\PhpParser\\Parser\\Php8' => '/nikic-php-parser/PhpParser/Parser/Php8.php', + 'PHPUnitPHAR\\PhpParser\\PhpVersion' => '/nikic-php-parser/PhpParser/PhpVersion.php', + 'PHPUnitPHAR\\PhpParser\\PrettyPrinter' => '/nikic-php-parser/PhpParser/PrettyPrinter.php', + 'PHPUnitPHAR\\PhpParser\\PrettyPrinterAbstract' => '/nikic-php-parser/PhpParser/PrettyPrinterAbstract.php', + 'PHPUnitPHAR\\PhpParser\\PrettyPrinter\\Standard' => '/nikic-php-parser/PhpParser/PrettyPrinter/Standard.php', + 'PHPUnitPHAR\\PhpParser\\Token' => '/nikic-php-parser/PhpParser/Token.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\AmbiguousOptionException' => '/sebastian-cli-parser/exceptions/AmbiguousOptionException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\Exception' => '/sebastian-cli-parser/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\OptionDoesNotAllowArgumentException' => '/sebastian-cli-parser/exceptions/OptionDoesNotAllowArgumentException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\Parser' => '/sebastian-cli-parser/Parser.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\RequiredOptionArgumentMissingException' => '/sebastian-cli-parser/exceptions/RequiredOptionArgumentMissingException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\UnknownOptionException' => '/sebastian-cli-parser/exceptions/UnknownOptionException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\BranchAndPathCoverageNotSupportedException' => '/php-code-coverage/Exception/BranchAndPathCoverageNotSupportedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\CodeCoverage' => '/php-code-coverage/CodeCoverage.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedBranchCoverageData' => '/php-code-coverage/Data/ProcessedBranchCoverageData.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedClassType' => '/php-code-coverage/Data/ProcessedClassType.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedCodeCoverageData' => '/php-code-coverage/Data/ProcessedCodeCoverageData.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedFunctionCoverageData' => '/php-code-coverage/Data/ProcessedFunctionCoverageData.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedFunctionType' => '/php-code-coverage/Data/ProcessedFunctionType.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedMethodType' => '/php-code-coverage/Data/ProcessedMethodType.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedPathCoverageData' => '/php-code-coverage/Data/ProcessedPathCoverageData.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedTraitType' => '/php-code-coverage/Data/ProcessedTraitType.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\RawCodeCoverageData' => '/php-code-coverage/Data/RawCodeCoverageData.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\Driver' => '/php-code-coverage/Driver/Driver.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\PcovDriver' => '/php-code-coverage/Driver/PcovDriver.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\PcovNotAvailableException' => '/php-code-coverage/Exception/PcovNotAvailableException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\Selector' => '/php-code-coverage/Driver/Selector.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\XdebugDriver' => '/php-code-coverage/Driver/XdebugDriver.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\XdebugNotAvailableException' => '/php-code-coverage/Exception/XdebugNotAvailableException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\XdebugNotEnabledException' => '/php-code-coverage/Exception/XdebugNotEnabledException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\XdebugVersionNotSupportedException' => '/php-code-coverage/Exception/XdebugVersionNotSupportedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Exception' => '/php-code-coverage/Exception/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\FileCouldNotBeWrittenException' => '/php-code-coverage/Exception/FileCouldNotBeWrittenException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Filter' => '/php-code-coverage/Filter.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\FilterProcessor' => '/php-code-coverage/FilterProcessor.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\InvalidArgumentException' => '/php-code-coverage/Exception/InvalidArgumentException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\MethodNotImplementedException' => '/php-code-coverage/Exception/MethodNotImplementedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\NoCodeCoverageDriverAvailableException' => '/php-code-coverage/Exception/NoCodeCoverageDriverAvailableException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\NoCodeCoverageDriverWithPathCoverageSupportAvailableException' => '/php-code-coverage/Exception/NoCodeCoverageDriverWithPathCoverageSupportAvailableException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\AbstractNode' => '/php-code-coverage/Node/AbstractNode.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\Builder' => '/php-code-coverage/Node/Builder.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\CrapIndex' => '/php-code-coverage/Node/CrapIndex.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\Directory' => '/php-code-coverage/Node/Directory.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\File' => '/php-code-coverage/Node/File.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\Iterator' => '/php-code-coverage/Node/Iterator.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\ParserException' => '/php-code-coverage/Exception/ParserException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\PathExistsButIsNotDirectoryException' => '/php-code-coverage/Exception/PathExistsButIsNotDirectoryException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\ReflectionException' => '/php-code-coverage/Exception/ReflectionException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\ReportAlreadyFinalizedException' => '/php-code-coverage/Exception/ReportAlreadyFinalizedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Clover' => '/php-code-coverage/Report/Clover.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Cobertura' => '/php-code-coverage/Report/Cobertura.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Crap4j' => '/php-code-coverage/Report/Crap4j.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Facade' => '/php-code-coverage/Report/Facade.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\BubbleChart' => '/php-code-coverage/Report/Html/Renderer/BubbleChart.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\Colors' => '/php-code-coverage/Report/Html/Colors.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\CustomCssFile' => '/php-code-coverage/Report/Html/CustomCssFile.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\Dashboard' => '/php-code-coverage/Report/Html/Renderer/Dashboard.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\Directory' => '/php-code-coverage/Report/Html/Renderer/Directory.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\Facade' => '/php-code-coverage/Report/Html/Facade.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\File' => '/php-code-coverage/Report/Html/Renderer/File.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\Renderer' => '/php-code-coverage/Report/Html/Renderer.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\SyntaxHighlighter' => '/php-code-coverage/Report/Html/SyntaxHighlighter.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\OpenClover' => '/php-code-coverage/Report/OpenClover.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Summary' => '/php-code-coverage/Report/Summary.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Text' => '/php-code-coverage/Report/Text.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Thresholds' => '/php-code-coverage/Report/Thresholds.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\BuildInformation' => '/php-code-coverage/Report/Xml/BuildInformation.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Coverage' => '/php-code-coverage/Report/Xml/Coverage.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Directory' => '/php-code-coverage/Report/Xml/Directory.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Facade' => '/php-code-coverage/Report/Xml/Facade.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\File' => '/php-code-coverage/Report/Xml/File.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Method' => '/php-code-coverage/Report/Xml/Method.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Node' => '/php-code-coverage/Report/Xml/Node.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Project' => '/php-code-coverage/Report/Xml/Project.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Report' => '/php-code-coverage/Report/Xml/Report.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Source' => '/php-code-coverage/Report/Xml/Source.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Tests' => '/php-code-coverage/Report/Xml/Tests.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Totals' => '/php-code-coverage/Report/Xml/Totals.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Unit' => '/php-code-coverage/Report/Xml/Unit.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\DriverMismatchException' => '/php-code-coverage/Exception/DriverMismatchException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\EmptyPathListException' => '/php-code-coverage/Exception/EmptyPathListException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\FileCouldNotBeReadException' => '/php-code-coverage/Exception/FileCouldNotBeReadException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\GitInformationMismatchException' => '/php-code-coverage/Exception/GitInformationMismatchException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\InvalidCoverageDataException' => '/php-code-coverage/Exception/InvalidCoverageDataException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\Merger' => '/php-code-coverage/Serialization/Merger.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\MixedGitInformationException' => '/php-code-coverage/Exception/MixedGitInformationException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\PharPrefixCouldNotBeStrippedException' => '/php-code-coverage/Exception/PharPrefixCouldNotBeStrippedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\RuntimeMismatchException' => '/php-code-coverage/Exception/RuntimeMismatchException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\Serializer' => '/php-code-coverage/Serialization/Serializer.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\Unserializer' => '/php-code-coverage/Serialization/Unserializer.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\VersionMismatchException' => '/php-code-coverage/Exception/VersionMismatchException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysisCacheNotConfiguredException' => '/php-code-coverage/Exception/StaticAnalysisCacheNotConfiguredException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\AnalysisResult' => '/php-code-coverage/StaticAnalysis/Value/AnalysisResult.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\AttributeParentConnectingVisitor' => '/php-code-coverage/StaticAnalysis/Visitor/AttributeParentConnectingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\CacheWarmer' => '/php-code-coverage/StaticAnalysis/CacheWarmer.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\CachingSourceAnalyser' => '/php-code-coverage/StaticAnalysis/CachingSourceAnalyser.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Class_' => '/php-code-coverage/StaticAnalysis/Value/Class_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\CodeUnitFindingVisitor' => '/php-code-coverage/StaticAnalysis/Visitor/CodeUnitFindingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\ExecutableLinesFindingVisitor' => '/php-code-coverage/StaticAnalysis/Visitor/ExecutableLinesFindingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\FileAnalyser' => '/php-code-coverage/StaticAnalysis/FileAnalyser.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Function_' => '/php-code-coverage/StaticAnalysis/Value/Function_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\IgnoredLinesFindingVisitor' => '/php-code-coverage/StaticAnalysis/Visitor/IgnoredLinesFindingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Interface_' => '/php-code-coverage/StaticAnalysis/Value/Interface_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\LinesOfCode' => '/php-code-coverage/StaticAnalysis/Value/LinesOfCode.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Method' => '/php-code-coverage/StaticAnalysis/Value/Method.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\ParsingSourceAnalyser' => '/php-code-coverage/StaticAnalysis/ParsingSourceAnalyser.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\SourceAnalyser' => '/php-code-coverage/StaticAnalysis/SourceAnalyser.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Trait_' => '/php-code-coverage/StaticAnalysis/Value/Trait_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Visibility' => '/php-code-coverage/StaticAnalysis/Value/Visibility.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\TestIdMissingException' => '/php-code-coverage/Exception/TestIdMissingException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Class_' => '/php-code-coverage/Test/Target/Class_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ClassesThatExtendClass' => '/php-code-coverage/Test/Target/ClassesThatExtendClass.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ClassesThatImplementInterface' => '/php-code-coverage/Test/Target/ClassesThatImplementInterface.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Function_' => '/php-code-coverage/Test/Target/Function_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\InvalidCodeCoverageTargetException' => '/php-code-coverage/Exception/InvalidCodeCoverageTargetException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\MapBuilder' => '/php-code-coverage/Test/Target/MapBuilder.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Mapper' => '/php-code-coverage/Test/Target/Mapper.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Method' => '/php-code-coverage/Test/Target/Method.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Namespace_' => '/php-code-coverage/Test/Target/Namespace_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Target' => '/php-code-coverage/Test/Target/Target.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollection' => '/php-code-coverage/Test/Target/TargetCollection.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollectionIterator' => '/php-code-coverage/Test/Target/TargetCollectionIterator.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollectionValidator' => '/php-code-coverage/Test/Target/TargetCollectionValidator.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Trait_' => '/php-code-coverage/Test/Target/Trait_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationFailure' => '/php-code-coverage/Test/Target/ValidationFailure.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationResult' => '/php-code-coverage/Test/Target/ValidationResult.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationSuccess' => '/php-code-coverage/Test/Target/ValidationSuccess.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize' => '/php-code-coverage/Test/TestSize.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus' => '/php-code-coverage/Test/TestStatus.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\UnintentionallyCoveredCodeChecker' => '/php-code-coverage/UnintentionallyCoveredCodeChecker.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\UnintentionallyCoveredCodeException' => '/php-code-coverage/Exception/UnintentionallyCoveredCodeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\DirectoryCouldNotBeCreatedException' => '/php-code-coverage/Exception/DirectoryCouldNotBeCreatedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\EnsuresUtf8' => '/php-code-coverage/Util/EnsuresUtf8.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\Filesystem' => '/php-code-coverage/Util/Filesystem.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\PathReducer' => '/php-code-coverage/Util/PathReducer.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\Percentage' => '/php-code-coverage/Util/Percentage.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\Xml' => '/php-code-coverage/Util/Xml.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Version' => '/php-code-coverage/Version.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\WriteOperationFailedException' => '/php-code-coverage/Exception/WriteOperationFailedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\XmlException' => '/php-code-coverage/Exception/XmlException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ArrayComparator' => '/sebastian-comparator/ArrayComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ClosureComparator' => '/sebastian-comparator/ClosureComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\Comparator' => '/sebastian-comparator/Comparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ComparisonFailure' => '/sebastian-comparator/ComparisonFailure.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\DOMNodeComparator' => '/sebastian-comparator/DOMNodeComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\DateIntervalComparator' => '/sebastian-comparator/DateIntervalComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\DateTimeComparator' => '/sebastian-comparator/DateTimeComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\EnumerationComparator' => '/sebastian-comparator/EnumerationComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\Exception' => '/sebastian-comparator/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ExceptionComparator' => '/sebastian-comparator/ExceptionComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\Factory' => '/sebastian-comparator/Factory.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\MockObjectComparator' => '/sebastian-comparator/MockObjectComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\NumberComparator' => '/sebastian-comparator/NumberComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\NumericComparator' => '/sebastian-comparator/NumericComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ObjectComparator' => '/sebastian-comparator/ObjectComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ResourceComparator' => '/sebastian-comparator/ResourceComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\RuntimeException' => '/sebastian-comparator/exceptions/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ScalarComparator' => '/sebastian-comparator/ScalarComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\SplObjectStorageComparator' => '/sebastian-comparator/SplObjectStorageComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\TypeComparator' => '/sebastian-comparator/TypeComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\Calculator' => '/sebastian-complexity/Calculator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\Complexity' => '/sebastian-complexity/Complexity/Complexity.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\ComplexityCalculatingVisitor' => '/sebastian-complexity/Visitor/ComplexityCalculatingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\ComplexityCollection' => '/sebastian-complexity/Complexity/ComplexityCollection.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\ComplexityCollectionIterator' => '/sebastian-complexity/Complexity/ComplexityCollectionIterator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\CyclomaticComplexityCalculatingVisitor' => '/sebastian-complexity/Visitor/CyclomaticComplexityCalculatingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\Exception' => '/sebastian-complexity/Exception/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\RuntimeException' => '/sebastian-complexity/Exception/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Chunk' => '/sebastian-diff/Chunk.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\ConfigurationException' => '/sebastian-diff/Exception/ConfigurationException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Diff' => '/sebastian-diff/Diff.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Differ' => '/sebastian-diff/Differ.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Exception' => '/sebastian-diff/Exception/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Line' => '/sebastian-diff/Line.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\LongestCommonSubsequenceCalculator' => '/sebastian-diff/LongestCommonSubsequenceCalculator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\MemoryEfficientLongestCommonSubsequenceCalculator' => '/sebastian-diff/MemoryEfficientLongestCommonSubsequenceCalculator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Output\\AbstractChunkOutputBuilder' => '/sebastian-diff/Output/AbstractChunkOutputBuilder.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Output\\DiffOnlyOutputBuilder' => '/sebastian-diff/Output/DiffOnlyOutputBuilder.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Output\\DiffOutputBuilderInterface' => '/sebastian-diff/Output/DiffOutputBuilderInterface.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Output\\StrictUnifiedDiffOutputBuilder' => '/sebastian-diff/Output/StrictUnifiedDiffOutputBuilder.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Output\\UnifiedDiffOutputBuilder' => '/sebastian-diff/Output/UnifiedDiffOutputBuilder.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Parser' => '/sebastian-diff/Parser.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\TimeEfficientLongestCommonSubsequenceCalculator' => '/sebastian-diff/TimeEfficientLongestCommonSubsequenceCalculator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Environment\\Console' => '/sebastian-environment/Console.php', + 'PHPUnitPHAR\\SebastianBergmann\\Environment\\Host' => '/sebastian-environment/Host.php', + 'PHPUnitPHAR\\SebastianBergmann\\Environment\\Runtime' => '/sebastian-environment/Runtime.php', + 'PHPUnitPHAR\\SebastianBergmann\\Exporter\\Exporter' => '/sebastian-exporter/Exporter.php', + 'PHPUnitPHAR\\SebastianBergmann\\FileIterator\\ExcludeIterator' => '/php-file-iterator/ExcludeIterator.php', + 'PHPUnitPHAR\\SebastianBergmann\\FileIterator\\Facade' => '/php-file-iterator/Facade.php', + 'PHPUnitPHAR\\SebastianBergmann\\FileIterator\\Factory' => '/php-file-iterator/Factory.php', + 'PHPUnitPHAR\\SebastianBergmann\\FileIterator\\Iterator' => '/php-file-iterator/Iterator.php', + 'PHPUnitPHAR\\SebastianBergmann\\GitState\\Builder' => '/sebastian-git-state/Builder.php', + 'PHPUnitPHAR\\SebastianBergmann\\GitState\\GitCommandRunner' => '/sebastian-git-state/GitCommandRunner.php', + 'PHPUnitPHAR\\SebastianBergmann\\GitState\\ShellCommandRunner' => '/sebastian-git-state/ShellCommandRunner.php', + 'PHPUnitPHAR\\SebastianBergmann\\GitState\\ShellCommandRunnerImplementation' => '/sebastian-git-state/ShellCommandRunnerImplementation.php', + 'PHPUnitPHAR\\SebastianBergmann\\GitState\\State' => '/sebastian-git-state/State.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\CodeExporter' => '/sebastian-global-state/CodeExporter.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\Exception' => '/sebastian-global-state/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\ExcludeList' => '/sebastian-global-state/ExcludeList.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\Restorer' => '/sebastian-global-state/Restorer.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\RuntimeException' => '/sebastian-global-state/exceptions/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\Snapshot' => '/sebastian-global-state/Snapshot.php', + 'PHPUnitPHAR\\SebastianBergmann\\Invoker\\Exception' => '/php-invoker/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Invoker\\Invoker' => '/php-invoker/Invoker.php', + 'PHPUnitPHAR\\SebastianBergmann\\Invoker\\ProcessControlExtensionNotLoadedException' => '/php-invoker/exceptions/ProcessControlExtensionNotLoadedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Invoker\\TimeoutException' => '/php-invoker/exceptions/TimeoutException.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\Counter' => '/sebastian-lines-of-code/Counter.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\Exception' => '/sebastian-lines-of-code/Exception/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\IllogicalValuesException' => '/sebastian-lines-of-code/Exception/IllogicalValuesException.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\LineCountingVisitor' => '/sebastian-lines-of-code/LineCountingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\LinesOfCode' => '/sebastian-lines-of-code/LinesOfCode.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\RuntimeException' => '/sebastian-lines-of-code/Exception/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\ObjectEnumerator\\Enumerator' => '/sebastian-object-enumerator/Enumerator.php', + 'PHPUnitPHAR\\SebastianBergmann\\ObjectReflector\\ObjectReflector' => '/sebastian-object-reflector/ObjectReflector.php', + 'PHPUnitPHAR\\SebastianBergmann\\RecursionContext\\Context' => '/sebastian-recursion-context/Context.php', + 'PHPUnitPHAR\\SebastianBergmann\\Template\\Exception' => '/php-text-template/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Template\\InvalidArgumentException' => '/php-text-template/exceptions/InvalidArgumentException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Template\\RuntimeException' => '/php-text-template/exceptions/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Template\\Template' => '/php-text-template/Template.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\Duration' => '/php-timer/Duration.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\Exception' => '/php-timer/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\NoActiveTimerException' => '/php-timer/exceptions/NoActiveTimerException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\ResourceUsageFormatter' => '/php-timer/ResourceUsageFormatter.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\TimeSinceStartOfRequestNotAvailableException' => '/php-timer/exceptions/TimeSinceStartOfRequestNotAvailableException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\Timer' => '/php-timer/Timer.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\CallableType' => '/sebastian-type/type/CallableType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\Exception' => '/sebastian-type/exception/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\FalseType' => '/sebastian-type/type/FalseType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\GenericObjectType' => '/sebastian-type/type/GenericObjectType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\IntersectionType' => '/sebastian-type/type/IntersectionType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\IterableType' => '/sebastian-type/type/IterableType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\MixedType' => '/sebastian-type/type/MixedType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\NeverType' => '/sebastian-type/type/NeverType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\NullType' => '/sebastian-type/type/NullType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\ObjectType' => '/sebastian-type/type/ObjectType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\Parameter' => '/sebastian-type/Parameter.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\ReflectionMapper' => '/sebastian-type/ReflectionMapper.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\RuntimeException' => '/sebastian-type/exception/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\SimpleType' => '/sebastian-type/type/SimpleType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\StaticType' => '/sebastian-type/type/StaticType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\TrueType' => '/sebastian-type/type/TrueType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\Type' => '/sebastian-type/type/Type.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\TypeName' => '/sebastian-type/TypeName.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\UnionType' => '/sebastian-type/type/UnionType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\UnknownType' => '/sebastian-type/type/UnknownType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\VoidType' => '/sebastian-type/type/VoidType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Version' => '/sebastian-version/Version.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\Exception' => '/theseer-tokenizer/Exception.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\NamespaceUri' => '/theseer-tokenizer/NamespaceUri.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\NamespaceUriException' => '/theseer-tokenizer/NamespaceUriException.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\Token' => '/theseer-tokenizer/Token.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\TokenCollection' => '/theseer-tokenizer/TokenCollection.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\TokenCollectionException' => '/theseer-tokenizer/TokenCollectionException.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\Tokenizer' => '/theseer-tokenizer/Tokenizer.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\XMLSerializer' => '/theseer-tokenizer/XMLSerializer.php', + 'PHPUnitPHAR\\staabm\\SideEffectsDetector\\SideEffect' => '/staabm-side-effects-detector/SideEffect.php', + 'PHPUnitPHAR\\staabm\\SideEffectsDetector\\SideEffectsDetector' => '/staabm-side-effects-detector/SideEffectsDetector.php', + 'PHPUnit\\Event\\Application\\Finished' => '/phpunit/Event/Events/Application/Finished.php', + 'PHPUnit\\Event\\Application\\FinishedSubscriber' => '/phpunit/Event/Events/Application/FinishedSubscriber.php', + 'PHPUnit\\Event\\Application\\Started' => '/phpunit/Event/Events/Application/Started.php', + 'PHPUnit\\Event\\Application\\StartedSubscriber' => '/phpunit/Event/Events/Application/StartedSubscriber.php', + 'PHPUnit\\Event\\Code\\ClassMethod' => '/phpunit/Event/Value/ClassMethod.php', + 'PHPUnit\\Event\\Code\\ComparisonFailure' => '/phpunit/Event/Value/ComparisonFailure.php', + 'PHPUnit\\Event\\Code\\ComparisonFailureBuilder' => '/phpunit/Event/Value/ComparisonFailureBuilder.php', + 'PHPUnit\\Event\\Code\\IssueTrigger\\Code' => '/phpunit/Event/Value/Test/Issue/Code.php', + 'PHPUnit\\Event\\Code\\IssueTrigger\\IssueTrigger' => '/phpunit/Event/Value/Test/Issue/IssueTrigger.php', + 'PHPUnit\\Event\\Code\\NoTestCaseObjectOnCallStackException' => '/phpunit/Event/Exception/NoTestCaseObjectOnCallStackException.php', + 'PHPUnit\\Event\\Code\\Phpt' => '/phpunit/Event/Value/Test/Phpt.php', + 'PHPUnit\\Event\\Code\\Test' => '/phpunit/Event/Value/Test/Test.php', + 'PHPUnit\\Event\\Code\\TestCollection' => '/phpunit/Event/Value/Test/TestCollection.php', + 'PHPUnit\\Event\\Code\\TestCollectionIterator' => '/phpunit/Event/Value/Test/TestCollectionIterator.php', + 'PHPUnit\\Event\\Code\\TestDox' => '/phpunit/Event/Value/Test/TestDox.php', + 'PHPUnit\\Event\\Code\\TestDoxBuilder' => '/phpunit/Event/Value/Test/TestDoxBuilder.php', + 'PHPUnit\\Event\\Code\\TestMethod' => '/phpunit/Event/Value/Test/TestMethod.php', + 'PHPUnit\\Event\\Code\\TestMethodBuilder' => '/phpunit/Event/Value/Test/TestMethodBuilder.php', + 'PHPUnit\\Event\\Code\\Throwable' => '/phpunit/Event/Value/Throwable.php', + 'PHPUnit\\Event\\Code\\ThrowableBuilder' => '/phpunit/Event/Value/ThrowableBuilder.php', + 'PHPUnit\\Event\\CollectingDispatcher' => '/phpunit/Event/Dispatcher/CollectingDispatcher.php', + 'PHPUnit\\Event\\DeferringDispatcher' => '/phpunit/Event/Dispatcher/DeferringDispatcher.php', + 'PHPUnit\\Event\\DirectDispatcher' => '/phpunit/Event/Dispatcher/DirectDispatcher.php', + 'PHPUnit\\Event\\Dispatcher' => '/phpunit/Event/Dispatcher/Dispatcher.php', + 'PHPUnit\\Event\\DispatchingEmitter' => '/phpunit/Event/Emitter/DispatchingEmitter.php', + 'PHPUnit\\Event\\Emitter' => '/phpunit/Event/Emitter/Emitter.php', + 'PHPUnit\\Event\\Event' => '/phpunit/Event/Events/Event.php', + 'PHPUnit\\Event\\EventAlreadyAssignedException' => '/phpunit/Event/Exception/EventAlreadyAssignedException.php', + 'PHPUnit\\Event\\EventCollection' => '/phpunit/Event/Events/EventCollection.php', + 'PHPUnit\\Event\\EventCollectionIterator' => '/phpunit/Event/Events/EventCollectionIterator.php', + 'PHPUnit\\Event\\EventFacadeIsSealedException' => '/phpunit/Event/Exception/EventFacadeIsSealedException.php', + 'PHPUnit\\Event\\Exception' => '/phpunit/Event/Exception/Exception.php', + 'PHPUnit\\Event\\Facade' => '/phpunit/Event/Facade.php', + 'PHPUnit\\Event\\InvalidArgumentException' => '/phpunit/Event/Exception/InvalidArgumentException.php', + 'PHPUnit\\Event\\InvalidEventException' => '/phpunit/Event/Exception/InvalidEventException.php', + 'PHPUnit\\Event\\InvalidSubscriberException' => '/phpunit/Event/Exception/InvalidSubscriberException.php', + 'PHPUnit\\Event\\MapError' => '/phpunit/Event/Exception/MapError.php', + 'PHPUnit\\Event\\NoPreviousThrowableException' => '/phpunit/Event/Exception/NoPreviousThrowableException.php', + 'PHPUnit\\Event\\RuntimeException' => '/phpunit/Event/Exception/RuntimeException.php', + 'PHPUnit\\Event\\Runtime\\OperatingSystem' => '/phpunit/Event/Value/Runtime/OperatingSystem.php', + 'PHPUnit\\Event\\Runtime\\PHP' => '/phpunit/Event/Value/Runtime/PHP.php', + 'PHPUnit\\Event\\Runtime\\PHPUnit' => '/phpunit/Event/Value/Runtime/PHPUnit.php', + 'PHPUnit\\Event\\Runtime\\Runtime' => '/phpunit/Event/Value/Runtime/Runtime.php', + 'PHPUnit\\Event\\SubscribableDispatcher' => '/phpunit/Event/Dispatcher/SubscribableDispatcher.php', + 'PHPUnit\\Event\\Subscriber' => '/phpunit/Event/Subscriber.php', + 'PHPUnit\\Event\\SubscriberTypeAlreadyRegisteredException' => '/phpunit/Event/Exception/SubscriberTypeAlreadyRegisteredException.php', + 'PHPUnit\\Event\\Telemetry\\Duration' => '/phpunit/Event/Value/Telemetry/Duration.php', + 'PHPUnit\\Event\\Telemetry\\GarbageCollectorStatus' => '/phpunit/Event/Value/Telemetry/GarbageCollectorStatus.php', + 'PHPUnit\\Event\\Telemetry\\GarbageCollectorStatusProvider' => '/phpunit/Event/Value/Telemetry/GarbageCollectorStatusProvider.php', + 'PHPUnit\\Event\\Telemetry\\HRTime' => '/phpunit/Event/Value/Telemetry/HRTime.php', + 'PHPUnit\\Event\\Telemetry\\Info' => '/phpunit/Event/Value/Telemetry/Info.php', + 'PHPUnit\\Event\\Telemetry\\MemoryMeter' => '/phpunit/Event/Value/Telemetry/MemoryMeter.php', + 'PHPUnit\\Event\\Telemetry\\MemoryUsage' => '/phpunit/Event/Value/Telemetry/MemoryUsage.php', + 'PHPUnit\\Event\\Telemetry\\Snapshot' => '/phpunit/Event/Value/Telemetry/Snapshot.php', + 'PHPUnit\\Event\\Telemetry\\StopWatch' => '/phpunit/Event/Value/Telemetry/StopWatch.php', + 'PHPUnit\\Event\\Telemetry\\System' => '/phpunit/Event/Value/Telemetry/System.php', + 'PHPUnit\\Event\\Telemetry\\SystemGarbageCollectorStatusProvider' => '/phpunit/Event/Value/Telemetry/SystemGarbageCollectorStatusProvider.php', + 'PHPUnit\\Event\\Telemetry\\SystemMemoryMeter' => '/phpunit/Event/Value/Telemetry/SystemMemoryMeter.php', + 'PHPUnit\\Event\\Telemetry\\SystemStopWatch' => '/phpunit/Event/Value/Telemetry/SystemStopWatch.php', + 'PHPUnit\\Event\\Telemetry\\SystemStopWatchWithOffset' => '/phpunit/Event/Value/Telemetry/SystemStopWatchWithOffset.php', + 'PHPUnit\\Event\\TestData\\DataFromDataProvider' => '/phpunit/Event/Value/Test/TestData/DataFromDataProvider.php', + 'PHPUnit\\Event\\TestData\\DataFromTestDependency' => '/phpunit/Event/Value/Test/TestData/DataFromTestDependency.php', + 'PHPUnit\\Event\\TestData\\NoDataSetFromDataProviderException' => '/phpunit/Event/Exception/NoDataSetFromDataProviderException.php', + 'PHPUnit\\Event\\TestData\\TestData' => '/phpunit/Event/Value/Test/TestData/TestData.php', + 'PHPUnit\\Event\\TestData\\TestDataCollection' => '/phpunit/Event/Value/Test/TestData/TestDataCollection.php', + 'PHPUnit\\Event\\TestData\\TestDataCollectionIterator' => '/phpunit/Event/Value/Test/TestData/TestDataCollectionIterator.php', + 'PHPUnit\\Event\\TestRunner\\BootstrapFinished' => '/phpunit/Event/Events/TestRunner/BootstrapFinished.php', + 'PHPUnit\\Event\\TestRunner\\BootstrapFinishedSubscriber' => '/phpunit/Event/Events/TestRunner/BootstrapFinishedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessErrored' => '/phpunit/Event/Events/TestRunner/ChildProcessErrored.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessErroredSubscriber' => '/phpunit/Event/Events/TestRunner/ChildProcessErroredSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessFinished' => '/phpunit/Event/Events/TestRunner/ChildProcessFinished.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessFinishedSubscriber' => '/phpunit/Event/Events/TestRunner/ChildProcessFinishedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessStarted' => '/phpunit/Event/Events/TestRunner/ChildProcessStarted.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessStartedSubscriber' => '/phpunit/Event/Events/TestRunner/ChildProcessStartedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\Configured' => '/phpunit/Event/Events/TestRunner/Configured.php', + 'PHPUnit\\Event\\TestRunner\\ConfiguredSubscriber' => '/phpunit/Event/Events/TestRunner/ConfiguredSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\DeprecationTriggered' => '/phpunit/Event/Events/TestRunner/DeprecationTriggered.php', + 'PHPUnit\\Event\\TestRunner\\DeprecationTriggeredSubscriber' => '/phpunit/Event/Events/TestRunner/DeprecationTriggeredSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\EventFacadeSealed' => '/phpunit/Event/Events/TestRunner/EventFacadeSealed.php', + 'PHPUnit\\Event\\TestRunner\\EventFacadeSealedSubscriber' => '/phpunit/Event/Events/TestRunner/EventFacadeSealedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionAborted' => '/phpunit/Event/Events/TestRunner/ExecutionAborted.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionAbortedSubscriber' => '/phpunit/Event/Events/TestRunner/ExecutionAbortedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionFinished' => '/phpunit/Event/Events/TestRunner/ExecutionFinished.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionFinishedSubscriber' => '/phpunit/Event/Events/TestRunner/ExecutionFinishedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionStarted' => '/phpunit/Event/Events/TestRunner/ExecutionStarted.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionStartedSubscriber' => '/phpunit/Event/Events/TestRunner/ExecutionStartedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ExtensionBootstrapped' => '/phpunit/Event/Events/TestRunner/ExtensionBootstrapped.php', + 'PHPUnit\\Event\\TestRunner\\ExtensionBootstrappedSubscriber' => '/phpunit/Event/Events/TestRunner/ExtensionBootstrappedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ExtensionLoadedFromPhar' => '/phpunit/Event/Events/TestRunner/ExtensionLoadedFromPhar.php', + 'PHPUnit\\Event\\TestRunner\\ExtensionLoadedFromPharSubscriber' => '/phpunit/Event/Events/TestRunner/ExtensionLoadedFromPharSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\Finished' => '/phpunit/Event/Events/TestRunner/Finished.php', + 'PHPUnit\\Event\\TestRunner\\FinishedSubscriber' => '/phpunit/Event/Events/TestRunner/FinishedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionDisabled' => '/phpunit/Event/Events/TestRunner/GarbageCollectionDisabled.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionDisabledSubscriber' => '/phpunit/Event/Events/TestRunner/GarbageCollectionDisabledSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionEnabled' => '/phpunit/Event/Events/TestRunner/GarbageCollectionEnabled.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionEnabledSubscriber' => '/phpunit/Event/Events/TestRunner/GarbageCollectionEnabledSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionTriggered' => '/phpunit/Event/Events/TestRunner/GarbageCollectionTriggered.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionTriggeredSubscriber' => '/phpunit/Event/Events/TestRunner/GarbageCollectionTriggeredSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\NoticeTriggered' => '/phpunit/Event/Events/TestRunner/NoticeTriggered.php', + 'PHPUnit\\Event\\TestRunner\\NoticeTriggeredSubscriber' => '/phpunit/Event/Events/TestRunner/NoticeTriggeredSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\Started' => '/phpunit/Event/Events/TestRunner/Started.php', + 'PHPUnit\\Event\\TestRunner\\StartedSubscriber' => '/phpunit/Event/Events/TestRunner/StartedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\StaticAnalysisForCodeCoverageFinished' => '/phpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinished.php', + 'PHPUnit\\Event\\TestRunner\\StaticAnalysisForCodeCoverageFinishedSubscriber' => '/phpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinishedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\StaticAnalysisForCodeCoverageStarted' => '/phpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStarted.php', + 'PHPUnit\\Event\\TestRunner\\StaticAnalysisForCodeCoverageStartedSubscriber' => '/phpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStartedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\WarningTriggered' => '/phpunit/Event/Events/TestRunner/WarningTriggered.php', + 'PHPUnit\\Event\\TestRunner\\WarningTriggeredSubscriber' => '/phpunit/Event/Events/TestRunner/WarningTriggeredSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Filtered' => '/phpunit/Event/Events/TestSuite/Filtered.php', + 'PHPUnit\\Event\\TestSuite\\FilteredSubscriber' => '/phpunit/Event/Events/TestSuite/FilteredSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Finished' => '/phpunit/Event/Events/TestSuite/Finished.php', + 'PHPUnit\\Event\\TestSuite\\FinishedSubscriber' => '/phpunit/Event/Events/TestSuite/FinishedSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Loaded' => '/phpunit/Event/Events/TestSuite/Loaded.php', + 'PHPUnit\\Event\\TestSuite\\LoadedSubscriber' => '/phpunit/Event/Events/TestSuite/LoadedSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Skipped' => '/phpunit/Event/Events/TestSuite/Skipped.php', + 'PHPUnit\\Event\\TestSuite\\SkippedSubscriber' => '/phpunit/Event/Events/TestSuite/SkippedSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Sorted' => '/phpunit/Event/Events/TestSuite/Sorted.php', + 'PHPUnit\\Event\\TestSuite\\SortedSubscriber' => '/phpunit/Event/Events/TestSuite/SortedSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Started' => '/phpunit/Event/Events/TestSuite/Started.php', + 'PHPUnit\\Event\\TestSuite\\StartedSubscriber' => '/phpunit/Event/Events/TestSuite/StartedSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\TestSuite' => '/phpunit/Event/Value/TestSuite/TestSuite.php', + 'PHPUnit\\Event\\TestSuite\\TestSuiteBuilder' => '/phpunit/Event/Value/TestSuite/TestSuiteBuilder.php', + 'PHPUnit\\Event\\TestSuite\\TestSuiteForTestClass' => '/phpunit/Event/Value/TestSuite/TestSuiteForTestClass.php', + 'PHPUnit\\Event\\TestSuite\\TestSuiteForTestMethodWithDataProvider' => '/phpunit/Event/Value/TestSuite/TestSuiteForTestMethodWithDataProvider.php', + 'PHPUnit\\Event\\TestSuite\\TestSuiteWithName' => '/phpunit/Event/Value/TestSuite/TestSuiteWithName.php', + 'PHPUnit\\Event\\Test\\AdditionalInformationProvided' => '/phpunit/Event/Events/Test/AdditionalInformationProvided.php', + 'PHPUnit\\Event\\Test\\AdditionalInformationProvidedSubscriber' => '/phpunit/Event/Events/Test/AdditionalInformationProvidedSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodCalled' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodCalled.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodErrored' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodErrored.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodFailed' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFailed.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodFinished' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFinished.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodCalled' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodCalled.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodErrored' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodErrored.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodFailed' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodFailed.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodFinished' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodFinished.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodCalled' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalled.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodErrored' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodErrored.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodFailed' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailed.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodFinished' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinished.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodCalled' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodCalled.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodErrored' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodErrored.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodFailed' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodFailed.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodFinished' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodFinished.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\ComparatorRegistered' => '/phpunit/Event/Events/Test/ComparatorRegistered.php', + 'PHPUnit\\Event\\Test\\ComparatorRegisteredSubscriber' => '/phpunit/Event/Events/Test/ComparatorRegisteredSubscriber.php', + 'PHPUnit\\Event\\Test\\ConsideredRisky' => '/phpunit/Event/Events/Test/Issue/ConsideredRisky.php', + 'PHPUnit\\Event\\Test\\ConsideredRiskySubscriber' => '/phpunit/Event/Events/Test/Issue/ConsideredRiskySubscriber.php', + 'PHPUnit\\Event\\Test\\CustomTestMethodInvocationUsed' => '/phpunit/Event/Events/Test/CustomTestMethodInvocationUsed.php', + 'PHPUnit\\Event\\Test\\CustomTestMethodInvocationUsedSubscriber' => '/phpunit/Event/Events/Test/CustomTestMethodInvocationUsedSubscriber.php', + 'PHPUnit\\Event\\Test\\DataProviderMethodCalled' => '/phpunit/Event/Events/Test/Lifecycle/DataProviderMethodCalled.php', + 'PHPUnit\\Event\\Test\\DataProviderMethodCalledSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/DataProviderMethodCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\DataProviderMethodFinished' => '/phpunit/Event/Events/Test/Lifecycle/DataProviderMethodFinished.php', + 'PHPUnit\\Event\\Test\\DataProviderMethodFinishedSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/DataProviderMethodFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\DeprecationTriggered' => '/phpunit/Event/Events/Test/Issue/DeprecationTriggered.php', + 'PHPUnit\\Event\\Test\\DeprecationTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/DeprecationTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\ErrorTriggered' => '/phpunit/Event/Events/Test/Issue/ErrorTriggered.php', + 'PHPUnit\\Event\\Test\\ErrorTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/ErrorTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\Errored' => '/phpunit/Event/Events/Test/Outcome/Errored.php', + 'PHPUnit\\Event\\Test\\ErroredSubscriber' => '/phpunit/Event/Events/Test/Outcome/ErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\Failed' => '/phpunit/Event/Events/Test/Outcome/Failed.php', + 'PHPUnit\\Event\\Test\\FailedSubscriber' => '/phpunit/Event/Events/Test/Outcome/FailedSubscriber.php', + 'PHPUnit\\Event\\Test\\Finished' => '/phpunit/Event/Events/Test/Lifecycle/Finished.php', + 'PHPUnit\\Event\\Test\\FinishedSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/FinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\MarkedIncomplete' => '/phpunit/Event/Events/Test/Outcome/MarkedIncomplete.php', + 'PHPUnit\\Event\\Test\\MarkedIncompleteSubscriber' => '/phpunit/Event/Events/Test/Outcome/MarkedIncompleteSubscriber.php', + 'PHPUnit\\Event\\Test\\MockObjectCreated' => '/phpunit/Event/Events/Test/TestDouble/MockObjectCreated.php', + 'PHPUnit\\Event\\Test\\MockObjectCreatedSubscriber' => '/phpunit/Event/Events/Test/TestDouble/MockObjectCreatedSubscriber.php', + 'PHPUnit\\Event\\Test\\MockObjectForIntersectionOfInterfacesCreated' => '/phpunit/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreated.php', + 'PHPUnit\\Event\\Test\\MockObjectForIntersectionOfInterfacesCreatedSubscriber' => '/phpunit/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreatedSubscriber.php', + 'PHPUnit\\Event\\Test\\NoComparisonFailureException' => '/phpunit/Event/Exception/NoComparisonFailureException.php', + 'PHPUnit\\Event\\Test\\NoticeTriggered' => '/phpunit/Event/Events/Test/Issue/NoticeTriggered.php', + 'PHPUnit\\Event\\Test\\NoticeTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/NoticeTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PartialMockObjectCreated' => '/phpunit/Event/Events/Test/TestDouble/PartialMockObjectCreated.php', + 'PHPUnit\\Event\\Test\\PartialMockObjectCreatedSubscriber' => '/phpunit/Event/Events/Test/TestDouble/PartialMockObjectCreatedSubscriber.php', + 'PHPUnit\\Event\\Test\\Passed' => '/phpunit/Event/Events/Test/Outcome/Passed.php', + 'PHPUnit\\Event\\Test\\PassedSubscriber' => '/phpunit/Event/Events/Test/Outcome/PassedSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpDeprecationTriggered' => '/phpunit/Event/Events/Test/Issue/PhpDeprecationTriggered.php', + 'PHPUnit\\Event\\Test\\PhpDeprecationTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpDeprecationTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpNoticeTriggered' => '/phpunit/Event/Events/Test/Issue/PhpNoticeTriggered.php', + 'PHPUnit\\Event\\Test\\PhpNoticeTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpNoticeTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpWarningTriggered' => '/phpunit/Event/Events/Test/Issue/PhpWarningTriggered.php', + 'PHPUnit\\Event\\Test\\PhpWarningTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpWarningTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpunitDeprecationTriggered' => '/phpunit/Event/Events/Test/Issue/PhpunitDeprecationTriggered.php', + 'PHPUnit\\Event\\Test\\PhpunitDeprecationTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpunitDeprecationTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpunitErrorTriggered' => '/phpunit/Event/Events/Test/Issue/PhpunitErrorTriggered.php', + 'PHPUnit\\Event\\Test\\PhpunitErrorTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpunitErrorTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpunitNoticeTriggered' => '/phpunit/Event/Events/Test/Issue/PhpunitNoticeTriggered.php', + 'PHPUnit\\Event\\Test\\PhpunitNoticeTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpunitNoticeTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpunitWarningTriggered' => '/phpunit/Event/Events/Test/Issue/PhpunitWarningTriggered.php', + 'PHPUnit\\Event\\Test\\PhpunitWarningTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpunitWarningTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PostConditionCalled' => '/phpunit/Event/Events/Test/HookMethod/PostConditionCalled.php', + 'PHPUnit\\Event\\Test\\PostConditionCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PostConditionCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\PostConditionErrored' => '/phpunit/Event/Events/Test/HookMethod/PostConditionErrored.php', + 'PHPUnit\\Event\\Test\\PostConditionErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PostConditionErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\PostConditionFailed' => '/phpunit/Event/Events/Test/HookMethod/PostConditionFailed.php', + 'PHPUnit\\Event\\Test\\PostConditionFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PostConditionFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\PostConditionFinished' => '/phpunit/Event/Events/Test/HookMethod/PostConditionFinished.php', + 'PHPUnit\\Event\\Test\\PostConditionFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PostConditionFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\PreConditionCalled' => '/phpunit/Event/Events/Test/HookMethod/PreConditionCalled.php', + 'PHPUnit\\Event\\Test\\PreConditionCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PreConditionCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\PreConditionErrored' => '/phpunit/Event/Events/Test/HookMethod/PreConditionErrored.php', + 'PHPUnit\\Event\\Test\\PreConditionErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PreConditionErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\PreConditionFailed' => '/phpunit/Event/Events/Test/HookMethod/PreConditionFailed.php', + 'PHPUnit\\Event\\Test\\PreConditionFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PreConditionFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\PreConditionFinished' => '/phpunit/Event/Events/Test/HookMethod/PreConditionFinished.php', + 'PHPUnit\\Event\\Test\\PreConditionFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PreConditionFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\PreparationErrored' => '/phpunit/Event/Events/Test/Lifecycle/PreparationErrored.php', + 'PHPUnit\\Event\\Test\\PreparationErroredSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/PreparationErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\PreparationFailed' => '/phpunit/Event/Events/Test/Lifecycle/PreparationFailed.php', + 'PHPUnit\\Event\\Test\\PreparationFailedSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/PreparationFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\PreparationStarted' => '/phpunit/Event/Events/Test/Lifecycle/PreparationStarted.php', + 'PHPUnit\\Event\\Test\\PreparationStartedSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/PreparationStartedSubscriber.php', + 'PHPUnit\\Event\\Test\\Prepared' => '/phpunit/Event/Events/Test/Lifecycle/Prepared.php', + 'PHPUnit\\Event\\Test\\PreparedSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/PreparedSubscriber.php', + 'PHPUnit\\Event\\Test\\PrintedUnexpectedOutput' => '/phpunit/Event/Events/Test/PrintedUnexpectedOutput.php', + 'PHPUnit\\Event\\Test\\PrintedUnexpectedOutputSubscriber' => '/phpunit/Event/Events/Test/PrintedUnexpectedOutputSubscriber.php', + 'PHPUnit\\Event\\Test\\Skipped' => '/phpunit/Event/Events/Test/Outcome/Skipped.php', + 'PHPUnit\\Event\\Test\\SkippedSubscriber' => '/phpunit/Event/Events/Test/Outcome/SkippedSubscriber.php', + 'PHPUnit\\Event\\Test\\TestStubCreated' => '/phpunit/Event/Events/Test/TestDouble/TestStubCreated.php', + 'PHPUnit\\Event\\Test\\TestStubCreatedSubscriber' => '/phpunit/Event/Events/Test/TestDouble/TestStubCreatedSubscriber.php', + 'PHPUnit\\Event\\Test\\TestStubForIntersectionOfInterfacesCreated' => '/phpunit/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreated.php', + 'PHPUnit\\Event\\Test\\TestStubForIntersectionOfInterfacesCreatedSubscriber' => '/phpunit/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreatedSubscriber.php', + 'PHPUnit\\Event\\Test\\WarningTriggered' => '/phpunit/Event/Events/Test/Issue/WarningTriggered.php', + 'PHPUnit\\Event\\Test\\WarningTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/WarningTriggeredSubscriber.php', + 'PHPUnit\\Event\\Tracer\\Tracer' => '/phpunit/Event/Tracer.php', + 'PHPUnit\\Event\\TypeMap' => '/phpunit/Event/TypeMap.php', + 'PHPUnit\\Event\\UnknownEventException' => '/phpunit/Event/Exception/UnknownEventException.php', + 'PHPUnit\\Event\\UnknownEventTypeException' => '/phpunit/Event/Exception/UnknownEventTypeException.php', + 'PHPUnit\\Event\\UnknownSubscriberException' => '/phpunit/Event/Exception/UnknownSubscriberException.php', + 'PHPUnit\\Event\\UnknownSubscriberTypeException' => '/phpunit/Event/Exception/UnknownSubscriberTypeException.php', + 'PHPUnit\\Exception' => '/phpunit/Exception.php', + 'PHPUnit\\Framework\\ActualValueIsNotAnObjectException' => '/phpunit/Framework/Exception/ObjectEquals/ActualValueIsNotAnObjectException.php', + 'PHPUnit\\Framework\\Assert' => '/phpunit/Framework/Assert.php', + 'PHPUnit\\Framework\\AssertionFailedError' => '/phpunit/Framework/Exception/AssertionFailedError.php', + 'PHPUnit\\Framework\\Attributes\\After' => '/phpunit/Framework/Attributes/After.php', + 'PHPUnit\\Framework\\Attributes\\AfterClass' => '/phpunit/Framework/Attributes/AfterClass.php', + 'PHPUnit\\Framework\\Attributes\\AllowMockObjectsWithoutExpectations' => '/phpunit/Framework/Attributes/AllowMockObjectsWithoutExpectations.php', + 'PHPUnit\\Framework\\Attributes\\BackupGlobals' => '/phpunit/Framework/Attributes/BackupGlobals.php', + 'PHPUnit\\Framework\\Attributes\\BackupStaticProperties' => '/phpunit/Framework/Attributes/BackupStaticProperties.php', + 'PHPUnit\\Framework\\Attributes\\Before' => '/phpunit/Framework/Attributes/Before.php', + 'PHPUnit\\Framework\\Attributes\\BeforeClass' => '/phpunit/Framework/Attributes/BeforeClass.php', + 'PHPUnit\\Framework\\Attributes\\CoversClass' => '/phpunit/Framework/Attributes/CoversClass.php', + 'PHPUnit\\Framework\\Attributes\\CoversClassesThatExtendClass' => '/phpunit/Framework/Attributes/CoversClassesThatExtendClass.php', + 'PHPUnit\\Framework\\Attributes\\CoversClassesThatImplementInterface' => '/phpunit/Framework/Attributes/CoversClassesThatImplementInterface.php', + 'PHPUnit\\Framework\\Attributes\\CoversFunction' => '/phpunit/Framework/Attributes/CoversFunction.php', + 'PHPUnit\\Framework\\Attributes\\CoversMethod' => '/phpunit/Framework/Attributes/CoversMethod.php', + 'PHPUnit\\Framework\\Attributes\\CoversNamespace' => '/phpunit/Framework/Attributes/CoversNamespace.php', + 'PHPUnit\\Framework\\Attributes\\CoversNothing' => '/phpunit/Framework/Attributes/CoversNothing.php', + 'PHPUnit\\Framework\\Attributes\\CoversTrait' => '/phpunit/Framework/Attributes/CoversTrait.php', + 'PHPUnit\\Framework\\Attributes\\DataProvider' => '/phpunit/Framework/Attributes/DataProvider.php', + 'PHPUnit\\Framework\\Attributes\\DataProviderClosure' => '/phpunit/Framework/Attributes/DataProviderClosure.php', + 'PHPUnit\\Framework\\Attributes\\DataProviderExternal' => '/phpunit/Framework/Attributes/DataProviderExternal.php', + 'PHPUnit\\Framework\\Attributes\\Depends' => '/phpunit/Framework/Attributes/Depends.php', + 'PHPUnit\\Framework\\Attributes\\DependsExternal' => '/phpunit/Framework/Attributes/DependsExternal.php', + 'PHPUnit\\Framework\\Attributes\\DependsExternalUsingDeepClone' => '/phpunit/Framework/Attributes/DependsExternalUsingDeepClone.php', + 'PHPUnit\\Framework\\Attributes\\DependsExternalUsingShallowClone' => '/phpunit/Framework/Attributes/DependsExternalUsingShallowClone.php', + 'PHPUnit\\Framework\\Attributes\\DependsOnClass' => '/phpunit/Framework/Attributes/DependsOnClass.php', + 'PHPUnit\\Framework\\Attributes\\DependsOnClassUsingDeepClone' => '/phpunit/Framework/Attributes/DependsOnClassUsingDeepClone.php', + 'PHPUnit\\Framework\\Attributes\\DependsOnClassUsingShallowClone' => '/phpunit/Framework/Attributes/DependsOnClassUsingShallowClone.php', + 'PHPUnit\\Framework\\Attributes\\DependsUsingDeepClone' => '/phpunit/Framework/Attributes/DependsUsingDeepClone.php', + 'PHPUnit\\Framework\\Attributes\\DependsUsingShallowClone' => '/phpunit/Framework/Attributes/DependsUsingShallowClone.php', + 'PHPUnit\\Framework\\Attributes\\DisableReturnValueGenerationForTestDoubles' => '/phpunit/Framework/Attributes/DisableReturnValueGenerationForTestDoubles.php', + 'PHPUnit\\Framework\\Attributes\\DoesNotPerformAssertions' => '/phpunit/Framework/Attributes/DoesNotPerformAssertions.php', + 'PHPUnit\\Framework\\Attributes\\ExcludeGlobalVariableFromBackup' => '/phpunit/Framework/Attributes/ExcludeGlobalVariableFromBackup.php', + 'PHPUnit\\Framework\\Attributes\\ExcludeStaticPropertyFromBackup' => '/phpunit/Framework/Attributes/ExcludeStaticPropertyFromBackup.php', + 'PHPUnit\\Framework\\Attributes\\Group' => '/phpunit/Framework/Attributes/Group.php', + 'PHPUnit\\Framework\\Attributes\\IgnoreDeprecations' => '/phpunit/Framework/Attributes/IgnoreDeprecations.php', + 'PHPUnit\\Framework\\Attributes\\IgnorePhpunitDeprecations' => '/phpunit/Framework/Attributes/IgnorePhpunitDeprecations.php', + 'PHPUnit\\Framework\\Attributes\\IgnorePhpunitWarnings' => '/phpunit/Framework/Attributes/IgnorePhpunitWarnings.php', + 'PHPUnit\\Framework\\Attributes\\Large' => '/phpunit/Framework/Attributes/Large.php', + 'PHPUnit\\Framework\\Attributes\\Medium' => '/phpunit/Framework/Attributes/Medium.php', + 'PHPUnit\\Framework\\Attributes\\PostCondition' => '/phpunit/Framework/Attributes/PostCondition.php', + 'PHPUnit\\Framework\\Attributes\\PreCondition' => '/phpunit/Framework/Attributes/PreCondition.php', + 'PHPUnit\\Framework\\Attributes\\PreserveGlobalState' => '/phpunit/Framework/Attributes/PreserveGlobalState.php', + 'PHPUnit\\Framework\\Attributes\\RequiresEnvironmentVariable' => '/phpunit/Framework/Attributes/RequiresEnvironmentVariable.php', + 'PHPUnit\\Framework\\Attributes\\RequiresFunction' => '/phpunit/Framework/Attributes/RequiresFunction.php', + 'PHPUnit\\Framework\\Attributes\\RequiresMethod' => '/phpunit/Framework/Attributes/RequiresMethod.php', + 'PHPUnit\\Framework\\Attributes\\RequiresOperatingSystem' => '/phpunit/Framework/Attributes/RequiresOperatingSystem.php', + 'PHPUnit\\Framework\\Attributes\\RequiresOperatingSystemFamily' => '/phpunit/Framework/Attributes/RequiresOperatingSystemFamily.php', + 'PHPUnit\\Framework\\Attributes\\RequiresPhp' => '/phpunit/Framework/Attributes/RequiresPhp.php', + 'PHPUnit\\Framework\\Attributes\\RequiresPhpExtension' => '/phpunit/Framework/Attributes/RequiresPhpExtension.php', + 'PHPUnit\\Framework\\Attributes\\RequiresPhpunit' => '/phpunit/Framework/Attributes/RequiresPhpunit.php', + 'PHPUnit\\Framework\\Attributes\\RequiresPhpunitExtension' => '/phpunit/Framework/Attributes/RequiresPhpunitExtension.php', + 'PHPUnit\\Framework\\Attributes\\RequiresSetting' => '/phpunit/Framework/Attributes/RequiresSetting.php', + 'PHPUnit\\Framework\\Attributes\\RunInSeparateProcess' => '/phpunit/Framework/Attributes/RunInSeparateProcess.php', + 'PHPUnit\\Framework\\Attributes\\RunTestsInSeparateProcesses' => '/phpunit/Framework/Attributes/RunTestsInSeparateProcesses.php', + 'PHPUnit\\Framework\\Attributes\\Small' => '/phpunit/Framework/Attributes/Small.php', + 'PHPUnit\\Framework\\Attributes\\Test' => '/phpunit/Framework/Attributes/Test.php', + 'PHPUnit\\Framework\\Attributes\\TestDox' => '/phpunit/Framework/Attributes/TestDox.php', + 'PHPUnit\\Framework\\Attributes\\TestDoxFormatter' => '/phpunit/Framework/Attributes/TestDoxFormatter.php', + 'PHPUnit\\Framework\\Attributes\\TestDoxFormatterExternal' => '/phpunit/Framework/Attributes/TestDoxFormatterExternal.php', + 'PHPUnit\\Framework\\Attributes\\TestWith' => '/phpunit/Framework/Attributes/TestWith.php', + 'PHPUnit\\Framework\\Attributes\\TestWithJson' => '/phpunit/Framework/Attributes/TestWithJson.php', + 'PHPUnit\\Framework\\Attributes\\Ticket' => '/phpunit/Framework/Attributes/Ticket.php', + 'PHPUnit\\Framework\\Attributes\\UsesClass' => '/phpunit/Framework/Attributes/UsesClass.php', + 'PHPUnit\\Framework\\Attributes\\UsesClassesThatExtendClass' => '/phpunit/Framework/Attributes/UsesClassesThatExtendClass.php', + 'PHPUnit\\Framework\\Attributes\\UsesClassesThatImplementInterface' => '/phpunit/Framework/Attributes/UsesClassesThatImplementInterface.php', + 'PHPUnit\\Framework\\Attributes\\UsesFunction' => '/phpunit/Framework/Attributes/UsesFunction.php', + 'PHPUnit\\Framework\\Attributes\\UsesMethod' => '/phpunit/Framework/Attributes/UsesMethod.php', + 'PHPUnit\\Framework\\Attributes\\UsesNamespace' => '/phpunit/Framework/Attributes/UsesNamespace.php', + 'PHPUnit\\Framework\\Attributes\\UsesTrait' => '/phpunit/Framework/Attributes/UsesTrait.php', + 'PHPUnit\\Framework\\Attributes\\WithEnvironmentVariable' => '/phpunit/Framework/Attributes/WithEnvironmentVariable.php', + 'PHPUnit\\Framework\\Attributes\\WithoutErrorHandler' => '/phpunit/Framework/Attributes/WithoutErrorHandler.php', + 'PHPUnit\\Framework\\ChildProcessResultProcessor' => '/phpunit/Framework/TestRunner/ChildProcessResultProcessor.php', + 'PHPUnit\\Framework\\ComparisonMethodDoesNotAcceptParameterTypeException' => '/phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotAcceptParameterTypeException.php', + 'PHPUnit\\Framework\\ComparisonMethodDoesNotDeclareBoolReturnTypeException' => '/phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php', + 'PHPUnit\\Framework\\ComparisonMethodDoesNotDeclareExactlyOneParameterException' => '/phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php', + 'PHPUnit\\Framework\\ComparisonMethodDoesNotDeclareParameterTypeException' => '/phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareParameterTypeException.php', + 'PHPUnit\\Framework\\ComparisonMethodDoesNotExistException' => '/phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotExistException.php', + 'PHPUnit\\Framework\\Constraint\\ArrayComparison' => '/phpunit/Framework/Constraint/Array/ArrayComparison.php', + 'PHPUnit\\Framework\\Constraint\\ArrayHasKey' => '/phpunit/Framework/Constraint/Array/ArrayHasKey.php', + 'PHPUnit\\Framework\\Constraint\\ArraysAreEqual' => '/phpunit/Framework/Constraint/Array/ArraysAreEqual.php', + 'PHPUnit\\Framework\\Constraint\\ArraysAreIdentical' => '/phpunit/Framework/Constraint/Array/ArraysAreIdentical.php', + 'PHPUnit\\Framework\\Constraint\\BinaryOperator' => '/phpunit/Framework/Constraint/Operator/BinaryOperator.php', + 'PHPUnit\\Framework\\Constraint\\Callback' => '/phpunit/Framework/Constraint/Callback.php', + 'PHPUnit\\Framework\\Constraint\\Constraint' => '/phpunit/Framework/Constraint/Constraint.php', + 'PHPUnit\\Framework\\Constraint\\Count' => '/phpunit/Framework/Constraint/Cardinality/Count.php', + 'PHPUnit\\Framework\\Constraint\\DirectoryExists' => '/phpunit/Framework/Constraint/Filesystem/DirectoryExists.php', + 'PHPUnit\\Framework\\Constraint\\Exception' => '/phpunit/Framework/Constraint/Exception/Exception.php', + 'PHPUnit\\Framework\\Constraint\\ExceptionCode' => '/phpunit/Framework/Constraint/Exception/ExceptionCode.php', + 'PHPUnit\\Framework\\Constraint\\ExceptionMessageIsOrContains' => '/phpunit/Framework/Constraint/Exception/ExceptionMessageIsOrContains.php', + 'PHPUnit\\Framework\\Constraint\\ExceptionMessageMatchesRegularExpression' => '/phpunit/Framework/Constraint/Exception/ExceptionMessageMatchesRegularExpression.php', + 'PHPUnit\\Framework\\Constraint\\FileExists' => '/phpunit/Framework/Constraint/Filesystem/FileExists.php', + 'PHPUnit\\Framework\\Constraint\\GreaterThan' => '/phpunit/Framework/Constraint/Cardinality/GreaterThan.php', + 'PHPUnit\\Framework\\Constraint\\IsAnything' => '/phpunit/Framework/Constraint/IsAnything.php', + 'PHPUnit\\Framework\\Constraint\\IsEmpty' => '/phpunit/Framework/Constraint/Cardinality/IsEmpty.php', + 'PHPUnit\\Framework\\Constraint\\IsEqual' => '/phpunit/Framework/Constraint/Equality/IsEqual.php', + 'PHPUnit\\Framework\\Constraint\\IsEqualCanonicalizing' => '/phpunit/Framework/Constraint/Equality/IsEqualCanonicalizing.php', + 'PHPUnit\\Framework\\Constraint\\IsEqualIgnoringCase' => '/phpunit/Framework/Constraint/Equality/IsEqualIgnoringCase.php', + 'PHPUnit\\Framework\\Constraint\\IsEqualWithDelta' => '/phpunit/Framework/Constraint/Equality/IsEqualWithDelta.php', + 'PHPUnit\\Framework\\Constraint\\IsFalse' => '/phpunit/Framework/Constraint/Boolean/IsFalse.php', + 'PHPUnit\\Framework\\Constraint\\IsFinite' => '/phpunit/Framework/Constraint/Math/IsFinite.php', + 'PHPUnit\\Framework\\Constraint\\IsIdentical' => '/phpunit/Framework/Constraint/IsIdentical.php', + 'PHPUnit\\Framework\\Constraint\\IsInfinite' => '/phpunit/Framework/Constraint/Math/IsInfinite.php', + 'PHPUnit\\Framework\\Constraint\\IsInstanceOf' => '/phpunit/Framework/Constraint/Type/IsInstanceOf.php', + 'PHPUnit\\Framework\\Constraint\\IsJson' => '/phpunit/Framework/Constraint/String/IsJson.php', + 'PHPUnit\\Framework\\Constraint\\IsList' => '/phpunit/Framework/Constraint/Array/IsList.php', + 'PHPUnit\\Framework\\Constraint\\IsNan' => '/phpunit/Framework/Constraint/Math/IsNan.php', + 'PHPUnit\\Framework\\Constraint\\IsNull' => '/phpunit/Framework/Constraint/Type/IsNull.php', + 'PHPUnit\\Framework\\Constraint\\IsReadable' => '/phpunit/Framework/Constraint/Filesystem/IsReadable.php', + 'PHPUnit\\Framework\\Constraint\\IsTrue' => '/phpunit/Framework/Constraint/Boolean/IsTrue.php', + 'PHPUnit\\Framework\\Constraint\\IsType' => '/phpunit/Framework/Constraint/Type/IsType.php', + 'PHPUnit\\Framework\\Constraint\\IsWritable' => '/phpunit/Framework/Constraint/Filesystem/IsWritable.php', + 'PHPUnit\\Framework\\Constraint\\JsonMatches' => '/phpunit/Framework/Constraint/JsonMatches.php', + 'PHPUnit\\Framework\\Constraint\\LessThan' => '/phpunit/Framework/Constraint/Cardinality/LessThan.php', + 'PHPUnit\\Framework\\Constraint\\LogicalAnd' => '/phpunit/Framework/Constraint/Operator/LogicalAnd.php', + 'PHPUnit\\Framework\\Constraint\\LogicalNot' => '/phpunit/Framework/Constraint/Operator/LogicalNot.php', + 'PHPUnit\\Framework\\Constraint\\LogicalOr' => '/phpunit/Framework/Constraint/Operator/LogicalOr.php', + 'PHPUnit\\Framework\\Constraint\\LogicalXor' => '/phpunit/Framework/Constraint/Operator/LogicalXor.php', + 'PHPUnit\\Framework\\Constraint\\ObjectEquals' => '/phpunit/Framework/Constraint/Object/ObjectEquals.php', + 'PHPUnit\\Framework\\Constraint\\ObjectHasProperty' => '/phpunit/Framework/Constraint/Object/ObjectHasProperty.php', + 'PHPUnit\\Framework\\Constraint\\Operator' => '/phpunit/Framework/Constraint/Operator/Operator.php', + 'PHPUnit\\Framework\\Constraint\\RegularExpression' => '/phpunit/Framework/Constraint/String/RegularExpression.php', + 'PHPUnit\\Framework\\Constraint\\SameSize' => '/phpunit/Framework/Constraint/Cardinality/SameSize.php', + 'PHPUnit\\Framework\\Constraint\\StringContains' => '/phpunit/Framework/Constraint/String/StringContains.php', + 'PHPUnit\\Framework\\Constraint\\StringEndsWith' => '/phpunit/Framework/Constraint/String/StringEndsWith.php', + 'PHPUnit\\Framework\\Constraint\\StringEqualsStringIgnoringLineEndings' => '/phpunit/Framework/Constraint/String/StringEqualsStringIgnoringLineEndings.php', + 'PHPUnit\\Framework\\Constraint\\StringMatchesFormatDescription' => '/phpunit/Framework/Constraint/String/StringMatchesFormatDescription.php', + 'PHPUnit\\Framework\\Constraint\\StringStartsWith' => '/phpunit/Framework/Constraint/String/StringStartsWith.php', + 'PHPUnit\\Framework\\Constraint\\TraversableContains' => '/phpunit/Framework/Constraint/Traversable/TraversableContains.php', + 'PHPUnit\\Framework\\Constraint\\TraversableContainsEqual' => '/phpunit/Framework/Constraint/Traversable/TraversableContainsEqual.php', + 'PHPUnit\\Framework\\Constraint\\TraversableContainsIdentical' => '/phpunit/Framework/Constraint/Traversable/TraversableContainsIdentical.php', + 'PHPUnit\\Framework\\Constraint\\TraversableContainsOnly' => '/phpunit/Framework/Constraint/Traversable/TraversableContainsOnly.php', + 'PHPUnit\\Framework\\Constraint\\UnaryOperator' => '/phpunit/Framework/Constraint/Operator/UnaryOperator.php', + 'PHPUnit\\Framework\\DataProviderTestSuite' => '/phpunit/Framework/DataProviderTestSuite.php', + 'PHPUnit\\Framework\\EmptyStringException' => '/phpunit/Framework/Exception/EmptyStringException.php', + 'PHPUnit\\Framework\\ErrorLogNotWritableException' => '/phpunit/Framework/Exception/ErrorLogNotWritableException.php', + 'PHPUnit\\Framework\\Exception' => '/phpunit/Framework/Exception/Exception.php', + 'PHPUnit\\Framework\\ExecutionOrderDependency' => '/phpunit/Framework/ExecutionOrderDependency.php', + 'PHPUnit\\Framework\\ExpectationFailedException' => '/phpunit/Framework/Exception/ExpectationFailedException.php', + 'PHPUnit\\Framework\\GeneratorNotSupportedException' => '/phpunit/Framework/Exception/GeneratorNotSupportedException.php', + 'PHPUnit\\Framework\\IncompleteTest' => '/phpunit/Framework/Exception/Incomplete/IncompleteTest.php', + 'PHPUnit\\Framework\\IncompleteTestError' => '/phpunit/Framework/Exception/Incomplete/IncompleteTestError.php', + 'PHPUnit\\Framework\\InvalidArgumentException' => '/phpunit/Framework/Exception/InvalidArgumentException.php', + 'PHPUnit\\Framework\\InvalidDataProviderException' => '/phpunit/Framework/Exception/InvalidDataProviderException.php', + 'PHPUnit\\Framework\\InvalidDependencyException' => '/phpunit/Framework/Exception/InvalidDependencyException.php', + 'PHPUnit\\Framework\\MockObject\\AbstractInvocationImplementation' => '/phpunit/Framework/MockObject/Runtime/AbstractInvocationImplementation.php', + 'PHPUnit\\Framework\\MockObject\\BadMethodCallException' => '/phpunit/Framework/MockObject/Exception/BadMethodCallException.php', + 'PHPUnit\\Framework\\MockObject\\CannotUseOnlyMethodsException' => '/phpunit/Framework/MockObject/Exception/CannotUseOnlyMethodsException.php', + 'PHPUnit\\Framework\\MockObject\\ConfigurableMethod' => '/phpunit/Framework/MockObject/ConfigurableMethod.php', + 'PHPUnit\\Framework\\MockObject\\DoubledCloneMethod' => '/phpunit/Framework/MockObject/Runtime/Api/DoubledCloneMethod.php', + 'PHPUnit\\Framework\\MockObject\\Exception' => '/phpunit/Framework/MockObject/Exception/Exception.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\ClassIsAnonymousException' => '/phpunit/Framework/MockObject/Generator/Exception/ClassIsAnonymousException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\ClassIsEnumerationException' => '/phpunit/Framework/MockObject/Generator/Exception/ClassIsEnumerationException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\ClassIsFinalException' => '/phpunit/Framework/MockObject/Generator/Exception/ClassIsFinalException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\DoubledClass' => '/phpunit/Framework/MockObject/Generator/DoubledClass.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\DoubledMethod' => '/phpunit/Framework/MockObject/Generator/DoubledMethod.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\DoubledMethodSet' => '/phpunit/Framework/MockObject/Generator/DoubledMethodSet.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\DuplicateMethodException' => '/phpunit/Framework/MockObject/Generator/Exception/DuplicateMethodException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\Exception' => '/phpunit/Framework/MockObject/Generator/Exception/Exception.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\Generator' => '/phpunit/Framework/MockObject/Generator/Generator.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\HookedProperty' => '/phpunit/Framework/MockObject/Generator/HookedProperty.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\HookedPropertyGenerator' => '/phpunit/Framework/MockObject/Generator/HookedPropertyGenerator.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\InvalidClassNameException' => '/phpunit/Framework/MockObject/Generator/Exception/InvalidClassNameException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\InvalidMethodNameException' => '/phpunit/Framework/MockObject/Generator/Exception/InvalidMethodNameException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\MethodNamedMethodException' => '/phpunit/Framework/MockObject/Generator/Exception/MethodNamedMethodException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\NameAlreadyInUseException' => '/phpunit/Framework/MockObject/Generator/Exception/NameAlreadyInUseException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\ReflectionException' => '/phpunit/Framework/MockObject/Generator/Exception/ReflectionException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\RuntimeException' => '/phpunit/Framework/MockObject/Generator/Exception/RuntimeException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\TemplateLoader' => '/phpunit/Framework/MockObject/Generator/TemplateLoader.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\UnknownInterfaceException' => '/phpunit/Framework/MockObject/Generator/Exception/UnknownInterfaceException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\UnknownTypeException' => '/phpunit/Framework/MockObject/Generator/Exception/UnknownTypeException.php', + 'PHPUnit\\Framework\\MockObject\\IncompatibleReturnValueException' => '/phpunit/Framework/MockObject/Exception/IncompatibleReturnValueException.php', + 'PHPUnit\\Framework\\MockObject\\Invocation' => '/phpunit/Framework/MockObject/Runtime/Invocation.php', + 'PHPUnit\\Framework\\MockObject\\InvocationHandler' => '/phpunit/Framework/MockObject/Runtime/InvocationHandler.php', + 'PHPUnit\\Framework\\MockObject\\InvocationMocker' => '/phpunit/Framework/MockObject/Runtime/Interface/InvocationMocker.php', + 'PHPUnit\\Framework\\MockObject\\InvocationMockerImplementation' => '/phpunit/Framework/MockObject/Runtime/InvocationMockerImplementation.php', + 'PHPUnit\\Framework\\MockObject\\InvocationStubber' => '/phpunit/Framework/MockObject/Runtime/Interface/InvocationStubber.php', + 'PHPUnit\\Framework\\MockObject\\InvocationStubberImplementation' => '/phpunit/Framework/MockObject/Runtime/InvocationStubberImplementation.php', + 'PHPUnit\\Framework\\MockObject\\MatchBuilderNotFoundException' => '/phpunit/Framework/MockObject/Exception/MatchBuilderNotFoundException.php', + 'PHPUnit\\Framework\\MockObject\\Matcher' => '/phpunit/Framework/MockObject/Runtime/Matcher.php', + 'PHPUnit\\Framework\\MockObject\\MatcherAlreadyRegisteredException' => '/phpunit/Framework/MockObject/Exception/MatcherAlreadyRegisteredException.php', + 'PHPUnit\\Framework\\MockObject\\Method' => '/phpunit/Framework/MockObject/Runtime/Api/Method.php', + 'PHPUnit\\Framework\\MockObject\\MethodCannotBeConfiguredException' => '/phpunit/Framework/MockObject/Exception/MethodCannotBeConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\MethodNameAlreadyConfiguredException' => '/phpunit/Framework/MockObject/Exception/MethodNameAlreadyConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\MethodNameConstraint' => '/phpunit/Framework/MockObject/Runtime/MethodNameConstraint.php', + 'PHPUnit\\Framework\\MockObject\\MethodNameNotConfiguredException' => '/phpunit/Framework/MockObject/Exception/MethodNameNotConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\MethodParametersAlreadyConfiguredException' => '/phpunit/Framework/MockObject/Exception/MethodParametersAlreadyConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\MockBuilder' => '/phpunit/Framework/MockObject/MockBuilder.php', + 'PHPUnit\\Framework\\MockObject\\MockObject' => '/phpunit/Framework/MockObject/Runtime/Interface/MockObject.php', + 'PHPUnit\\Framework\\MockObject\\MockObjectApi' => '/phpunit/Framework/MockObject/Runtime/Api/MockObjectApi.php', + 'PHPUnit\\Framework\\MockObject\\MockObjectInternal' => '/phpunit/Framework/MockObject/Runtime/Interface/MockObjectInternal.php', + 'PHPUnit\\Framework\\MockObject\\NeverReturningMethodException' => '/phpunit/Framework/MockObject/Exception/NeverReturningMethodException.php', + 'PHPUnit\\Framework\\MockObject\\NoMoreParameterSetsConfiguredException' => '/phpunit/Framework/MockObject/Exception/NoMoreParameterSetsConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\NoMoreReturnValuesConfiguredException' => '/phpunit/Framework/MockObject/Exception/NoMoreReturnValuesConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\ProxiedCloneMethod' => '/phpunit/Framework/MockObject/Runtime/Api/ProxiedCloneMethod.php', + 'PHPUnit\\Framework\\MockObject\\ReturnValueGenerator' => '/phpunit/Framework/MockObject/Runtime/ReturnValueGenerator.php', + 'PHPUnit\\Framework\\MockObject\\ReturnValueNotConfiguredException' => '/phpunit/Framework/MockObject/Exception/ReturnValueNotConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\AnyInvokedCount' => '/phpunit/Framework/MockObject/Runtime/Rule/AnyInvokedCount.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\AnyParameters' => '/phpunit/Framework/MockObject/Runtime/Rule/AnyParameters.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\InvocationOrder' => '/phpunit/Framework/MockObject/Runtime/Rule/InvocationOrder.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtLeastCount' => '/phpunit/Framework/MockObject/Runtime/Rule/InvokedAtLeastCount.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtLeastOnce' => '/phpunit/Framework/MockObject/Runtime/Rule/InvokedAtLeastOnce.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtMostCount' => '/phpunit/Framework/MockObject/Runtime/Rule/InvokedAtMostCount.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\InvokedCount' => '/phpunit/Framework/MockObject/Runtime/Rule/InvokedCount.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\MethodName' => '/phpunit/Framework/MockObject/Runtime/Rule/MethodName.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\OrderedParameterSets' => '/phpunit/Framework/MockObject/Runtime/Rule/OrderedParameterSets.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\Parameters' => '/phpunit/Framework/MockObject/Runtime/Rule/Parameters.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\ParametersRule' => '/phpunit/Framework/MockObject/Runtime/Rule/ParametersRule.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\UnorderedParameterSets' => '/phpunit/Framework/MockObject/Runtime/Rule/UnorderedParameterSets.php', + 'PHPUnit\\Framework\\MockObject\\RuntimeException' => '/phpunit/Framework/MockObject/Exception/RuntimeException.php', + 'PHPUnit\\Framework\\MockObject\\Runtime\\PropertyGetHook' => '/phpunit/Framework/MockObject/Runtime/PropertyHook/PropertyGetHook.php', + 'PHPUnit\\Framework\\MockObject\\Runtime\\PropertyHook' => '/phpunit/Framework/MockObject/Runtime/PropertyHook/PropertyHook.php', + 'PHPUnit\\Framework\\MockObject\\Runtime\\PropertySetHook' => '/phpunit/Framework/MockObject/Runtime/PropertyHook/PropertySetHook.php', + 'PHPUnit\\Framework\\MockObject\\Stub' => '/phpunit/Framework/MockObject/Runtime/Interface/Stub.php', + 'PHPUnit\\Framework\\MockObject\\StubApi' => '/phpunit/Framework/MockObject/Runtime/Api/StubApi.php', + 'PHPUnit\\Framework\\MockObject\\StubInternal' => '/phpunit/Framework/MockObject/Runtime/Interface/StubInternal.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ConsecutiveCalls' => '/phpunit/Framework/MockObject/Runtime/Stub/ConsecutiveCalls.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\Exception' => '/phpunit/Framework/MockObject/Runtime/Stub/Exception.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnArgument' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnArgument.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnCallback' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnCallback.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnReference' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnReference.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnSelf' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnSelf.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnStub' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnStub.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnValueMap' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnValueMap.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\Stub' => '/phpunit/Framework/MockObject/Runtime/Stub/Stub.php', + 'PHPUnit\\Framework\\MockObject\\TestDoubleBuilder' => '/phpunit/Framework/MockObject/TestDoubleBuilder.php', + 'PHPUnit\\Framework\\MockObject\\TestDoubleSealedException' => '/phpunit/Framework/MockObject/Exception/TestDoubleSealedException.php', + 'PHPUnit\\Framework\\MockObject\\TestDoubleState' => '/phpunit/Framework/MockObject/Runtime/Api/TestDoubleState.php', + 'PHPUnit\\Framework\\MockObject\\TestStubBuilder' => '/phpunit/Framework/MockObject/TestStubBuilder.php', + 'PHPUnit\\Framework\\NativeType' => '/phpunit/Framework/NativeType.php', + 'PHPUnit\\Framework\\NoChildTestSuiteException' => '/phpunit/Framework/Exception/NoChildTestSuiteException.php', + 'PHPUnit\\Framework\\PhptAssertionFailedError' => '/phpunit/Framework/Exception/PhptAssertionFailedError.php', + 'PHPUnit\\Framework\\ProcessIsolationException' => '/phpunit/Framework/Exception/ProcessIsolationException.php', + 'PHPUnit\\Framework\\Reorderable' => '/phpunit/Framework/Reorderable.php', + 'PHPUnit\\Framework\\SelfDescribing' => '/phpunit/Framework/SelfDescribing.php', + 'PHPUnit\\Framework\\SeparateProcessTestRunner' => '/phpunit/Framework/TestRunner/SeparateProcessTestRunner.php', + 'PHPUnit\\Framework\\SkippedTest' => '/phpunit/Framework/Exception/Skipped/SkippedTest.php', + 'PHPUnit\\Framework\\SkippedTestSuiteError' => '/phpunit/Framework/Exception/Skipped/SkippedTestSuiteError.php', + 'PHPUnit\\Framework\\SkippedWithMessageException' => '/phpunit/Framework/Exception/Skipped/SkippedWithMessageException.php', + 'PHPUnit\\Framework\\Test' => '/phpunit/Framework/Test.php', + 'PHPUnit\\Framework\\TestBuilder' => '/phpunit/Framework/TestBuilder.php', + 'PHPUnit\\Framework\\TestCase' => '/phpunit/Framework/TestCase.php', + 'PHPUnit\\Framework\\TestRunner' => '/phpunit/Framework/TestRunner/TestRunner.php', + 'PHPUnit\\Framework\\TestSize\\Known' => '/phpunit/Framework/TestSize/Known.php', + 'PHPUnit\\Framework\\TestSize\\Large' => '/phpunit/Framework/TestSize/Large.php', + 'PHPUnit\\Framework\\TestSize\\Medium' => '/phpunit/Framework/TestSize/Medium.php', + 'PHPUnit\\Framework\\TestSize\\Small' => '/phpunit/Framework/TestSize/Small.php', + 'PHPUnit\\Framework\\TestSize\\TestSize' => '/phpunit/Framework/TestSize/TestSize.php', + 'PHPUnit\\Framework\\TestSize\\Unknown' => '/phpunit/Framework/TestSize/Unknown.php', + 'PHPUnit\\Framework\\TestStatus\\Deprecation' => '/phpunit/Framework/TestStatus/Deprecation.php', + 'PHPUnit\\Framework\\TestStatus\\Error' => '/phpunit/Framework/TestStatus/Error.php', + 'PHPUnit\\Framework\\TestStatus\\Failure' => '/phpunit/Framework/TestStatus/Failure.php', + 'PHPUnit\\Framework\\TestStatus\\Incomplete' => '/phpunit/Framework/TestStatus/Incomplete.php', + 'PHPUnit\\Framework\\TestStatus\\Known' => '/phpunit/Framework/TestStatus/Known.php', + 'PHPUnit\\Framework\\TestStatus\\Notice' => '/phpunit/Framework/TestStatus/Notice.php', + 'PHPUnit\\Framework\\TestStatus\\Risky' => '/phpunit/Framework/TestStatus/Risky.php', + 'PHPUnit\\Framework\\TestStatus\\Skipped' => '/phpunit/Framework/TestStatus/Skipped.php', + 'PHPUnit\\Framework\\TestStatus\\Success' => '/phpunit/Framework/TestStatus/Success.php', + 'PHPUnit\\Framework\\TestStatus\\TestStatus' => '/phpunit/Framework/TestStatus/TestStatus.php', + 'PHPUnit\\Framework\\TestStatus\\Unknown' => '/phpunit/Framework/TestStatus/Unknown.php', + 'PHPUnit\\Framework\\TestStatus\\Warning' => '/phpunit/Framework/TestStatus/Warning.php', + 'PHPUnit\\Framework\\TestSuite' => '/phpunit/Framework/TestSuite.php', + 'PHPUnit\\Framework\\TestSuiteIterator' => '/phpunit/Framework/TestSuiteIterator.php', + 'PHPUnit\\Framework\\UnknownClassOrInterfaceException' => '/phpunit/Framework/Exception/UnknownClassOrInterfaceException.php', + 'PHPUnit\\Framework\\UnknownNativeTypeException' => '/phpunit/Framework/Exception/UnknownNativeTypeException.php', + 'PHPUnit\\Logging\\EventLogger' => '/phpunit/Logging/EventLogger.php', + 'PHPUnit\\Logging\\JUnit\\JunitXmlLogger' => '/phpunit/Logging/JUnit/JunitXmlLogger.php', + 'PHPUnit\\Logging\\JUnit\\Subscriber' => '/phpunit/Logging/JUnit/Subscriber/Subscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestErroredSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestFailedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestFinishedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestMarkedIncompleteSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestPreparationErroredSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestPreparationErroredSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestPreparationFailedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestPreparationFailedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestPreparationStartedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestPreparationStartedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestPreparedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestPrintedUnexpectedOutputSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestPrintedUnexpectedOutputSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestRunnerExecutionFinishedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestRunnerExecutionFinishedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestSkippedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestSuiteFinishedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestSuiteFinishedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestSuiteSkippedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestSuiteSkippedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestSuiteStartedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestSuiteStartedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\AfterLastTestMethodErroredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodErroredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\AfterLastTestMethodFailedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodFailedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\BeforeFirstTestMethodErroredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodErroredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\BeforeFirstTestMethodFailedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodFailedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\CannotOpenUriForWritingException' => '/phpunit/Logging/OpenTestReporting/Exception/CannotOpenUriForWritingException.php', + 'PHPUnit\\Logging\\OpenTestReporting\\Exception' => '/phpunit/Logging/OpenTestReporting/Exception/Exception.php', + 'PHPUnit\\Logging\\OpenTestReporting\\OtrXmlLogger' => '/phpunit/Logging/OpenTestReporting/OtrXmlLogger.php', + 'PHPUnit\\Logging\\OpenTestReporting\\Status' => '/phpunit/Logging/OpenTestReporting/Status.php', + 'PHPUnit\\Logging\\OpenTestReporting\\Subscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/Subscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestAbortedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestAbortedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestConsideredRiskySubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestDeprecationTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestDeprecationTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestErrorTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestErrorTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestErroredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestFailedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestFinishedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestNoticeTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestNoticeTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpDeprecationTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpDeprecationTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpNoticeTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpNoticeTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpWarningTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpWarningTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpunitDeprecationTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitDeprecationTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpunitErrorTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitErrorTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpunitNoticeTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitNoticeTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpunitWarningTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitWarningTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPreparationErroredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPreparationErroredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPreparationFailedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPreparationFailedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPreparedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPrintedUnexpectedOutputSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPrintedUnexpectedOutputSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestRunnerFinishedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestRunnerFinishedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestRunnerStartedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestRunnerStartedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestSkippedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestSuiteFinishedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestSuiteFinishedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestSuiteSkippedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestSuiteSkippedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestSuiteStartedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestSuiteStartedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestWarningTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestWarningTriggeredSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\Subscriber' => '/phpunit/Logging/TeamCity/Subscriber/Subscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TeamCityLogger' => '/phpunit/Logging/TeamCity/TeamCityLogger.php', + 'PHPUnit\\Logging\\TeamCity\\TestConsideredRiskySubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestErroredSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestFailedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestFinishedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestMarkedIncompleteSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestPreparationErroredSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestPreparationErroredSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestPreparationFailedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestPreparationFailedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestPreparationStartedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestPreparationStartedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestPreparedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestRunnerExecutionFinishedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestRunnerExecutionFinishedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSkippedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSuiteBeforeFirstTestMethodErroredSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSuiteBeforeFirstTestMethodErroredSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSuiteBeforeFirstTestMethodFailedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSuiteBeforeFirstTestMethodFailedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSuiteFinishedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSuiteFinishedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSuiteSkippedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSuiteSkippedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSuiteStartedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSuiteStartedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\HtmlRenderer' => '/phpunit/Logging/TestDox/HtmlRenderer.php', + 'PHPUnit\\Logging\\TestDox\\NamePrettifier' => '/phpunit/Logging/TestDox/NamePrettifier.php', + 'PHPUnit\\Logging\\TestDox\\PlainTextRenderer' => '/phpunit/Logging/TestDox/PlainTextRenderer.php', + 'PHPUnit\\Logging\\TestDox\\Subscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/Subscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestConsideredRiskySubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestErroredSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestFailedSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestFinishedSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestMarkedIncompleteSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestPassedSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestPassedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestPreparedSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestResult' => '/phpunit/Logging/TestDox/TestResult/TestResult.php', + 'PHPUnit\\Logging\\TestDox\\TestResultCollection' => '/phpunit/Logging/TestDox/TestResult/TestResultCollection.php', + 'PHPUnit\\Logging\\TestDox\\TestResultCollectionIterator' => '/phpunit/Logging/TestDox/TestResult/TestResultCollectionIterator.php', + 'PHPUnit\\Logging\\TestDox\\TestResultCollector' => '/phpunit/Logging/TestDox/TestResult/TestResultCollector.php', + 'PHPUnit\\Logging\\TestDox\\TestSkippedSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredDeprecationSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredNoticeSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpDeprecationSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpNoticeSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpWarningSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpunitDeprecationSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpunitErrorSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpunitWarningSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredWarningSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredWarningSubscriber.php', + 'PHPUnit\\Metadata\\After' => '/phpunit/Metadata/After.php', + 'PHPUnit\\Metadata\\AfterClass' => '/phpunit/Metadata/AfterClass.php', + 'PHPUnit\\Metadata\\AllowMockObjectsWithoutExpectations' => '/phpunit/Metadata/AllowMockObjectsWithoutExpectations.php', + 'PHPUnit\\Metadata\\Api\\CodeCoverage' => '/phpunit/Metadata/Api/CodeCoverage.php', + 'PHPUnit\\Metadata\\Api\\DataProvider' => '/phpunit/Metadata/Api/DataProvider.php', + 'PHPUnit\\Metadata\\Api\\Dependencies' => '/phpunit/Metadata/Api/Dependencies.php', + 'PHPUnit\\Metadata\\Api\\Groups' => '/phpunit/Metadata/Api/Groups.php', + 'PHPUnit\\Metadata\\Api\\HookMethods' => '/phpunit/Metadata/Api/HookMethods.php', + 'PHPUnit\\Metadata\\Api\\ProvidedData' => '/phpunit/Metadata/Api/ProvidedData.php', + 'PHPUnit\\Metadata\\Api\\Requirements' => '/phpunit/Metadata/Api/Requirements.php', + 'PHPUnit\\Metadata\\BackupGlobals' => '/phpunit/Metadata/BackupGlobals.php', + 'PHPUnit\\Metadata\\BackupStaticProperties' => '/phpunit/Metadata/BackupStaticProperties.php', + 'PHPUnit\\Metadata\\Before' => '/phpunit/Metadata/Before.php', + 'PHPUnit\\Metadata\\BeforeClass' => '/phpunit/Metadata/BeforeClass.php', + 'PHPUnit\\Metadata\\CoversClass' => '/phpunit/Metadata/CoversClass.php', + 'PHPUnit\\Metadata\\CoversClassesThatExtendClass' => '/phpunit/Metadata/CoversClassesThatExtendClass.php', + 'PHPUnit\\Metadata\\CoversClassesThatImplementInterface' => '/phpunit/Metadata/CoversClassesThatImplementInterface.php', + 'PHPUnit\\Metadata\\CoversFunction' => '/phpunit/Metadata/CoversFunction.php', + 'PHPUnit\\Metadata\\CoversMethod' => '/phpunit/Metadata/CoversMethod.php', + 'PHPUnit\\Metadata\\CoversNamespace' => '/phpunit/Metadata/CoversNamespace.php', + 'PHPUnit\\Metadata\\CoversNothing' => '/phpunit/Metadata/CoversNothing.php', + 'PHPUnit\\Metadata\\CoversTrait' => '/phpunit/Metadata/CoversTrait.php', + 'PHPUnit\\Metadata\\DataProvider' => '/phpunit/Metadata/DataProvider.php', + 'PHPUnit\\Metadata\\DataProviderClosure' => '/phpunit/Metadata/DataProviderClosure.php', + 'PHPUnit\\Metadata\\DependsOnClass' => '/phpunit/Metadata/DependsOnClass.php', + 'PHPUnit\\Metadata\\DependsOnMethod' => '/phpunit/Metadata/DependsOnMethod.php', + 'PHPUnit\\Metadata\\DisableReturnValueGenerationForTestDoubles' => '/phpunit/Metadata/DisableReturnValueGenerationForTestDoubles.php', + 'PHPUnit\\Metadata\\DoesNotPerformAssertions' => '/phpunit/Metadata/DoesNotPerformAssertions.php', + 'PHPUnit\\Metadata\\Exception' => '/phpunit/Metadata/Exception/Exception.php', + 'PHPUnit\\Metadata\\ExcludeGlobalVariableFromBackup' => '/phpunit/Metadata/ExcludeGlobalVariableFromBackup.php', + 'PHPUnit\\Metadata\\ExcludeStaticPropertyFromBackup' => '/phpunit/Metadata/ExcludeStaticPropertyFromBackup.php', + 'PHPUnit\\Metadata\\Group' => '/phpunit/Metadata/Group.php', + 'PHPUnit\\Metadata\\IgnoreDeprecations' => '/phpunit/Metadata/IgnoreDeprecations.php', + 'PHPUnit\\Metadata\\IgnorePhpunitDeprecations' => '/phpunit/Metadata/IgnorePhpunitDeprecations.php', + 'PHPUnit\\Metadata\\IgnorePhpunitWarnings' => '/phpunit/Metadata/IgnorePhpunitWarnings.php', + 'PHPUnit\\Metadata\\InvalidAttributeException' => '/phpunit/Metadata/Exception/InvalidAttributeException.php', + 'PHPUnit\\Metadata\\InvalidVersionRequirementException' => '/phpunit/Metadata/Exception/InvalidVersionRequirementException.php', + 'PHPUnit\\Metadata\\Level' => '/phpunit/Metadata/Level.php', + 'PHPUnit\\Metadata\\Metadata' => '/phpunit/Metadata/Metadata.php', + 'PHPUnit\\Metadata\\MetadataCollection' => '/phpunit/Metadata/MetadataCollection.php', + 'PHPUnit\\Metadata\\MetadataCollectionIterator' => '/phpunit/Metadata/MetadataCollectionIterator.php', + 'PHPUnit\\Metadata\\NoVersionRequirementException' => '/phpunit/Metadata/Exception/NoVersionRequirementException.php', + 'PHPUnit\\Metadata\\Parser\\AttributeParser' => '/phpunit/Metadata/Parser/AttributeParser.php', + 'PHPUnit\\Metadata\\Parser\\CachingParser' => '/phpunit/Metadata/Parser/CachingParser.php', + 'PHPUnit\\Metadata\\Parser\\Parser' => '/phpunit/Metadata/Parser/Parser.php', + 'PHPUnit\\Metadata\\Parser\\Registry' => '/phpunit/Metadata/Parser/Registry.php', + 'PHPUnit\\Metadata\\PostCondition' => '/phpunit/Metadata/PostCondition.php', + 'PHPUnit\\Metadata\\PreCondition' => '/phpunit/Metadata/PreCondition.php', + 'PHPUnit\\Metadata\\PreserveGlobalState' => '/phpunit/Metadata/PreserveGlobalState.php', + 'PHPUnit\\Metadata\\RequiresEnvironmentVariable' => '/phpunit/Metadata/RequiresEnvironmentVariable.php', + 'PHPUnit\\Metadata\\RequiresFunction' => '/phpunit/Metadata/RequiresFunction.php', + 'PHPUnit\\Metadata\\RequiresMethod' => '/phpunit/Metadata/RequiresMethod.php', + 'PHPUnit\\Metadata\\RequiresOperatingSystem' => '/phpunit/Metadata/RequiresOperatingSystem.php', + 'PHPUnit\\Metadata\\RequiresOperatingSystemFamily' => '/phpunit/Metadata/RequiresOperatingSystemFamily.php', + 'PHPUnit\\Metadata\\RequiresPhp' => '/phpunit/Metadata/RequiresPhp.php', + 'PHPUnit\\Metadata\\RequiresPhpExtension' => '/phpunit/Metadata/RequiresPhpExtension.php', + 'PHPUnit\\Metadata\\RequiresPhpunit' => '/phpunit/Metadata/RequiresPhpunit.php', + 'PHPUnit\\Metadata\\RequiresPhpunitExtension' => '/phpunit/Metadata/RequiresPhpunitExtension.php', + 'PHPUnit\\Metadata\\RequiresSetting' => '/phpunit/Metadata/RequiresSetting.php', + 'PHPUnit\\Metadata\\RunInSeparateProcess' => '/phpunit/Metadata/RunInSeparateProcess.php', + 'PHPUnit\\Metadata\\RunTestsInSeparateProcesses' => '/phpunit/Metadata/RunTestsInSeparateProcesses.php', + 'PHPUnit\\Metadata\\Test' => '/phpunit/Metadata/Test.php', + 'PHPUnit\\Metadata\\TestDox' => '/phpunit/Metadata/TestDox.php', + 'PHPUnit\\Metadata\\TestDoxFormatter' => '/phpunit/Metadata/TestDoxFormatter.php', + 'PHPUnit\\Metadata\\TestWith' => '/phpunit/Metadata/TestWith.php', + 'PHPUnit\\Metadata\\UsesClass' => '/phpunit/Metadata/UsesClass.php', + 'PHPUnit\\Metadata\\UsesClassesThatExtendClass' => '/phpunit/Metadata/UsesClassesThatExtendClass.php', + 'PHPUnit\\Metadata\\UsesClassesThatImplementInterface' => '/phpunit/Metadata/UsesClassesThatImplementInterface.php', + 'PHPUnit\\Metadata\\UsesFunction' => '/phpunit/Metadata/UsesFunction.php', + 'PHPUnit\\Metadata\\UsesMethod' => '/phpunit/Metadata/UsesMethod.php', + 'PHPUnit\\Metadata\\UsesNamespace' => '/phpunit/Metadata/UsesNamespace.php', + 'PHPUnit\\Metadata\\UsesTrait' => '/phpunit/Metadata/UsesTrait.php', + 'PHPUnit\\Metadata\\Version\\ComparisonRequirement' => '/phpunit/Metadata/Version/ComparisonRequirement.php', + 'PHPUnit\\Metadata\\Version\\ConstraintRequirement' => '/phpunit/Metadata/Version/ConstraintRequirement.php', + 'PHPUnit\\Metadata\\Version\\Requirement' => '/phpunit/Metadata/Version/Requirement.php', + 'PHPUnit\\Metadata\\WithEnvironmentVariable' => '/phpunit/Metadata/WithEnvironmentVariable.php', + 'PHPUnit\\Metadata\\WithoutErrorHandler' => '/phpunit/Metadata/WithoutErrorHandler.php', + 'PHPUnit\\Runner\\BackedUpEnvironmentVariable' => '/phpunit/Runner/BackedUpEnvironmentVariable.php', + 'PHPUnit\\Runner\\Baseline\\Baseline' => '/phpunit/Runner/Baseline/Baseline.php', + 'PHPUnit\\Runner\\Baseline\\CannotLoadBaselineException' => '/phpunit/Runner/Baseline/Exception/CannotLoadBaselineException.php', + 'PHPUnit\\Runner\\Baseline\\CannotWriteBaselineException' => '/phpunit/Runner/Baseline/Exception/CannotWriteBaselineException.php', + 'PHPUnit\\Runner\\Baseline\\FileDoesNotHaveLineException' => '/phpunit/Runner/Baseline/Exception/FileDoesNotHaveLineException.php', + 'PHPUnit\\Runner\\Baseline\\Generator' => '/phpunit/Runner/Baseline/Generator.php', + 'PHPUnit\\Runner\\Baseline\\Issue' => '/phpunit/Runner/Baseline/Issue.php', + 'PHPUnit\\Runner\\Baseline\\Reader' => '/phpunit/Runner/Baseline/Reader.php', + 'PHPUnit\\Runner\\Baseline\\RelativePathCalculator' => '/phpunit/Runner/Baseline/RelativePathCalculator.php', + 'PHPUnit\\Runner\\Baseline\\Subscriber' => '/phpunit/Runner/Baseline/Subscriber/Subscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredDeprecationSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredDeprecationSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredNoticeSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredNoticeSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredPhpDeprecationSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredPhpDeprecationSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredPhpNoticeSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredPhpNoticeSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredPhpWarningSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredPhpWarningSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredWarningSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredWarningSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\Writer' => '/phpunit/Runner/Baseline/Writer.php', + 'PHPUnit\\Runner\\ClassCannotBeFoundException' => '/phpunit/Runner/Exception/ClassCannotBeFoundException.php', + 'PHPUnit\\Runner\\ClassDoesNotExtendTestCaseException' => '/phpunit/Runner/Exception/ClassDoesNotExtendTestCaseException.php', + 'PHPUnit\\Runner\\ClassIsAbstractException' => '/phpunit/Runner/Exception/ClassIsAbstractException.php', + 'PHPUnit\\Runner\\CodeCoverage' => '/phpunit/Runner/CodeCoverage.php', + 'PHPUnit\\Runner\\CodeCoverageFileExistsException' => '/phpunit/Runner/Exception/CodeCoverageFileExistsException.php', + 'PHPUnit\\Runner\\CodeCoverageInitializationStatus' => '/phpunit/Runner/CodeCoverageInitializationStatus.php', + 'PHPUnit\\Runner\\DeprecationCollector\\Collector' => '/phpunit/Runner/DeprecationCollector/Collector.php', + 'PHPUnit\\Runner\\DeprecationCollector\\Facade' => '/phpunit/Runner/DeprecationCollector/Facade.php', + 'PHPUnit\\Runner\\DeprecationCollector\\InIsolationCollector' => '/phpunit/Runner/DeprecationCollector/InIsolationCollector.php', + 'PHPUnit\\Runner\\DeprecationCollector\\Subscriber' => '/phpunit/Runner/DeprecationCollector/Subscriber/Subscriber.php', + 'PHPUnit\\Runner\\DeprecationCollector\\TestPreparedSubscriber' => '/phpunit/Runner/DeprecationCollector/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Runner\\DeprecationCollector\\TestTriggeredDeprecationSubscriber' => '/phpunit/Runner/DeprecationCollector/Subscriber/TestTriggeredDeprecationSubscriber.php', + 'PHPUnit\\Runner\\DirectoryDoesNotExistException' => '/phpunit/Runner/Exception/DirectoryDoesNotExistException.php', + 'PHPUnit\\Runner\\ErrorException' => '/phpunit/Runner/Exception/ErrorException.php', + 'PHPUnit\\Runner\\ErrorHandler' => '/phpunit/Runner/ErrorHandler.php', + 'PHPUnit\\Runner\\Exception' => '/phpunit/Runner/Exception/Exception.php', + 'PHPUnit\\Runner\\Extension\\Extension' => '/phpunit/Runner/Extension/Extension.php', + 'PHPUnit\\Runner\\Extension\\ExtensionBootstrapper' => '/phpunit/Runner/Extension/ExtensionBootstrapper.php', + 'PHPUnit\\Runner\\Extension\\ExtensionFacade' => '/phpunit/Runner/Extension/ExtensionFacade.php', + 'PHPUnit\\Runner\\Extension\\Facade' => '/phpunit/Runner/Extension/Facade.php', + 'PHPUnit\\Runner\\Extension\\ParameterCollection' => '/phpunit/Runner/Extension/ParameterCollection.php', + 'PHPUnit\\Runner\\Extension\\PharLoader' => '/phpunit/Runner/Extension/PharLoader.php', + 'PHPUnit\\Runner\\FileDoesNotExistException' => '/phpunit/Runner/Exception/FileDoesNotExistException.php', + 'PHPUnit\\Runner\\Filter\\ExcludeGroupFilterIterator' => '/phpunit/Runner/Filter/ExcludeGroupFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\ExcludeNameFilterIterator' => '/phpunit/Runner/Filter/ExcludeNameFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\Factory' => '/phpunit/Runner/Filter/Factory.php', + 'PHPUnit\\Runner\\Filter\\GroupFilterIterator' => '/phpunit/Runner/Filter/GroupFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\IncludeGroupFilterIterator' => '/phpunit/Runner/Filter/IncludeGroupFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\IncludeNameFilterIterator' => '/phpunit/Runner/Filter/IncludeNameFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\NameFilterIterator' => '/phpunit/Runner/Filter/NameFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\TestIdFilterIterator' => '/phpunit/Runner/Filter/TestIdFilterIterator.php', + 'PHPUnit\\Runner\\GarbageCollection\\ExecutionFinishedSubscriber' => '/phpunit/Runner/GarbageCollection/Subscriber/ExecutionFinishedSubscriber.php', + 'PHPUnit\\Runner\\GarbageCollection\\ExecutionStartedSubscriber' => '/phpunit/Runner/GarbageCollection/Subscriber/ExecutionStartedSubscriber.php', + 'PHPUnit\\Runner\\GarbageCollection\\GarbageCollectionHandler' => '/phpunit/Runner/GarbageCollection/GarbageCollectionHandler.php', + 'PHPUnit\\Runner\\GarbageCollection\\Subscriber' => '/phpunit/Runner/GarbageCollection/Subscriber/Subscriber.php', + 'PHPUnit\\Runner\\GarbageCollection\\TestFinishedSubscriber' => '/phpunit/Runner/GarbageCollection/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Runner\\HookMethod' => '/phpunit/Runner/HookMethod/HookMethod.php', + 'PHPUnit\\Runner\\HookMethodCollection' => '/phpunit/Runner/HookMethod/HookMethodCollection.php', + 'PHPUnit\\Runner\\InvalidOrderException' => '/phpunit/Runner/Exception/InvalidOrderException.php', + 'PHPUnit\\Runner\\IssueTriggerResolver\\DefaultResolver' => '/phpunit/Runner/IssueTriggerResolver/DefaultResolver.php', + 'PHPUnit\\Runner\\IssueTriggerResolver\\Resolution' => '/phpunit/Runner/IssueTriggerResolver/Resolution.php', + 'PHPUnit\\Runner\\IssueTriggerResolver\\Resolver' => '/phpunit/Runner/IssueTriggerResolver/Resolver.php', + 'PHPUnit\\Runner\\ParameterDoesNotExistException' => '/phpunit/Runner/Exception/ParameterDoesNotExistException.php', + 'PHPUnit\\Runner\\Phpt\\InvalidPhptFileException' => '/phpunit/Runner/Phpt/Exception/InvalidPhptFileException.php', + 'PHPUnit\\Runner\\Phpt\\Parser' => '/phpunit/Runner/Phpt/Parser.php', + 'PHPUnit\\Runner\\Phpt\\PhptExternalFileCannotBeLoadedException' => '/phpunit/Runner/Phpt/Exception/PhptExternalFileCannotBeLoadedException.php', + 'PHPUnit\\Runner\\Phpt\\Renderer' => '/phpunit/Runner/Phpt/Renderer.php', + 'PHPUnit\\Runner\\Phpt\\TestCase' => '/phpunit/Runner/Phpt/TestCase.php', + 'PHPUnit\\Runner\\Phpt\\UnsupportedPhptSectionException' => '/phpunit/Runner/Phpt/Exception/UnsupportedPhptSectionException.php', + 'PHPUnit\\Runner\\ResultCache\\DefaultResultCache' => '/phpunit/Runner/ResultCache/DefaultResultCache.php', + 'PHPUnit\\Runner\\ResultCache\\NullResultCache' => '/phpunit/Runner/ResultCache/NullResultCache.php', + 'PHPUnit\\Runner\\ResultCache\\ResultCache' => '/phpunit/Runner/ResultCache/ResultCache.php', + 'PHPUnit\\Runner\\ResultCache\\ResultCacheHandler' => '/phpunit/Runner/ResultCache/ResultCacheHandler.php', + 'PHPUnit\\Runner\\ResultCache\\ResultCacheId' => '/phpunit/Runner/ResultCache/ResultCacheId.php', + 'PHPUnit\\Runner\\ResultCache\\Subscriber' => '/phpunit/Runner/ResultCache/Subscriber/Subscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestConsideredRiskySubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestErroredSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestFailedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestFinishedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestMarkedIncompleteSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestPreparedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestSkippedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestSuiteFinishedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestSuiteFinishedSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestSuiteStartedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestSuiteStartedSubscriber.php', + 'PHPUnit\\Runner\\ShutdownHandler' => '/phpunit/Runner/ShutdownHandler.php', + 'PHPUnit\\Runner\\TestSuiteLoader' => '/phpunit/Runner/TestSuiteLoader.php', + 'PHPUnit\\Runner\\TestSuiteSorter' => '/phpunit/Runner/TestSuiteSorter.php', + 'PHPUnit\\Runner\\Version' => '/phpunit/Runner/Version.php', + 'PHPUnit\\TestRunner\\IssueFilter' => '/phpunit/Runner/IssueFilter.php', + 'PHPUnit\\TestRunner\\TestResult\\AfterTestClassMethodErroredSubscriber' => '/phpunit/Runner/TestResult/Subscriber/AfterTestClassMethodErroredSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\AfterTestClassMethodFailedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/AfterTestClassMethodFailedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\BeforeTestClassMethodErroredSubscriber' => '/phpunit/Runner/TestResult/Subscriber/BeforeTestClassMethodErroredSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\BeforeTestClassMethodFailedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/BeforeTestClassMethodFailedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\ChildProcessErroredSubscriber' => '/phpunit/Runner/TestResult/Subscriber/ChildProcessErroredSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\Collector' => '/phpunit/Runner/TestResult/Collector.php', + 'PHPUnit\\TestRunner\\TestResult\\ExecutionStartedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/ExecutionStartedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\Facade' => '/phpunit/Runner/TestResult/Facade.php', + 'PHPUnit\\TestRunner\\TestResult\\Issues\\Issue' => '/phpunit/Runner/TestResult/Issue.php', + 'PHPUnit\\TestRunner\\TestResult\\PassedTests' => '/phpunit/Runner/TestResult/PassedTests.php', + 'PHPUnit\\TestRunner\\TestResult\\Subscriber' => '/phpunit/Runner/TestResult/Subscriber/Subscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestConsideredRiskySubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestErroredSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestFailedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestFinishedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestMarkedIncompleteSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestPreparedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestResult' => '/phpunit/Runner/TestResult/TestResult.php', + 'PHPUnit\\TestRunner\\TestResult\\TestRunnerTriggeredDeprecationSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredDeprecationSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestRunnerTriggeredNoticeSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredNoticeSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestRunnerTriggeredWarningSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredWarningSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestSkippedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestSuiteFinishedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestSuiteFinishedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestSuiteSkippedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestSuiteSkippedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestSuiteStartedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestSuiteStartedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredDeprecationSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredErrorSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredErrorSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredNoticeSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpDeprecationSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpNoticeSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpWarningSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpunitDeprecationSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpunitErrorSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpunitNoticeSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpunitWarningSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredWarningSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredWarningSubscriber.php', + 'PHPUnit\\TextUI\\Application' => '/phpunit/TextUI/Application.php', + 'PHPUnit\\TextUI\\CannotOpenSocketException' => '/phpunit/TextUI/Exception/CannotOpenSocketException.php', + 'PHPUnit\\TextUI\\CliArguments\\Builder' => '/phpunit/TextUI/Configuration/Cli/Builder.php', + 'PHPUnit\\TextUI\\CliArguments\\Configuration' => '/phpunit/TextUI/Configuration/Cli/Configuration.php', + 'PHPUnit\\TextUI\\CliArguments\\Exception' => '/phpunit/TextUI/Configuration/Cli/Exception.php', + 'PHPUnit\\TextUI\\CliArguments\\XmlConfigurationFileFinder' => '/phpunit/TextUI/Configuration/Cli/XmlConfigurationFileFinder.php', + 'PHPUnit\\TextUI\\Command\\AtLeastVersionCommand' => '/phpunit/TextUI/Command/Commands/AtLeastVersionCommand.php', + 'PHPUnit\\TextUI\\Command\\CheckPhpConfigurationCommand' => '/phpunit/TextUI/Command/Commands/CheckPhpConfigurationCommand.php', + 'PHPUnit\\TextUI\\Command\\Command' => '/phpunit/TextUI/Command/Command.php', + 'PHPUnit\\TextUI\\Command\\GenerateConfigurationCommand' => '/phpunit/TextUI/Command/Commands/GenerateConfigurationCommand.php', + 'PHPUnit\\TextUI\\Command\\ListGroupsCommand' => '/phpunit/TextUI/Command/Commands/ListGroupsCommand.php', + 'PHPUnit\\TextUI\\Command\\ListTestFilesCommand' => '/phpunit/TextUI/Command/Commands/ListTestFilesCommand.php', + 'PHPUnit\\TextUI\\Command\\ListTestSuitesCommand' => '/phpunit/TextUI/Command/Commands/ListTestSuitesCommand.php', + 'PHPUnit\\TextUI\\Command\\ListTestsAsTextCommand' => '/phpunit/TextUI/Command/Commands/ListTestsAsTextCommand.php', + 'PHPUnit\\TextUI\\Command\\ListTestsAsXmlCommand' => '/phpunit/TextUI/Command/Commands/ListTestsAsXmlCommand.php', + 'PHPUnit\\TextUI\\Command\\MigrateConfigurationCommand' => '/phpunit/TextUI/Command/Commands/MigrateConfigurationCommand.php', + 'PHPUnit\\TextUI\\Command\\Result' => '/phpunit/TextUI/Command/Result.php', + 'PHPUnit\\TextUI\\Command\\ShowHelpCommand' => '/phpunit/TextUI/Command/Commands/ShowHelpCommand.php', + 'PHPUnit\\TextUI\\Command\\ShowVersionCommand' => '/phpunit/TextUI/Command/Commands/ShowVersionCommand.php', + 'PHPUnit\\TextUI\\Command\\VersionCheckCommand' => '/phpunit/TextUI/Command/Commands/VersionCheckCommand.php', + 'PHPUnit\\TextUI\\Command\\WarmCodeCoverageCacheCommand' => '/phpunit/TextUI/Command/Commands/WarmCodeCoverageCacheCommand.php', + 'PHPUnit\\TextUI\\Configuration\\BootstrapLoader' => '/phpunit/TextUI/Configuration/BootstrapLoader.php', + 'PHPUnit\\TextUI\\Configuration\\BootstrapScriptDoesNotExistException' => '/phpunit/TextUI/Configuration/Exception/BootstrapScriptDoesNotExistException.php', + 'PHPUnit\\TextUI\\Configuration\\BootstrapScriptException' => '/phpunit/TextUI/Configuration/Exception/BootstrapScriptException.php', + 'PHPUnit\\TextUI\\Configuration\\Builder' => '/phpunit/TextUI/Configuration/Builder.php', + 'PHPUnit\\TextUI\\Configuration\\CodeCoverageFilterRegistry' => '/phpunit/TextUI/Configuration/CodeCoverageFilterRegistry.php', + 'PHPUnit\\TextUI\\Configuration\\CodeCoverageReportNotConfiguredException' => '/phpunit/TextUI/Configuration/Exception/CodeCoverageReportNotConfiguredException.php', + 'PHPUnit\\TextUI\\Configuration\\Configuration' => '/phpunit/TextUI/Configuration/Configuration.php', + 'PHPUnit\\TextUI\\Configuration\\ConfigurationCannotBeBuiltException' => '/phpunit/TextUI/Configuration/Exception/ConfigurationCannotBeBuiltException.php', + 'PHPUnit\\TextUI\\Configuration\\Constant' => '/phpunit/TextUI/Configuration/Value/Constant.php', + 'PHPUnit\\TextUI\\Configuration\\ConstantCollection' => '/phpunit/TextUI/Configuration/Value/ConstantCollection.php', + 'PHPUnit\\TextUI\\Configuration\\ConstantCollectionIterator' => '/phpunit/TextUI/Configuration/Value/ConstantCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\Directory' => '/phpunit/TextUI/Configuration/Value/Directory.php', + 'PHPUnit\\TextUI\\Configuration\\DirectoryCollection' => '/phpunit/TextUI/Configuration/Value/DirectoryCollection.php', + 'PHPUnit\\TextUI\\Configuration\\DirectoryCollectionIterator' => '/phpunit/TextUI/Configuration/Value/DirectoryCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\Exception' => '/phpunit/TextUI/Configuration/Exception/Exception.php', + 'PHPUnit\\TextUI\\Configuration\\ExtensionBootstrap' => '/phpunit/TextUI/Configuration/Value/ExtensionBootstrap.php', + 'PHPUnit\\TextUI\\Configuration\\ExtensionBootstrapCollection' => '/phpunit/TextUI/Configuration/Value/ExtensionBootstrapCollection.php', + 'PHPUnit\\TextUI\\Configuration\\ExtensionBootstrapCollectionIterator' => '/phpunit/TextUI/Configuration/Value/ExtensionBootstrapCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\File' => '/phpunit/TextUI/Configuration/Value/File.php', + 'PHPUnit\\TextUI\\Configuration\\FileCollection' => '/phpunit/TextUI/Configuration/Value/FileCollection.php', + 'PHPUnit\\TextUI\\Configuration\\FileCollectionIterator' => '/phpunit/TextUI/Configuration/Value/FileCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\FilterDirectory' => '/phpunit/TextUI/Configuration/Value/FilterDirectory.php', + 'PHPUnit\\TextUI\\Configuration\\FilterDirectoryCollection' => '/phpunit/TextUI/Configuration/Value/FilterDirectoryCollection.php', + 'PHPUnit\\TextUI\\Configuration\\FilterDirectoryCollectionIterator' => '/phpunit/TextUI/Configuration/Value/FilterDirectoryCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\FilterFile' => '/phpunit/TextUI/Configuration/Value/FilterFile.php', + 'PHPUnit\\TextUI\\Configuration\\FilterFileCollection' => '/phpunit/TextUI/Configuration/Value/FilterFileCollection.php', + 'PHPUnit\\TextUI\\Configuration\\FilterFileCollectionIterator' => '/phpunit/TextUI/Configuration/Value/FilterFileCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\FilterNotConfiguredException' => '/phpunit/TextUI/Configuration/Exception/FilterNotConfiguredException.php', + 'PHPUnit\\TextUI\\Configuration\\Group' => '/phpunit/TextUI/Configuration/Value/Group.php', + 'PHPUnit\\TextUI\\Configuration\\GroupCollection' => '/phpunit/TextUI/Configuration/Value/GroupCollection.php', + 'PHPUnit\\TextUI\\Configuration\\GroupCollectionIterator' => '/phpunit/TextUI/Configuration/Value/GroupCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\IniSetting' => '/phpunit/TextUI/Configuration/Value/IniSetting.php', + 'PHPUnit\\TextUI\\Configuration\\IniSettingCollection' => '/phpunit/TextUI/Configuration/Value/IniSettingCollection.php', + 'PHPUnit\\TextUI\\Configuration\\IniSettingCollectionIterator' => '/phpunit/TextUI/Configuration/Value/IniSettingCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\LoggingNotConfiguredException' => '/phpunit/TextUI/Configuration/Exception/LoggingNotConfiguredException.php', + 'PHPUnit\\TextUI\\Configuration\\Merger' => '/phpunit/TextUI/Configuration/Merger.php', + 'PHPUnit\\TextUI\\Configuration\\NoBaselineException' => '/phpunit/TextUI/Configuration/Exception/NoBaselineException.php', + 'PHPUnit\\TextUI\\Configuration\\NoBootstrapException' => '/phpunit/TextUI/Configuration/Exception/NoBootstrapException.php', + 'PHPUnit\\TextUI\\Configuration\\NoCacheDirectoryException' => '/phpunit/TextUI/Configuration/Exception/NoCacheDirectoryException.php', + 'PHPUnit\\TextUI\\Configuration\\NoConfigurationFileException' => '/phpunit/TextUI/Configuration/Exception/NoConfigurationFileException.php', + 'PHPUnit\\TextUI\\Configuration\\NoCoverageCacheDirectoryException' => '/phpunit/TextUI/Configuration/Exception/NoCoverageCacheDirectoryException.php', + 'PHPUnit\\TextUI\\Configuration\\NoCustomCssFileException' => '/phpunit/TextUI/Configuration/Exception/NoCustomCssFileException.php', + 'PHPUnit\\TextUI\\Configuration\\NoDefaultTestSuiteException' => '/phpunit/TextUI/Configuration/Exception/NoDefaultTestSuiteException.php', + 'PHPUnit\\TextUI\\Configuration\\NoHtmlCoverageTargetException' => '/phpunit/TextUI/Configuration/Exception/NoHtmlCoverageTargetException.php', + 'PHPUnit\\TextUI\\Configuration\\NoPharExtensionDirectoryException' => '/phpunit/TextUI/Configuration/Exception/NoPharExtensionDirectoryException.php', + 'PHPUnit\\TextUI\\Configuration\\NoTestFilesFileException' => '/phpunit/TextUI/Configuration/Exception/NoTestFilesFileException.php', + 'PHPUnit\\TextUI\\Configuration\\Php' => '/phpunit/TextUI/Configuration/Value/Php.php', + 'PHPUnit\\TextUI\\Configuration\\PhpHandler' => '/phpunit/TextUI/Configuration/PhpHandler.php', + 'PHPUnit\\TextUI\\Configuration\\Registry' => '/phpunit/TextUI/Configuration/Registry.php', + 'PHPUnit\\TextUI\\Configuration\\Source' => '/phpunit/TextUI/Configuration/Value/Source.php', + 'PHPUnit\\TextUI\\Configuration\\SourceFilter' => '/phpunit/TextUI/Configuration/SourceFilter.php', + 'PHPUnit\\TextUI\\Configuration\\SourceMapper' => '/phpunit/TextUI/Configuration/SourceMapper.php', + 'PHPUnit\\TextUI\\Configuration\\SpecificDeprecationToStopOnNotConfiguredException' => '/phpunit/TextUI/Configuration/Exception/SpecificDeprecationToStopOnNotConfiguredException.php', + 'PHPUnit\\TextUI\\Configuration\\TestDirectory' => '/phpunit/TextUI/Configuration/Value/TestDirectory.php', + 'PHPUnit\\TextUI\\Configuration\\TestDirectoryCollection' => '/phpunit/TextUI/Configuration/Value/TestDirectoryCollection.php', + 'PHPUnit\\TextUI\\Configuration\\TestDirectoryCollectionIterator' => '/phpunit/TextUI/Configuration/Value/TestDirectoryCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\TestFile' => '/phpunit/TextUI/Configuration/Value/TestFile.php', + 'PHPUnit\\TextUI\\Configuration\\TestFileCollection' => '/phpunit/TextUI/Configuration/Value/TestFileCollection.php', + 'PHPUnit\\TextUI\\Configuration\\TestFileCollectionIterator' => '/phpunit/TextUI/Configuration/Value/TestFileCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\TestSuite' => '/phpunit/TextUI/Configuration/Value/TestSuite.php', + 'PHPUnit\\TextUI\\Configuration\\TestSuiteBuilder' => '/phpunit/TextUI/Configuration/TestSuiteBuilder.php', + 'PHPUnit\\TextUI\\Configuration\\TestSuiteCollection' => '/phpunit/TextUI/Configuration/Value/TestSuiteCollection.php', + 'PHPUnit\\TextUI\\Configuration\\TestSuiteCollectionIterator' => '/phpunit/TextUI/Configuration/Value/TestSuiteCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\Variable' => '/phpunit/TextUI/Configuration/Value/Variable.php', + 'PHPUnit\\TextUI\\Configuration\\VariableCollection' => '/phpunit/TextUI/Configuration/Value/VariableCollection.php', + 'PHPUnit\\TextUI\\Configuration\\VariableCollectionIterator' => '/phpunit/TextUI/Configuration/Value/VariableCollectionIterator.php', + 'PHPUnit\\TextUI\\Exception' => '/phpunit/TextUI/Exception/Exception.php', + 'PHPUnit\\TextUI\\Help' => '/phpunit/TextUI/Help.php', + 'PHPUnit\\TextUI\\InvalidSocketException' => '/phpunit/TextUI/Exception/InvalidSocketException.php', + 'PHPUnit\\TextUI\\Output\\DefaultPrinter' => '/phpunit/TextUI/Output/Printer/DefaultPrinter.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\BeforeTestClassMethodErroredSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/BeforeTestClassMethodErroredSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\ChildProcessErroredSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/ChildProcessErroredSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\ProgressPrinter' => '/phpunit/TextUI/Output/Default/ProgressPrinter/ProgressPrinter.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\Subscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/Subscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestConsideredRiskySubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestErroredSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestFailedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestFinishedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestMarkedIncompleteSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestPreparedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestRunnerExecutionStartedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestRunnerExecutionStartedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestSkippedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestSuiteSkippedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestSuiteSkippedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredDeprecationSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredDeprecationSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredErrorSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredErrorSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredNoticeSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredNoticeSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpDeprecationSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpDeprecationSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpNoticeSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpNoticeSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpWarningSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpWarningSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpunitDeprecationSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpunitNoticeSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpunitWarningSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitWarningSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredWarningSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredWarningSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ResultPrinter' => '/phpunit/TextUI/Output/Default/ResultPrinter.php', + 'PHPUnit\\TextUI\\Output\\Default\\UnexpectedOutputPrinter' => '/phpunit/TextUI/Output/Default/UnexpectedOutputPrinter.php', + 'PHPUnit\\TextUI\\Output\\Facade' => '/phpunit/TextUI/Output/Facade.php', + 'PHPUnit\\TextUI\\Output\\NullPrinter' => '/phpunit/TextUI/Output/Printer/NullPrinter.php', + 'PHPUnit\\TextUI\\Output\\Printer' => '/phpunit/TextUI/Output/Printer/Printer.php', + 'PHPUnit\\TextUI\\Output\\SummaryPrinter' => '/phpunit/TextUI/Output/SummaryPrinter.php', + 'PHPUnit\\TextUI\\Output\\TestDox\\ResultPrinter' => '/phpunit/TextUI/Output/TestDox/ResultPrinter.php', + 'PHPUnit\\TextUI\\RuntimeException' => '/phpunit/TextUI/Exception/RuntimeException.php', + 'PHPUnit\\TextUI\\ShellExitCodeCalculator' => '/phpunit/TextUI/ShellExitCodeCalculator.php', + 'PHPUnit\\TextUI\\TestDirectoryNotFoundException' => '/phpunit/TextUI/Exception/TestDirectoryNotFoundException.php', + 'PHPUnit\\TextUI\\TestFileNotFoundException' => '/phpunit/TextUI/Exception/TestFileNotFoundException.php', + 'PHPUnit\\TextUI\\TestRunner' => '/phpunit/TextUI/TestRunner.php', + 'PHPUnit\\TextUI\\TestSuiteFilterProcessor' => '/phpunit/TextUI/TestSuiteFilterProcessor.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CannotFindSchemaException' => '/phpunit/TextUI/Configuration/Exception/CannotFindSchemaException.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\CodeCoverage' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/CodeCoverage.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Clover' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Clover.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Cobertura' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Cobertura.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Crap4j' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Crap4j.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Html' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Html.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\OpenClover' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/OpenClover.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Php' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Php.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Text' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Text.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Xml' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Xml.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Configuration' => '/phpunit/TextUI/Configuration/Xml/Configuration.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\ConvertLogTypes' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/ConvertLogTypes.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoverageCloverToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageCloverToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoverageCrap4jToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageCrap4jToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoverageHtmlToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageHtmlToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoveragePhpToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoveragePhpToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoverageTextToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageTextToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoverageXmlToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageXmlToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\DefaultConfiguration' => '/phpunit/TextUI/Configuration/Xml/DefaultConfiguration.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Exception' => '/phpunit/TextUI/Configuration/Xml/Exception.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\FailedSchemaDetectionResult' => '/phpunit/TextUI/Configuration/Xml/SchemaDetector/FailedSchemaDetectionResult.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Generator' => '/phpunit/TextUI/Configuration/Xml/Generator.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Groups' => '/phpunit/TextUI/Configuration/Xml/Groups.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\IntroduceCacheDirectoryAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCacheDirectoryAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\IntroduceCoverageElement' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCoverageElement.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\LoadedFromFileConfiguration' => '/phpunit/TextUI/Configuration/Xml/LoadedFromFileConfiguration.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Loader' => '/phpunit/TextUI/Configuration/Xml/Loader.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\LogToReportMigration' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/LogToReportMigration.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\Junit' => '/phpunit/TextUI/Configuration/Xml/Logging/Junit.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\Logging' => '/phpunit/TextUI/Configuration/Xml/Logging/Logging.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\Otr' => '/phpunit/TextUI/Configuration/Xml/Logging/Otr.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\TeamCity' => '/phpunit/TextUI/Configuration/Xml/Logging/TeamCity.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\TestDox\\Html' => '/phpunit/TextUI/Configuration/Xml/Logging/TestDox/Html.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\TestDox\\Text' => '/phpunit/TextUI/Configuration/Xml/Logging/TestDox/Text.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Migration' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/Migration.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MigrationBuilder' => '/phpunit/TextUI/Configuration/Xml/Migration/MigrationBuilder.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MigrationException' => '/phpunit/TextUI/Configuration/Xml/Migration/MigrationException.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Migrator' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrator.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromFilterWhitelistToCoverage' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromRootToCoverage' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromRootToCoverage.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MoveCoverageDirectoriesToSource' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveCoverageDirectoriesToSource.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistExcludesToCoverage' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistExcludesToCoverage.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistIncludesToCoverage' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistIncludesToCoverage.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\PHPUnit' => '/phpunit/TextUI/Configuration/Xml/PHPUnit.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveBeStrictAboutTodoAnnotatedTestsAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutTodoAnnotatedTestsAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveCacheResultFileAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheResultFileAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveCacheTokensAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheTokensAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveConversionToExceptionsAttributes' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveConversionToExceptionsAttributes.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveCoverageElementCacheDirectoryAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementCacheDirectoryAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveCoverageElementProcessUncoveredFilesAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementProcessUncoveredFilesAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveEmptyFilter' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveEmptyFilter.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveListeners' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveListeners.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveLogTypes' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveLogTypes.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveLoggingElements' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveLoggingElements.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveNoInteractionAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveNoInteractionAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemovePrinterAttributes' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemovePrinterAttributes.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveTestDoxGroupsElement' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestDoxGroupsElement.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveTestSuiteLoaderAttributes' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestSuiteLoaderAttributes.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveVerboseAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveVerboseAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RenameBackupStaticAttributesAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameBackupStaticAttributesAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RenameBeStrictAboutCoversAnnotationAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameBeStrictAboutCoversAnnotationAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RenameForceCoversAnnotationAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameForceCoversAnnotationAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\ReplaceRestrictDeprecationsWithIgnoreDeprecations' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/ReplaceRestrictDeprecationsWithIgnoreDeprecations.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\SchemaDetectionResult' => '/phpunit/TextUI/Configuration/Xml/SchemaDetector/SchemaDetectionResult.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\SchemaDetector' => '/phpunit/TextUI/Configuration/Xml/SchemaDetector/SchemaDetector.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\SchemaFinder' => '/phpunit/TextUI/Configuration/Xml/SchemaFinder.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\SnapshotNodeList' => '/phpunit/TextUI/Configuration/Xml/Migration/SnapshotNodeList.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\SuccessfulSchemaDetectionResult' => '/phpunit/TextUI/Configuration/Xml/SchemaDetector/SuccessfulSchemaDetectionResult.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\TestSuiteMapper' => '/phpunit/TextUI/Configuration/Xml/TestSuiteMapper.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\UpdateSchemaLocation' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/UpdateSchemaLocation.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\ValidationResult' => '/phpunit/TextUI/Configuration/Xml/Validator/ValidationResult.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Validator' => '/phpunit/TextUI/Configuration/Xml/Validator/Validator.php', + 'PHPUnit\\Util\\Color' => '/phpunit/Util/Color.php', + 'PHPUnit\\Util\\Exception' => '/phpunit/Util/Exception/Exception.php', + 'PHPUnit\\Util\\ExcludeList' => '/phpunit/Util/ExcludeList.php', + 'PHPUnit\\Util\\Exporter' => '/phpunit/Util/Exporter.php', + 'PHPUnit\\Util\\Filesystem' => '/phpunit/Util/Filesystem.php', + 'PHPUnit\\Util\\Filter' => '/phpunit/Util/Filter.php', + 'PHPUnit\\Util\\GlobalState' => '/phpunit/Util/GlobalState.php', + 'PHPUnit\\Util\\GlobalStateResult' => '/phpunit/Util/GlobalStateResult.php', + 'PHPUnit\\Util\\Http\\Downloader' => '/phpunit/Util/Http/Downloader.php', + 'PHPUnit\\Util\\Http\\PhpDownloader' => '/phpunit/Util/Http/PhpDownloader.php', + 'PHPUnit\\Util\\InvalidDirectoryException' => '/phpunit/Util/Exception/InvalidDirectoryException.php', + 'PHPUnit\\Util\\InvalidJsonException' => '/phpunit/Util/Exception/InvalidJsonException.php', + 'PHPUnit\\Util\\InvalidVersionOperatorException' => '/phpunit/Util/Exception/InvalidVersionOperatorException.php', + 'PHPUnit\\Util\\Json' => '/phpunit/Util/Json.php', + 'PHPUnit\\Util\\PHP\\Job' => '/phpunit/Util/PHP/Job.php', + 'PHPUnit\\Util\\PHP\\JobRunner' => '/phpunit/Util/PHP/JobRunner.php', + 'PHPUnit\\Util\\PHP\\JobRunnerRegistry' => '/phpunit/Util/PHP/JobRunnerRegistry.php', + 'PHPUnit\\Util\\PHP\\PhpProcessException' => '/phpunit/Util/Exception/PhpProcessException.php', + 'PHPUnit\\Util\\PHP\\Result' => '/phpunit/Util/PHP/Result.php', + 'PHPUnit\\Util\\Reflection' => '/phpunit/Util/Reflection.php', + 'PHPUnit\\Util\\Sanitizer' => '/phpunit/Util/Sanitizer.php', + 'PHPUnit\\Util\\Test' => '/phpunit/Util/Test.php', + 'PHPUnit\\Util\\ThrowableToStringMapper' => '/phpunit/Util/ThrowableToStringMapper.php', + 'PHPUnit\\Util\\VersionComparisonOperator' => '/phpunit/Util/VersionComparisonOperator.php', + 'PHPUnit\\Util\\Xml' => '/phpunit/Util/Xml/Xml.php', + 'PHPUnit\\Util\\Xml\\Loader' => '/phpunit/Util/Xml/Loader.php', + 'PHPUnit\\Util\\Xml\\XmlException' => '/phpunit/Util/Exception/XmlException.php']; + } + + if (isset($classes[$class])) { + require_once 'phar://phpunit-13.1.13.phar' . $classes[$class]; + } + }, + true, + false +); + +foreach (['PHPUnitPHAR\\DeepCopy\\DeepCopy' => '/myclabs-deep-copy/DeepCopy/DeepCopy.php', + 'PHPUnitPHAR\\DeepCopy\\Exception\\CloneException' => '/myclabs-deep-copy/DeepCopy/Exception/CloneException.php', + 'PHPUnitPHAR\\DeepCopy\\Exception\\PropertyException' => '/myclabs-deep-copy/DeepCopy/Exception/PropertyException.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\ChainableFilter' => '/myclabs-deep-copy/DeepCopy/Filter/ChainableFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\Doctrine\\DoctrineCollectionFilter' => '/myclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\Doctrine\\DoctrineEmptyCollectionFilter' => '/myclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\Doctrine\\DoctrineProxyFilter' => '/myclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\Filter' => '/myclabs-deep-copy/DeepCopy/Filter/Filter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\KeepFilter' => '/myclabs-deep-copy/DeepCopy/Filter/KeepFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\ReplaceFilter' => '/myclabs-deep-copy/DeepCopy/Filter/ReplaceFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Filter\\SetNullFilter' => '/myclabs-deep-copy/DeepCopy/Filter/SetNullFilter.php', + 'PHPUnitPHAR\\DeepCopy\\Matcher\\Doctrine\\DoctrineProxyMatcher' => '/myclabs-deep-copy/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php', + 'PHPUnitPHAR\\DeepCopy\\Matcher\\Matcher' => '/myclabs-deep-copy/DeepCopy/Matcher/Matcher.php', + 'PHPUnitPHAR\\DeepCopy\\Matcher\\PropertyMatcher' => '/myclabs-deep-copy/DeepCopy/Matcher/PropertyMatcher.php', + 'PHPUnitPHAR\\DeepCopy\\Matcher\\PropertyNameMatcher' => '/myclabs-deep-copy/DeepCopy/Matcher/PropertyNameMatcher.php', + 'PHPUnitPHAR\\DeepCopy\\Matcher\\PropertyTypeMatcher' => '/myclabs-deep-copy/DeepCopy/Matcher/PropertyTypeMatcher.php', + 'PHPUnitPHAR\\DeepCopy\\Reflection\\ReflectionHelper' => '/myclabs-deep-copy/DeepCopy/Reflection/ReflectionHelper.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\Date\\DateIntervalFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/Date/DateIntervalFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\Date\\DatePeriodFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/Date/DatePeriodFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\ReplaceFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/ReplaceFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\ShallowCopyFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/ShallowCopyFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\Spl\\ArrayObjectFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/Spl/ArrayObjectFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\Spl\\SplDoublyLinkedList' => '/myclabs-deep-copy/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\Spl\\SplDoublyLinkedListFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeFilter\\TypeFilter' => '/myclabs-deep-copy/DeepCopy/TypeFilter/TypeFilter.php', + 'PHPUnitPHAR\\DeepCopy\\TypeMatcher\\TypeMatcher' => '/myclabs-deep-copy/DeepCopy/TypeMatcher/TypeMatcher.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Application' => '/phar-io-manifest/values/Application.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ApplicationName' => '/phar-io-manifest/values/ApplicationName.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Author' => '/phar-io-manifest/values/Author.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\AuthorCollection' => '/phar-io-manifest/values/AuthorCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\AuthorCollectionIterator' => '/phar-io-manifest/values/AuthorCollectionIterator.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\AuthorElement' => '/phar-io-manifest/xml/AuthorElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\AuthorElementCollection' => '/phar-io-manifest/xml/AuthorElementCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\BundledComponent' => '/phar-io-manifest/values/BundledComponent.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\BundledComponentCollection' => '/phar-io-manifest/values/BundledComponentCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\BundledComponentCollectionIterator' => '/phar-io-manifest/values/BundledComponentCollectionIterator.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\BundlesElement' => '/phar-io-manifest/xml/BundlesElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ComponentElement' => '/phar-io-manifest/xml/ComponentElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ComponentElementCollection' => '/phar-io-manifest/xml/ComponentElementCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ContainsElement' => '/phar-io-manifest/xml/ContainsElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\CopyrightElement' => '/phar-io-manifest/xml/CopyrightElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\CopyrightInformation' => '/phar-io-manifest/values/CopyrightInformation.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ElementCollection' => '/phar-io-manifest/xml/ElementCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ElementCollectionException' => '/phar-io-manifest/exceptions/ElementCollectionException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Email' => '/phar-io-manifest/values/Email.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Exception' => '/phar-io-manifest/exceptions/Exception.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ExtElement' => '/phar-io-manifest/xml/ExtElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ExtElementCollection' => '/phar-io-manifest/xml/ExtElementCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Extension' => '/phar-io-manifest/values/Extension.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ExtensionElement' => '/phar-io-manifest/xml/ExtensionElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\InvalidApplicationNameException' => '/phar-io-manifest/exceptions/InvalidApplicationNameException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\InvalidEmailException' => '/phar-io-manifest/exceptions/InvalidEmailException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\InvalidUrlException' => '/phar-io-manifest/exceptions/InvalidUrlException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Library' => '/phar-io-manifest/values/Library.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\License' => '/phar-io-manifest/values/License.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\LicenseElement' => '/phar-io-manifest/xml/LicenseElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Manifest' => '/phar-io-manifest/values/Manifest.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestDocument' => '/phar-io-manifest/xml/ManifestDocument.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestDocumentException' => '/phar-io-manifest/exceptions/ManifestDocumentException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestDocumentLoadingException' => '/phar-io-manifest/exceptions/ManifestDocumentLoadingException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestDocumentMapper' => '/phar-io-manifest/ManifestDocumentMapper.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestDocumentMapperException' => '/phar-io-manifest/exceptions/ManifestDocumentMapperException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestElement' => '/phar-io-manifest/xml/ManifestElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestElementException' => '/phar-io-manifest/exceptions/ManifestElementException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestLoader' => '/phar-io-manifest/ManifestLoader.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestLoaderException' => '/phar-io-manifest/exceptions/ManifestLoaderException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\ManifestSerializer' => '/phar-io-manifest/ManifestSerializer.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\NoEmailAddressException' => '/phar-io-manifest/exceptions/NoEmailAddressException.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\PhpElement' => '/phar-io-manifest/xml/PhpElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\PhpExtensionRequirement' => '/phar-io-manifest/values/PhpExtensionRequirement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\PhpVersionRequirement' => '/phar-io-manifest/values/PhpVersionRequirement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Requirement' => '/phar-io-manifest/values/Requirement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\RequirementCollection' => '/phar-io-manifest/values/RequirementCollection.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\RequirementCollectionIterator' => '/phar-io-manifest/values/RequirementCollectionIterator.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\RequiresElement' => '/phar-io-manifest/xml/RequiresElement.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Type' => '/phar-io-manifest/values/Type.php', + 'PHPUnitPHAR\\PharIo\\Manifest\\Url' => '/phar-io-manifest/values/Url.php', + 'PHPUnitPHAR\\PharIo\\Version\\AbstractVersionConstraint' => '/phar-io-version/constraints/AbstractVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\AndVersionConstraintGroup' => '/phar-io-version/constraints/AndVersionConstraintGroup.php', + 'PHPUnitPHAR\\PharIo\\Version\\AnyVersionConstraint' => '/phar-io-version/constraints/AnyVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\BuildMetaData' => '/phar-io-version/BuildMetaData.php', + 'PHPUnitPHAR\\PharIo\\Version\\ExactVersionConstraint' => '/phar-io-version/constraints/ExactVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\Exception' => '/phar-io-version/exceptions/Exception.php', + 'PHPUnitPHAR\\PharIo\\Version\\GreaterThanOrEqualToVersionConstraint' => '/phar-io-version/constraints/GreaterThanOrEqualToVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\InvalidPreReleaseSuffixException' => '/phar-io-version/exceptions/InvalidPreReleaseSuffixException.php', + 'PHPUnitPHAR\\PharIo\\Version\\InvalidVersionException' => '/phar-io-version/exceptions/InvalidVersionException.php', + 'PHPUnitPHAR\\PharIo\\Version\\NoBuildMetaDataException' => '/phar-io-version/exceptions/NoBuildMetaDataException.php', + 'PHPUnitPHAR\\PharIo\\Version\\NoPreReleaseSuffixException' => '/phar-io-version/exceptions/NoPreReleaseSuffixException.php', + 'PHPUnitPHAR\\PharIo\\Version\\OrVersionConstraintGroup' => '/phar-io-version/constraints/OrVersionConstraintGroup.php', + 'PHPUnitPHAR\\PharIo\\Version\\PreReleaseSuffix' => '/phar-io-version/PreReleaseSuffix.php', + 'PHPUnitPHAR\\PharIo\\Version\\SpecificMajorAndMinorVersionConstraint' => '/phar-io-version/constraints/SpecificMajorAndMinorVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\SpecificMajorVersionConstraint' => '/phar-io-version/constraints/SpecificMajorVersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\UnsupportedVersionConstraintException' => '/phar-io-version/exceptions/UnsupportedVersionConstraintException.php', + 'PHPUnitPHAR\\PharIo\\Version\\Version' => '/phar-io-version/Version.php', + 'PHPUnitPHAR\\PharIo\\Version\\VersionConstraint' => '/phar-io-version/constraints/VersionConstraint.php', + 'PHPUnitPHAR\\PharIo\\Version\\VersionConstraintParser' => '/phar-io-version/VersionConstraintParser.php', + 'PHPUnitPHAR\\PharIo\\Version\\VersionConstraintValue' => '/phar-io-version/VersionConstraintValue.php', + 'PHPUnitPHAR\\PharIo\\Version\\VersionNumber' => '/phar-io-version/VersionNumber.php', + 'PHPUnitPHAR\\PhpParser\\Builder' => '/nikic-php-parser/PhpParser/Builder.php', + 'PHPUnitPHAR\\PhpParser\\BuilderFactory' => '/nikic-php-parser/PhpParser/BuilderFactory.php', + 'PHPUnitPHAR\\PhpParser\\BuilderHelpers' => '/nikic-php-parser/PhpParser/BuilderHelpers.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\ClassConst' => '/nikic-php-parser/PhpParser/Builder/ClassConst.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Class_' => '/nikic-php-parser/PhpParser/Builder/Class_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Declaration' => '/nikic-php-parser/PhpParser/Builder/Declaration.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\EnumCase' => '/nikic-php-parser/PhpParser/Builder/EnumCase.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Enum_' => '/nikic-php-parser/PhpParser/Builder/Enum_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\FunctionLike' => '/nikic-php-parser/PhpParser/Builder/FunctionLike.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Function_' => '/nikic-php-parser/PhpParser/Builder/Function_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Interface_' => '/nikic-php-parser/PhpParser/Builder/Interface_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Method' => '/nikic-php-parser/PhpParser/Builder/Method.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Namespace_' => '/nikic-php-parser/PhpParser/Builder/Namespace_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Param' => '/nikic-php-parser/PhpParser/Builder/Param.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Property' => '/nikic-php-parser/PhpParser/Builder/Property.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\TraitUse' => '/nikic-php-parser/PhpParser/Builder/TraitUse.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\TraitUseAdaptation' => '/nikic-php-parser/PhpParser/Builder/TraitUseAdaptation.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Trait_' => '/nikic-php-parser/PhpParser/Builder/Trait_.php', + 'PHPUnitPHAR\\PhpParser\\Builder\\Use_' => '/nikic-php-parser/PhpParser/Builder/Use_.php', + 'PHPUnitPHAR\\PhpParser\\Comment' => '/nikic-php-parser/PhpParser/Comment.php', + 'PHPUnitPHAR\\PhpParser\\Comment\\Doc' => '/nikic-php-parser/PhpParser/Comment/Doc.php', + 'PHPUnitPHAR\\PhpParser\\ConstExprEvaluationException' => '/nikic-php-parser/PhpParser/ConstExprEvaluationException.php', + 'PHPUnitPHAR\\PhpParser\\ConstExprEvaluator' => '/nikic-php-parser/PhpParser/ConstExprEvaluator.php', + 'PHPUnitPHAR\\PhpParser\\Error' => '/nikic-php-parser/PhpParser/Error.php', + 'PHPUnitPHAR\\PhpParser\\ErrorHandler' => '/nikic-php-parser/PhpParser/ErrorHandler.php', + 'PHPUnitPHAR\\PhpParser\\ErrorHandler\\Collecting' => '/nikic-php-parser/PhpParser/ErrorHandler/Collecting.php', + 'PHPUnitPHAR\\PhpParser\\ErrorHandler\\Throwing' => '/nikic-php-parser/PhpParser/ErrorHandler/Throwing.php', + 'PHPUnitPHAR\\PhpParser\\Internal\\DiffElem' => '/nikic-php-parser/PhpParser/Internal/DiffElem.php', + 'PHPUnitPHAR\\PhpParser\\Internal\\Differ' => '/nikic-php-parser/PhpParser/Internal/Differ.php', + 'PHPUnitPHAR\\PhpParser\\Internal\\PrintableNewAnonClassNode' => '/nikic-php-parser/PhpParser/Internal/PrintableNewAnonClassNode.php', + 'PHPUnitPHAR\\PhpParser\\Internal\\TokenPolyfill' => '/nikic-php-parser/PhpParser/Internal/TokenPolyfill.php', + 'PHPUnitPHAR\\PhpParser\\Internal\\TokenStream' => '/nikic-php-parser/PhpParser/Internal/TokenStream.php', + 'PHPUnitPHAR\\PhpParser\\JsonDecoder' => '/nikic-php-parser/PhpParser/JsonDecoder.php', + 'PHPUnitPHAR\\PhpParser\\Lexer' => '/nikic-php-parser/PhpParser/Lexer.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\Emulative' => '/nikic-php-parser/PhpParser/Lexer/Emulative.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\AsymmetricVisibilityTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/AsymmetricVisibilityTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\AttributeEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\EnumTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\ExplicitOctalEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\KeywordEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\MatchTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\NullsafeTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\PipeOperatorEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/PipeOperatorEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\PropertyTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/PropertyTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyFunctionTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyTokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\ReverseEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\TokenEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/TokenEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Lexer\\TokenEmulator\\VoidCastEmulator' => '/nikic-php-parser/PhpParser/Lexer/TokenEmulator/VoidCastEmulator.php', + 'PHPUnitPHAR\\PhpParser\\Modifiers' => '/nikic-php-parser/PhpParser/Modifiers.php', + 'PHPUnitPHAR\\PhpParser\\NameContext' => '/nikic-php-parser/PhpParser/NameContext.php', + 'PHPUnitPHAR\\PhpParser\\Node' => '/nikic-php-parser/PhpParser/Node.php', + 'PHPUnitPHAR\\PhpParser\\NodeAbstract' => '/nikic-php-parser/PhpParser/NodeAbstract.php', + 'PHPUnitPHAR\\PhpParser\\NodeDumper' => '/nikic-php-parser/PhpParser/NodeDumper.php', + 'PHPUnitPHAR\\PhpParser\\NodeFinder' => '/nikic-php-parser/PhpParser/NodeFinder.php', + 'PHPUnitPHAR\\PhpParser\\NodeTraverser' => '/nikic-php-parser/PhpParser/NodeTraverser.php', + 'PHPUnitPHAR\\PhpParser\\NodeTraverserInterface' => '/nikic-php-parser/PhpParser/NodeTraverserInterface.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitorAbstract' => '/nikic-php-parser/PhpParser/NodeVisitorAbstract.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\CloningVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/CloningVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\CommentAnnotatingVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/CommentAnnotatingVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\FindingVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/FindingVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\FirstFindingVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/FirstFindingVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\NameResolver' => '/nikic-php-parser/PhpParser/NodeVisitor/NameResolver.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\NodeConnectingVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/NodeConnectingVisitor.php', + 'PHPUnitPHAR\\PhpParser\\NodeVisitor\\ParentConnectingVisitor' => '/nikic-php-parser/PhpParser/NodeVisitor/ParentConnectingVisitor.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Arg' => '/nikic-php-parser/PhpParser/Node/Arg.php', + 'PHPUnitPHAR\\PhpParser\\Node\\ArrayItem' => '/nikic-php-parser/PhpParser/Node/ArrayItem.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Attribute' => '/nikic-php-parser/PhpParser/Node/Attribute.php', + 'PHPUnitPHAR\\PhpParser\\Node\\AttributeGroup' => '/nikic-php-parser/PhpParser/Node/AttributeGroup.php', + 'PHPUnitPHAR\\PhpParser\\Node\\ClosureUse' => '/nikic-php-parser/PhpParser/Node/ClosureUse.php', + 'PHPUnitPHAR\\PhpParser\\Node\\ComplexType' => '/nikic-php-parser/PhpParser/Node/ComplexType.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Const_' => '/nikic-php-parser/PhpParser/Node/Const_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\DeclareItem' => '/nikic-php-parser/PhpParser/Node/DeclareItem.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr' => '/nikic-php-parser/PhpParser/Node/Expr.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ArrayDimFetch' => '/nikic-php-parser/PhpParser/Node/Expr/ArrayDimFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Array_' => '/nikic-php-parser/PhpParser/Node/Expr/Array_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ArrowFunction' => '/nikic-php-parser/PhpParser/Node/Expr/ArrowFunction.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Assign' => '/nikic-php-parser/PhpParser/Node/Expr/Assign.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Coalesce.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Concat.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Div' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Div.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Minus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Mod.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Mul.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Plus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/Pow.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => '/nikic-php-parser/PhpParser/Node/Expr/AssignOp/ShiftRight.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\AssignRef' => '/nikic-php-parser/PhpParser/Node/Expr/AssignRef.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Coalesce.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Concat.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Div.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Equal.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Greater.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Identical.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Minus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Mod.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Mul.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/NotEqual.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Pipe' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Pipe.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Plus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Pow.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Smaller.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => '/nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Spaceship.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BitwiseNot' => '/nikic-php-parser/PhpParser/Node/Expr/BitwiseNot.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\BooleanNot' => '/nikic-php-parser/PhpParser/Node/Expr/BooleanNot.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\CallLike' => '/nikic-php-parser/PhpParser/Node/Expr/CallLike.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast' => '/nikic-php-parser/PhpParser/Node/Expr/Cast.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Array_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Array_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Bool_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Bool_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Double' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Double.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Int_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Int_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Object_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Object_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\String_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/String_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Unset_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Unset_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Cast\\Void_' => '/nikic-php-parser/PhpParser/Node/Expr/Cast/Void_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ClassConstFetch' => '/nikic-php-parser/PhpParser/Node/Expr/ClassConstFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Clone_' => '/nikic-php-parser/PhpParser/Node/Expr/Clone_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Closure' => '/nikic-php-parser/PhpParser/Node/Expr/Closure.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ConstFetch' => '/nikic-php-parser/PhpParser/Node/Expr/ConstFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Empty_' => '/nikic-php-parser/PhpParser/Node/Expr/Empty_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Error' => '/nikic-php-parser/PhpParser/Node/Expr/Error.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ErrorSuppress' => '/nikic-php-parser/PhpParser/Node/Expr/ErrorSuppress.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Eval_' => '/nikic-php-parser/PhpParser/Node/Expr/Eval_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Exit_' => '/nikic-php-parser/PhpParser/Node/Expr/Exit_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\FuncCall' => '/nikic-php-parser/PhpParser/Node/Expr/FuncCall.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Include_' => '/nikic-php-parser/PhpParser/Node/Expr/Include_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Instanceof_' => '/nikic-php-parser/PhpParser/Node/Expr/Instanceof_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Isset_' => '/nikic-php-parser/PhpParser/Node/Expr/Isset_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\List_' => '/nikic-php-parser/PhpParser/Node/Expr/List_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Match_' => '/nikic-php-parser/PhpParser/Node/Expr/Match_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\MethodCall' => '/nikic-php-parser/PhpParser/Node/Expr/MethodCall.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\New_' => '/nikic-php-parser/PhpParser/Node/Expr/New_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\NullsafeMethodCall' => '/nikic-php-parser/PhpParser/Node/Expr/NullsafeMethodCall.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\NullsafePropertyFetch' => '/nikic-php-parser/PhpParser/Node/Expr/NullsafePropertyFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\PostDec' => '/nikic-php-parser/PhpParser/Node/Expr/PostDec.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\PostInc' => '/nikic-php-parser/PhpParser/Node/Expr/PostInc.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\PreDec' => '/nikic-php-parser/PhpParser/Node/Expr/PreDec.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\PreInc' => '/nikic-php-parser/PhpParser/Node/Expr/PreInc.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Print_' => '/nikic-php-parser/PhpParser/Node/Expr/Print_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\PropertyFetch' => '/nikic-php-parser/PhpParser/Node/Expr/PropertyFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\ShellExec' => '/nikic-php-parser/PhpParser/Node/Expr/ShellExec.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\StaticCall' => '/nikic-php-parser/PhpParser/Node/Expr/StaticCall.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => '/nikic-php-parser/PhpParser/Node/Expr/StaticPropertyFetch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Ternary' => '/nikic-php-parser/PhpParser/Node/Expr/Ternary.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Throw_' => '/nikic-php-parser/PhpParser/Node/Expr/Throw_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\UnaryMinus' => '/nikic-php-parser/PhpParser/Node/Expr/UnaryMinus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\UnaryPlus' => '/nikic-php-parser/PhpParser/Node/Expr/UnaryPlus.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Variable' => '/nikic-php-parser/PhpParser/Node/Expr/Variable.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\YieldFrom' => '/nikic-php-parser/PhpParser/Node/Expr/YieldFrom.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Expr\\Yield_' => '/nikic-php-parser/PhpParser/Node/Expr/Yield_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\FunctionLike' => '/nikic-php-parser/PhpParser/Node/FunctionLike.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Identifier' => '/nikic-php-parser/PhpParser/Node/Identifier.php', + 'PHPUnitPHAR\\PhpParser\\Node\\InterpolatedStringPart' => '/nikic-php-parser/PhpParser/Node/InterpolatedStringPart.php', + 'PHPUnitPHAR\\PhpParser\\Node\\IntersectionType' => '/nikic-php-parser/PhpParser/Node/IntersectionType.php', + 'PHPUnitPHAR\\PhpParser\\Node\\MatchArm' => '/nikic-php-parser/PhpParser/Node/MatchArm.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Name' => '/nikic-php-parser/PhpParser/Node/Name.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Name\\FullyQualified' => '/nikic-php-parser/PhpParser/Node/Name/FullyQualified.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Name\\Relative' => '/nikic-php-parser/PhpParser/Node/Name/Relative.php', + 'PHPUnitPHAR\\PhpParser\\Node\\NullableType' => '/nikic-php-parser/PhpParser/Node/NullableType.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Param' => '/nikic-php-parser/PhpParser/Node/Param.php', + 'PHPUnitPHAR\\PhpParser\\Node\\PropertyHook' => '/nikic-php-parser/PhpParser/Node/PropertyHook.php', + 'PHPUnitPHAR\\PhpParser\\Node\\PropertyItem' => '/nikic-php-parser/PhpParser/Node/PropertyItem.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar' => '/nikic-php-parser/PhpParser/Node/Scalar.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\Float_' => '/nikic-php-parser/PhpParser/Node/Scalar/Float_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\Int_' => '/nikic-php-parser/PhpParser/Node/Scalar/Int_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\InterpolatedString' => '/nikic-php-parser/PhpParser/Node/Scalar/InterpolatedString.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Class_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Dir.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\File' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/File.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Function_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Line.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Method.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Namespace_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Property' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Property.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => '/nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Trait_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Scalar\\String_' => '/nikic-php-parser/PhpParser/Node/Scalar/String_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\StaticVar' => '/nikic-php-parser/PhpParser/Node/StaticVar.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt' => '/nikic-php-parser/PhpParser/Node/Stmt.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Block' => '/nikic-php-parser/PhpParser/Node/Stmt/Block.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Break_' => '/nikic-php-parser/PhpParser/Node/Stmt/Break_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Case_' => '/nikic-php-parser/PhpParser/Node/Stmt/Case_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Catch_' => '/nikic-php-parser/PhpParser/Node/Stmt/Catch_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\ClassConst' => '/nikic-php-parser/PhpParser/Node/Stmt/ClassConst.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\ClassLike' => '/nikic-php-parser/PhpParser/Node/Stmt/ClassLike.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\ClassMethod' => '/nikic-php-parser/PhpParser/Node/Stmt/ClassMethod.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Class_' => '/nikic-php-parser/PhpParser/Node/Stmt/Class_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Const_' => '/nikic-php-parser/PhpParser/Node/Stmt/Const_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Continue_' => '/nikic-php-parser/PhpParser/Node/Stmt/Continue_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Declare_' => '/nikic-php-parser/PhpParser/Node/Stmt/Declare_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Do_' => '/nikic-php-parser/PhpParser/Node/Stmt/Do_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Echo_' => '/nikic-php-parser/PhpParser/Node/Stmt/Echo_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\ElseIf_' => '/nikic-php-parser/PhpParser/Node/Stmt/ElseIf_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Else_' => '/nikic-php-parser/PhpParser/Node/Stmt/Else_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\EnumCase' => '/nikic-php-parser/PhpParser/Node/Stmt/EnumCase.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Enum_' => '/nikic-php-parser/PhpParser/Node/Stmt/Enum_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Expression' => '/nikic-php-parser/PhpParser/Node/Stmt/Expression.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Finally_' => '/nikic-php-parser/PhpParser/Node/Stmt/Finally_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\For_' => '/nikic-php-parser/PhpParser/Node/Stmt/For_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Foreach_' => '/nikic-php-parser/PhpParser/Node/Stmt/Foreach_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Function_' => '/nikic-php-parser/PhpParser/Node/Stmt/Function_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Global_' => '/nikic-php-parser/PhpParser/Node/Stmt/Global_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Goto_' => '/nikic-php-parser/PhpParser/Node/Stmt/Goto_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\GroupUse' => '/nikic-php-parser/PhpParser/Node/Stmt/GroupUse.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\HaltCompiler' => '/nikic-php-parser/PhpParser/Node/Stmt/HaltCompiler.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\If_' => '/nikic-php-parser/PhpParser/Node/Stmt/If_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\InlineHTML' => '/nikic-php-parser/PhpParser/Node/Stmt/InlineHTML.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Interface_' => '/nikic-php-parser/PhpParser/Node/Stmt/Interface_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Label' => '/nikic-php-parser/PhpParser/Node/Stmt/Label.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Namespace_' => '/nikic-php-parser/PhpParser/Node/Stmt/Namespace_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Nop' => '/nikic-php-parser/PhpParser/Node/Stmt/Nop.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Property' => '/nikic-php-parser/PhpParser/Node/Stmt/Property.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Return_' => '/nikic-php-parser/PhpParser/Node/Stmt/Return_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Static_' => '/nikic-php-parser/PhpParser/Node/Stmt/Static_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Switch_' => '/nikic-php-parser/PhpParser/Node/Stmt/Switch_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\TraitUse' => '/nikic-php-parser/PhpParser/Node/Stmt/TraitUse.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\TraitUseAdaptation' => '/nikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Alias' => '/nikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Precedence' => '/nikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Trait_' => '/nikic-php-parser/PhpParser/Node/Stmt/Trait_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\TryCatch' => '/nikic-php-parser/PhpParser/Node/Stmt/TryCatch.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Unset_' => '/nikic-php-parser/PhpParser/Node/Stmt/Unset_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\Use_' => '/nikic-php-parser/PhpParser/Node/Stmt/Use_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\Stmt\\While_' => '/nikic-php-parser/PhpParser/Node/Stmt/While_.php', + 'PHPUnitPHAR\\PhpParser\\Node\\UnionType' => '/nikic-php-parser/PhpParser/Node/UnionType.php', + 'PHPUnitPHAR\\PhpParser\\Node\\UseItem' => '/nikic-php-parser/PhpParser/Node/UseItem.php', + 'PHPUnitPHAR\\PhpParser\\Node\\VarLikeIdentifier' => '/nikic-php-parser/PhpParser/Node/VarLikeIdentifier.php', + 'PHPUnitPHAR\\PhpParser\\Node\\VariadicPlaceholder' => '/nikic-php-parser/PhpParser/Node/VariadicPlaceholder.php', + 'PHPUnitPHAR\\PhpParser\\Parser' => '/nikic-php-parser/PhpParser/Parser.php', + 'PHPUnitPHAR\\PhpParser\\ParserAbstract' => '/nikic-php-parser/PhpParser/ParserAbstract.php', + 'PHPUnitPHAR\\PhpParser\\ParserFactory' => '/nikic-php-parser/PhpParser/ParserFactory.php', + 'PHPUnitPHAR\\PhpParser\\Parser\\Php7' => '/nikic-php-parser/PhpParser/Parser/Php7.php', + 'PHPUnitPHAR\\PhpParser\\Parser\\Php8' => '/nikic-php-parser/PhpParser/Parser/Php8.php', + 'PHPUnitPHAR\\PhpParser\\PhpVersion' => '/nikic-php-parser/PhpParser/PhpVersion.php', + 'PHPUnitPHAR\\PhpParser\\PrettyPrinter' => '/nikic-php-parser/PhpParser/PrettyPrinter.php', + 'PHPUnitPHAR\\PhpParser\\PrettyPrinterAbstract' => '/nikic-php-parser/PhpParser/PrettyPrinterAbstract.php', + 'PHPUnitPHAR\\PhpParser\\PrettyPrinter\\Standard' => '/nikic-php-parser/PhpParser/PrettyPrinter/Standard.php', + 'PHPUnitPHAR\\PhpParser\\Token' => '/nikic-php-parser/PhpParser/Token.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\AmbiguousOptionException' => '/sebastian-cli-parser/exceptions/AmbiguousOptionException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\Exception' => '/sebastian-cli-parser/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\OptionDoesNotAllowArgumentException' => '/sebastian-cli-parser/exceptions/OptionDoesNotAllowArgumentException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\Parser' => '/sebastian-cli-parser/Parser.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\RequiredOptionArgumentMissingException' => '/sebastian-cli-parser/exceptions/RequiredOptionArgumentMissingException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CliParser\\UnknownOptionException' => '/sebastian-cli-parser/exceptions/UnknownOptionException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\BranchAndPathCoverageNotSupportedException' => '/php-code-coverage/Exception/BranchAndPathCoverageNotSupportedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\CodeCoverage' => '/php-code-coverage/CodeCoverage.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedBranchCoverageData' => '/php-code-coverage/Data/ProcessedBranchCoverageData.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedClassType' => '/php-code-coverage/Data/ProcessedClassType.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedCodeCoverageData' => '/php-code-coverage/Data/ProcessedCodeCoverageData.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedFunctionCoverageData' => '/php-code-coverage/Data/ProcessedFunctionCoverageData.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedFunctionType' => '/php-code-coverage/Data/ProcessedFunctionType.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedMethodType' => '/php-code-coverage/Data/ProcessedMethodType.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedPathCoverageData' => '/php-code-coverage/Data/ProcessedPathCoverageData.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\ProcessedTraitType' => '/php-code-coverage/Data/ProcessedTraitType.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Data\\RawCodeCoverageData' => '/php-code-coverage/Data/RawCodeCoverageData.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\Driver' => '/php-code-coverage/Driver/Driver.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\PcovDriver' => '/php-code-coverage/Driver/PcovDriver.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\PcovNotAvailableException' => '/php-code-coverage/Exception/PcovNotAvailableException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\Selector' => '/php-code-coverage/Driver/Selector.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\XdebugDriver' => '/php-code-coverage/Driver/XdebugDriver.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\XdebugNotAvailableException' => '/php-code-coverage/Exception/XdebugNotAvailableException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\XdebugNotEnabledException' => '/php-code-coverage/Exception/XdebugNotEnabledException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Driver\\XdebugVersionNotSupportedException' => '/php-code-coverage/Exception/XdebugVersionNotSupportedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Exception' => '/php-code-coverage/Exception/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\FileCouldNotBeWrittenException' => '/php-code-coverage/Exception/FileCouldNotBeWrittenException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Filter' => '/php-code-coverage/Filter.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\FilterProcessor' => '/php-code-coverage/FilterProcessor.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\InvalidArgumentException' => '/php-code-coverage/Exception/InvalidArgumentException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\MethodNotImplementedException' => '/php-code-coverage/Exception/MethodNotImplementedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\NoCodeCoverageDriverAvailableException' => '/php-code-coverage/Exception/NoCodeCoverageDriverAvailableException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\NoCodeCoverageDriverWithPathCoverageSupportAvailableException' => '/php-code-coverage/Exception/NoCodeCoverageDriverWithPathCoverageSupportAvailableException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\AbstractNode' => '/php-code-coverage/Node/AbstractNode.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\Builder' => '/php-code-coverage/Node/Builder.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\CrapIndex' => '/php-code-coverage/Node/CrapIndex.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\Directory' => '/php-code-coverage/Node/Directory.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\File' => '/php-code-coverage/Node/File.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Node\\Iterator' => '/php-code-coverage/Node/Iterator.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\ParserException' => '/php-code-coverage/Exception/ParserException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\PathExistsButIsNotDirectoryException' => '/php-code-coverage/Exception/PathExistsButIsNotDirectoryException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\ReflectionException' => '/php-code-coverage/Exception/ReflectionException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\ReportAlreadyFinalizedException' => '/php-code-coverage/Exception/ReportAlreadyFinalizedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Clover' => '/php-code-coverage/Report/Clover.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Cobertura' => '/php-code-coverage/Report/Cobertura.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Crap4j' => '/php-code-coverage/Report/Crap4j.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Facade' => '/php-code-coverage/Report/Facade.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\BubbleChart' => '/php-code-coverage/Report/Html/Renderer/BubbleChart.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\Colors' => '/php-code-coverage/Report/Html/Colors.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\CustomCssFile' => '/php-code-coverage/Report/Html/CustomCssFile.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\Dashboard' => '/php-code-coverage/Report/Html/Renderer/Dashboard.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\Directory' => '/php-code-coverage/Report/Html/Renderer/Directory.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\Facade' => '/php-code-coverage/Report/Html/Facade.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\File' => '/php-code-coverage/Report/Html/Renderer/File.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\Renderer' => '/php-code-coverage/Report/Html/Renderer.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Html\\SyntaxHighlighter' => '/php-code-coverage/Report/Html/SyntaxHighlighter.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\OpenClover' => '/php-code-coverage/Report/OpenClover.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Summary' => '/php-code-coverage/Report/Summary.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Text' => '/php-code-coverage/Report/Text.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Thresholds' => '/php-code-coverage/Report/Thresholds.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\BuildInformation' => '/php-code-coverage/Report/Xml/BuildInformation.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Coverage' => '/php-code-coverage/Report/Xml/Coverage.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Directory' => '/php-code-coverage/Report/Xml/Directory.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Facade' => '/php-code-coverage/Report/Xml/Facade.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\File' => '/php-code-coverage/Report/Xml/File.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Method' => '/php-code-coverage/Report/Xml/Method.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Node' => '/php-code-coverage/Report/Xml/Node.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Project' => '/php-code-coverage/Report/Xml/Project.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Report' => '/php-code-coverage/Report/Xml/Report.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Source' => '/php-code-coverage/Report/Xml/Source.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Tests' => '/php-code-coverage/Report/Xml/Tests.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Totals' => '/php-code-coverage/Report/Xml/Totals.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\Xml\\Unit' => '/php-code-coverage/Report/Xml/Unit.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\DriverMismatchException' => '/php-code-coverage/Exception/DriverMismatchException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\EmptyPathListException' => '/php-code-coverage/Exception/EmptyPathListException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\FileCouldNotBeReadException' => '/php-code-coverage/Exception/FileCouldNotBeReadException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\GitInformationMismatchException' => '/php-code-coverage/Exception/GitInformationMismatchException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\InvalidCoverageDataException' => '/php-code-coverage/Exception/InvalidCoverageDataException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\Merger' => '/php-code-coverage/Serialization/Merger.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\MixedGitInformationException' => '/php-code-coverage/Exception/MixedGitInformationException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\PharPrefixCouldNotBeStrippedException' => '/php-code-coverage/Exception/PharPrefixCouldNotBeStrippedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\RuntimeMismatchException' => '/php-code-coverage/Exception/RuntimeMismatchException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\Serializer' => '/php-code-coverage/Serialization/Serializer.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\Unserializer' => '/php-code-coverage/Serialization/Unserializer.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Serialization\\VersionMismatchException' => '/php-code-coverage/Exception/VersionMismatchException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysisCacheNotConfiguredException' => '/php-code-coverage/Exception/StaticAnalysisCacheNotConfiguredException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\AnalysisResult' => '/php-code-coverage/StaticAnalysis/Value/AnalysisResult.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\AttributeParentConnectingVisitor' => '/php-code-coverage/StaticAnalysis/Visitor/AttributeParentConnectingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\CacheWarmer' => '/php-code-coverage/StaticAnalysis/CacheWarmer.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\CachingSourceAnalyser' => '/php-code-coverage/StaticAnalysis/CachingSourceAnalyser.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Class_' => '/php-code-coverage/StaticAnalysis/Value/Class_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\CodeUnitFindingVisitor' => '/php-code-coverage/StaticAnalysis/Visitor/CodeUnitFindingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\ExecutableLinesFindingVisitor' => '/php-code-coverage/StaticAnalysis/Visitor/ExecutableLinesFindingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\FileAnalyser' => '/php-code-coverage/StaticAnalysis/FileAnalyser.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Function_' => '/php-code-coverage/StaticAnalysis/Value/Function_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\IgnoredLinesFindingVisitor' => '/php-code-coverage/StaticAnalysis/Visitor/IgnoredLinesFindingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Interface_' => '/php-code-coverage/StaticAnalysis/Value/Interface_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\LinesOfCode' => '/php-code-coverage/StaticAnalysis/Value/LinesOfCode.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Method' => '/php-code-coverage/StaticAnalysis/Value/Method.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\ParsingSourceAnalyser' => '/php-code-coverage/StaticAnalysis/ParsingSourceAnalyser.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\SourceAnalyser' => '/php-code-coverage/StaticAnalysis/SourceAnalyser.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Trait_' => '/php-code-coverage/StaticAnalysis/Value/Trait_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\StaticAnalysis\\Visibility' => '/php-code-coverage/StaticAnalysis/Value/Visibility.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\TestIdMissingException' => '/php-code-coverage/Exception/TestIdMissingException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Class_' => '/php-code-coverage/Test/Target/Class_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ClassesThatExtendClass' => '/php-code-coverage/Test/Target/ClassesThatExtendClass.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ClassesThatImplementInterface' => '/php-code-coverage/Test/Target/ClassesThatImplementInterface.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Function_' => '/php-code-coverage/Test/Target/Function_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\InvalidCodeCoverageTargetException' => '/php-code-coverage/Exception/InvalidCodeCoverageTargetException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\MapBuilder' => '/php-code-coverage/Test/Target/MapBuilder.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Mapper' => '/php-code-coverage/Test/Target/Mapper.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Method' => '/php-code-coverage/Test/Target/Method.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Namespace_' => '/php-code-coverage/Test/Target/Namespace_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Target' => '/php-code-coverage/Test/Target/Target.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollection' => '/php-code-coverage/Test/Target/TargetCollection.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollectionIterator' => '/php-code-coverage/Test/Target/TargetCollectionIterator.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollectionValidator' => '/php-code-coverage/Test/Target/TargetCollectionValidator.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Trait_' => '/php-code-coverage/Test/Target/Trait_.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationFailure' => '/php-code-coverage/Test/Target/ValidationFailure.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationResult' => '/php-code-coverage/Test/Target/ValidationResult.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationSuccess' => '/php-code-coverage/Test/Target/ValidationSuccess.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize' => '/php-code-coverage/Test/TestSize.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus' => '/php-code-coverage/Test/TestStatus.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\UnintentionallyCoveredCodeChecker' => '/php-code-coverage/UnintentionallyCoveredCodeChecker.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\UnintentionallyCoveredCodeException' => '/php-code-coverage/Exception/UnintentionallyCoveredCodeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\DirectoryCouldNotBeCreatedException' => '/php-code-coverage/Exception/DirectoryCouldNotBeCreatedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\EnsuresUtf8' => '/php-code-coverage/Util/EnsuresUtf8.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\Filesystem' => '/php-code-coverage/Util/Filesystem.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\PathReducer' => '/php-code-coverage/Util/PathReducer.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\Percentage' => '/php-code-coverage/Util/Percentage.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Util\\Xml' => '/php-code-coverage/Util/Xml.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Version' => '/php-code-coverage/Version.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\WriteOperationFailedException' => '/php-code-coverage/Exception/WriteOperationFailedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\XmlException' => '/php-code-coverage/Exception/XmlException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ArrayComparator' => '/sebastian-comparator/ArrayComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ClosureComparator' => '/sebastian-comparator/ClosureComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\Comparator' => '/sebastian-comparator/Comparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ComparisonFailure' => '/sebastian-comparator/ComparisonFailure.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\DOMNodeComparator' => '/sebastian-comparator/DOMNodeComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\DateIntervalComparator' => '/sebastian-comparator/DateIntervalComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\DateTimeComparator' => '/sebastian-comparator/DateTimeComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\EnumerationComparator' => '/sebastian-comparator/EnumerationComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\Exception' => '/sebastian-comparator/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ExceptionComparator' => '/sebastian-comparator/ExceptionComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\Factory' => '/sebastian-comparator/Factory.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\MockObjectComparator' => '/sebastian-comparator/MockObjectComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\NumberComparator' => '/sebastian-comparator/NumberComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\NumericComparator' => '/sebastian-comparator/NumericComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ObjectComparator' => '/sebastian-comparator/ObjectComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ResourceComparator' => '/sebastian-comparator/ResourceComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\RuntimeException' => '/sebastian-comparator/exceptions/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\ScalarComparator' => '/sebastian-comparator/ScalarComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\SplObjectStorageComparator' => '/sebastian-comparator/SplObjectStorageComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Comparator\\TypeComparator' => '/sebastian-comparator/TypeComparator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\Calculator' => '/sebastian-complexity/Calculator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\Complexity' => '/sebastian-complexity/Complexity/Complexity.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\ComplexityCalculatingVisitor' => '/sebastian-complexity/Visitor/ComplexityCalculatingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\ComplexityCollection' => '/sebastian-complexity/Complexity/ComplexityCollection.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\ComplexityCollectionIterator' => '/sebastian-complexity/Complexity/ComplexityCollectionIterator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\CyclomaticComplexityCalculatingVisitor' => '/sebastian-complexity/Visitor/CyclomaticComplexityCalculatingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\Exception' => '/sebastian-complexity/Exception/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Complexity\\RuntimeException' => '/sebastian-complexity/Exception/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Chunk' => '/sebastian-diff/Chunk.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\ConfigurationException' => '/sebastian-diff/Exception/ConfigurationException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Diff' => '/sebastian-diff/Diff.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Differ' => '/sebastian-diff/Differ.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Exception' => '/sebastian-diff/Exception/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Line' => '/sebastian-diff/Line.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\LongestCommonSubsequenceCalculator' => '/sebastian-diff/LongestCommonSubsequenceCalculator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\MemoryEfficientLongestCommonSubsequenceCalculator' => '/sebastian-diff/MemoryEfficientLongestCommonSubsequenceCalculator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Output\\AbstractChunkOutputBuilder' => '/sebastian-diff/Output/AbstractChunkOutputBuilder.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Output\\DiffOnlyOutputBuilder' => '/sebastian-diff/Output/DiffOnlyOutputBuilder.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Output\\DiffOutputBuilderInterface' => '/sebastian-diff/Output/DiffOutputBuilderInterface.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Output\\StrictUnifiedDiffOutputBuilder' => '/sebastian-diff/Output/StrictUnifiedDiffOutputBuilder.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Output\\UnifiedDiffOutputBuilder' => '/sebastian-diff/Output/UnifiedDiffOutputBuilder.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\Parser' => '/sebastian-diff/Parser.php', + 'PHPUnitPHAR\\SebastianBergmann\\Diff\\TimeEfficientLongestCommonSubsequenceCalculator' => '/sebastian-diff/TimeEfficientLongestCommonSubsequenceCalculator.php', + 'PHPUnitPHAR\\SebastianBergmann\\Environment\\Console' => '/sebastian-environment/Console.php', + 'PHPUnitPHAR\\SebastianBergmann\\Environment\\Host' => '/sebastian-environment/Host.php', + 'PHPUnitPHAR\\SebastianBergmann\\Environment\\Runtime' => '/sebastian-environment/Runtime.php', + 'PHPUnitPHAR\\SebastianBergmann\\Exporter\\Exporter' => '/sebastian-exporter/Exporter.php', + 'PHPUnitPHAR\\SebastianBergmann\\FileIterator\\ExcludeIterator' => '/php-file-iterator/ExcludeIterator.php', + 'PHPUnitPHAR\\SebastianBergmann\\FileIterator\\Facade' => '/php-file-iterator/Facade.php', + 'PHPUnitPHAR\\SebastianBergmann\\FileIterator\\Factory' => '/php-file-iterator/Factory.php', + 'PHPUnitPHAR\\SebastianBergmann\\FileIterator\\Iterator' => '/php-file-iterator/Iterator.php', + 'PHPUnitPHAR\\SebastianBergmann\\GitState\\Builder' => '/sebastian-git-state/Builder.php', + 'PHPUnitPHAR\\SebastianBergmann\\GitState\\GitCommandRunner' => '/sebastian-git-state/GitCommandRunner.php', + 'PHPUnitPHAR\\SebastianBergmann\\GitState\\ShellCommandRunner' => '/sebastian-git-state/ShellCommandRunner.php', + 'PHPUnitPHAR\\SebastianBergmann\\GitState\\ShellCommandRunnerImplementation' => '/sebastian-git-state/ShellCommandRunnerImplementation.php', + 'PHPUnitPHAR\\SebastianBergmann\\GitState\\State' => '/sebastian-git-state/State.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\CodeExporter' => '/sebastian-global-state/CodeExporter.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\Exception' => '/sebastian-global-state/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\ExcludeList' => '/sebastian-global-state/ExcludeList.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\Restorer' => '/sebastian-global-state/Restorer.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\RuntimeException' => '/sebastian-global-state/exceptions/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\GlobalState\\Snapshot' => '/sebastian-global-state/Snapshot.php', + 'PHPUnitPHAR\\SebastianBergmann\\Invoker\\Exception' => '/php-invoker/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Invoker\\Invoker' => '/php-invoker/Invoker.php', + 'PHPUnitPHAR\\SebastianBergmann\\Invoker\\ProcessControlExtensionNotLoadedException' => '/php-invoker/exceptions/ProcessControlExtensionNotLoadedException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Invoker\\TimeoutException' => '/php-invoker/exceptions/TimeoutException.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\Counter' => '/sebastian-lines-of-code/Counter.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\Exception' => '/sebastian-lines-of-code/Exception/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\IllogicalValuesException' => '/sebastian-lines-of-code/Exception/IllogicalValuesException.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\LineCountingVisitor' => '/sebastian-lines-of-code/LineCountingVisitor.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\LinesOfCode' => '/sebastian-lines-of-code/LinesOfCode.php', + 'PHPUnitPHAR\\SebastianBergmann\\LinesOfCode\\RuntimeException' => '/sebastian-lines-of-code/Exception/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\ObjectEnumerator\\Enumerator' => '/sebastian-object-enumerator/Enumerator.php', + 'PHPUnitPHAR\\SebastianBergmann\\ObjectReflector\\ObjectReflector' => '/sebastian-object-reflector/ObjectReflector.php', + 'PHPUnitPHAR\\SebastianBergmann\\RecursionContext\\Context' => '/sebastian-recursion-context/Context.php', + 'PHPUnitPHAR\\SebastianBergmann\\Template\\Exception' => '/php-text-template/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Template\\InvalidArgumentException' => '/php-text-template/exceptions/InvalidArgumentException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Template\\RuntimeException' => '/php-text-template/exceptions/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Template\\Template' => '/php-text-template/Template.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\Duration' => '/php-timer/Duration.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\Exception' => '/php-timer/exceptions/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\NoActiveTimerException' => '/php-timer/exceptions/NoActiveTimerException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\ResourceUsageFormatter' => '/php-timer/ResourceUsageFormatter.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\TimeSinceStartOfRequestNotAvailableException' => '/php-timer/exceptions/TimeSinceStartOfRequestNotAvailableException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Timer\\Timer' => '/php-timer/Timer.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\CallableType' => '/sebastian-type/type/CallableType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\Exception' => '/sebastian-type/exception/Exception.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\FalseType' => '/sebastian-type/type/FalseType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\GenericObjectType' => '/sebastian-type/type/GenericObjectType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\IntersectionType' => '/sebastian-type/type/IntersectionType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\IterableType' => '/sebastian-type/type/IterableType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\MixedType' => '/sebastian-type/type/MixedType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\NeverType' => '/sebastian-type/type/NeverType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\NullType' => '/sebastian-type/type/NullType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\ObjectType' => '/sebastian-type/type/ObjectType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\Parameter' => '/sebastian-type/Parameter.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\ReflectionMapper' => '/sebastian-type/ReflectionMapper.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\RuntimeException' => '/sebastian-type/exception/RuntimeException.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\SimpleType' => '/sebastian-type/type/SimpleType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\StaticType' => '/sebastian-type/type/StaticType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\TrueType' => '/sebastian-type/type/TrueType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\Type' => '/sebastian-type/type/Type.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\TypeName' => '/sebastian-type/TypeName.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\UnionType' => '/sebastian-type/type/UnionType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\UnknownType' => '/sebastian-type/type/UnknownType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Type\\VoidType' => '/sebastian-type/type/VoidType.php', + 'PHPUnitPHAR\\SebastianBergmann\\Version' => '/sebastian-version/Version.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\Exception' => '/theseer-tokenizer/Exception.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\NamespaceUri' => '/theseer-tokenizer/NamespaceUri.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\NamespaceUriException' => '/theseer-tokenizer/NamespaceUriException.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\Token' => '/theseer-tokenizer/Token.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\TokenCollection' => '/theseer-tokenizer/TokenCollection.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\TokenCollectionException' => '/theseer-tokenizer/TokenCollectionException.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\Tokenizer' => '/theseer-tokenizer/Tokenizer.php', + 'PHPUnitPHAR\\TheSeer\\Tokenizer\\XMLSerializer' => '/theseer-tokenizer/XMLSerializer.php', + 'PHPUnitPHAR\\staabm\\SideEffectsDetector\\SideEffect' => '/staabm-side-effects-detector/SideEffect.php', + 'PHPUnitPHAR\\staabm\\SideEffectsDetector\\SideEffectsDetector' => '/staabm-side-effects-detector/SideEffectsDetector.php', + 'PHPUnit\\Event\\Application\\Finished' => '/phpunit/Event/Events/Application/Finished.php', + 'PHPUnit\\Event\\Application\\FinishedSubscriber' => '/phpunit/Event/Events/Application/FinishedSubscriber.php', + 'PHPUnit\\Event\\Application\\Started' => '/phpunit/Event/Events/Application/Started.php', + 'PHPUnit\\Event\\Application\\StartedSubscriber' => '/phpunit/Event/Events/Application/StartedSubscriber.php', + 'PHPUnit\\Event\\Code\\ClassMethod' => '/phpunit/Event/Value/ClassMethod.php', + 'PHPUnit\\Event\\Code\\ComparisonFailure' => '/phpunit/Event/Value/ComparisonFailure.php', + 'PHPUnit\\Event\\Code\\ComparisonFailureBuilder' => '/phpunit/Event/Value/ComparisonFailureBuilder.php', + 'PHPUnit\\Event\\Code\\IssueTrigger\\Code' => '/phpunit/Event/Value/Test/Issue/Code.php', + 'PHPUnit\\Event\\Code\\IssueTrigger\\IssueTrigger' => '/phpunit/Event/Value/Test/Issue/IssueTrigger.php', + 'PHPUnit\\Event\\Code\\NoTestCaseObjectOnCallStackException' => '/phpunit/Event/Exception/NoTestCaseObjectOnCallStackException.php', + 'PHPUnit\\Event\\Code\\Phpt' => '/phpunit/Event/Value/Test/Phpt.php', + 'PHPUnit\\Event\\Code\\Test' => '/phpunit/Event/Value/Test/Test.php', + 'PHPUnit\\Event\\Code\\TestCollection' => '/phpunit/Event/Value/Test/TestCollection.php', + 'PHPUnit\\Event\\Code\\TestCollectionIterator' => '/phpunit/Event/Value/Test/TestCollectionIterator.php', + 'PHPUnit\\Event\\Code\\TestDox' => '/phpunit/Event/Value/Test/TestDox.php', + 'PHPUnit\\Event\\Code\\TestDoxBuilder' => '/phpunit/Event/Value/Test/TestDoxBuilder.php', + 'PHPUnit\\Event\\Code\\TestMethod' => '/phpunit/Event/Value/Test/TestMethod.php', + 'PHPUnit\\Event\\Code\\TestMethodBuilder' => '/phpunit/Event/Value/Test/TestMethodBuilder.php', + 'PHPUnit\\Event\\Code\\Throwable' => '/phpunit/Event/Value/Throwable.php', + 'PHPUnit\\Event\\Code\\ThrowableBuilder' => '/phpunit/Event/Value/ThrowableBuilder.php', + 'PHPUnit\\Event\\CollectingDispatcher' => '/phpunit/Event/Dispatcher/CollectingDispatcher.php', + 'PHPUnit\\Event\\DeferringDispatcher' => '/phpunit/Event/Dispatcher/DeferringDispatcher.php', + 'PHPUnit\\Event\\DirectDispatcher' => '/phpunit/Event/Dispatcher/DirectDispatcher.php', + 'PHPUnit\\Event\\Dispatcher' => '/phpunit/Event/Dispatcher/Dispatcher.php', + 'PHPUnit\\Event\\DispatchingEmitter' => '/phpunit/Event/Emitter/DispatchingEmitter.php', + 'PHPUnit\\Event\\Emitter' => '/phpunit/Event/Emitter/Emitter.php', + 'PHPUnit\\Event\\Event' => '/phpunit/Event/Events/Event.php', + 'PHPUnit\\Event\\EventAlreadyAssignedException' => '/phpunit/Event/Exception/EventAlreadyAssignedException.php', + 'PHPUnit\\Event\\EventCollection' => '/phpunit/Event/Events/EventCollection.php', + 'PHPUnit\\Event\\EventCollectionIterator' => '/phpunit/Event/Events/EventCollectionIterator.php', + 'PHPUnit\\Event\\EventFacadeIsSealedException' => '/phpunit/Event/Exception/EventFacadeIsSealedException.php', + 'PHPUnit\\Event\\Exception' => '/phpunit/Event/Exception/Exception.php', + 'PHPUnit\\Event\\Facade' => '/phpunit/Event/Facade.php', + 'PHPUnit\\Event\\InvalidArgumentException' => '/phpunit/Event/Exception/InvalidArgumentException.php', + 'PHPUnit\\Event\\InvalidEventException' => '/phpunit/Event/Exception/InvalidEventException.php', + 'PHPUnit\\Event\\InvalidSubscriberException' => '/phpunit/Event/Exception/InvalidSubscriberException.php', + 'PHPUnit\\Event\\MapError' => '/phpunit/Event/Exception/MapError.php', + 'PHPUnit\\Event\\NoPreviousThrowableException' => '/phpunit/Event/Exception/NoPreviousThrowableException.php', + 'PHPUnit\\Event\\RuntimeException' => '/phpunit/Event/Exception/RuntimeException.php', + 'PHPUnit\\Event\\Runtime\\OperatingSystem' => '/phpunit/Event/Value/Runtime/OperatingSystem.php', + 'PHPUnit\\Event\\Runtime\\PHP' => '/phpunit/Event/Value/Runtime/PHP.php', + 'PHPUnit\\Event\\Runtime\\PHPUnit' => '/phpunit/Event/Value/Runtime/PHPUnit.php', + 'PHPUnit\\Event\\Runtime\\Runtime' => '/phpunit/Event/Value/Runtime/Runtime.php', + 'PHPUnit\\Event\\SubscribableDispatcher' => '/phpunit/Event/Dispatcher/SubscribableDispatcher.php', + 'PHPUnit\\Event\\Subscriber' => '/phpunit/Event/Subscriber.php', + 'PHPUnit\\Event\\SubscriberTypeAlreadyRegisteredException' => '/phpunit/Event/Exception/SubscriberTypeAlreadyRegisteredException.php', + 'PHPUnit\\Event\\Telemetry\\Duration' => '/phpunit/Event/Value/Telemetry/Duration.php', + 'PHPUnit\\Event\\Telemetry\\GarbageCollectorStatus' => '/phpunit/Event/Value/Telemetry/GarbageCollectorStatus.php', + 'PHPUnit\\Event\\Telemetry\\GarbageCollectorStatusProvider' => '/phpunit/Event/Value/Telemetry/GarbageCollectorStatusProvider.php', + 'PHPUnit\\Event\\Telemetry\\HRTime' => '/phpunit/Event/Value/Telemetry/HRTime.php', + 'PHPUnit\\Event\\Telemetry\\Info' => '/phpunit/Event/Value/Telemetry/Info.php', + 'PHPUnit\\Event\\Telemetry\\MemoryMeter' => '/phpunit/Event/Value/Telemetry/MemoryMeter.php', + 'PHPUnit\\Event\\Telemetry\\MemoryUsage' => '/phpunit/Event/Value/Telemetry/MemoryUsage.php', + 'PHPUnit\\Event\\Telemetry\\Snapshot' => '/phpunit/Event/Value/Telemetry/Snapshot.php', + 'PHPUnit\\Event\\Telemetry\\StopWatch' => '/phpunit/Event/Value/Telemetry/StopWatch.php', + 'PHPUnit\\Event\\Telemetry\\System' => '/phpunit/Event/Value/Telemetry/System.php', + 'PHPUnit\\Event\\Telemetry\\SystemGarbageCollectorStatusProvider' => '/phpunit/Event/Value/Telemetry/SystemGarbageCollectorStatusProvider.php', + 'PHPUnit\\Event\\Telemetry\\SystemMemoryMeter' => '/phpunit/Event/Value/Telemetry/SystemMemoryMeter.php', + 'PHPUnit\\Event\\Telemetry\\SystemStopWatch' => '/phpunit/Event/Value/Telemetry/SystemStopWatch.php', + 'PHPUnit\\Event\\Telemetry\\SystemStopWatchWithOffset' => '/phpunit/Event/Value/Telemetry/SystemStopWatchWithOffset.php', + 'PHPUnit\\Event\\TestData\\DataFromDataProvider' => '/phpunit/Event/Value/Test/TestData/DataFromDataProvider.php', + 'PHPUnit\\Event\\TestData\\DataFromTestDependency' => '/phpunit/Event/Value/Test/TestData/DataFromTestDependency.php', + 'PHPUnit\\Event\\TestData\\NoDataSetFromDataProviderException' => '/phpunit/Event/Exception/NoDataSetFromDataProviderException.php', + 'PHPUnit\\Event\\TestData\\TestData' => '/phpunit/Event/Value/Test/TestData/TestData.php', + 'PHPUnit\\Event\\TestData\\TestDataCollection' => '/phpunit/Event/Value/Test/TestData/TestDataCollection.php', + 'PHPUnit\\Event\\TestData\\TestDataCollectionIterator' => '/phpunit/Event/Value/Test/TestData/TestDataCollectionIterator.php', + 'PHPUnit\\Event\\TestRunner\\BootstrapFinished' => '/phpunit/Event/Events/TestRunner/BootstrapFinished.php', + 'PHPUnit\\Event\\TestRunner\\BootstrapFinishedSubscriber' => '/phpunit/Event/Events/TestRunner/BootstrapFinishedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessErrored' => '/phpunit/Event/Events/TestRunner/ChildProcessErrored.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessErroredSubscriber' => '/phpunit/Event/Events/TestRunner/ChildProcessErroredSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessFinished' => '/phpunit/Event/Events/TestRunner/ChildProcessFinished.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessFinishedSubscriber' => '/phpunit/Event/Events/TestRunner/ChildProcessFinishedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessStarted' => '/phpunit/Event/Events/TestRunner/ChildProcessStarted.php', + 'PHPUnit\\Event\\TestRunner\\ChildProcessStartedSubscriber' => '/phpunit/Event/Events/TestRunner/ChildProcessStartedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\Configured' => '/phpunit/Event/Events/TestRunner/Configured.php', + 'PHPUnit\\Event\\TestRunner\\ConfiguredSubscriber' => '/phpunit/Event/Events/TestRunner/ConfiguredSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\DeprecationTriggered' => '/phpunit/Event/Events/TestRunner/DeprecationTriggered.php', + 'PHPUnit\\Event\\TestRunner\\DeprecationTriggeredSubscriber' => '/phpunit/Event/Events/TestRunner/DeprecationTriggeredSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\EventFacadeSealed' => '/phpunit/Event/Events/TestRunner/EventFacadeSealed.php', + 'PHPUnit\\Event\\TestRunner\\EventFacadeSealedSubscriber' => '/phpunit/Event/Events/TestRunner/EventFacadeSealedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionAborted' => '/phpunit/Event/Events/TestRunner/ExecutionAborted.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionAbortedSubscriber' => '/phpunit/Event/Events/TestRunner/ExecutionAbortedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionFinished' => '/phpunit/Event/Events/TestRunner/ExecutionFinished.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionFinishedSubscriber' => '/phpunit/Event/Events/TestRunner/ExecutionFinishedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionStarted' => '/phpunit/Event/Events/TestRunner/ExecutionStarted.php', + 'PHPUnit\\Event\\TestRunner\\ExecutionStartedSubscriber' => '/phpunit/Event/Events/TestRunner/ExecutionStartedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ExtensionBootstrapped' => '/phpunit/Event/Events/TestRunner/ExtensionBootstrapped.php', + 'PHPUnit\\Event\\TestRunner\\ExtensionBootstrappedSubscriber' => '/phpunit/Event/Events/TestRunner/ExtensionBootstrappedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\ExtensionLoadedFromPhar' => '/phpunit/Event/Events/TestRunner/ExtensionLoadedFromPhar.php', + 'PHPUnit\\Event\\TestRunner\\ExtensionLoadedFromPharSubscriber' => '/phpunit/Event/Events/TestRunner/ExtensionLoadedFromPharSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\Finished' => '/phpunit/Event/Events/TestRunner/Finished.php', + 'PHPUnit\\Event\\TestRunner\\FinishedSubscriber' => '/phpunit/Event/Events/TestRunner/FinishedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionDisabled' => '/phpunit/Event/Events/TestRunner/GarbageCollectionDisabled.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionDisabledSubscriber' => '/phpunit/Event/Events/TestRunner/GarbageCollectionDisabledSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionEnabled' => '/phpunit/Event/Events/TestRunner/GarbageCollectionEnabled.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionEnabledSubscriber' => '/phpunit/Event/Events/TestRunner/GarbageCollectionEnabledSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionTriggered' => '/phpunit/Event/Events/TestRunner/GarbageCollectionTriggered.php', + 'PHPUnit\\Event\\TestRunner\\GarbageCollectionTriggeredSubscriber' => '/phpunit/Event/Events/TestRunner/GarbageCollectionTriggeredSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\NoticeTriggered' => '/phpunit/Event/Events/TestRunner/NoticeTriggered.php', + 'PHPUnit\\Event\\TestRunner\\NoticeTriggeredSubscriber' => '/phpunit/Event/Events/TestRunner/NoticeTriggeredSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\Started' => '/phpunit/Event/Events/TestRunner/Started.php', + 'PHPUnit\\Event\\TestRunner\\StartedSubscriber' => '/phpunit/Event/Events/TestRunner/StartedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\StaticAnalysisForCodeCoverageFinished' => '/phpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinished.php', + 'PHPUnit\\Event\\TestRunner\\StaticAnalysisForCodeCoverageFinishedSubscriber' => '/phpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinishedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\StaticAnalysisForCodeCoverageStarted' => '/phpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStarted.php', + 'PHPUnit\\Event\\TestRunner\\StaticAnalysisForCodeCoverageStartedSubscriber' => '/phpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStartedSubscriber.php', + 'PHPUnit\\Event\\TestRunner\\WarningTriggered' => '/phpunit/Event/Events/TestRunner/WarningTriggered.php', + 'PHPUnit\\Event\\TestRunner\\WarningTriggeredSubscriber' => '/phpunit/Event/Events/TestRunner/WarningTriggeredSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Filtered' => '/phpunit/Event/Events/TestSuite/Filtered.php', + 'PHPUnit\\Event\\TestSuite\\FilteredSubscriber' => '/phpunit/Event/Events/TestSuite/FilteredSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Finished' => '/phpunit/Event/Events/TestSuite/Finished.php', + 'PHPUnit\\Event\\TestSuite\\FinishedSubscriber' => '/phpunit/Event/Events/TestSuite/FinishedSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Loaded' => '/phpunit/Event/Events/TestSuite/Loaded.php', + 'PHPUnit\\Event\\TestSuite\\LoadedSubscriber' => '/phpunit/Event/Events/TestSuite/LoadedSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Skipped' => '/phpunit/Event/Events/TestSuite/Skipped.php', + 'PHPUnit\\Event\\TestSuite\\SkippedSubscriber' => '/phpunit/Event/Events/TestSuite/SkippedSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Sorted' => '/phpunit/Event/Events/TestSuite/Sorted.php', + 'PHPUnit\\Event\\TestSuite\\SortedSubscriber' => '/phpunit/Event/Events/TestSuite/SortedSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\Started' => '/phpunit/Event/Events/TestSuite/Started.php', + 'PHPUnit\\Event\\TestSuite\\StartedSubscriber' => '/phpunit/Event/Events/TestSuite/StartedSubscriber.php', + 'PHPUnit\\Event\\TestSuite\\TestSuite' => '/phpunit/Event/Value/TestSuite/TestSuite.php', + 'PHPUnit\\Event\\TestSuite\\TestSuiteBuilder' => '/phpunit/Event/Value/TestSuite/TestSuiteBuilder.php', + 'PHPUnit\\Event\\TestSuite\\TestSuiteForTestClass' => '/phpunit/Event/Value/TestSuite/TestSuiteForTestClass.php', + 'PHPUnit\\Event\\TestSuite\\TestSuiteForTestMethodWithDataProvider' => '/phpunit/Event/Value/TestSuite/TestSuiteForTestMethodWithDataProvider.php', + 'PHPUnit\\Event\\TestSuite\\TestSuiteWithName' => '/phpunit/Event/Value/TestSuite/TestSuiteWithName.php', + 'PHPUnit\\Event\\Test\\AdditionalInformationProvided' => '/phpunit/Event/Events/Test/AdditionalInformationProvided.php', + 'PHPUnit\\Event\\Test\\AdditionalInformationProvidedSubscriber' => '/phpunit/Event/Events/Test/AdditionalInformationProvidedSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodCalled' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodCalled.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodErrored' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodErrored.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodFailed' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFailed.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodFinished' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFinished.php', + 'PHPUnit\\Event\\Test\\AfterLastTestMethodFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodCalled' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodCalled.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodErrored' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodErrored.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodFailed' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodFailed.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodFinished' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodFinished.php', + 'PHPUnit\\Event\\Test\\AfterTestMethodFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/AfterTestMethodFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodCalled' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalled.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodErrored' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodErrored.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodFailed' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailed.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodFinished' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinished.php', + 'PHPUnit\\Event\\Test\\BeforeFirstTestMethodFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodCalled' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodCalled.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodErrored' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodErrored.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodFailed' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodFailed.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodFinished' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodFinished.php', + 'PHPUnit\\Event\\Test\\BeforeTestMethodFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/BeforeTestMethodFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\ComparatorRegistered' => '/phpunit/Event/Events/Test/ComparatorRegistered.php', + 'PHPUnit\\Event\\Test\\ComparatorRegisteredSubscriber' => '/phpunit/Event/Events/Test/ComparatorRegisteredSubscriber.php', + 'PHPUnit\\Event\\Test\\ConsideredRisky' => '/phpunit/Event/Events/Test/Issue/ConsideredRisky.php', + 'PHPUnit\\Event\\Test\\ConsideredRiskySubscriber' => '/phpunit/Event/Events/Test/Issue/ConsideredRiskySubscriber.php', + 'PHPUnit\\Event\\Test\\CustomTestMethodInvocationUsed' => '/phpunit/Event/Events/Test/CustomTestMethodInvocationUsed.php', + 'PHPUnit\\Event\\Test\\CustomTestMethodInvocationUsedSubscriber' => '/phpunit/Event/Events/Test/CustomTestMethodInvocationUsedSubscriber.php', + 'PHPUnit\\Event\\Test\\DataProviderMethodCalled' => '/phpunit/Event/Events/Test/Lifecycle/DataProviderMethodCalled.php', + 'PHPUnit\\Event\\Test\\DataProviderMethodCalledSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/DataProviderMethodCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\DataProviderMethodFinished' => '/phpunit/Event/Events/Test/Lifecycle/DataProviderMethodFinished.php', + 'PHPUnit\\Event\\Test\\DataProviderMethodFinishedSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/DataProviderMethodFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\DeprecationTriggered' => '/phpunit/Event/Events/Test/Issue/DeprecationTriggered.php', + 'PHPUnit\\Event\\Test\\DeprecationTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/DeprecationTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\ErrorTriggered' => '/phpunit/Event/Events/Test/Issue/ErrorTriggered.php', + 'PHPUnit\\Event\\Test\\ErrorTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/ErrorTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\Errored' => '/phpunit/Event/Events/Test/Outcome/Errored.php', + 'PHPUnit\\Event\\Test\\ErroredSubscriber' => '/phpunit/Event/Events/Test/Outcome/ErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\Failed' => '/phpunit/Event/Events/Test/Outcome/Failed.php', + 'PHPUnit\\Event\\Test\\FailedSubscriber' => '/phpunit/Event/Events/Test/Outcome/FailedSubscriber.php', + 'PHPUnit\\Event\\Test\\Finished' => '/phpunit/Event/Events/Test/Lifecycle/Finished.php', + 'PHPUnit\\Event\\Test\\FinishedSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/FinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\MarkedIncomplete' => '/phpunit/Event/Events/Test/Outcome/MarkedIncomplete.php', + 'PHPUnit\\Event\\Test\\MarkedIncompleteSubscriber' => '/phpunit/Event/Events/Test/Outcome/MarkedIncompleteSubscriber.php', + 'PHPUnit\\Event\\Test\\MockObjectCreated' => '/phpunit/Event/Events/Test/TestDouble/MockObjectCreated.php', + 'PHPUnit\\Event\\Test\\MockObjectCreatedSubscriber' => '/phpunit/Event/Events/Test/TestDouble/MockObjectCreatedSubscriber.php', + 'PHPUnit\\Event\\Test\\MockObjectForIntersectionOfInterfacesCreated' => '/phpunit/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreated.php', + 'PHPUnit\\Event\\Test\\MockObjectForIntersectionOfInterfacesCreatedSubscriber' => '/phpunit/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreatedSubscriber.php', + 'PHPUnit\\Event\\Test\\NoComparisonFailureException' => '/phpunit/Event/Exception/NoComparisonFailureException.php', + 'PHPUnit\\Event\\Test\\NoticeTriggered' => '/phpunit/Event/Events/Test/Issue/NoticeTriggered.php', + 'PHPUnit\\Event\\Test\\NoticeTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/NoticeTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PartialMockObjectCreated' => '/phpunit/Event/Events/Test/TestDouble/PartialMockObjectCreated.php', + 'PHPUnit\\Event\\Test\\PartialMockObjectCreatedSubscriber' => '/phpunit/Event/Events/Test/TestDouble/PartialMockObjectCreatedSubscriber.php', + 'PHPUnit\\Event\\Test\\Passed' => '/phpunit/Event/Events/Test/Outcome/Passed.php', + 'PHPUnit\\Event\\Test\\PassedSubscriber' => '/phpunit/Event/Events/Test/Outcome/PassedSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpDeprecationTriggered' => '/phpunit/Event/Events/Test/Issue/PhpDeprecationTriggered.php', + 'PHPUnit\\Event\\Test\\PhpDeprecationTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpDeprecationTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpNoticeTriggered' => '/phpunit/Event/Events/Test/Issue/PhpNoticeTriggered.php', + 'PHPUnit\\Event\\Test\\PhpNoticeTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpNoticeTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpWarningTriggered' => '/phpunit/Event/Events/Test/Issue/PhpWarningTriggered.php', + 'PHPUnit\\Event\\Test\\PhpWarningTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpWarningTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpunitDeprecationTriggered' => '/phpunit/Event/Events/Test/Issue/PhpunitDeprecationTriggered.php', + 'PHPUnit\\Event\\Test\\PhpunitDeprecationTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpunitDeprecationTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpunitErrorTriggered' => '/phpunit/Event/Events/Test/Issue/PhpunitErrorTriggered.php', + 'PHPUnit\\Event\\Test\\PhpunitErrorTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpunitErrorTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpunitNoticeTriggered' => '/phpunit/Event/Events/Test/Issue/PhpunitNoticeTriggered.php', + 'PHPUnit\\Event\\Test\\PhpunitNoticeTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpunitNoticeTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PhpunitWarningTriggered' => '/phpunit/Event/Events/Test/Issue/PhpunitWarningTriggered.php', + 'PHPUnit\\Event\\Test\\PhpunitWarningTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/PhpunitWarningTriggeredSubscriber.php', + 'PHPUnit\\Event\\Test\\PostConditionCalled' => '/phpunit/Event/Events/Test/HookMethod/PostConditionCalled.php', + 'PHPUnit\\Event\\Test\\PostConditionCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PostConditionCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\PostConditionErrored' => '/phpunit/Event/Events/Test/HookMethod/PostConditionErrored.php', + 'PHPUnit\\Event\\Test\\PostConditionErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PostConditionErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\PostConditionFailed' => '/phpunit/Event/Events/Test/HookMethod/PostConditionFailed.php', + 'PHPUnit\\Event\\Test\\PostConditionFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PostConditionFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\PostConditionFinished' => '/phpunit/Event/Events/Test/HookMethod/PostConditionFinished.php', + 'PHPUnit\\Event\\Test\\PostConditionFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PostConditionFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\PreConditionCalled' => '/phpunit/Event/Events/Test/HookMethod/PreConditionCalled.php', + 'PHPUnit\\Event\\Test\\PreConditionCalledSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PreConditionCalledSubscriber.php', + 'PHPUnit\\Event\\Test\\PreConditionErrored' => '/phpunit/Event/Events/Test/HookMethod/PreConditionErrored.php', + 'PHPUnit\\Event\\Test\\PreConditionErroredSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PreConditionErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\PreConditionFailed' => '/phpunit/Event/Events/Test/HookMethod/PreConditionFailed.php', + 'PHPUnit\\Event\\Test\\PreConditionFailedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PreConditionFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\PreConditionFinished' => '/phpunit/Event/Events/Test/HookMethod/PreConditionFinished.php', + 'PHPUnit\\Event\\Test\\PreConditionFinishedSubscriber' => '/phpunit/Event/Events/Test/HookMethod/PreConditionFinishedSubscriber.php', + 'PHPUnit\\Event\\Test\\PreparationErrored' => '/phpunit/Event/Events/Test/Lifecycle/PreparationErrored.php', + 'PHPUnit\\Event\\Test\\PreparationErroredSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/PreparationErroredSubscriber.php', + 'PHPUnit\\Event\\Test\\PreparationFailed' => '/phpunit/Event/Events/Test/Lifecycle/PreparationFailed.php', + 'PHPUnit\\Event\\Test\\PreparationFailedSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/PreparationFailedSubscriber.php', + 'PHPUnit\\Event\\Test\\PreparationStarted' => '/phpunit/Event/Events/Test/Lifecycle/PreparationStarted.php', + 'PHPUnit\\Event\\Test\\PreparationStartedSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/PreparationStartedSubscriber.php', + 'PHPUnit\\Event\\Test\\Prepared' => '/phpunit/Event/Events/Test/Lifecycle/Prepared.php', + 'PHPUnit\\Event\\Test\\PreparedSubscriber' => '/phpunit/Event/Events/Test/Lifecycle/PreparedSubscriber.php', + 'PHPUnit\\Event\\Test\\PrintedUnexpectedOutput' => '/phpunit/Event/Events/Test/PrintedUnexpectedOutput.php', + 'PHPUnit\\Event\\Test\\PrintedUnexpectedOutputSubscriber' => '/phpunit/Event/Events/Test/PrintedUnexpectedOutputSubscriber.php', + 'PHPUnit\\Event\\Test\\Skipped' => '/phpunit/Event/Events/Test/Outcome/Skipped.php', + 'PHPUnit\\Event\\Test\\SkippedSubscriber' => '/phpunit/Event/Events/Test/Outcome/SkippedSubscriber.php', + 'PHPUnit\\Event\\Test\\TestStubCreated' => '/phpunit/Event/Events/Test/TestDouble/TestStubCreated.php', + 'PHPUnit\\Event\\Test\\TestStubCreatedSubscriber' => '/phpunit/Event/Events/Test/TestDouble/TestStubCreatedSubscriber.php', + 'PHPUnit\\Event\\Test\\TestStubForIntersectionOfInterfacesCreated' => '/phpunit/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreated.php', + 'PHPUnit\\Event\\Test\\TestStubForIntersectionOfInterfacesCreatedSubscriber' => '/phpunit/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreatedSubscriber.php', + 'PHPUnit\\Event\\Test\\WarningTriggered' => '/phpunit/Event/Events/Test/Issue/WarningTriggered.php', + 'PHPUnit\\Event\\Test\\WarningTriggeredSubscriber' => '/phpunit/Event/Events/Test/Issue/WarningTriggeredSubscriber.php', + 'PHPUnit\\Event\\Tracer\\Tracer' => '/phpunit/Event/Tracer.php', + 'PHPUnit\\Event\\TypeMap' => '/phpunit/Event/TypeMap.php', + 'PHPUnit\\Event\\UnknownEventException' => '/phpunit/Event/Exception/UnknownEventException.php', + 'PHPUnit\\Event\\UnknownEventTypeException' => '/phpunit/Event/Exception/UnknownEventTypeException.php', + 'PHPUnit\\Event\\UnknownSubscriberException' => '/phpunit/Event/Exception/UnknownSubscriberException.php', + 'PHPUnit\\Event\\UnknownSubscriberTypeException' => '/phpunit/Event/Exception/UnknownSubscriberTypeException.php', + 'PHPUnit\\Exception' => '/phpunit/Exception.php', + 'PHPUnit\\Framework\\ActualValueIsNotAnObjectException' => '/phpunit/Framework/Exception/ObjectEquals/ActualValueIsNotAnObjectException.php', + 'PHPUnit\\Framework\\Assert' => '/phpunit/Framework/Assert.php', + 'PHPUnit\\Framework\\AssertionFailedError' => '/phpunit/Framework/Exception/AssertionFailedError.php', + 'PHPUnit\\Framework\\Attributes\\After' => '/phpunit/Framework/Attributes/After.php', + 'PHPUnit\\Framework\\Attributes\\AfterClass' => '/phpunit/Framework/Attributes/AfterClass.php', + 'PHPUnit\\Framework\\Attributes\\AllowMockObjectsWithoutExpectations' => '/phpunit/Framework/Attributes/AllowMockObjectsWithoutExpectations.php', + 'PHPUnit\\Framework\\Attributes\\BackupGlobals' => '/phpunit/Framework/Attributes/BackupGlobals.php', + 'PHPUnit\\Framework\\Attributes\\BackupStaticProperties' => '/phpunit/Framework/Attributes/BackupStaticProperties.php', + 'PHPUnit\\Framework\\Attributes\\Before' => '/phpunit/Framework/Attributes/Before.php', + 'PHPUnit\\Framework\\Attributes\\BeforeClass' => '/phpunit/Framework/Attributes/BeforeClass.php', + 'PHPUnit\\Framework\\Attributes\\CoversClass' => '/phpunit/Framework/Attributes/CoversClass.php', + 'PHPUnit\\Framework\\Attributes\\CoversClassesThatExtendClass' => '/phpunit/Framework/Attributes/CoversClassesThatExtendClass.php', + 'PHPUnit\\Framework\\Attributes\\CoversClassesThatImplementInterface' => '/phpunit/Framework/Attributes/CoversClassesThatImplementInterface.php', + 'PHPUnit\\Framework\\Attributes\\CoversFunction' => '/phpunit/Framework/Attributes/CoversFunction.php', + 'PHPUnit\\Framework\\Attributes\\CoversMethod' => '/phpunit/Framework/Attributes/CoversMethod.php', + 'PHPUnit\\Framework\\Attributes\\CoversNamespace' => '/phpunit/Framework/Attributes/CoversNamespace.php', + 'PHPUnit\\Framework\\Attributes\\CoversNothing' => '/phpunit/Framework/Attributes/CoversNothing.php', + 'PHPUnit\\Framework\\Attributes\\CoversTrait' => '/phpunit/Framework/Attributes/CoversTrait.php', + 'PHPUnit\\Framework\\Attributes\\DataProvider' => '/phpunit/Framework/Attributes/DataProvider.php', + 'PHPUnit\\Framework\\Attributes\\DataProviderClosure' => '/phpunit/Framework/Attributes/DataProviderClosure.php', + 'PHPUnit\\Framework\\Attributes\\DataProviderExternal' => '/phpunit/Framework/Attributes/DataProviderExternal.php', + 'PHPUnit\\Framework\\Attributes\\Depends' => '/phpunit/Framework/Attributes/Depends.php', + 'PHPUnit\\Framework\\Attributes\\DependsExternal' => '/phpunit/Framework/Attributes/DependsExternal.php', + 'PHPUnit\\Framework\\Attributes\\DependsExternalUsingDeepClone' => '/phpunit/Framework/Attributes/DependsExternalUsingDeepClone.php', + 'PHPUnit\\Framework\\Attributes\\DependsExternalUsingShallowClone' => '/phpunit/Framework/Attributes/DependsExternalUsingShallowClone.php', + 'PHPUnit\\Framework\\Attributes\\DependsOnClass' => '/phpunit/Framework/Attributes/DependsOnClass.php', + 'PHPUnit\\Framework\\Attributes\\DependsOnClassUsingDeepClone' => '/phpunit/Framework/Attributes/DependsOnClassUsingDeepClone.php', + 'PHPUnit\\Framework\\Attributes\\DependsOnClassUsingShallowClone' => '/phpunit/Framework/Attributes/DependsOnClassUsingShallowClone.php', + 'PHPUnit\\Framework\\Attributes\\DependsUsingDeepClone' => '/phpunit/Framework/Attributes/DependsUsingDeepClone.php', + 'PHPUnit\\Framework\\Attributes\\DependsUsingShallowClone' => '/phpunit/Framework/Attributes/DependsUsingShallowClone.php', + 'PHPUnit\\Framework\\Attributes\\DisableReturnValueGenerationForTestDoubles' => '/phpunit/Framework/Attributes/DisableReturnValueGenerationForTestDoubles.php', + 'PHPUnit\\Framework\\Attributes\\DoesNotPerformAssertions' => '/phpunit/Framework/Attributes/DoesNotPerformAssertions.php', + 'PHPUnit\\Framework\\Attributes\\ExcludeGlobalVariableFromBackup' => '/phpunit/Framework/Attributes/ExcludeGlobalVariableFromBackup.php', + 'PHPUnit\\Framework\\Attributes\\ExcludeStaticPropertyFromBackup' => '/phpunit/Framework/Attributes/ExcludeStaticPropertyFromBackup.php', + 'PHPUnit\\Framework\\Attributes\\Group' => '/phpunit/Framework/Attributes/Group.php', + 'PHPUnit\\Framework\\Attributes\\IgnoreDeprecations' => '/phpunit/Framework/Attributes/IgnoreDeprecations.php', + 'PHPUnit\\Framework\\Attributes\\IgnorePhpunitDeprecations' => '/phpunit/Framework/Attributes/IgnorePhpunitDeprecations.php', + 'PHPUnit\\Framework\\Attributes\\IgnorePhpunitWarnings' => '/phpunit/Framework/Attributes/IgnorePhpunitWarnings.php', + 'PHPUnit\\Framework\\Attributes\\Large' => '/phpunit/Framework/Attributes/Large.php', + 'PHPUnit\\Framework\\Attributes\\Medium' => '/phpunit/Framework/Attributes/Medium.php', + 'PHPUnit\\Framework\\Attributes\\PostCondition' => '/phpunit/Framework/Attributes/PostCondition.php', + 'PHPUnit\\Framework\\Attributes\\PreCondition' => '/phpunit/Framework/Attributes/PreCondition.php', + 'PHPUnit\\Framework\\Attributes\\PreserveGlobalState' => '/phpunit/Framework/Attributes/PreserveGlobalState.php', + 'PHPUnit\\Framework\\Attributes\\RequiresEnvironmentVariable' => '/phpunit/Framework/Attributes/RequiresEnvironmentVariable.php', + 'PHPUnit\\Framework\\Attributes\\RequiresFunction' => '/phpunit/Framework/Attributes/RequiresFunction.php', + 'PHPUnit\\Framework\\Attributes\\RequiresMethod' => '/phpunit/Framework/Attributes/RequiresMethod.php', + 'PHPUnit\\Framework\\Attributes\\RequiresOperatingSystem' => '/phpunit/Framework/Attributes/RequiresOperatingSystem.php', + 'PHPUnit\\Framework\\Attributes\\RequiresOperatingSystemFamily' => '/phpunit/Framework/Attributes/RequiresOperatingSystemFamily.php', + 'PHPUnit\\Framework\\Attributes\\RequiresPhp' => '/phpunit/Framework/Attributes/RequiresPhp.php', + 'PHPUnit\\Framework\\Attributes\\RequiresPhpExtension' => '/phpunit/Framework/Attributes/RequiresPhpExtension.php', + 'PHPUnit\\Framework\\Attributes\\RequiresPhpunit' => '/phpunit/Framework/Attributes/RequiresPhpunit.php', + 'PHPUnit\\Framework\\Attributes\\RequiresPhpunitExtension' => '/phpunit/Framework/Attributes/RequiresPhpunitExtension.php', + 'PHPUnit\\Framework\\Attributes\\RequiresSetting' => '/phpunit/Framework/Attributes/RequiresSetting.php', + 'PHPUnit\\Framework\\Attributes\\RunInSeparateProcess' => '/phpunit/Framework/Attributes/RunInSeparateProcess.php', + 'PHPUnit\\Framework\\Attributes\\RunTestsInSeparateProcesses' => '/phpunit/Framework/Attributes/RunTestsInSeparateProcesses.php', + 'PHPUnit\\Framework\\Attributes\\Small' => '/phpunit/Framework/Attributes/Small.php', + 'PHPUnit\\Framework\\Attributes\\Test' => '/phpunit/Framework/Attributes/Test.php', + 'PHPUnit\\Framework\\Attributes\\TestDox' => '/phpunit/Framework/Attributes/TestDox.php', + 'PHPUnit\\Framework\\Attributes\\TestDoxFormatter' => '/phpunit/Framework/Attributes/TestDoxFormatter.php', + 'PHPUnit\\Framework\\Attributes\\TestDoxFormatterExternal' => '/phpunit/Framework/Attributes/TestDoxFormatterExternal.php', + 'PHPUnit\\Framework\\Attributes\\TestWith' => '/phpunit/Framework/Attributes/TestWith.php', + 'PHPUnit\\Framework\\Attributes\\TestWithJson' => '/phpunit/Framework/Attributes/TestWithJson.php', + 'PHPUnit\\Framework\\Attributes\\Ticket' => '/phpunit/Framework/Attributes/Ticket.php', + 'PHPUnit\\Framework\\Attributes\\UsesClass' => '/phpunit/Framework/Attributes/UsesClass.php', + 'PHPUnit\\Framework\\Attributes\\UsesClassesThatExtendClass' => '/phpunit/Framework/Attributes/UsesClassesThatExtendClass.php', + 'PHPUnit\\Framework\\Attributes\\UsesClassesThatImplementInterface' => '/phpunit/Framework/Attributes/UsesClassesThatImplementInterface.php', + 'PHPUnit\\Framework\\Attributes\\UsesFunction' => '/phpunit/Framework/Attributes/UsesFunction.php', + 'PHPUnit\\Framework\\Attributes\\UsesMethod' => '/phpunit/Framework/Attributes/UsesMethod.php', + 'PHPUnit\\Framework\\Attributes\\UsesNamespace' => '/phpunit/Framework/Attributes/UsesNamespace.php', + 'PHPUnit\\Framework\\Attributes\\UsesTrait' => '/phpunit/Framework/Attributes/UsesTrait.php', + 'PHPUnit\\Framework\\Attributes\\WithEnvironmentVariable' => '/phpunit/Framework/Attributes/WithEnvironmentVariable.php', + 'PHPUnit\\Framework\\Attributes\\WithoutErrorHandler' => '/phpunit/Framework/Attributes/WithoutErrorHandler.php', + 'PHPUnit\\Framework\\ChildProcessResultProcessor' => '/phpunit/Framework/TestRunner/ChildProcessResultProcessor.php', + 'PHPUnit\\Framework\\ComparisonMethodDoesNotAcceptParameterTypeException' => '/phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotAcceptParameterTypeException.php', + 'PHPUnit\\Framework\\ComparisonMethodDoesNotDeclareBoolReturnTypeException' => '/phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php', + 'PHPUnit\\Framework\\ComparisonMethodDoesNotDeclareExactlyOneParameterException' => '/phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php', + 'PHPUnit\\Framework\\ComparisonMethodDoesNotDeclareParameterTypeException' => '/phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareParameterTypeException.php', + 'PHPUnit\\Framework\\ComparisonMethodDoesNotExistException' => '/phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotExistException.php', + 'PHPUnit\\Framework\\Constraint\\ArrayComparison' => '/phpunit/Framework/Constraint/Array/ArrayComparison.php', + 'PHPUnit\\Framework\\Constraint\\ArrayHasKey' => '/phpunit/Framework/Constraint/Array/ArrayHasKey.php', + 'PHPUnit\\Framework\\Constraint\\ArraysAreEqual' => '/phpunit/Framework/Constraint/Array/ArraysAreEqual.php', + 'PHPUnit\\Framework\\Constraint\\ArraysAreIdentical' => '/phpunit/Framework/Constraint/Array/ArraysAreIdentical.php', + 'PHPUnit\\Framework\\Constraint\\BinaryOperator' => '/phpunit/Framework/Constraint/Operator/BinaryOperator.php', + 'PHPUnit\\Framework\\Constraint\\Callback' => '/phpunit/Framework/Constraint/Callback.php', + 'PHPUnit\\Framework\\Constraint\\Constraint' => '/phpunit/Framework/Constraint/Constraint.php', + 'PHPUnit\\Framework\\Constraint\\Count' => '/phpunit/Framework/Constraint/Cardinality/Count.php', + 'PHPUnit\\Framework\\Constraint\\DirectoryExists' => '/phpunit/Framework/Constraint/Filesystem/DirectoryExists.php', + 'PHPUnit\\Framework\\Constraint\\Exception' => '/phpunit/Framework/Constraint/Exception/Exception.php', + 'PHPUnit\\Framework\\Constraint\\ExceptionCode' => '/phpunit/Framework/Constraint/Exception/ExceptionCode.php', + 'PHPUnit\\Framework\\Constraint\\ExceptionMessageIsOrContains' => '/phpunit/Framework/Constraint/Exception/ExceptionMessageIsOrContains.php', + 'PHPUnit\\Framework\\Constraint\\ExceptionMessageMatchesRegularExpression' => '/phpunit/Framework/Constraint/Exception/ExceptionMessageMatchesRegularExpression.php', + 'PHPUnit\\Framework\\Constraint\\FileExists' => '/phpunit/Framework/Constraint/Filesystem/FileExists.php', + 'PHPUnit\\Framework\\Constraint\\GreaterThan' => '/phpunit/Framework/Constraint/Cardinality/GreaterThan.php', + 'PHPUnit\\Framework\\Constraint\\IsAnything' => '/phpunit/Framework/Constraint/IsAnything.php', + 'PHPUnit\\Framework\\Constraint\\IsEmpty' => '/phpunit/Framework/Constraint/Cardinality/IsEmpty.php', + 'PHPUnit\\Framework\\Constraint\\IsEqual' => '/phpunit/Framework/Constraint/Equality/IsEqual.php', + 'PHPUnit\\Framework\\Constraint\\IsEqualCanonicalizing' => '/phpunit/Framework/Constraint/Equality/IsEqualCanonicalizing.php', + 'PHPUnit\\Framework\\Constraint\\IsEqualIgnoringCase' => '/phpunit/Framework/Constraint/Equality/IsEqualIgnoringCase.php', + 'PHPUnit\\Framework\\Constraint\\IsEqualWithDelta' => '/phpunit/Framework/Constraint/Equality/IsEqualWithDelta.php', + 'PHPUnit\\Framework\\Constraint\\IsFalse' => '/phpunit/Framework/Constraint/Boolean/IsFalse.php', + 'PHPUnit\\Framework\\Constraint\\IsFinite' => '/phpunit/Framework/Constraint/Math/IsFinite.php', + 'PHPUnit\\Framework\\Constraint\\IsIdentical' => '/phpunit/Framework/Constraint/IsIdentical.php', + 'PHPUnit\\Framework\\Constraint\\IsInfinite' => '/phpunit/Framework/Constraint/Math/IsInfinite.php', + 'PHPUnit\\Framework\\Constraint\\IsInstanceOf' => '/phpunit/Framework/Constraint/Type/IsInstanceOf.php', + 'PHPUnit\\Framework\\Constraint\\IsJson' => '/phpunit/Framework/Constraint/String/IsJson.php', + 'PHPUnit\\Framework\\Constraint\\IsList' => '/phpunit/Framework/Constraint/Array/IsList.php', + 'PHPUnit\\Framework\\Constraint\\IsNan' => '/phpunit/Framework/Constraint/Math/IsNan.php', + 'PHPUnit\\Framework\\Constraint\\IsNull' => '/phpunit/Framework/Constraint/Type/IsNull.php', + 'PHPUnit\\Framework\\Constraint\\IsReadable' => '/phpunit/Framework/Constraint/Filesystem/IsReadable.php', + 'PHPUnit\\Framework\\Constraint\\IsTrue' => '/phpunit/Framework/Constraint/Boolean/IsTrue.php', + 'PHPUnit\\Framework\\Constraint\\IsType' => '/phpunit/Framework/Constraint/Type/IsType.php', + 'PHPUnit\\Framework\\Constraint\\IsWritable' => '/phpunit/Framework/Constraint/Filesystem/IsWritable.php', + 'PHPUnit\\Framework\\Constraint\\JsonMatches' => '/phpunit/Framework/Constraint/JsonMatches.php', + 'PHPUnit\\Framework\\Constraint\\LessThan' => '/phpunit/Framework/Constraint/Cardinality/LessThan.php', + 'PHPUnit\\Framework\\Constraint\\LogicalAnd' => '/phpunit/Framework/Constraint/Operator/LogicalAnd.php', + 'PHPUnit\\Framework\\Constraint\\LogicalNot' => '/phpunit/Framework/Constraint/Operator/LogicalNot.php', + 'PHPUnit\\Framework\\Constraint\\LogicalOr' => '/phpunit/Framework/Constraint/Operator/LogicalOr.php', + 'PHPUnit\\Framework\\Constraint\\LogicalXor' => '/phpunit/Framework/Constraint/Operator/LogicalXor.php', + 'PHPUnit\\Framework\\Constraint\\ObjectEquals' => '/phpunit/Framework/Constraint/Object/ObjectEquals.php', + 'PHPUnit\\Framework\\Constraint\\ObjectHasProperty' => '/phpunit/Framework/Constraint/Object/ObjectHasProperty.php', + 'PHPUnit\\Framework\\Constraint\\Operator' => '/phpunit/Framework/Constraint/Operator/Operator.php', + 'PHPUnit\\Framework\\Constraint\\RegularExpression' => '/phpunit/Framework/Constraint/String/RegularExpression.php', + 'PHPUnit\\Framework\\Constraint\\SameSize' => '/phpunit/Framework/Constraint/Cardinality/SameSize.php', + 'PHPUnit\\Framework\\Constraint\\StringContains' => '/phpunit/Framework/Constraint/String/StringContains.php', + 'PHPUnit\\Framework\\Constraint\\StringEndsWith' => '/phpunit/Framework/Constraint/String/StringEndsWith.php', + 'PHPUnit\\Framework\\Constraint\\StringEqualsStringIgnoringLineEndings' => '/phpunit/Framework/Constraint/String/StringEqualsStringIgnoringLineEndings.php', + 'PHPUnit\\Framework\\Constraint\\StringMatchesFormatDescription' => '/phpunit/Framework/Constraint/String/StringMatchesFormatDescription.php', + 'PHPUnit\\Framework\\Constraint\\StringStartsWith' => '/phpunit/Framework/Constraint/String/StringStartsWith.php', + 'PHPUnit\\Framework\\Constraint\\TraversableContains' => '/phpunit/Framework/Constraint/Traversable/TraversableContains.php', + 'PHPUnit\\Framework\\Constraint\\TraversableContainsEqual' => '/phpunit/Framework/Constraint/Traversable/TraversableContainsEqual.php', + 'PHPUnit\\Framework\\Constraint\\TraversableContainsIdentical' => '/phpunit/Framework/Constraint/Traversable/TraversableContainsIdentical.php', + 'PHPUnit\\Framework\\Constraint\\TraversableContainsOnly' => '/phpunit/Framework/Constraint/Traversable/TraversableContainsOnly.php', + 'PHPUnit\\Framework\\Constraint\\UnaryOperator' => '/phpunit/Framework/Constraint/Operator/UnaryOperator.php', + 'PHPUnit\\Framework\\DataProviderTestSuite' => '/phpunit/Framework/DataProviderTestSuite.php', + 'PHPUnit\\Framework\\EmptyStringException' => '/phpunit/Framework/Exception/EmptyStringException.php', + 'PHPUnit\\Framework\\ErrorLogNotWritableException' => '/phpunit/Framework/Exception/ErrorLogNotWritableException.php', + 'PHPUnit\\Framework\\Exception' => '/phpunit/Framework/Exception/Exception.php', + 'PHPUnit\\Framework\\ExecutionOrderDependency' => '/phpunit/Framework/ExecutionOrderDependency.php', + 'PHPUnit\\Framework\\ExpectationFailedException' => '/phpunit/Framework/Exception/ExpectationFailedException.php', + 'PHPUnit\\Framework\\GeneratorNotSupportedException' => '/phpunit/Framework/Exception/GeneratorNotSupportedException.php', + 'PHPUnit\\Framework\\IncompleteTest' => '/phpunit/Framework/Exception/Incomplete/IncompleteTest.php', + 'PHPUnit\\Framework\\IncompleteTestError' => '/phpunit/Framework/Exception/Incomplete/IncompleteTestError.php', + 'PHPUnit\\Framework\\InvalidArgumentException' => '/phpunit/Framework/Exception/InvalidArgumentException.php', + 'PHPUnit\\Framework\\InvalidDataProviderException' => '/phpunit/Framework/Exception/InvalidDataProviderException.php', + 'PHPUnit\\Framework\\InvalidDependencyException' => '/phpunit/Framework/Exception/InvalidDependencyException.php', + 'PHPUnit\\Framework\\MockObject\\AbstractInvocationImplementation' => '/phpunit/Framework/MockObject/Runtime/AbstractInvocationImplementation.php', + 'PHPUnit\\Framework\\MockObject\\BadMethodCallException' => '/phpunit/Framework/MockObject/Exception/BadMethodCallException.php', + 'PHPUnit\\Framework\\MockObject\\CannotUseOnlyMethodsException' => '/phpunit/Framework/MockObject/Exception/CannotUseOnlyMethodsException.php', + 'PHPUnit\\Framework\\MockObject\\ConfigurableMethod' => '/phpunit/Framework/MockObject/ConfigurableMethod.php', + 'PHPUnit\\Framework\\MockObject\\DoubledCloneMethod' => '/phpunit/Framework/MockObject/Runtime/Api/DoubledCloneMethod.php', + 'PHPUnit\\Framework\\MockObject\\Exception' => '/phpunit/Framework/MockObject/Exception/Exception.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\ClassIsAnonymousException' => '/phpunit/Framework/MockObject/Generator/Exception/ClassIsAnonymousException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\ClassIsEnumerationException' => '/phpunit/Framework/MockObject/Generator/Exception/ClassIsEnumerationException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\ClassIsFinalException' => '/phpunit/Framework/MockObject/Generator/Exception/ClassIsFinalException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\DoubledClass' => '/phpunit/Framework/MockObject/Generator/DoubledClass.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\DoubledMethod' => '/phpunit/Framework/MockObject/Generator/DoubledMethod.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\DoubledMethodSet' => '/phpunit/Framework/MockObject/Generator/DoubledMethodSet.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\DuplicateMethodException' => '/phpunit/Framework/MockObject/Generator/Exception/DuplicateMethodException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\Exception' => '/phpunit/Framework/MockObject/Generator/Exception/Exception.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\Generator' => '/phpunit/Framework/MockObject/Generator/Generator.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\HookedProperty' => '/phpunit/Framework/MockObject/Generator/HookedProperty.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\HookedPropertyGenerator' => '/phpunit/Framework/MockObject/Generator/HookedPropertyGenerator.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\InvalidClassNameException' => '/phpunit/Framework/MockObject/Generator/Exception/InvalidClassNameException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\InvalidMethodNameException' => '/phpunit/Framework/MockObject/Generator/Exception/InvalidMethodNameException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\MethodNamedMethodException' => '/phpunit/Framework/MockObject/Generator/Exception/MethodNamedMethodException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\NameAlreadyInUseException' => '/phpunit/Framework/MockObject/Generator/Exception/NameAlreadyInUseException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\ReflectionException' => '/phpunit/Framework/MockObject/Generator/Exception/ReflectionException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\RuntimeException' => '/phpunit/Framework/MockObject/Generator/Exception/RuntimeException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\TemplateLoader' => '/phpunit/Framework/MockObject/Generator/TemplateLoader.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\UnknownInterfaceException' => '/phpunit/Framework/MockObject/Generator/Exception/UnknownInterfaceException.php', + 'PHPUnit\\Framework\\MockObject\\Generator\\UnknownTypeException' => '/phpunit/Framework/MockObject/Generator/Exception/UnknownTypeException.php', + 'PHPUnit\\Framework\\MockObject\\IncompatibleReturnValueException' => '/phpunit/Framework/MockObject/Exception/IncompatibleReturnValueException.php', + 'PHPUnit\\Framework\\MockObject\\Invocation' => '/phpunit/Framework/MockObject/Runtime/Invocation.php', + 'PHPUnit\\Framework\\MockObject\\InvocationHandler' => '/phpunit/Framework/MockObject/Runtime/InvocationHandler.php', + 'PHPUnit\\Framework\\MockObject\\InvocationMocker' => '/phpunit/Framework/MockObject/Runtime/Interface/InvocationMocker.php', + 'PHPUnit\\Framework\\MockObject\\InvocationMockerImplementation' => '/phpunit/Framework/MockObject/Runtime/InvocationMockerImplementation.php', + 'PHPUnit\\Framework\\MockObject\\InvocationStubber' => '/phpunit/Framework/MockObject/Runtime/Interface/InvocationStubber.php', + 'PHPUnit\\Framework\\MockObject\\InvocationStubberImplementation' => '/phpunit/Framework/MockObject/Runtime/InvocationStubberImplementation.php', + 'PHPUnit\\Framework\\MockObject\\MatchBuilderNotFoundException' => '/phpunit/Framework/MockObject/Exception/MatchBuilderNotFoundException.php', + 'PHPUnit\\Framework\\MockObject\\Matcher' => '/phpunit/Framework/MockObject/Runtime/Matcher.php', + 'PHPUnit\\Framework\\MockObject\\MatcherAlreadyRegisteredException' => '/phpunit/Framework/MockObject/Exception/MatcherAlreadyRegisteredException.php', + 'PHPUnit\\Framework\\MockObject\\Method' => '/phpunit/Framework/MockObject/Runtime/Api/Method.php', + 'PHPUnit\\Framework\\MockObject\\MethodCannotBeConfiguredException' => '/phpunit/Framework/MockObject/Exception/MethodCannotBeConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\MethodNameAlreadyConfiguredException' => '/phpunit/Framework/MockObject/Exception/MethodNameAlreadyConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\MethodNameConstraint' => '/phpunit/Framework/MockObject/Runtime/MethodNameConstraint.php', + 'PHPUnit\\Framework\\MockObject\\MethodNameNotConfiguredException' => '/phpunit/Framework/MockObject/Exception/MethodNameNotConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\MethodParametersAlreadyConfiguredException' => '/phpunit/Framework/MockObject/Exception/MethodParametersAlreadyConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\MockBuilder' => '/phpunit/Framework/MockObject/MockBuilder.php', + 'PHPUnit\\Framework\\MockObject\\MockObject' => '/phpunit/Framework/MockObject/Runtime/Interface/MockObject.php', + 'PHPUnit\\Framework\\MockObject\\MockObjectApi' => '/phpunit/Framework/MockObject/Runtime/Api/MockObjectApi.php', + 'PHPUnit\\Framework\\MockObject\\MockObjectInternal' => '/phpunit/Framework/MockObject/Runtime/Interface/MockObjectInternal.php', + 'PHPUnit\\Framework\\MockObject\\NeverReturningMethodException' => '/phpunit/Framework/MockObject/Exception/NeverReturningMethodException.php', + 'PHPUnit\\Framework\\MockObject\\NoMoreParameterSetsConfiguredException' => '/phpunit/Framework/MockObject/Exception/NoMoreParameterSetsConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\NoMoreReturnValuesConfiguredException' => '/phpunit/Framework/MockObject/Exception/NoMoreReturnValuesConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\ProxiedCloneMethod' => '/phpunit/Framework/MockObject/Runtime/Api/ProxiedCloneMethod.php', + 'PHPUnit\\Framework\\MockObject\\ReturnValueGenerator' => '/phpunit/Framework/MockObject/Runtime/ReturnValueGenerator.php', + 'PHPUnit\\Framework\\MockObject\\ReturnValueNotConfiguredException' => '/phpunit/Framework/MockObject/Exception/ReturnValueNotConfiguredException.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\AnyInvokedCount' => '/phpunit/Framework/MockObject/Runtime/Rule/AnyInvokedCount.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\AnyParameters' => '/phpunit/Framework/MockObject/Runtime/Rule/AnyParameters.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\InvocationOrder' => '/phpunit/Framework/MockObject/Runtime/Rule/InvocationOrder.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtLeastCount' => '/phpunit/Framework/MockObject/Runtime/Rule/InvokedAtLeastCount.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtLeastOnce' => '/phpunit/Framework/MockObject/Runtime/Rule/InvokedAtLeastOnce.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\InvokedAtMostCount' => '/phpunit/Framework/MockObject/Runtime/Rule/InvokedAtMostCount.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\InvokedCount' => '/phpunit/Framework/MockObject/Runtime/Rule/InvokedCount.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\MethodName' => '/phpunit/Framework/MockObject/Runtime/Rule/MethodName.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\OrderedParameterSets' => '/phpunit/Framework/MockObject/Runtime/Rule/OrderedParameterSets.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\Parameters' => '/phpunit/Framework/MockObject/Runtime/Rule/Parameters.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\ParametersRule' => '/phpunit/Framework/MockObject/Runtime/Rule/ParametersRule.php', + 'PHPUnit\\Framework\\MockObject\\Rule\\UnorderedParameterSets' => '/phpunit/Framework/MockObject/Runtime/Rule/UnorderedParameterSets.php', + 'PHPUnit\\Framework\\MockObject\\RuntimeException' => '/phpunit/Framework/MockObject/Exception/RuntimeException.php', + 'PHPUnit\\Framework\\MockObject\\Runtime\\PropertyGetHook' => '/phpunit/Framework/MockObject/Runtime/PropertyHook/PropertyGetHook.php', + 'PHPUnit\\Framework\\MockObject\\Runtime\\PropertyHook' => '/phpunit/Framework/MockObject/Runtime/PropertyHook/PropertyHook.php', + 'PHPUnit\\Framework\\MockObject\\Runtime\\PropertySetHook' => '/phpunit/Framework/MockObject/Runtime/PropertyHook/PropertySetHook.php', + 'PHPUnit\\Framework\\MockObject\\Stub' => '/phpunit/Framework/MockObject/Runtime/Interface/Stub.php', + 'PHPUnit\\Framework\\MockObject\\StubApi' => '/phpunit/Framework/MockObject/Runtime/Api/StubApi.php', + 'PHPUnit\\Framework\\MockObject\\StubInternal' => '/phpunit/Framework/MockObject/Runtime/Interface/StubInternal.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ConsecutiveCalls' => '/phpunit/Framework/MockObject/Runtime/Stub/ConsecutiveCalls.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\Exception' => '/phpunit/Framework/MockObject/Runtime/Stub/Exception.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnArgument' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnArgument.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnCallback' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnCallback.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnReference' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnReference.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnSelf' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnSelf.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnStub' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnStub.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\ReturnValueMap' => '/phpunit/Framework/MockObject/Runtime/Stub/ReturnValueMap.php', + 'PHPUnit\\Framework\\MockObject\\Stub\\Stub' => '/phpunit/Framework/MockObject/Runtime/Stub/Stub.php', + 'PHPUnit\\Framework\\MockObject\\TestDoubleBuilder' => '/phpunit/Framework/MockObject/TestDoubleBuilder.php', + 'PHPUnit\\Framework\\MockObject\\TestDoubleSealedException' => '/phpunit/Framework/MockObject/Exception/TestDoubleSealedException.php', + 'PHPUnit\\Framework\\MockObject\\TestDoubleState' => '/phpunit/Framework/MockObject/Runtime/Api/TestDoubleState.php', + 'PHPUnit\\Framework\\MockObject\\TestStubBuilder' => '/phpunit/Framework/MockObject/TestStubBuilder.php', + 'PHPUnit\\Framework\\NativeType' => '/phpunit/Framework/NativeType.php', + 'PHPUnit\\Framework\\NoChildTestSuiteException' => '/phpunit/Framework/Exception/NoChildTestSuiteException.php', + 'PHPUnit\\Framework\\PhptAssertionFailedError' => '/phpunit/Framework/Exception/PhptAssertionFailedError.php', + 'PHPUnit\\Framework\\ProcessIsolationException' => '/phpunit/Framework/Exception/ProcessIsolationException.php', + 'PHPUnit\\Framework\\Reorderable' => '/phpunit/Framework/Reorderable.php', + 'PHPUnit\\Framework\\SelfDescribing' => '/phpunit/Framework/SelfDescribing.php', + 'PHPUnit\\Framework\\SeparateProcessTestRunner' => '/phpunit/Framework/TestRunner/SeparateProcessTestRunner.php', + 'PHPUnit\\Framework\\SkippedTest' => '/phpunit/Framework/Exception/Skipped/SkippedTest.php', + 'PHPUnit\\Framework\\SkippedTestSuiteError' => '/phpunit/Framework/Exception/Skipped/SkippedTestSuiteError.php', + 'PHPUnit\\Framework\\SkippedWithMessageException' => '/phpunit/Framework/Exception/Skipped/SkippedWithMessageException.php', + 'PHPUnit\\Framework\\Test' => '/phpunit/Framework/Test.php', + 'PHPUnit\\Framework\\TestBuilder' => '/phpunit/Framework/TestBuilder.php', + 'PHPUnit\\Framework\\TestCase' => '/phpunit/Framework/TestCase.php', + 'PHPUnit\\Framework\\TestRunner' => '/phpunit/Framework/TestRunner/TestRunner.php', + 'PHPUnit\\Framework\\TestSize\\Known' => '/phpunit/Framework/TestSize/Known.php', + 'PHPUnit\\Framework\\TestSize\\Large' => '/phpunit/Framework/TestSize/Large.php', + 'PHPUnit\\Framework\\TestSize\\Medium' => '/phpunit/Framework/TestSize/Medium.php', + 'PHPUnit\\Framework\\TestSize\\Small' => '/phpunit/Framework/TestSize/Small.php', + 'PHPUnit\\Framework\\TestSize\\TestSize' => '/phpunit/Framework/TestSize/TestSize.php', + 'PHPUnit\\Framework\\TestSize\\Unknown' => '/phpunit/Framework/TestSize/Unknown.php', + 'PHPUnit\\Framework\\TestStatus\\Deprecation' => '/phpunit/Framework/TestStatus/Deprecation.php', + 'PHPUnit\\Framework\\TestStatus\\Error' => '/phpunit/Framework/TestStatus/Error.php', + 'PHPUnit\\Framework\\TestStatus\\Failure' => '/phpunit/Framework/TestStatus/Failure.php', + 'PHPUnit\\Framework\\TestStatus\\Incomplete' => '/phpunit/Framework/TestStatus/Incomplete.php', + 'PHPUnit\\Framework\\TestStatus\\Known' => '/phpunit/Framework/TestStatus/Known.php', + 'PHPUnit\\Framework\\TestStatus\\Notice' => '/phpunit/Framework/TestStatus/Notice.php', + 'PHPUnit\\Framework\\TestStatus\\Risky' => '/phpunit/Framework/TestStatus/Risky.php', + 'PHPUnit\\Framework\\TestStatus\\Skipped' => '/phpunit/Framework/TestStatus/Skipped.php', + 'PHPUnit\\Framework\\TestStatus\\Success' => '/phpunit/Framework/TestStatus/Success.php', + 'PHPUnit\\Framework\\TestStatus\\TestStatus' => '/phpunit/Framework/TestStatus/TestStatus.php', + 'PHPUnit\\Framework\\TestStatus\\Unknown' => '/phpunit/Framework/TestStatus/Unknown.php', + 'PHPUnit\\Framework\\TestStatus\\Warning' => '/phpunit/Framework/TestStatus/Warning.php', + 'PHPUnit\\Framework\\TestSuite' => '/phpunit/Framework/TestSuite.php', + 'PHPUnit\\Framework\\TestSuiteIterator' => '/phpunit/Framework/TestSuiteIterator.php', + 'PHPUnit\\Framework\\UnknownClassOrInterfaceException' => '/phpunit/Framework/Exception/UnknownClassOrInterfaceException.php', + 'PHPUnit\\Framework\\UnknownNativeTypeException' => '/phpunit/Framework/Exception/UnknownNativeTypeException.php', + 'PHPUnit\\Logging\\EventLogger' => '/phpunit/Logging/EventLogger.php', + 'PHPUnit\\Logging\\JUnit\\JunitXmlLogger' => '/phpunit/Logging/JUnit/JunitXmlLogger.php', + 'PHPUnit\\Logging\\JUnit\\Subscriber' => '/phpunit/Logging/JUnit/Subscriber/Subscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestErroredSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestFailedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestFinishedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestMarkedIncompleteSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestPreparationErroredSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestPreparationErroredSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestPreparationFailedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestPreparationFailedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestPreparationStartedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestPreparationStartedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestPreparedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestPrintedUnexpectedOutputSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestPrintedUnexpectedOutputSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestRunnerExecutionFinishedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestRunnerExecutionFinishedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestSkippedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestSuiteFinishedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestSuiteFinishedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestSuiteSkippedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestSuiteSkippedSubscriber.php', + 'PHPUnit\\Logging\\JUnit\\TestSuiteStartedSubscriber' => '/phpunit/Logging/JUnit/Subscriber/TestSuiteStartedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\AfterLastTestMethodErroredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodErroredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\AfterLastTestMethodFailedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodFailedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\BeforeFirstTestMethodErroredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodErroredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\BeforeFirstTestMethodFailedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodFailedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\CannotOpenUriForWritingException' => '/phpunit/Logging/OpenTestReporting/Exception/CannotOpenUriForWritingException.php', + 'PHPUnit\\Logging\\OpenTestReporting\\Exception' => '/phpunit/Logging/OpenTestReporting/Exception/Exception.php', + 'PHPUnit\\Logging\\OpenTestReporting\\OtrXmlLogger' => '/phpunit/Logging/OpenTestReporting/OtrXmlLogger.php', + 'PHPUnit\\Logging\\OpenTestReporting\\Status' => '/phpunit/Logging/OpenTestReporting/Status.php', + 'PHPUnit\\Logging\\OpenTestReporting\\Subscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/Subscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestAbortedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestAbortedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestConsideredRiskySubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestDeprecationTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestDeprecationTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestErrorTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestErrorTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestErroredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestFailedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestFinishedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestNoticeTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestNoticeTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpDeprecationTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpDeprecationTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpNoticeTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpNoticeTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpWarningTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpWarningTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpunitDeprecationTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitDeprecationTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpunitErrorTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitErrorTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpunitNoticeTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitNoticeTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPhpunitWarningTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitWarningTriggeredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPreparationErroredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPreparationErroredSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPreparationFailedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPreparationFailedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPreparedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestPrintedUnexpectedOutputSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestPrintedUnexpectedOutputSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestRunnerFinishedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestRunnerFinishedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestRunnerStartedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestRunnerStartedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestSkippedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestSuiteFinishedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestSuiteFinishedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestSuiteSkippedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestSuiteSkippedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestSuiteStartedSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestSuiteStartedSubscriber.php', + 'PHPUnit\\Logging\\OpenTestReporting\\TestWarningTriggeredSubscriber' => '/phpunit/Logging/OpenTestReporting/Subscriber/TestWarningTriggeredSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\Subscriber' => '/phpunit/Logging/TeamCity/Subscriber/Subscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TeamCityLogger' => '/phpunit/Logging/TeamCity/TeamCityLogger.php', + 'PHPUnit\\Logging\\TeamCity\\TestConsideredRiskySubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestErroredSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestFailedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestFinishedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestMarkedIncompleteSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestPreparationErroredSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestPreparationErroredSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestPreparationFailedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestPreparationFailedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestPreparationStartedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestPreparationStartedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestPreparedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestRunnerExecutionFinishedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestRunnerExecutionFinishedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSkippedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSuiteBeforeFirstTestMethodErroredSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSuiteBeforeFirstTestMethodErroredSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSuiteBeforeFirstTestMethodFailedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSuiteBeforeFirstTestMethodFailedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSuiteFinishedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSuiteFinishedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSuiteSkippedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSuiteSkippedSubscriber.php', + 'PHPUnit\\Logging\\TeamCity\\TestSuiteStartedSubscriber' => '/phpunit/Logging/TeamCity/Subscriber/TestSuiteStartedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\HtmlRenderer' => '/phpunit/Logging/TestDox/HtmlRenderer.php', + 'PHPUnit\\Logging\\TestDox\\NamePrettifier' => '/phpunit/Logging/TestDox/NamePrettifier.php', + 'PHPUnit\\Logging\\TestDox\\PlainTextRenderer' => '/phpunit/Logging/TestDox/PlainTextRenderer.php', + 'PHPUnit\\Logging\\TestDox\\Subscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/Subscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestConsideredRiskySubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestErroredSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestFailedSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestFinishedSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestMarkedIncompleteSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestPassedSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestPassedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestPreparedSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestResult' => '/phpunit/Logging/TestDox/TestResult/TestResult.php', + 'PHPUnit\\Logging\\TestDox\\TestResultCollection' => '/phpunit/Logging/TestDox/TestResult/TestResultCollection.php', + 'PHPUnit\\Logging\\TestDox\\TestResultCollectionIterator' => '/phpunit/Logging/TestDox/TestResult/TestResultCollectionIterator.php', + 'PHPUnit\\Logging\\TestDox\\TestResultCollector' => '/phpunit/Logging/TestDox/TestResult/TestResultCollector.php', + 'PHPUnit\\Logging\\TestDox\\TestSkippedSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredDeprecationSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredNoticeSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpDeprecationSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpNoticeSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpWarningSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpunitDeprecationSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpunitErrorSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredPhpunitWarningSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php', + 'PHPUnit\\Logging\\TestDox\\TestTriggeredWarningSubscriber' => '/phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredWarningSubscriber.php', + 'PHPUnit\\Metadata\\After' => '/phpunit/Metadata/After.php', + 'PHPUnit\\Metadata\\AfterClass' => '/phpunit/Metadata/AfterClass.php', + 'PHPUnit\\Metadata\\AllowMockObjectsWithoutExpectations' => '/phpunit/Metadata/AllowMockObjectsWithoutExpectations.php', + 'PHPUnit\\Metadata\\Api\\CodeCoverage' => '/phpunit/Metadata/Api/CodeCoverage.php', + 'PHPUnit\\Metadata\\Api\\DataProvider' => '/phpunit/Metadata/Api/DataProvider.php', + 'PHPUnit\\Metadata\\Api\\Dependencies' => '/phpunit/Metadata/Api/Dependencies.php', + 'PHPUnit\\Metadata\\Api\\Groups' => '/phpunit/Metadata/Api/Groups.php', + 'PHPUnit\\Metadata\\Api\\HookMethods' => '/phpunit/Metadata/Api/HookMethods.php', + 'PHPUnit\\Metadata\\Api\\ProvidedData' => '/phpunit/Metadata/Api/ProvidedData.php', + 'PHPUnit\\Metadata\\Api\\Requirements' => '/phpunit/Metadata/Api/Requirements.php', + 'PHPUnit\\Metadata\\BackupGlobals' => '/phpunit/Metadata/BackupGlobals.php', + 'PHPUnit\\Metadata\\BackupStaticProperties' => '/phpunit/Metadata/BackupStaticProperties.php', + 'PHPUnit\\Metadata\\Before' => '/phpunit/Metadata/Before.php', + 'PHPUnit\\Metadata\\BeforeClass' => '/phpunit/Metadata/BeforeClass.php', + 'PHPUnit\\Metadata\\CoversClass' => '/phpunit/Metadata/CoversClass.php', + 'PHPUnit\\Metadata\\CoversClassesThatExtendClass' => '/phpunit/Metadata/CoversClassesThatExtendClass.php', + 'PHPUnit\\Metadata\\CoversClassesThatImplementInterface' => '/phpunit/Metadata/CoversClassesThatImplementInterface.php', + 'PHPUnit\\Metadata\\CoversFunction' => '/phpunit/Metadata/CoversFunction.php', + 'PHPUnit\\Metadata\\CoversMethod' => '/phpunit/Metadata/CoversMethod.php', + 'PHPUnit\\Metadata\\CoversNamespace' => '/phpunit/Metadata/CoversNamespace.php', + 'PHPUnit\\Metadata\\CoversNothing' => '/phpunit/Metadata/CoversNothing.php', + 'PHPUnit\\Metadata\\CoversTrait' => '/phpunit/Metadata/CoversTrait.php', + 'PHPUnit\\Metadata\\DataProvider' => '/phpunit/Metadata/DataProvider.php', + 'PHPUnit\\Metadata\\DataProviderClosure' => '/phpunit/Metadata/DataProviderClosure.php', + 'PHPUnit\\Metadata\\DependsOnClass' => '/phpunit/Metadata/DependsOnClass.php', + 'PHPUnit\\Metadata\\DependsOnMethod' => '/phpunit/Metadata/DependsOnMethod.php', + 'PHPUnit\\Metadata\\DisableReturnValueGenerationForTestDoubles' => '/phpunit/Metadata/DisableReturnValueGenerationForTestDoubles.php', + 'PHPUnit\\Metadata\\DoesNotPerformAssertions' => '/phpunit/Metadata/DoesNotPerformAssertions.php', + 'PHPUnit\\Metadata\\Exception' => '/phpunit/Metadata/Exception/Exception.php', + 'PHPUnit\\Metadata\\ExcludeGlobalVariableFromBackup' => '/phpunit/Metadata/ExcludeGlobalVariableFromBackup.php', + 'PHPUnit\\Metadata\\ExcludeStaticPropertyFromBackup' => '/phpunit/Metadata/ExcludeStaticPropertyFromBackup.php', + 'PHPUnit\\Metadata\\Group' => '/phpunit/Metadata/Group.php', + 'PHPUnit\\Metadata\\IgnoreDeprecations' => '/phpunit/Metadata/IgnoreDeprecations.php', + 'PHPUnit\\Metadata\\IgnorePhpunitDeprecations' => '/phpunit/Metadata/IgnorePhpunitDeprecations.php', + 'PHPUnit\\Metadata\\IgnorePhpunitWarnings' => '/phpunit/Metadata/IgnorePhpunitWarnings.php', + 'PHPUnit\\Metadata\\InvalidAttributeException' => '/phpunit/Metadata/Exception/InvalidAttributeException.php', + 'PHPUnit\\Metadata\\InvalidVersionRequirementException' => '/phpunit/Metadata/Exception/InvalidVersionRequirementException.php', + 'PHPUnit\\Metadata\\Level' => '/phpunit/Metadata/Level.php', + 'PHPUnit\\Metadata\\Metadata' => '/phpunit/Metadata/Metadata.php', + 'PHPUnit\\Metadata\\MetadataCollection' => '/phpunit/Metadata/MetadataCollection.php', + 'PHPUnit\\Metadata\\MetadataCollectionIterator' => '/phpunit/Metadata/MetadataCollectionIterator.php', + 'PHPUnit\\Metadata\\NoVersionRequirementException' => '/phpunit/Metadata/Exception/NoVersionRequirementException.php', + 'PHPUnit\\Metadata\\Parser\\AttributeParser' => '/phpunit/Metadata/Parser/AttributeParser.php', + 'PHPUnit\\Metadata\\Parser\\CachingParser' => '/phpunit/Metadata/Parser/CachingParser.php', + 'PHPUnit\\Metadata\\Parser\\Parser' => '/phpunit/Metadata/Parser/Parser.php', + 'PHPUnit\\Metadata\\Parser\\Registry' => '/phpunit/Metadata/Parser/Registry.php', + 'PHPUnit\\Metadata\\PostCondition' => '/phpunit/Metadata/PostCondition.php', + 'PHPUnit\\Metadata\\PreCondition' => '/phpunit/Metadata/PreCondition.php', + 'PHPUnit\\Metadata\\PreserveGlobalState' => '/phpunit/Metadata/PreserveGlobalState.php', + 'PHPUnit\\Metadata\\RequiresEnvironmentVariable' => '/phpunit/Metadata/RequiresEnvironmentVariable.php', + 'PHPUnit\\Metadata\\RequiresFunction' => '/phpunit/Metadata/RequiresFunction.php', + 'PHPUnit\\Metadata\\RequiresMethod' => '/phpunit/Metadata/RequiresMethod.php', + 'PHPUnit\\Metadata\\RequiresOperatingSystem' => '/phpunit/Metadata/RequiresOperatingSystem.php', + 'PHPUnit\\Metadata\\RequiresOperatingSystemFamily' => '/phpunit/Metadata/RequiresOperatingSystemFamily.php', + 'PHPUnit\\Metadata\\RequiresPhp' => '/phpunit/Metadata/RequiresPhp.php', + 'PHPUnit\\Metadata\\RequiresPhpExtension' => '/phpunit/Metadata/RequiresPhpExtension.php', + 'PHPUnit\\Metadata\\RequiresPhpunit' => '/phpunit/Metadata/RequiresPhpunit.php', + 'PHPUnit\\Metadata\\RequiresPhpunitExtension' => '/phpunit/Metadata/RequiresPhpunitExtension.php', + 'PHPUnit\\Metadata\\RequiresSetting' => '/phpunit/Metadata/RequiresSetting.php', + 'PHPUnit\\Metadata\\RunInSeparateProcess' => '/phpunit/Metadata/RunInSeparateProcess.php', + 'PHPUnit\\Metadata\\RunTestsInSeparateProcesses' => '/phpunit/Metadata/RunTestsInSeparateProcesses.php', + 'PHPUnit\\Metadata\\Test' => '/phpunit/Metadata/Test.php', + 'PHPUnit\\Metadata\\TestDox' => '/phpunit/Metadata/TestDox.php', + 'PHPUnit\\Metadata\\TestDoxFormatter' => '/phpunit/Metadata/TestDoxFormatter.php', + 'PHPUnit\\Metadata\\TestWith' => '/phpunit/Metadata/TestWith.php', + 'PHPUnit\\Metadata\\UsesClass' => '/phpunit/Metadata/UsesClass.php', + 'PHPUnit\\Metadata\\UsesClassesThatExtendClass' => '/phpunit/Metadata/UsesClassesThatExtendClass.php', + 'PHPUnit\\Metadata\\UsesClassesThatImplementInterface' => '/phpunit/Metadata/UsesClassesThatImplementInterface.php', + 'PHPUnit\\Metadata\\UsesFunction' => '/phpunit/Metadata/UsesFunction.php', + 'PHPUnit\\Metadata\\UsesMethod' => '/phpunit/Metadata/UsesMethod.php', + 'PHPUnit\\Metadata\\UsesNamespace' => '/phpunit/Metadata/UsesNamespace.php', + 'PHPUnit\\Metadata\\UsesTrait' => '/phpunit/Metadata/UsesTrait.php', + 'PHPUnit\\Metadata\\Version\\ComparisonRequirement' => '/phpunit/Metadata/Version/ComparisonRequirement.php', + 'PHPUnit\\Metadata\\Version\\ConstraintRequirement' => '/phpunit/Metadata/Version/ConstraintRequirement.php', + 'PHPUnit\\Metadata\\Version\\Requirement' => '/phpunit/Metadata/Version/Requirement.php', + 'PHPUnit\\Metadata\\WithEnvironmentVariable' => '/phpunit/Metadata/WithEnvironmentVariable.php', + 'PHPUnit\\Metadata\\WithoutErrorHandler' => '/phpunit/Metadata/WithoutErrorHandler.php', + 'PHPUnit\\Runner\\BackedUpEnvironmentVariable' => '/phpunit/Runner/BackedUpEnvironmentVariable.php', + 'PHPUnit\\Runner\\Baseline\\Baseline' => '/phpunit/Runner/Baseline/Baseline.php', + 'PHPUnit\\Runner\\Baseline\\CannotLoadBaselineException' => '/phpunit/Runner/Baseline/Exception/CannotLoadBaselineException.php', + 'PHPUnit\\Runner\\Baseline\\CannotWriteBaselineException' => '/phpunit/Runner/Baseline/Exception/CannotWriteBaselineException.php', + 'PHPUnit\\Runner\\Baseline\\FileDoesNotHaveLineException' => '/phpunit/Runner/Baseline/Exception/FileDoesNotHaveLineException.php', + 'PHPUnit\\Runner\\Baseline\\Generator' => '/phpunit/Runner/Baseline/Generator.php', + 'PHPUnit\\Runner\\Baseline\\Issue' => '/phpunit/Runner/Baseline/Issue.php', + 'PHPUnit\\Runner\\Baseline\\Reader' => '/phpunit/Runner/Baseline/Reader.php', + 'PHPUnit\\Runner\\Baseline\\RelativePathCalculator' => '/phpunit/Runner/Baseline/RelativePathCalculator.php', + 'PHPUnit\\Runner\\Baseline\\Subscriber' => '/phpunit/Runner/Baseline/Subscriber/Subscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredDeprecationSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredDeprecationSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredNoticeSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredNoticeSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredPhpDeprecationSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredPhpDeprecationSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredPhpNoticeSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredPhpNoticeSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredPhpWarningSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredPhpWarningSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\TestTriggeredWarningSubscriber' => '/phpunit/Runner/Baseline/Subscriber/TestTriggeredWarningSubscriber.php', + 'PHPUnit\\Runner\\Baseline\\Writer' => '/phpunit/Runner/Baseline/Writer.php', + 'PHPUnit\\Runner\\ClassCannotBeFoundException' => '/phpunit/Runner/Exception/ClassCannotBeFoundException.php', + 'PHPUnit\\Runner\\ClassDoesNotExtendTestCaseException' => '/phpunit/Runner/Exception/ClassDoesNotExtendTestCaseException.php', + 'PHPUnit\\Runner\\ClassIsAbstractException' => '/phpunit/Runner/Exception/ClassIsAbstractException.php', + 'PHPUnit\\Runner\\CodeCoverage' => '/phpunit/Runner/CodeCoverage.php', + 'PHPUnit\\Runner\\CodeCoverageFileExistsException' => '/phpunit/Runner/Exception/CodeCoverageFileExistsException.php', + 'PHPUnit\\Runner\\CodeCoverageInitializationStatus' => '/phpunit/Runner/CodeCoverageInitializationStatus.php', + 'PHPUnit\\Runner\\DeprecationCollector\\Collector' => '/phpunit/Runner/DeprecationCollector/Collector.php', + 'PHPUnit\\Runner\\DeprecationCollector\\Facade' => '/phpunit/Runner/DeprecationCollector/Facade.php', + 'PHPUnit\\Runner\\DeprecationCollector\\InIsolationCollector' => '/phpunit/Runner/DeprecationCollector/InIsolationCollector.php', + 'PHPUnit\\Runner\\DeprecationCollector\\Subscriber' => '/phpunit/Runner/DeprecationCollector/Subscriber/Subscriber.php', + 'PHPUnit\\Runner\\DeprecationCollector\\TestPreparedSubscriber' => '/phpunit/Runner/DeprecationCollector/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Runner\\DeprecationCollector\\TestTriggeredDeprecationSubscriber' => '/phpunit/Runner/DeprecationCollector/Subscriber/TestTriggeredDeprecationSubscriber.php', + 'PHPUnit\\Runner\\DirectoryDoesNotExistException' => '/phpunit/Runner/Exception/DirectoryDoesNotExistException.php', + 'PHPUnit\\Runner\\ErrorException' => '/phpunit/Runner/Exception/ErrorException.php', + 'PHPUnit\\Runner\\ErrorHandler' => '/phpunit/Runner/ErrorHandler.php', + 'PHPUnit\\Runner\\Exception' => '/phpunit/Runner/Exception/Exception.php', + 'PHPUnit\\Runner\\Extension\\Extension' => '/phpunit/Runner/Extension/Extension.php', + 'PHPUnit\\Runner\\Extension\\ExtensionBootstrapper' => '/phpunit/Runner/Extension/ExtensionBootstrapper.php', + 'PHPUnit\\Runner\\Extension\\ExtensionFacade' => '/phpunit/Runner/Extension/ExtensionFacade.php', + 'PHPUnit\\Runner\\Extension\\Facade' => '/phpunit/Runner/Extension/Facade.php', + 'PHPUnit\\Runner\\Extension\\ParameterCollection' => '/phpunit/Runner/Extension/ParameterCollection.php', + 'PHPUnit\\Runner\\Extension\\PharLoader' => '/phpunit/Runner/Extension/PharLoader.php', + 'PHPUnit\\Runner\\FileDoesNotExistException' => '/phpunit/Runner/Exception/FileDoesNotExistException.php', + 'PHPUnit\\Runner\\Filter\\ExcludeGroupFilterIterator' => '/phpunit/Runner/Filter/ExcludeGroupFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\ExcludeNameFilterIterator' => '/phpunit/Runner/Filter/ExcludeNameFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\Factory' => '/phpunit/Runner/Filter/Factory.php', + 'PHPUnit\\Runner\\Filter\\GroupFilterIterator' => '/phpunit/Runner/Filter/GroupFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\IncludeGroupFilterIterator' => '/phpunit/Runner/Filter/IncludeGroupFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\IncludeNameFilterIterator' => '/phpunit/Runner/Filter/IncludeNameFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\NameFilterIterator' => '/phpunit/Runner/Filter/NameFilterIterator.php', + 'PHPUnit\\Runner\\Filter\\TestIdFilterIterator' => '/phpunit/Runner/Filter/TestIdFilterIterator.php', + 'PHPUnit\\Runner\\GarbageCollection\\ExecutionFinishedSubscriber' => '/phpunit/Runner/GarbageCollection/Subscriber/ExecutionFinishedSubscriber.php', + 'PHPUnit\\Runner\\GarbageCollection\\ExecutionStartedSubscriber' => '/phpunit/Runner/GarbageCollection/Subscriber/ExecutionStartedSubscriber.php', + 'PHPUnit\\Runner\\GarbageCollection\\GarbageCollectionHandler' => '/phpunit/Runner/GarbageCollection/GarbageCollectionHandler.php', + 'PHPUnit\\Runner\\GarbageCollection\\Subscriber' => '/phpunit/Runner/GarbageCollection/Subscriber/Subscriber.php', + 'PHPUnit\\Runner\\GarbageCollection\\TestFinishedSubscriber' => '/phpunit/Runner/GarbageCollection/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Runner\\HookMethod' => '/phpunit/Runner/HookMethod/HookMethod.php', + 'PHPUnit\\Runner\\HookMethodCollection' => '/phpunit/Runner/HookMethod/HookMethodCollection.php', + 'PHPUnit\\Runner\\InvalidOrderException' => '/phpunit/Runner/Exception/InvalidOrderException.php', + 'PHPUnit\\Runner\\IssueTriggerResolver\\DefaultResolver' => '/phpunit/Runner/IssueTriggerResolver/DefaultResolver.php', + 'PHPUnit\\Runner\\IssueTriggerResolver\\Resolution' => '/phpunit/Runner/IssueTriggerResolver/Resolution.php', + 'PHPUnit\\Runner\\IssueTriggerResolver\\Resolver' => '/phpunit/Runner/IssueTriggerResolver/Resolver.php', + 'PHPUnit\\Runner\\ParameterDoesNotExistException' => '/phpunit/Runner/Exception/ParameterDoesNotExistException.php', + 'PHPUnit\\Runner\\Phpt\\InvalidPhptFileException' => '/phpunit/Runner/Phpt/Exception/InvalidPhptFileException.php', + 'PHPUnit\\Runner\\Phpt\\Parser' => '/phpunit/Runner/Phpt/Parser.php', + 'PHPUnit\\Runner\\Phpt\\PhptExternalFileCannotBeLoadedException' => '/phpunit/Runner/Phpt/Exception/PhptExternalFileCannotBeLoadedException.php', + 'PHPUnit\\Runner\\Phpt\\Renderer' => '/phpunit/Runner/Phpt/Renderer.php', + 'PHPUnit\\Runner\\Phpt\\TestCase' => '/phpunit/Runner/Phpt/TestCase.php', + 'PHPUnit\\Runner\\Phpt\\UnsupportedPhptSectionException' => '/phpunit/Runner/Phpt/Exception/UnsupportedPhptSectionException.php', + 'PHPUnit\\Runner\\ResultCache\\DefaultResultCache' => '/phpunit/Runner/ResultCache/DefaultResultCache.php', + 'PHPUnit\\Runner\\ResultCache\\NullResultCache' => '/phpunit/Runner/ResultCache/NullResultCache.php', + 'PHPUnit\\Runner\\ResultCache\\ResultCache' => '/phpunit/Runner/ResultCache/ResultCache.php', + 'PHPUnit\\Runner\\ResultCache\\ResultCacheHandler' => '/phpunit/Runner/ResultCache/ResultCacheHandler.php', + 'PHPUnit\\Runner\\ResultCache\\ResultCacheId' => '/phpunit/Runner/ResultCache/ResultCacheId.php', + 'PHPUnit\\Runner\\ResultCache\\Subscriber' => '/phpunit/Runner/ResultCache/Subscriber/Subscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestConsideredRiskySubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestErroredSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestFailedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestFinishedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestMarkedIncompleteSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestPreparedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestSkippedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestSuiteFinishedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestSuiteFinishedSubscriber.php', + 'PHPUnit\\Runner\\ResultCache\\TestSuiteStartedSubscriber' => '/phpunit/Runner/ResultCache/Subscriber/TestSuiteStartedSubscriber.php', + 'PHPUnit\\Runner\\ShutdownHandler' => '/phpunit/Runner/ShutdownHandler.php', + 'PHPUnit\\Runner\\TestSuiteLoader' => '/phpunit/Runner/TestSuiteLoader.php', + 'PHPUnit\\Runner\\TestSuiteSorter' => '/phpunit/Runner/TestSuiteSorter.php', + 'PHPUnit\\Runner\\Version' => '/phpunit/Runner/Version.php', + 'PHPUnit\\TestRunner\\IssueFilter' => '/phpunit/Runner/IssueFilter.php', + 'PHPUnit\\TestRunner\\TestResult\\AfterTestClassMethodErroredSubscriber' => '/phpunit/Runner/TestResult/Subscriber/AfterTestClassMethodErroredSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\AfterTestClassMethodFailedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/AfterTestClassMethodFailedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\BeforeTestClassMethodErroredSubscriber' => '/phpunit/Runner/TestResult/Subscriber/BeforeTestClassMethodErroredSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\BeforeTestClassMethodFailedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/BeforeTestClassMethodFailedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\ChildProcessErroredSubscriber' => '/phpunit/Runner/TestResult/Subscriber/ChildProcessErroredSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\Collector' => '/phpunit/Runner/TestResult/Collector.php', + 'PHPUnit\\TestRunner\\TestResult\\ExecutionStartedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/ExecutionStartedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\Facade' => '/phpunit/Runner/TestResult/Facade.php', + 'PHPUnit\\TestRunner\\TestResult\\Issues\\Issue' => '/phpunit/Runner/TestResult/Issue.php', + 'PHPUnit\\TestRunner\\TestResult\\PassedTests' => '/phpunit/Runner/TestResult/PassedTests.php', + 'PHPUnit\\TestRunner\\TestResult\\Subscriber' => '/phpunit/Runner/TestResult/Subscriber/Subscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestConsideredRiskySubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestErroredSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestFailedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestFinishedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestMarkedIncompleteSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestPreparedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestResult' => '/phpunit/Runner/TestResult/TestResult.php', + 'PHPUnit\\TestRunner\\TestResult\\TestRunnerTriggeredDeprecationSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredDeprecationSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestRunnerTriggeredNoticeSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredNoticeSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestRunnerTriggeredWarningSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredWarningSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestSkippedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestSuiteFinishedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestSuiteFinishedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestSuiteSkippedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestSuiteSkippedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestSuiteStartedSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestSuiteStartedSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredDeprecationSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredErrorSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredErrorSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredNoticeSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpDeprecationSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpNoticeSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpWarningSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpunitDeprecationSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpunitErrorSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpunitNoticeSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredPhpunitWarningSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php', + 'PHPUnit\\TestRunner\\TestResult\\TestTriggeredWarningSubscriber' => '/phpunit/Runner/TestResult/Subscriber/TestTriggeredWarningSubscriber.php', + 'PHPUnit\\TextUI\\Application' => '/phpunit/TextUI/Application.php', + 'PHPUnit\\TextUI\\CannotOpenSocketException' => '/phpunit/TextUI/Exception/CannotOpenSocketException.php', + 'PHPUnit\\TextUI\\CliArguments\\Builder' => '/phpunit/TextUI/Configuration/Cli/Builder.php', + 'PHPUnit\\TextUI\\CliArguments\\Configuration' => '/phpunit/TextUI/Configuration/Cli/Configuration.php', + 'PHPUnit\\TextUI\\CliArguments\\Exception' => '/phpunit/TextUI/Configuration/Cli/Exception.php', + 'PHPUnit\\TextUI\\CliArguments\\XmlConfigurationFileFinder' => '/phpunit/TextUI/Configuration/Cli/XmlConfigurationFileFinder.php', + 'PHPUnit\\TextUI\\Command\\AtLeastVersionCommand' => '/phpunit/TextUI/Command/Commands/AtLeastVersionCommand.php', + 'PHPUnit\\TextUI\\Command\\CheckPhpConfigurationCommand' => '/phpunit/TextUI/Command/Commands/CheckPhpConfigurationCommand.php', + 'PHPUnit\\TextUI\\Command\\Command' => '/phpunit/TextUI/Command/Command.php', + 'PHPUnit\\TextUI\\Command\\GenerateConfigurationCommand' => '/phpunit/TextUI/Command/Commands/GenerateConfigurationCommand.php', + 'PHPUnit\\TextUI\\Command\\ListGroupsCommand' => '/phpunit/TextUI/Command/Commands/ListGroupsCommand.php', + 'PHPUnit\\TextUI\\Command\\ListTestFilesCommand' => '/phpunit/TextUI/Command/Commands/ListTestFilesCommand.php', + 'PHPUnit\\TextUI\\Command\\ListTestSuitesCommand' => '/phpunit/TextUI/Command/Commands/ListTestSuitesCommand.php', + 'PHPUnit\\TextUI\\Command\\ListTestsAsTextCommand' => '/phpunit/TextUI/Command/Commands/ListTestsAsTextCommand.php', + 'PHPUnit\\TextUI\\Command\\ListTestsAsXmlCommand' => '/phpunit/TextUI/Command/Commands/ListTestsAsXmlCommand.php', + 'PHPUnit\\TextUI\\Command\\MigrateConfigurationCommand' => '/phpunit/TextUI/Command/Commands/MigrateConfigurationCommand.php', + 'PHPUnit\\TextUI\\Command\\Result' => '/phpunit/TextUI/Command/Result.php', + 'PHPUnit\\TextUI\\Command\\ShowHelpCommand' => '/phpunit/TextUI/Command/Commands/ShowHelpCommand.php', + 'PHPUnit\\TextUI\\Command\\ShowVersionCommand' => '/phpunit/TextUI/Command/Commands/ShowVersionCommand.php', + 'PHPUnit\\TextUI\\Command\\VersionCheckCommand' => '/phpunit/TextUI/Command/Commands/VersionCheckCommand.php', + 'PHPUnit\\TextUI\\Command\\WarmCodeCoverageCacheCommand' => '/phpunit/TextUI/Command/Commands/WarmCodeCoverageCacheCommand.php', + 'PHPUnit\\TextUI\\Configuration\\BootstrapLoader' => '/phpunit/TextUI/Configuration/BootstrapLoader.php', + 'PHPUnit\\TextUI\\Configuration\\BootstrapScriptDoesNotExistException' => '/phpunit/TextUI/Configuration/Exception/BootstrapScriptDoesNotExistException.php', + 'PHPUnit\\TextUI\\Configuration\\BootstrapScriptException' => '/phpunit/TextUI/Configuration/Exception/BootstrapScriptException.php', + 'PHPUnit\\TextUI\\Configuration\\Builder' => '/phpunit/TextUI/Configuration/Builder.php', + 'PHPUnit\\TextUI\\Configuration\\CodeCoverageFilterRegistry' => '/phpunit/TextUI/Configuration/CodeCoverageFilterRegistry.php', + 'PHPUnit\\TextUI\\Configuration\\CodeCoverageReportNotConfiguredException' => '/phpunit/TextUI/Configuration/Exception/CodeCoverageReportNotConfiguredException.php', + 'PHPUnit\\TextUI\\Configuration\\Configuration' => '/phpunit/TextUI/Configuration/Configuration.php', + 'PHPUnit\\TextUI\\Configuration\\ConfigurationCannotBeBuiltException' => '/phpunit/TextUI/Configuration/Exception/ConfigurationCannotBeBuiltException.php', + 'PHPUnit\\TextUI\\Configuration\\Constant' => '/phpunit/TextUI/Configuration/Value/Constant.php', + 'PHPUnit\\TextUI\\Configuration\\ConstantCollection' => '/phpunit/TextUI/Configuration/Value/ConstantCollection.php', + 'PHPUnit\\TextUI\\Configuration\\ConstantCollectionIterator' => '/phpunit/TextUI/Configuration/Value/ConstantCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\Directory' => '/phpunit/TextUI/Configuration/Value/Directory.php', + 'PHPUnit\\TextUI\\Configuration\\DirectoryCollection' => '/phpunit/TextUI/Configuration/Value/DirectoryCollection.php', + 'PHPUnit\\TextUI\\Configuration\\DirectoryCollectionIterator' => '/phpunit/TextUI/Configuration/Value/DirectoryCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\Exception' => '/phpunit/TextUI/Configuration/Exception/Exception.php', + 'PHPUnit\\TextUI\\Configuration\\ExtensionBootstrap' => '/phpunit/TextUI/Configuration/Value/ExtensionBootstrap.php', + 'PHPUnit\\TextUI\\Configuration\\ExtensionBootstrapCollection' => '/phpunit/TextUI/Configuration/Value/ExtensionBootstrapCollection.php', + 'PHPUnit\\TextUI\\Configuration\\ExtensionBootstrapCollectionIterator' => '/phpunit/TextUI/Configuration/Value/ExtensionBootstrapCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\File' => '/phpunit/TextUI/Configuration/Value/File.php', + 'PHPUnit\\TextUI\\Configuration\\FileCollection' => '/phpunit/TextUI/Configuration/Value/FileCollection.php', + 'PHPUnit\\TextUI\\Configuration\\FileCollectionIterator' => '/phpunit/TextUI/Configuration/Value/FileCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\FilterDirectory' => '/phpunit/TextUI/Configuration/Value/FilterDirectory.php', + 'PHPUnit\\TextUI\\Configuration\\FilterDirectoryCollection' => '/phpunit/TextUI/Configuration/Value/FilterDirectoryCollection.php', + 'PHPUnit\\TextUI\\Configuration\\FilterDirectoryCollectionIterator' => '/phpunit/TextUI/Configuration/Value/FilterDirectoryCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\FilterFile' => '/phpunit/TextUI/Configuration/Value/FilterFile.php', + 'PHPUnit\\TextUI\\Configuration\\FilterFileCollection' => '/phpunit/TextUI/Configuration/Value/FilterFileCollection.php', + 'PHPUnit\\TextUI\\Configuration\\FilterFileCollectionIterator' => '/phpunit/TextUI/Configuration/Value/FilterFileCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\FilterNotConfiguredException' => '/phpunit/TextUI/Configuration/Exception/FilterNotConfiguredException.php', + 'PHPUnit\\TextUI\\Configuration\\Group' => '/phpunit/TextUI/Configuration/Value/Group.php', + 'PHPUnit\\TextUI\\Configuration\\GroupCollection' => '/phpunit/TextUI/Configuration/Value/GroupCollection.php', + 'PHPUnit\\TextUI\\Configuration\\GroupCollectionIterator' => '/phpunit/TextUI/Configuration/Value/GroupCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\IniSetting' => '/phpunit/TextUI/Configuration/Value/IniSetting.php', + 'PHPUnit\\TextUI\\Configuration\\IniSettingCollection' => '/phpunit/TextUI/Configuration/Value/IniSettingCollection.php', + 'PHPUnit\\TextUI\\Configuration\\IniSettingCollectionIterator' => '/phpunit/TextUI/Configuration/Value/IniSettingCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\LoggingNotConfiguredException' => '/phpunit/TextUI/Configuration/Exception/LoggingNotConfiguredException.php', + 'PHPUnit\\TextUI\\Configuration\\Merger' => '/phpunit/TextUI/Configuration/Merger.php', + 'PHPUnit\\TextUI\\Configuration\\NoBaselineException' => '/phpunit/TextUI/Configuration/Exception/NoBaselineException.php', + 'PHPUnit\\TextUI\\Configuration\\NoBootstrapException' => '/phpunit/TextUI/Configuration/Exception/NoBootstrapException.php', + 'PHPUnit\\TextUI\\Configuration\\NoCacheDirectoryException' => '/phpunit/TextUI/Configuration/Exception/NoCacheDirectoryException.php', + 'PHPUnit\\TextUI\\Configuration\\NoConfigurationFileException' => '/phpunit/TextUI/Configuration/Exception/NoConfigurationFileException.php', + 'PHPUnit\\TextUI\\Configuration\\NoCoverageCacheDirectoryException' => '/phpunit/TextUI/Configuration/Exception/NoCoverageCacheDirectoryException.php', + 'PHPUnit\\TextUI\\Configuration\\NoCustomCssFileException' => '/phpunit/TextUI/Configuration/Exception/NoCustomCssFileException.php', + 'PHPUnit\\TextUI\\Configuration\\NoDefaultTestSuiteException' => '/phpunit/TextUI/Configuration/Exception/NoDefaultTestSuiteException.php', + 'PHPUnit\\TextUI\\Configuration\\NoHtmlCoverageTargetException' => '/phpunit/TextUI/Configuration/Exception/NoHtmlCoverageTargetException.php', + 'PHPUnit\\TextUI\\Configuration\\NoPharExtensionDirectoryException' => '/phpunit/TextUI/Configuration/Exception/NoPharExtensionDirectoryException.php', + 'PHPUnit\\TextUI\\Configuration\\NoTestFilesFileException' => '/phpunit/TextUI/Configuration/Exception/NoTestFilesFileException.php', + 'PHPUnit\\TextUI\\Configuration\\Php' => '/phpunit/TextUI/Configuration/Value/Php.php', + 'PHPUnit\\TextUI\\Configuration\\PhpHandler' => '/phpunit/TextUI/Configuration/PhpHandler.php', + 'PHPUnit\\TextUI\\Configuration\\Registry' => '/phpunit/TextUI/Configuration/Registry.php', + 'PHPUnit\\TextUI\\Configuration\\Source' => '/phpunit/TextUI/Configuration/Value/Source.php', + 'PHPUnit\\TextUI\\Configuration\\SourceFilter' => '/phpunit/TextUI/Configuration/SourceFilter.php', + 'PHPUnit\\TextUI\\Configuration\\SourceMapper' => '/phpunit/TextUI/Configuration/SourceMapper.php', + 'PHPUnit\\TextUI\\Configuration\\SpecificDeprecationToStopOnNotConfiguredException' => '/phpunit/TextUI/Configuration/Exception/SpecificDeprecationToStopOnNotConfiguredException.php', + 'PHPUnit\\TextUI\\Configuration\\TestDirectory' => '/phpunit/TextUI/Configuration/Value/TestDirectory.php', + 'PHPUnit\\TextUI\\Configuration\\TestDirectoryCollection' => '/phpunit/TextUI/Configuration/Value/TestDirectoryCollection.php', + 'PHPUnit\\TextUI\\Configuration\\TestDirectoryCollectionIterator' => '/phpunit/TextUI/Configuration/Value/TestDirectoryCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\TestFile' => '/phpunit/TextUI/Configuration/Value/TestFile.php', + 'PHPUnit\\TextUI\\Configuration\\TestFileCollection' => '/phpunit/TextUI/Configuration/Value/TestFileCollection.php', + 'PHPUnit\\TextUI\\Configuration\\TestFileCollectionIterator' => '/phpunit/TextUI/Configuration/Value/TestFileCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\TestSuite' => '/phpunit/TextUI/Configuration/Value/TestSuite.php', + 'PHPUnit\\TextUI\\Configuration\\TestSuiteBuilder' => '/phpunit/TextUI/Configuration/TestSuiteBuilder.php', + 'PHPUnit\\TextUI\\Configuration\\TestSuiteCollection' => '/phpunit/TextUI/Configuration/Value/TestSuiteCollection.php', + 'PHPUnit\\TextUI\\Configuration\\TestSuiteCollectionIterator' => '/phpunit/TextUI/Configuration/Value/TestSuiteCollectionIterator.php', + 'PHPUnit\\TextUI\\Configuration\\Variable' => '/phpunit/TextUI/Configuration/Value/Variable.php', + 'PHPUnit\\TextUI\\Configuration\\VariableCollection' => '/phpunit/TextUI/Configuration/Value/VariableCollection.php', + 'PHPUnit\\TextUI\\Configuration\\VariableCollectionIterator' => '/phpunit/TextUI/Configuration/Value/VariableCollectionIterator.php', + 'PHPUnit\\TextUI\\Exception' => '/phpunit/TextUI/Exception/Exception.php', + 'PHPUnit\\TextUI\\Help' => '/phpunit/TextUI/Help.php', + 'PHPUnit\\TextUI\\InvalidSocketException' => '/phpunit/TextUI/Exception/InvalidSocketException.php', + 'PHPUnit\\TextUI\\Output\\DefaultPrinter' => '/phpunit/TextUI/Output/Printer/DefaultPrinter.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\BeforeTestClassMethodErroredSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/BeforeTestClassMethodErroredSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\ChildProcessErroredSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/ChildProcessErroredSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\ProgressPrinter' => '/phpunit/TextUI/Output/Default/ProgressPrinter/ProgressPrinter.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\Subscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/Subscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestConsideredRiskySubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestConsideredRiskySubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestErroredSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestErroredSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestFailedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFailedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestFinishedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFinishedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestMarkedIncompleteSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestMarkedIncompleteSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestPreparedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestPreparedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestRunnerExecutionStartedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestRunnerExecutionStartedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestSkippedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestSuiteSkippedSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestSuiteSkippedSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredDeprecationSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredDeprecationSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredErrorSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredErrorSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredNoticeSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredNoticeSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpDeprecationSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpDeprecationSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpNoticeSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpNoticeSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpWarningSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpWarningSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpunitDeprecationSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpunitNoticeSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredPhpunitWarningSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitWarningSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ProgressPrinter\\TestTriggeredWarningSubscriber' => '/phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredWarningSubscriber.php', + 'PHPUnit\\TextUI\\Output\\Default\\ResultPrinter' => '/phpunit/TextUI/Output/Default/ResultPrinter.php', + 'PHPUnit\\TextUI\\Output\\Default\\UnexpectedOutputPrinter' => '/phpunit/TextUI/Output/Default/UnexpectedOutputPrinter.php', + 'PHPUnit\\TextUI\\Output\\Facade' => '/phpunit/TextUI/Output/Facade.php', + 'PHPUnit\\TextUI\\Output\\NullPrinter' => '/phpunit/TextUI/Output/Printer/NullPrinter.php', + 'PHPUnit\\TextUI\\Output\\Printer' => '/phpunit/TextUI/Output/Printer/Printer.php', + 'PHPUnit\\TextUI\\Output\\SummaryPrinter' => '/phpunit/TextUI/Output/SummaryPrinter.php', + 'PHPUnit\\TextUI\\Output\\TestDox\\ResultPrinter' => '/phpunit/TextUI/Output/TestDox/ResultPrinter.php', + 'PHPUnit\\TextUI\\RuntimeException' => '/phpunit/TextUI/Exception/RuntimeException.php', + 'PHPUnit\\TextUI\\ShellExitCodeCalculator' => '/phpunit/TextUI/ShellExitCodeCalculator.php', + 'PHPUnit\\TextUI\\TestDirectoryNotFoundException' => '/phpunit/TextUI/Exception/TestDirectoryNotFoundException.php', + 'PHPUnit\\TextUI\\TestFileNotFoundException' => '/phpunit/TextUI/Exception/TestFileNotFoundException.php', + 'PHPUnit\\TextUI\\TestRunner' => '/phpunit/TextUI/TestRunner.php', + 'PHPUnit\\TextUI\\TestSuiteFilterProcessor' => '/phpunit/TextUI/TestSuiteFilterProcessor.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CannotFindSchemaException' => '/phpunit/TextUI/Configuration/Exception/CannotFindSchemaException.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\CodeCoverage' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/CodeCoverage.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Clover' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Clover.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Cobertura' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Cobertura.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Crap4j' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Crap4j.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Html' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Html.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\OpenClover' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/OpenClover.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Php' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Php.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Text' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Text.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CodeCoverage\\Report\\Xml' => '/phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Xml.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Configuration' => '/phpunit/TextUI/Configuration/Xml/Configuration.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\ConvertLogTypes' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/ConvertLogTypes.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoverageCloverToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageCloverToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoverageCrap4jToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageCrap4jToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoverageHtmlToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageHtmlToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoveragePhpToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoveragePhpToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoverageTextToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageTextToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\CoverageXmlToReport' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageXmlToReport.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\DefaultConfiguration' => '/phpunit/TextUI/Configuration/Xml/DefaultConfiguration.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Exception' => '/phpunit/TextUI/Configuration/Xml/Exception.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\FailedSchemaDetectionResult' => '/phpunit/TextUI/Configuration/Xml/SchemaDetector/FailedSchemaDetectionResult.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Generator' => '/phpunit/TextUI/Configuration/Xml/Generator.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Groups' => '/phpunit/TextUI/Configuration/Xml/Groups.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\IntroduceCacheDirectoryAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCacheDirectoryAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\IntroduceCoverageElement' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCoverageElement.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\LoadedFromFileConfiguration' => '/phpunit/TextUI/Configuration/Xml/LoadedFromFileConfiguration.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Loader' => '/phpunit/TextUI/Configuration/Xml/Loader.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\LogToReportMigration' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/LogToReportMigration.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\Junit' => '/phpunit/TextUI/Configuration/Xml/Logging/Junit.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\Logging' => '/phpunit/TextUI/Configuration/Xml/Logging/Logging.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\Otr' => '/phpunit/TextUI/Configuration/Xml/Logging/Otr.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\TeamCity' => '/phpunit/TextUI/Configuration/Xml/Logging/TeamCity.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\TestDox\\Html' => '/phpunit/TextUI/Configuration/Xml/Logging/TestDox/Html.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Logging\\TestDox\\Text' => '/phpunit/TextUI/Configuration/Xml/Logging/TestDox/Text.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Migration' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/Migration.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MigrationBuilder' => '/phpunit/TextUI/Configuration/Xml/Migration/MigrationBuilder.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MigrationException' => '/phpunit/TextUI/Configuration/Xml/Migration/MigrationException.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Migrator' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrator.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromFilterWhitelistToCoverage' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MoveAttributesFromRootToCoverage' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromRootToCoverage.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MoveCoverageDirectoriesToSource' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveCoverageDirectoriesToSource.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistExcludesToCoverage' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistExcludesToCoverage.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\MoveWhitelistIncludesToCoverage' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistIncludesToCoverage.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\PHPUnit' => '/phpunit/TextUI/Configuration/Xml/PHPUnit.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveBeStrictAboutTodoAnnotatedTestsAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutTodoAnnotatedTestsAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveCacheResultFileAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheResultFileAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveCacheTokensAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheTokensAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveConversionToExceptionsAttributes' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveConversionToExceptionsAttributes.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveCoverageElementCacheDirectoryAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementCacheDirectoryAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveCoverageElementProcessUncoveredFilesAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementProcessUncoveredFilesAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveEmptyFilter' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveEmptyFilter.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveListeners' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveListeners.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveLogTypes' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveLogTypes.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveLoggingElements' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveLoggingElements.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveNoInteractionAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveNoInteractionAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemovePrinterAttributes' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemovePrinterAttributes.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveTestDoxGroupsElement' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestDoxGroupsElement.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveTestSuiteLoaderAttributes' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestSuiteLoaderAttributes.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RemoveVerboseAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveVerboseAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RenameBackupStaticAttributesAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameBackupStaticAttributesAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RenameBeStrictAboutCoversAnnotationAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameBeStrictAboutCoversAnnotationAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\RenameForceCoversAnnotationAttribute' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameForceCoversAnnotationAttribute.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\ReplaceRestrictDeprecationsWithIgnoreDeprecations' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/ReplaceRestrictDeprecationsWithIgnoreDeprecations.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\SchemaDetectionResult' => '/phpunit/TextUI/Configuration/Xml/SchemaDetector/SchemaDetectionResult.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\SchemaDetector' => '/phpunit/TextUI/Configuration/Xml/SchemaDetector/SchemaDetector.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\SchemaFinder' => '/phpunit/TextUI/Configuration/Xml/SchemaFinder.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\SnapshotNodeList' => '/phpunit/TextUI/Configuration/Xml/Migration/SnapshotNodeList.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\SuccessfulSchemaDetectionResult' => '/phpunit/TextUI/Configuration/Xml/SchemaDetector/SuccessfulSchemaDetectionResult.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\TestSuiteMapper' => '/phpunit/TextUI/Configuration/Xml/TestSuiteMapper.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\UpdateSchemaLocation' => '/phpunit/TextUI/Configuration/Xml/Migration/Migrations/UpdateSchemaLocation.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\ValidationResult' => '/phpunit/TextUI/Configuration/Xml/Validator/ValidationResult.php', + 'PHPUnit\\TextUI\\XmlConfiguration\\Validator' => '/phpunit/TextUI/Configuration/Xml/Validator/Validator.php', + 'PHPUnit\\Util\\Color' => '/phpunit/Util/Color.php', + 'PHPUnit\\Util\\Exception' => '/phpunit/Util/Exception/Exception.php', + 'PHPUnit\\Util\\ExcludeList' => '/phpunit/Util/ExcludeList.php', + 'PHPUnit\\Util\\Exporter' => '/phpunit/Util/Exporter.php', + 'PHPUnit\\Util\\Filesystem' => '/phpunit/Util/Filesystem.php', + 'PHPUnit\\Util\\Filter' => '/phpunit/Util/Filter.php', + 'PHPUnit\\Util\\GlobalState' => '/phpunit/Util/GlobalState.php', + 'PHPUnit\\Util\\GlobalStateResult' => '/phpunit/Util/GlobalStateResult.php', + 'PHPUnit\\Util\\Http\\Downloader' => '/phpunit/Util/Http/Downloader.php', + 'PHPUnit\\Util\\Http\\PhpDownloader' => '/phpunit/Util/Http/PhpDownloader.php', + 'PHPUnit\\Util\\InvalidDirectoryException' => '/phpunit/Util/Exception/InvalidDirectoryException.php', + 'PHPUnit\\Util\\InvalidJsonException' => '/phpunit/Util/Exception/InvalidJsonException.php', + 'PHPUnit\\Util\\InvalidVersionOperatorException' => '/phpunit/Util/Exception/InvalidVersionOperatorException.php', + 'PHPUnit\\Util\\Json' => '/phpunit/Util/Json.php', + 'PHPUnit\\Util\\PHP\\Job' => '/phpunit/Util/PHP/Job.php', + 'PHPUnit\\Util\\PHP\\JobRunner' => '/phpunit/Util/PHP/JobRunner.php', + 'PHPUnit\\Util\\PHP\\JobRunnerRegistry' => '/phpunit/Util/PHP/JobRunnerRegistry.php', + 'PHPUnit\\Util\\PHP\\PhpProcessException' => '/phpunit/Util/Exception/PhpProcessException.php', + 'PHPUnit\\Util\\PHP\\Result' => '/phpunit/Util/PHP/Result.php', + 'PHPUnit\\Util\\Reflection' => '/phpunit/Util/Reflection.php', + 'PHPUnit\\Util\\Sanitizer' => '/phpunit/Util/Sanitizer.php', + 'PHPUnit\\Util\\Test' => '/phpunit/Util/Test.php', + 'PHPUnit\\Util\\ThrowableToStringMapper' => '/phpunit/Util/ThrowableToStringMapper.php', + 'PHPUnit\\Util\\VersionComparisonOperator' => '/phpunit/Util/VersionComparisonOperator.php', + 'PHPUnit\\Util\\Xml' => '/phpunit/Util/Xml/Xml.php', + 'PHPUnit\\Util\\Xml\\Loader' => '/phpunit/Util/Xml/Loader.php', + 'PHPUnit\\Util\\Xml\\XmlException' => '/phpunit/Util/Exception/XmlException.php'] as $file) { + require_once 'phar://phpunit-13.1.13.phar' . $file; +} + +require __PHPUNIT_PHAR_ROOT__ . '/phpunit/Framework/Assert/Functions.php'; + +if ($execute) { + if (isset($printComposerLock)) { + print file_get_contents(__PHPUNIT_PHAR_ROOT__ . '/composer.lock'); + + exit; + } + + if (isset($printManifest)) { + print file_get_contents(__PHPUNIT_PHAR_ROOT__ . '/manifest.txt'); + + exit; + } + + if (isset($printSbom)) { + print file_get_contents(__PHPUNIT_PHAR_ROOT__ . '/sbom.xml'); + + exit; + } + + unset($execute); + + exit((new PHPUnit\TextUI\Application)->run($_SERVER['argv'])); +} + +__HALT_COMPILER(); ?> +¹'Æphpunit-13.1.13.phar composer.lockœùj66 +ö¤ manifest.txtàœùjàº3¸S¤'myclabs-deep-copy/DeepCopy/DeepCopy.php@!œùj@!në=¤7myclabs-deep-copy/DeepCopy/Exception/CloneException.phpŠœùjŠJDéȤ:myclabs-deep-copy/DeepCopy/Exception/PropertyException.phpƒœùjƒo‘¼#¤5myclabs-deep-copy/DeepCopy/Filter/ChainableFilter.phpËœùjË–=(e¤Gmyclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.phpLœùjL6b]U¤Lmyclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php%œùj%Œd²-¤Bmyclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.phpªœùjªfQc_¤,myclabs-deep-copy/DeepCopy/Filter/Filter.phphœùjh¸ß½¤0myclabs-deep-copy/DeepCopy/Filter/KeepFilter.phpœùjÿ7#¤3myclabs-deep-copy/DeepCopy/Filter/ReplaceFilter.phpÙœùjÙ²{C¤3myclabs-deep-copy/DeepCopy/Filter/SetNullFilter.php.œùj.~ð^¤Dmyclabs-deep-copy/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php‹œùj‹ ‹3ä¤.myclabs-deep-copy/DeepCopy/Matcher/Matcher.phpáœùjáÈfËä6myclabs-deep-copy/DeepCopy/Matcher/PropertyMatcher.phpºœùjºÝÀA^¤:myclabs-deep-copy/DeepCopy/Matcher/PropertyNameMatcher.phpœùjÑì¡P¤:myclabs-deep-copy/DeepCopy/Matcher/PropertyTypeMatcher.phpnœùjnm$Ãu¤:myclabs-deep-copy/DeepCopy/Reflection/ReflectionHelper.php9œùj91•¦†¤Amyclabs-deep-copy/DeepCopy/TypeFilter/Date/DateIntervalFilter.php“œùj“[‚ã¤?myclabs-deep-copy/DeepCopy/TypeFilter/Date/DatePeriodFilter.php`œùj`m9£œ¤7myclabs-deep-copy/DeepCopy/TypeFilter/ReplaceFilter.phpœùj»8;¤;myclabs-deep-copy/DeepCopy/TypeFilter/ShallowCopyFilter.phpëœùjëF_e ¤?myclabs-deep-copy/DeepCopy/TypeFilter/Spl/ArrayObjectFilter.phpðœùjð£Ø©¤Amyclabs-deep-copy/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php¼œùj¼K픤Gmyclabs-deep-copy/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php*œùj*L-Ø ¤4myclabs-deep-copy/DeepCopy/TypeFilter/TypeFilter.phpΜùjÎÔŠ‡¤6myclabs-deep-copy/DeepCopy/TypeMatcher/TypeMatcher.phpÞœùjÞû×$¤(myclabs-deep-copy/DeepCopy/deep_copy.php¥œùj¥¢WÈ•¤myclabs-deep-copy/LICENSE5œùj5Ê­Ë„¤nikic-php-parser/LICENSEðœùjð¥ä”*¤&nikic-php-parser/PhpParser/Builder.phpלùj×’[ṳ1nikic-php-parser/PhpParser/Builder/ClassConst.php;œùj;(kïü¤-nikic-php-parser/PhpParser/Builder/Class_.phpkœùjkÓÞQ¤2nikic-php-parser/PhpParser/Builder/Declaration.phpþœùjþ`X:¤/nikic-php-parser/PhpParser/Builder/EnumCase.phpÖœùjÖȸÚ¤,nikic-php-parser/PhpParser/Builder/Enum_.phpà œùjà ÅUfƒ¤3nikic-php-parser/PhpParser/Builder/FunctionLike.php9œùj9B¹ã¤0nikic-php-parser/PhpParser/Builder/Function_.php‹œùj‹¥33A¤1nikic-php-parser/PhpParser/Builder/Interface_.phph +œùjh +£‹·|¤-nikic-php-parser/PhpParser/Builder/Method.php§œùj§Ú·t„¤1nikic-php-parser/PhpParser/Builder/Namespace_.phpuœùju Öî¤,nikic-php-parser/PhpParser/Builder/Param.php¬œùj¬_먊¤/nikic-php-parser/PhpParser/Builder/Property.phpxœùjxVÆnâ¤/nikic-php-parser/PhpParser/Builder/TraitUse.php¼œùj¼!rѤ9nikic-php-parser/PhpParser/Builder/TraitUseAdaptation.phpúœùjúŒ0¤-nikic-php-parser/PhpParser/Builder/Trait_.php4 œùj4 ëѬZ¤+nikic-php-parser/PhpParser/Builder/Use_.php,œùj,K,g¤-nikic-php-parser/PhpParser/BuilderFactory.php)œùj) –Ò½¤-nikic-php-parser/PhpParser/BuilderHelpers.phpl%œùjl%‚^Š[¤&nikic-php-parser/PhpParser/Comment.phpœùjVUG¤*nikic-php-parser/PhpParser/Comment/Doc.php€œùj€Í袤;nikic-php-parser/PhpParser/ConstExprEvaluationException.php}œùj}ÍÞO¤1nikic-php-parser/PhpParser/ConstExprEvaluator.php&œùj&V7=å¤$nikic-php-parser/PhpParser/Error.php]œùj]×:¸¤+nikic-php-parser/PhpParser/ErrorHandler.php9œùj9–yo¤6nikic-php-parser/PhpParser/ErrorHandler/Collecting.php•œùj•HÏr(¤4nikic-php-parser/PhpParser/ErrorHandler/Throwing.php˜œùj˜Îr¾£¤0nikic-php-parser/PhpParser/Internal/DiffElem.php +œùj +à_P¤.nikic-php-parser/PhpParser/Internal/Differ.phpÇœùjÇd;v,¤Anikic-php-parser/PhpParser/Internal/PrintableNewAnonClassNode.phpe +œùje +²G×o¤5nikic-php-parser/PhpParser/Internal/TokenPolyfill.php·$œùj·$wdz®¤3nikic-php-parser/PhpParser/Internal/TokenStream.php£#œùj£#GzÙ¤*nikic-php-parser/PhpParser/JsonDecoder.php® œùj®  +øn¤$nikic-php-parser/PhpParser/Lexer.php(œùj(&Àì¤.nikic-php-parser/PhpParser/Lexer/Emulative.phpû œùjû YÃøI¤Tnikic-php-parser/PhpParser/Lexer/TokenEmulator/AsymmetricVisibilityTokenEmulator.php² œùj² ÑÆÍ¤Dnikic-php-parser/PhpParser/Lexer/TokenEmulator/AttributeEmulator.phpÏœùjÏæ g$¤Dnikic-php-parser/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php¾œùj¾¿¾¤Hnikic-php-parser/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.phpœùjHU¨j¤Bnikic-php-parser/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php2œùj2$ÐG­¤Enikic-php-parser/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.phpÈœùjÈÂ9æG¤Hnikic-php-parser/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php-œùj-[SŤGnikic-php-parser/PhpParser/Lexer/TokenEmulator/PipeOperatorEmulator.php€œùj€÷uMߤHnikic-php-parser/PhpParser/Lexer/TokenEmulator/PropertyTokenEmulator.phpלùj×ü4"Ù¤Pnikic-php-parser/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.phpõœùjõÜP“ΤHnikic-php-parser/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.phpdœùjd/Cê¤Bnikic-php-parser/PhpParser/Lexer/TokenEmulator/ReverseEmulator.phpœùjï—‚Ù¤@nikic-php-parser/PhpParser/Lexer/TokenEmulator/TokenEmulator.phpWœùjW3˜ù¤Cnikic-php-parser/PhpParser/Lexer/TokenEmulator/VoidCastEmulator.php* œùj* q ô„¤(nikic-php-parser/PhpParser/Modifiers.phpF +œùjF +`ؤ*nikic-php-parser/PhpParser/NameContext.php &œùj & 8ÄÕ¤#nikic-php-parser/PhpParser/Node.phpœùj¶h¦m¤'nikic-php-parser/PhpParser/Node/Arg.php œùj #Eªˆ¤-nikic-php-parser/PhpParser/Node/ArrayItem.phpÞœùjÞ¸ªÙݤ-nikic-php-parser/PhpParser/Node/Attribute.php`œùj`–v¤2nikic-php-parser/PhpParser/Node/AttributeGroup.php¨œùj¨Gãiʤ.nikic-php-parser/PhpParser/Node/ClosureUse.phpîœùjî\±jt¤/nikic-php-parser/PhpParser/Node/ComplexType.php[œùj[š0Us¤*nikic-php-parser/PhpParser/Node/Const_.phpëœùjëT¼=y¤/nikic-php-parser/PhpParser/Node/DeclareItem.php œùj ¸o#¤(nikic-php-parser/PhpParser/Node/Expr.phpœùj|Å)¬¤6nikic-php-parser/PhpParser/Node/Expr/ArrayDimFetch.phpWœùjWSé!¤/nikic-php-parser/PhpParser/Node/Expr/Array_.phprœùjr§sG¤6nikic-php-parser/PhpParser/Node/Expr/ArrowFunction.php> +œùj> +«ÚM¤/nikic-php-parser/PhpParser/Node/Expr/Assign.php'œùj'0)œ +¤1nikic-php-parser/PhpParser/Node/Expr/AssignOp.phpôœùjô¢Œb/¤<nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseAnd.phpœùjÆ?Q¤;nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseOr.phpœùj)Þñ¤<nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseXor.phpœùj&ÉTþ¤:nikic-php-parser/PhpParser/Node/Expr/AssignOp/Coalesce.phpœùj9˜·¤¤8nikic-php-parser/PhpParser/Node/Expr/AssignOp/Concat.phpÿœùjÿGÅ3¤5nikic-php-parser/PhpParser/Node/Expr/AssignOp/Div.phpùœùjùÍÔ/¤7nikic-php-parser/PhpParser/Node/Expr/AssignOp/Minus.phpýœùjý¦„¶c¤5nikic-php-parser/PhpParser/Node/Expr/AssignOp/Mod.phpùœùjùÃjŒ¤5nikic-php-parser/PhpParser/Node/Expr/AssignOp/Mul.phpùœùjùY:Å;¤6nikic-php-parser/PhpParser/Node/Expr/AssignOp/Plus.phpûœùjûKÍã]¤5nikic-php-parser/PhpParser/Node/Expr/AssignOp/Pow.phpùœùjùߊÍA¤;nikic-php-parser/PhpParser/Node/Expr/AssignOp/ShiftLeft.phpœùj–(?¤<nikic-php-parser/PhpParser/Node/Expr/AssignOp/ShiftRight.phpœùj®·íâ¤2nikic-php-parser/PhpParser/Node/Expr/AssignRef.phpXœùjX[—·¤1nikic-php-parser/PhpParser/Node/Expr/BinaryOp.phpdœùjdñ`˜­¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.phpVœùjVNVD¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseOr.phpTœùjTÝŸ¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseXor.phpVœùjVà3$¶¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BooleanAnd.phpWœùjWú€Ýÿ¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BooleanOr.phpUœùjU‰¡G¤:nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Coalesce.phpSœùjS¯/à¤8nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Concat.phpNœùjN¶€¤5nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Div.phpHœùjH¨A+¤7nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Equal.phpMœùjMá$3¤9nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Greater.phpPœùjPX‡Š¤@nikic-php-parser/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php_œùj_³Âå ¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Identical.phpVœùjV´Ðã¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalAnd.phpXœùjXFü—=¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalOr.phpUœùjU-”š3¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalXor.phpXœùjXÞÁŠé¤7nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Minus.phpLœùjL"7®æ¤5nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Mod.phpHœùjHÓ + +ñ¤5nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Mul.phpHœùjH œt¤:nikic-php-parser/PhpParser/Node/Expr/BinaryOp/NotEqual.phpSœùjS¨½£Í¤>nikic-php-parser/PhpParser/Node/Expr/BinaryOp/NotIdentical.php\œùj\õc_¤6nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Pipe.phpKœùjKuõ$¤6nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Plus.phpJœùjJcm¤5nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Pow.phpIœùjI­Þ,ô¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/ShiftLeft.phpUœùjUC”Xe¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/ShiftRight.phpWœùjWü;‘¤9nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Smaller.phpPœùjPT—å¤@nikic-php-parser/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php_œùj_èJ³¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Spaceship.phpVœùjVã”Ex¤3nikic-php-parser/PhpParser/Node/Expr/BitwiseNot.php­œùj­}lMˤ3nikic-php-parser/PhpParser/Node/Expr/BooleanNot.php­œùj­sÂ7Þ¤1nikic-php-parser/PhpParser/Node/Expr/CallLike.phpœùjö$‘b¤-nikic-php-parser/PhpParser/Node/Expr/Cast.phpUœùjU¼ö³ð¤4nikic-php-parser/PhpParser/Node/Expr/Cast/Array_.phpîœùjîȯ¾š¤3nikic-php-parser/PhpParser/Node/Expr/Cast/Bool_.phpœùjux å¤4nikic-php-parser/PhpParser/Node/Expr/Cast/Double.php·œùj·S(Û¤2nikic-php-parser/PhpParser/Node/Expr/Cast/Int_.php{œùj{ú{¤5nikic-php-parser/PhpParser/Node/Expr/Cast/Object_.phpðœùjð\­‘°¤5nikic-php-parser/PhpParser/Node/Expr/Cast/String_.php…œùj…Øú{Ƥ4nikic-php-parser/PhpParser/Node/Expr/Cast/Unset_.phpîœùjîÉ”™Ô¤3nikic-php-parser/PhpParser/Node/Expr/Cast/Void_.phpìœùjìšõ±d¤8nikic-php-parser/PhpParser/Node/Expr/ClassConstFetch.phpœùj2å¤/nikic-php-parser/PhpParser/Node/Expr/Clone_.phpžœùjž™×¤0nikic-php-parser/PhpParser/Node/Expr/Closure.phpj œùjj òI¶¤3nikic-php-parser/PhpParser/Node/Expr/ConstFetch.phpØœùjØs>6¤/nikic-php-parser/PhpParser/Node/Expr/Empty_.php¡œùj¡¸¨Ý¤.nikic-php-parser/PhpParser/Node/Expr/Error.phpœùj$ŸLŒ¤6nikic-php-parser/PhpParser/Node/Expr/ErrorSuppress.php·œùj·Î &¤.nikic-php-parser/PhpParser/Node/Expr/Eval_.phpžœùjžA[¤.nikic-php-parser/PhpParser/Node/Expr/Exit_.phpœùjgÝí¼¤1nikic-php-parser/PhpParser/Node/Expr/FuncCall.phpœùj@"]¤1nikic-php-parser/PhpParser/Node/Expr/Include_.phpÍœùjÍ—ÀÊ ¤4nikic-php-parser/PhpParser/Node/Expr/Instanceof_.php•œùj•.§B ¤/nikic-php-parser/PhpParser/Node/Expr/Isset_.php£œùj£ò>:¤.nikic-php-parser/PhpParser/Node/Expr/List_.php£œùj£2ò¿)¤/nikic-php-parser/PhpParser/Node/Expr/Match_.php;œùj;hü¤3nikic-php-parser/PhpParser/Node/Expr/MethodCall.phpQœùjQOD¥å¤-nikic-php-parser/PhpParser/Node/Expr/New_.php•œùj•<~h¤;nikic-php-parser/PhpParser/Node/Expr/NullsafeMethodCall.phphœùjhk[˜S¤>nikic-php-parser/PhpParser/Node/Expr/NullsafePropertyFetch.phpœùjk*¢¤0nikic-php-parser/PhpParser/Node/Expr/PostDec.php œùj Ph@¤0nikic-php-parser/PhpParser/Node/Expr/PostInc.php œùj dÞ‡¤/nikic-php-parser/PhpParser/Node/Expr/PreDec.phpœùjÍmB'¤/nikic-php-parser/PhpParser/Node/Expr/PreInc.phpœùjÔ·$x¤/nikic-php-parser/PhpParser/Node/Expr/Print_.php¡œùj¡U¤óô¤6nikic-php-parser/PhpParser/Node/Expr/PropertyFetch.phpêœùjê:%g¤2nikic-php-parser/PhpParser/Node/Expr/ShellExec.phpHœùjHedü¤3nikic-php-parser/PhpParser/Node/Expr/StaticCall.php\œùj\©ÁP¼¤<nikic-php-parser/PhpParser/Node/Expr/StaticPropertyFetch.php;œùj;ç.½ ¤0nikic-php-parser/PhpParser/Node/Expr/Ternary.phpèœùjè:X(¤/nikic-php-parser/PhpParser/Node/Expr/Throw_.php½œùj½#‚6¢¤3nikic-php-parser/PhpParser/Node/Expr/UnaryMinus.php­œùj­¾*C‰¤2nikic-php-parser/PhpParser/Node/Expr/UnaryPlus.phpªœùjªF!Ĥ1nikic-php-parser/PhpParser/Node/Expr/Variable.phpžœùjžìEk¤2nikic-php-parser/PhpParser/Node/Expr/YieldFrom.php»œùj»ôBß ¤/nikic-php-parser/PhpParser/Node/Expr/Yield_.phpoœùjo‘Æ´¤0nikic-php-parser/PhpParser/Node/FunctionLike.phpïœùjïÊj¸¤.nikic-php-parser/PhpParser/Node/Identifier.phpRœùjR¦œú¤:nikic-php-parser/PhpParser/Node/InterpolatedStringPart.phprœùjrkGþn¤4nikic-php-parser/PhpParser/Node/IntersectionType.php¯œùj¯€”u«¤,nikic-php-parser/PhpParser/Node/MatchArm.php¹œùj¹›Q\¤¤(nikic-php-parser/PhpParser/Node/Name.phpÙ!œùjÙ!ÿ6Vˤ7nikic-php-parser/PhpParser/Node/Name/FullyQualified.phpœùjÂø 2¤1nikic-php-parser/PhpParser/Node/Name/Relative.php¿œùj¿‰8½V¤0nikic-php-parser/PhpParser/Node/NullableType.phpÈœùjÈÕä¤)nikic-php-parser/PhpParser/Node/Param.phpëœùjër +@ž¤0nikic-php-parser/PhpParser/Node/PropertyHook.phpÉ œùjÉ \üBA¤0nikic-php-parser/PhpParser/Node/PropertyItem.php\œùj\¦`º¤*nikic-php-parser/PhpParser/Node/Scalar.phpoœùjo­¦þ=¤1nikic-php-parser/PhpParser/Node/Scalar/Float_.phpWœùjWj©Æ¤/nikic-php-parser/PhpParser/Node/Scalar/Int_.phpø œùjø Ÿ‘¤=nikic-php-parser/PhpParser/Node/Scalar/InterpolatedString.phpÝœùjÝ?à Z¤5nikic-php-parser/PhpParser/Node/Scalar/MagicConst.phpxœùjx÷Ï®÷¤<nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Class_.phpZœùjZÁÆÓ5¤9nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Dir.phpSœùjSrÙfɤ:nikic-php-parser/PhpParser/Node/Scalar/MagicConst/File.phpVœùjV6›Q¤?nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Function_.phpcœùjc—5¤¤:nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Line.phpVœùjVèDEš¤<nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Method.php\œùj\Ë2 N¤@nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Namespace_.phpfœùjf‹Ãq¤>nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Property.phpbœùjb0º«¤<nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Trait_.phpZœùjZ˵ݤ2nikic-php-parser/PhpParser/Node/Scalar/String_.phpÀœùjÀ‰–ƒË¤-nikic-php-parser/PhpParser/Node/StaticVar.phpœùjñT>¤(nikic-php-parser/PhpParser/Node/Stmt.phpœùj«yþ¤.nikic-php-parser/PhpParser/Node/Stmt/Block.php§œùj§×j¤/nikic-php-parser/PhpParser/Node/Stmt/Break_.phpÛœùjÛmj–¤.nikic-php-parser/PhpParser/Node/Stmt/Case_.php†œùj†ݸO/¤/nikic-php-parser/PhpParser/Node/Stmt/Catch_.phpyœùjy{é^}¤3nikic-php-parser/PhpParser/Node/Stmt/ClassConst.phpSœùjS/꾬¤2nikic-php-parser/PhpParser/Node/Stmt/ClassLike.php œùj üÄsݤ4nikic-php-parser/PhpParser/Node/Stmt/ClassMethod.php÷œùj÷ #c¤/nikic-php-parser/PhpParser/Node/Stmt/Class_.php¸ œùj¸ Æ1è?¤/nikic-php-parser/PhpParser/Node/Stmt/Const_.phpÊœùjÊ ¤2nikic-php-parser/PhpParser/Node/Stmt/Continue_.phpêœùjêÇò¥€¤1nikic-php-parser/PhpParser/Node/Stmt/Declare_.php½œùj½5‹`ä¤,nikic-php-parser/PhpParser/Node/Stmt/Do_.phpTœùjT%ú0¤.nikic-php-parser/PhpParser/Node/Stmt/Echo_.php´œùj´±°`)¤0nikic-php-parser/PhpParser/Node/Stmt/ElseIf_.php[œùj[bE·Ñ¤.nikic-php-parser/PhpParser/Node/Stmt/Else_.php·œùj·&ô¡Á¤1nikic-php-parser/PhpParser/Node/Stmt/EnumCase.php»œùj»w4m¤.nikic-php-parser/PhpParser/Node/Stmt/Enum_.phpJœùjJ›Œï?¤3nikic-php-parser/PhpParser/Node/Stmt/Expression.php÷œùj÷ À¤1nikic-php-parser/PhpParser/Node/Stmt/Finally_.php¿œùj¿8ååå¤-nikic-php-parser/PhpParser/Node/Stmt/For_.php¼œùj¼€‚½+¤1nikic-php-parser/PhpParser/Node/Stmt/Foreach_.phpМùjе0–פ2nikic-php-parser/PhpParser/Node/Stmt/Function_.php¬ +œùj¬ +f*키0nikic-php-parser/PhpParser/Node/Stmt/Global_.phpÇœùjÇPo6¤.nikic-php-parser/PhpParser/Node/Stmt/Goto_.php"œùj"ÐX –¤1nikic-php-parser/PhpParser/Node/Stmt/GroupUse.php^œùj^€¦7Ѥ5nikic-php-parser/PhpParser/Node/Stmt/HaltCompiler.php!œùj!˜×y¤,nikic-php-parser/PhpParser/Node/Stmt/If_.php‘œùj‘4‡o¤3nikic-php-parser/PhpParser/Node/Stmt/InlineHTML.php´œùj´oûȇ¤3nikic-php-parser/PhpParser/Node/Stmt/Interface_.phpNœùjN™yáÆ¤.nikic-php-parser/PhpParser/Node/Stmt/Label.phpüœùjüŸäJ¤3nikic-php-parser/PhpParser/Node/Stmt/Namespace_.phpÝœùjÝSvEj¤,nikic-php-parser/PhpParser/Node/Stmt/Nop.phpFœùjF$6¿Ø¤1nikic-php-parser/PhpParser/Node/Stmt/Property.phpÑ œùjÑ rݦ¥¤0nikic-php-parser/PhpParser/Node/Stmt/Return_.phpÈœùjÈ|M¤0nikic-php-parser/PhpParser/Node/Stmt/Static_.phpþœùjþ’ٜޤ0nikic-php-parser/PhpParser/Node/Stmt/Switch_.phpIœùjIiËÇü¤1nikic-php-parser/PhpParser/Node/Stmt/TraitUse.phpšœùjš?óô\¤;nikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation.php=œùj={:ФAnikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php1œùj1b Ö¤Fnikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php>œùj>¶Ñÿ ¤/nikic-php-parser/PhpParser/Node/Stmt/Trait_.phpQœùjQËEøQ¤1nikic-php-parser/PhpParser/Node/Stmt/TryCatch.php6œùj6‚ã2.¤/nikic-php-parser/PhpParser/Node/Stmt/Unset_.php¿œùj¿:VÉɤ-nikic-php-parser/PhpParser/Node/Stmt/Use_.phpÔœùjÔ Ç|¤/nikic-php-parser/PhpParser/Node/Stmt/While_.phpWœùjWQ/£×¤-nikic-php-parser/PhpParser/Node/UnionType.php»œùj»’Hš­¤+nikic-php-parser/PhpParser/Node/UseItem.phpÇœùjÇ73Uƒ¤5nikic-php-parser/PhpParser/Node/VarLikeIdentifier.phpœùjy.¤7nikic-php-parser/PhpParser/Node/VariadicPlaceholder.php¯œùj¯mäWè¤+nikic-php-parser/PhpParser/NodeAbstract.php7œùj7ë¾i‚¤)nikic-php-parser/PhpParser/NodeDumper.phpû'œùjû'ŒÍO ¤)nikic-php-parser/PhpParser/NodeFinder.phpW +œùjW +¥¹^‘¤,nikic-php-parser/PhpParser/NodeTraverser.php«&œùj«&ñ†øm¤5nikic-php-parser/PhpParser/NodeTraverserInterface.phpaœùja½©ìð¤*nikic-php-parser/PhpParser/NodeVisitor.phpXœùjXÝp}ª¤9nikic-php-parser/PhpParser/NodeVisitor/CloningVisitor.phpœùjî"Û¤Cnikic-php-parser/PhpParser/NodeVisitor/CommentAnnotatingVisitor.php¶ +œùj¶ +ªÉ^µ¤9nikic-php-parser/PhpParser/NodeVisitor/FindingVisitor.php¥œùj¥í1A¤>nikic-php-parser/PhpParser/NodeVisitor/FirstFindingVisitor.phpœùj~Ĭ*¤7nikic-php-parser/PhpParser/NodeVisitor/NameResolver.phpA(œùjA(x_Á ¤@nikic-php-parser/PhpParser/NodeVisitor/NodeConnectingVisitor.php$ œùj$ Vü¤Bnikic-php-parser/PhpParser/NodeVisitor/ParentConnectingVisitor.phpkœùjk[>¤2nikic-php-parser/PhpParser/NodeVisitorAbstract.phpÙœùjÙ¡¿é~¤%nikic-php-parser/PhpParser/Parser.php œùj œ0@¤*nikic-php-parser/PhpParser/Parser/Php7.php厜ùj厩?/}¤*nikic-php-parser/PhpParser/Parser/Php8.phpmœùjmÁ†Dʤ-nikic-php-parser/PhpParser/ParserAbstract.phpÇœùjÇ.€m©¤,nikic-php-parser/PhpParser/ParserFactory.phpÖœùjÖ(ŸÉc¤)nikic-php-parser/PhpParser/PhpVersion.php—œùj—ªþßj¤,nikic-php-parser/PhpParser/PrettyPrinter.php¸œùj¸>¹—´¤5nikic-php-parser/PhpParser/PrettyPrinter/Standard.php Ïœùj Ï­Û'{¤4nikic-php-parser/PhpParser/PrettyPrinterAbstract.php +œùj +8f(¤$nikic-php-parser/PhpParser/Token.phpûœùjûÇã ̤3nikic-php-parser/PhpParser/compatibility_tokens.php1 œùj1 ¬”‚ɤobject-enumerator/LICENSEûœùjûÏÜpŸ¤object-reflector/LICENSEûœùjûûO«¤phar-io-manifest/LICENSE`œùj`÷þp¤+phar-io-manifest/ManifestDocumentMapper.phpëœùjë^DŒï¤#phar-io-manifest/ManifestLoader.phpÿœùjÿÙX©j¤'phar-io-manifest/ManifestSerializer.phpÏœùjÏ?jª'¤:phar-io-manifest/exceptions/ElementCollectionException.phpœùjIn‡¤)phar-io-manifest/exceptions/Exception.phpÓœùjÓֽФ?phar-io-manifest/exceptions/InvalidApplicationNameException.php<œùj<°°¯W¤5phar-io-manifest/exceptions/InvalidEmailException.phpœùj)Ϫ}¤3phar-io-manifest/exceptions/InvalidUrlException.php œùj x᳤9phar-io-manifest/exceptions/ManifestDocumentException.phpœùj/úï"¤@phar-io-manifest/exceptions/ManifestDocumentLoadingException.php~œùj~H}»¤?phar-io-manifest/exceptions/ManifestDocumentMapperException.phpœùjJ¯R1¤8phar-io-manifest/exceptions/ManifestElementException.phpœùjÌæ¤7phar-io-manifest/exceptions/ManifestLoaderException.phpäœùjäÍl +½¤7phar-io-manifest/exceptions/NoEmailAddressException.phpœùjáÁü¤'phar-io-manifest/values/Application.php œùj ;Äk¤+phar-io-manifest/values/ApplicationName.php…œùj…á”ù¤"phar-io-manifest/values/Author.phpœùj÷x•ü¤,phar-io-manifest/values/AuthorCollection.php-œùj-àÍá¤4phar-io-manifest/values/AuthorCollectionIterator.php¡œùj¡¨Ðªe¤,phar-io-manifest/values/BundledComponent.phpdœùjd7õõ¤6phar-io-manifest/values/BundledComponentCollection.php¹œùj¹·æߤ>phar-io-manifest/values/BundledComponentCollectionIterator.phpœùj _»¤0phar-io-manifest/values/CopyrightInformation.phppœùjp‚“æP¤!phar-io-manifest/values/Email.php¦œùj¦«S·¤%phar-io-manifest/values/Extension.phpÅœùjÅF {¤#phar-io-manifest/values/Library.phpœùj±ýžv¤#phar-io-manifest/values/License.phpœùj4Êýç¤$phar-io-manifest/values/Manifest.php& +œùj& +¾øüú¤3phar-io-manifest/values/PhpExtensionRequirement.php¼œùj¼²Pη¤1phar-io-manifest/values/PhpVersionRequirement.phpAœùjAÄñi‰¤'phar-io-manifest/values/Requirement.php´œùj´ ŸïU¤1phar-io-manifest/values/RequirementCollection.phpsœùjs6ý•M¤9phar-io-manifest/values/RequirementCollectionIterator.phpÝœùjÝUޤ phar-io-manifest/values/Type.phpÔœùjÔܲ3«¤phar-io-manifest/values/Url.phpÁœùjÁëO©ƒ¤&phar-io-manifest/xml/AuthorElement.phpðœùjðÎÊÂÚ¤0phar-io-manifest/xml/AuthorElementCollection.phpMœùjMj£·¤'phar-io-manifest/xml/BundlesElement.phptœùjt]Y´‹¤)phar-io-manifest/xml/ComponentElement.php™œùj™”na¤3phar-io-manifest/xml/ComponentElementCollection.phpVœùjVú¥?¤(phar-io-manifest/xml/ContainsElement.phpŒœùjŒl8è¤)phar-io-manifest/xml/CopyrightElement.phpóœùjó¹hDp¤*phar-io-manifest/xml/ElementCollection.phpœùjÂ<^ÉÞ¤#phar-io-manifest/xml/ExtElement.php*œùj*^º×¤-phar-io-manifest/xml/ExtElementCollection.phpDœùjDβSó¤)phar-io-manifest/xml/ExtensionElement.phpœùj€ JŒ¤'phar-io-manifest/xml/LicenseElement.phpœùjvâ/!¤)phar-io-manifest/xml/ManifestDocument.phpƒ œùjƒ ™Åi_¤(phar-io-manifest/xml/ManifestElement.phpÝœùjÝ#¨=¤#phar-io-manifest/xml/PhpElement.phpœùjYʤ(phar-io-manifest/xml/RequiresElement.phpEœùjEdwʤ!phar-io-version/BuildMetaData.phpãœùjã3A(*¤phar-io-version/LICENSE&œùj&Òª ¤$phar-io-version/PreReleaseSuffix.phpœùj8^æ¤phar-io-version/Version.phpñœùjñ‘¬¤+phar-io-version/VersionConstraintParser.phpN œùjN n­%ˤ*phar-io-version/VersionConstraintValue.phpA +œùjA +²fi™¤!phar-io-version/VersionNumber.phpµœùjµKp‘_¤9phar-io-version/constraints/AbstractVersionConstraint.phpÁœùjÁ42ƒo¤9phar-io-version/constraints/AndVersionConstraintGroup.phpéœùjékO•¤4phar-io-version/constraints/AnyVersionConstraint.phpTœùjT¸v¤6phar-io-version/constraints/ExactVersionConstraint.phpÖœùjÖgÉÐq¤Ephar-io-version/constraints/GreaterThanOrEqualToVersionConstraint.php‰œùj‰©ÞÚ_¤8phar-io-version/constraints/OrVersionConstraintGroup.phpœùj£¥ƒ6¤Fphar-io-version/constraints/SpecificMajorAndMinorVersionConstraint.phpÌœùjÌBº”,¤>phar-io-version/constraints/SpecificMajorVersionConstraint.php œùj êÒé¤1phar-io-version/constraints/VersionConstraint.phpøœùjøï¾dã¤(phar-io-version/exceptions/Exception.php³œùj³ôÓ<²¤?phar-io-version/exceptions/InvalidPreReleaseSuffixException.php›œùj›Ë[–¤6phar-io-version/exceptions/InvalidVersionException.php¡œùj¡·ðy¤7phar-io-version/exceptions/NoBuildMetaDataException.php“œùj“+${¡¤:phar-io-version/exceptions/NoPreReleaseSuffixException.php–œùj–º"Ï÷¤Dphar-io-version/exceptions/UnsupportedVersionConstraintException.phpßœùjߤ´æ¨¤"php-code-coverage/CodeCoverage.phpÉ/œùjÉ/ +K™¤6php-code-coverage/Data/ProcessedBranchCoverageData.php +œùj +U”!'¤-php-code-coverage/Data/ProcessedClassType.php*œùj*{š•¤4php-code-coverage/Data/ProcessedCodeCoverageData.phpR#œùjR#7‡Lj¤8php-code-coverage/Data/ProcessedFunctionCoverageData.php œùj }ü¤0php-code-coverage/Data/ProcessedFunctionType.phpœùj&hMg¤.php-code-coverage/Data/ProcessedMethodType.phpœùjxröƒ¤4php-code-coverage/Data/ProcessedPathCoverageData.php'œùj'Y¾¤-php-code-coverage/Data/ProcessedTraitType.php*œùj*t.¤.php-code-coverage/Data/RawCodeCoverageData.php¶%œùj¶%¾¤#php-code-coverage/Driver/Driver.php… œùj… ±m=]¤'php-code-coverage/Driver/PcovDriver.php œùj O?¡h¤%php-code-coverage/Driver/Selector.php«œùj«=»¨,¤)php-code-coverage/Driver/XdebugDriver.php›œùj›©3<¤Jphp-code-coverage/Exception/BranchAndPathCoverageNotSupportedException.phpJœùjJ¯ ÛϤCphp-code-coverage/Exception/DirectoryCouldNotBeCreatedException.php‚œùj‚’’‹¤7php-code-coverage/Exception/DriverMismatchException.php œùj ðî[­¤6php-code-coverage/Exception/EmptyPathListException.phpõœùjõáC_—¤)php-code-coverage/Exception/Exception.phpœùj+<µ‘¤;php-code-coverage/Exception/FileCouldNotBeReadException.phpƒœùjƒ×EË_¤>php-code-coverage/Exception/FileCouldNotBeWrittenException.php>œùj>\¢‚ì¤?php-code-coverage/Exception/GitInformationMismatchException.php—œùj—G`nޤ8php-code-coverage/Exception/InvalidArgumentException.php+œùj+µT&Y¤Bphp-code-coverage/Exception/InvalidCodeCoverageTargetException.phpFœùjF :¤<php-code-coverage/Exception/InvalidCoverageDataException.php„œùj„üPm¤=php-code-coverage/Exception/MethodNotImplementedException.php=œùj=ÉÈûá¤<php-code-coverage/Exception/MixedGitInformationException.phpœùj˜ò]¬¤Fphp-code-coverage/Exception/NoCodeCoverageDriverAvailableException.php¶œùj¶/´v*¤]php-code-coverage/Exception/NoCodeCoverageDriverWithPathCoverageSupportAvailableException.phpèœùjè€Kõ¤/php-code-coverage/Exception/ParserException.php/œùj/VKR ¤Dphp-code-coverage/Exception/PathExistsButIsNotDirectoryException.phpçœùjç”:f<¤9php-code-coverage/Exception/PcovNotAvailableException.phpìœùjìÍ’îÞ¤Ephp-code-coverage/Exception/PharPrefixCouldNotBeStrippedException.php œùj ꔫ¤3php-code-coverage/Exception/ReflectionException.php3œùj3ñæ©¡¤?php-code-coverage/Exception/ReportAlreadyFinalizedException.phpÁœùjÁÁsD¤8php-code-coverage/Exception/RuntimeMismatchException.phpœùj]P(פIphp-code-coverage/Exception/StaticAnalysisCacheNotConfiguredException.phpIœùjIfšó¤6php-code-coverage/Exception/TestIdMissingException.php—œùj—‚û“¬¤Cphp-code-coverage/Exception/UnintentionallyCoveredCodeException.phpUœùjUÈêN¤8php-code-coverage/Exception/VersionMismatchException.php®œùj®ìºÂ?¤=php-code-coverage/Exception/WriteOperationFailedException.phpÒœùjÒ½’ïè¤;php-code-coverage/Exception/XdebugNotAvailableException.phpðœùjðfÖuݤ9php-code-coverage/Exception/XdebugNotEnabledException.php6œùj6½ÂvL¤Bphp-code-coverage/Exception/XdebugVersionNotSupportedException.phpuœùju{„"ê¤,php-code-coverage/Exception/XmlException.php,œùj,àÔó¤php-code-coverage/Filter.php œùj U/3-¤%php-code-coverage/FilterProcessor.phpgœùjgtŒA¤php-code-coverage/LICENSEûœùjû„+•K¤'php-code-coverage/Node/AbstractNode.phpjœùjj%D¾Å¤"php-code-coverage/Node/Builder.phpEœùjEuŸ^ä$php-code-coverage/Node/CrapIndex.php@œùj@Bºj¤$php-code-coverage/Node/Directory.php *œùj * ýŸ¤php-code-coverage/Node/File.phpüSœùjüS*ÃGâ¤#php-code-coverage/Node/Iterator.php±œùj±èc¤#php-code-coverage/Report/Clover.php×&œùj×&ÉpøÞ¤&php-code-coverage/Report/Cobertura.php$0œùj$0õŠß¤#php-code-coverage/Report/Crap4j.phpÞœùjÞéRÅȤ#php-code-coverage/Report/Facade.phpÍœùjÍÊ:ž¤(php-code-coverage/Report/Html/Colors.php–œùj–RÂû™¤/php-code-coverage/Report/Html/CustomCssFile.php³œùj³y d–¤(php-code-coverage/Report/Html/Facade.phpÝœùjÝ<’Ö&¤*php-code-coverage/Report/Html/Renderer.phpž#œùjž#ú_³^¤6php-code-coverage/Report/Html/Renderer/BubbleChart.php"œùj"ý¹¨¤4php-code-coverage/Report/Html/Renderer/Dashboard.phpéœùjéÛ*/N¤4php-code-coverage/Report/Html/Renderer/Directory.php{œùj{“§$|¤/php-code-coverage/Report/Html/Renderer/File.php‰|œùj‰|oµÔ¤Bphp-code-coverage/Report/Html/Renderer/Template/branches.html.distôœùjôh2+¤Fphp-code-coverage/Report/Html/Renderer/Template/coverage_bar.html.dist/œùj/ÕchÁ¤Mphp-code-coverage/Report/Html/Renderer/Template/coverage_bar_branch.html.dist/œùj/ÕchÁ¤Ephp-code-coverage/Report/Html/Renderer/Template/css/bootstrap.min.cssRŠœùjRŠ Ìý¤>php-code-coverage/Report/Html/Renderer/Template/css/custom.cssœùj¤@php-code-coverage/Report/Html/Renderer/Template/css/octicons.cssXœùjX'#ï¤=php-code-coverage/Report/Html/Renderer/Template/css/style.css¶œùj¶v顎¤Cphp-code-coverage/Report/Html/Renderer/Template/dashboard.html.distœùj¸ô%¤Jphp-code-coverage/Report/Html/Renderer/Template/dashboard_branch.html.distœùj¸ô%¤Cphp-code-coverage/Report/Html/Renderer/Template/directory.html.distöœùjöÎÕ†á¤Jphp-code-coverage/Report/Html/Renderer/Template/directory_branch.html.dist”œùj”n2]¤Hphp-code-coverage/Report/Html/Renderer/Template/directory_item.html.distAœùjAds¤Ophp-code-coverage/Report/Html/Renderer/Template/directory_item_branch.html.dist;œùj;ªm½Û¤>php-code-coverage/Report/Html/Renderer/Template/file.html.distöœùjö9Á¤Ephp-code-coverage/Report/Html/Renderer/Template/file_branch.html.dist“ œùj“ ûu ¤Cphp-code-coverage/Report/Html/Renderer/Template/file_item.html.distrœùjréð/y¤Jphp-code-coverage/Report/Html/Renderer/Template/file_item_branch.html.distlœùjl¡-°÷¤Cphp-code-coverage/Report/Html/Renderer/Template/icons/file-code.svg0œùj0ÙQUU¤Hphp-code-coverage/Report/Html/Renderer/Template/icons/file-directory.svgêœùjêýÚZÿ¤Jphp-code-coverage/Report/Html/Renderer/Template/js/bootstrap.bundle.min.jsg;œùjg;âOê$¤:php-code-coverage/Report/Html/Renderer/Template/js/file.jsÈœùjÈ 5-¤@php-code-coverage/Report/Html/Renderer/Template/js/jquery.min.jsìUœùjìU¥ŸGœ¤>php-code-coverage/Report/Html/Renderer/Template/line.html.distÜùj÷ä´_¤?php-code-coverage/Report/Html/Renderer/Template/lines.html.disteœùjedf ¤Ephp-code-coverage/Report/Html/Renderer/Template/method_item.html.dist«œùj«‹jפLphp-code-coverage/Report/Html/Renderer/Template/method_item_branch.html.dist¥œùj¥yÄŽk¤?php-code-coverage/Report/Html/Renderer/Template/paths.html.distòœùjòã*'ݤ3php-code-coverage/Report/Html/SyntaxHighlighter.phpSœùjSqC¬¤'php-code-coverage/Report/OpenClover.php‰1œùj‰1ŠÖe¤$php-code-coverage/Report/Summary.php¡œùj¡OÅǤ!php-code-coverage/Report/Text.php[)œùj[)™C`S¤'php-code-coverage/Report/Thresholds.phpÆœùjÆœe¿'¤1php-code-coverage/Report/Xml/BuildInformation.phpÁœùjÁEÆJå¤)php-code-coverage/Report/Xml/Coverage.phpœùj¦b¥š¤*php-code-coverage/Report/Xml/Directory.phpkœùjk·Õ‰¤'php-code-coverage/Report/Xml/Facade.php +)œùj +)¬Ï–’¤%php-code-coverage/Report/Xml/File.php œùj ±Uñæ¤'php-code-coverage/Report/Xml/Method.phpœùjKe?/¤%php-code-coverage/Report/Xml/Node.php|œùj|Ä:|!¤(php-code-coverage/Report/Xml/Project.phpœùj±!ô¤'php-code-coverage/Report/Xml/Report.phpW œùjW ÿóÖ¤'php-code-coverage/Report/Xml/Source.phpvœùjvêº×[¤&php-code-coverage/Report/Xml/Tests.phpßœùjßÌ*¤'php-code-coverage/Report/Xml/Totals.php¸ œùj¸ EÇ•û¤%php-code-coverage/Report/Xml/Unit.phpéœùjéfŽ&¤*php-code-coverage/Serialization/Merger.php^œùj^†ÚµS¤.php-code-coverage/Serialization/Serializer.phpœùjÔ#¢Ð¤0php-code-coverage/Serialization/Unserializer.phpöœùjöö|F¤0php-code-coverage/StaticAnalysis/CacheWarmer.php/œùj/Güþ¤:php-code-coverage/StaticAnalysis/CachingSourceAnalyser.phpœùjó>èÿ¤1php-code-coverage/StaticAnalysis/FileAnalyser.php¿œùj¿t ?¤:php-code-coverage/StaticAnalysis/ParsingSourceAnalyser.php7œùj7*Õ7c¤3php-code-coverage/StaticAnalysis/SourceAnalyser.phpBœùjBÇV–<¤9php-code-coverage/StaticAnalysis/Value/AnalysisResult.phpà œùjà )—By¤1php-code-coverage/StaticAnalysis/Value/Class_.phpRœùjRä™Àô¤4php-code-coverage/StaticAnalysis/Value/Function_.php œùj u1}¤5php-code-coverage/StaticAnalysis/Value/Interface_.phpô œùjô Wç:Ò¤6php-code-coverage/StaticAnalysis/Value/LinesOfCode.phpΜùjÎúx訤1php-code-coverage/StaticAnalysis/Value/Method.phpf œùjf Å?™È¤1php-code-coverage/StaticAnalysis/Value/Trait_.phpI œùjI ÁAï ¤5php-code-coverage/StaticAnalysis/Value/Visibility.phpÇœùjǶ>¤Mphp-code-coverage/StaticAnalysis/Visitor/AttributeParentConnectingVisitor.php‰œùj‰0þ~¤Cphp-code-coverage/StaticAnalysis/Visitor/CodeUnitFindingVisitor.phpµ-œùjµ- ¨'¤Jphp-code-coverage/StaticAnalysis/Visitor/ExecutableLinesFindingVisitor.phpR9œùjR9ƒD¤Gphp-code-coverage/StaticAnalysis/Visitor/IgnoredLinesFindingVisitor.phpPœùjP|ûĤ(php-code-coverage/Test/Target/Class_.phpGœùjGæLÁå¤8php-code-coverage/Test/Target/ClassesThatExtendClass.php‹œùj‹“!x¤?php-code-coverage/Test/Target/ClassesThatImplementInterface.phpÇœùjÇ\<x¤+php-code-coverage/Test/Target/Function_.phpvœùjv”½'¤,php-code-coverage/Test/Target/MapBuilder.php¶%œùj¶%¥?wû¤(php-code-coverage/Test/Target/Mapper.phpd œùjd d#ø¤(php-code-coverage/Test/Target/Method.php¤œùj¤î f£¤,php-code-coverage/Test/Target/Namespace_.phpbœùjbʾ!¤(php-code-coverage/Test/Target/Target.phpÕ +œùjÕ +EÂ̤2php-code-coverage/Test/Target/TargetCollection.phpîœùjî3aª?¤:php-code-coverage/Test/Target/TargetCollectionIterator.phpòœùjòÛ÷M¤;php-code-coverage/Test/Target/TargetCollectionValidator.phpœùjŠ>Sy¤(php-code-coverage/Test/Target/Trait_.phpFœùjFüWà +¤3php-code-coverage/Test/Target/ValidationFailure.phpœùj™¬md¤2php-code-coverage/Test/Target/ValidationResult.php\œùj\T¼¤3php-code-coverage/Test/Target/ValidationSuccess.phptœùjt!Ãb¤#php-code-coverage/Test/TestSize.php¥œùj¥‘4Äɤ%php-code-coverage/Test/TestStatus.phpýœùjýveºÔ¤7php-code-coverage/UnintentionallyCoveredCodeChecker.phpƒœùjƒã Ù¤&php-code-coverage/Util/EnsuresUtf8.php#œùj# |¢w¤%php-code-coverage/Util/Filesystem.php{œùj{U²›]¤&php-code-coverage/Util/PathReducer.phpŽ œùjŽ ¨ç¹i¤%php-code-coverage/Util/Percentage.phpÓœùjÓ˜¸¤php-code-coverage/Util/Xml.phpaœùja@ÙCú¤php-code-coverage/Version.php2œùj2¸¼«¤%php-file-iterator/ExcludeIterator.phpõœùjõC 5ë¤php-file-iterator/Facade.php•œùj•Í…!Z¤php-file-iterator/Factory.phpsœùjs3áø¤php-file-iterator/Iterator.php8 œùj8 °*çó¤php-file-iterator/LICENSEûœùjû„+•K¤php-invoker/Invoker.php7œùj7>(6ʤ$php-invoker/exceptions/Exception.phpvœùjv'P=¤Dphp-invoker/exceptions/ProcessControlExtensionNotLoadedException.phpÑœùjÑed e¤+php-invoker/exceptions/TimeoutException.php¢œùj¢—tJï¤php-text-template/LICENSEûœùjû„+•K¤php-text-template/Template.phpà œùjà iªÕ–¤*php-text-template/exceptions/Exception.php}œùj}Áã`"¤9php-text-template/exceptions/InvalidArgumentException.php¤œùj¤ô¼¸Â¤1php-text-template/exceptions/RuntimeException.php¹œùj¹Ö]Mp¤php-timer/Duration.php œùj }h#¤php-timer/LICENSEûœùjûw¶-&¤$php-timer/ResourceUsageFormatter.phpœùj°”vø¤php-timer/Timer.phpŠœùjŠCHì¤"php-timer/exceptions/Exception.phprœùjr˜›<¤/php-timer/exceptions/NoActiveTimerException.php œùj *®õ¤Ephp-timer/exceptions/TimeSinceStartOfRequestNotAvailableException.phpºœùjºÐ.ñ¤ phpunit.xsdËVœùjËV0¿é¤1phpunit/Event/Dispatcher/CollectingDispatcher.phpœùjØ­:¤0phpunit/Event/Dispatcher/DeferringDispatcher.php¢œùj¢MW°‰¤-phpunit/Event/Dispatcher/DirectDispatcher.phpœùjÐ$"e¤'phpunit/Event/Dispatcher/Dispatcher.php}œùj};G`œ¤3phpunit/Event/Dispatcher/SubscribableDispatcher.phpœùj»>òL¤,phpunit/Event/Emitter/DispatchingEmitter.php‰œùj‰5yܤ!phpunit/Event/Emitter/Emitter.php0œùj0µ‡¾¤-phpunit/Event/Events/Application/Finished.phpœùj{D6Õ¤7phpunit/Event/Events/Application/FinishedSubscriber.php6œùj6Íþ)÷¤,phpunit/Event/Events/Application/Started.phpœùjŠf¤6phpunit/Event/Events/Application/StartedSubscriber.php4œùj4JÜ'¤phpunit/Event/Events/Event.php:œùj:¾ûké¤(phpunit/Event/Events/EventCollection.phpJœùjJ·æI¤0phpunit/Event/Events/EventCollectionIterator.phpyœùjyüi¿¤;phpunit/Event/Events/Test/AdditionalInformationProvided.phpÜœùjÜOï¤Ephpunit/Event/Events/Test/AdditionalInformationProvidedSubscriber.phpRœùjRj6ü¤2phpunit/Event/Events/Test/ComparatorRegistered.phpÛœùjÛÕÿ䉤<phpunit/Event/Events/Test/ComparatorRegisteredSubscriber.php@œùj@Ú­êö¤<phpunit/Event/Events/Test/CustomTestMethodInvocationUsed.php­œùj­Û¼i¤Fphpunit/Event/Events/Test/CustomTestMethodInvocationUsedSubscriber.phpTœùjT~'¤Bphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodCalled.phpœùj¾4 ŤLphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodCalledSubscriber.phpJœùjJ‘Éü ¤Cphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodErrored.phpœùj<+®¤Mphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodErroredSubscriber.phpLœùjLø¿¤Bphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFailed.phpŽœùjŽÚ,¸d¤Lphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFailedSubscriber.phpJœùjJ ¶0¤Dphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFinished.phpýœùjýJæþÙ¤Nphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFinishedSubscriber.phpNœùjNwœàK¤>phpunit/Event/Events/Test/HookMethod/AfterTestMethodCalled.php*œùj*R¦·¤Hphpunit/Event/Events/Test/HookMethod/AfterTestMethodCalledSubscriber.phpBœùjB£R‘ÿ¤?phpunit/Event/Events/Test/HookMethod/AfterTestMethodErrored.php¨œùj¨í ¤Iphpunit/Event/Events/Test/HookMethod/AfterTestMethodErroredSubscriber.phpDœùjD%?±ò¤>phpunit/Event/Events/Test/HookMethod/AfterTestMethodFailed.php¦œùj¦1R#º¤Hphpunit/Event/Events/Test/HookMethod/AfterTestMethodFailedSubscriber.phpBœùjBÞÙŽ¤@phpunit/Event/Events/Test/HookMethod/AfterTestMethodFinished.phpœùjV}SN¤Jphpunit/Event/Events/Test/HookMethod/AfterTestMethodFinishedSubscriber.phpFœùjF–^‰_¤Dphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalled.phpœùjU£AѤNphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalledSubscriber.phpNœùjNeÚäu¤Ephpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodErrored.php”œùj”âŠz¤Ophpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodErroredSubscriber.phpPœùjPñ¨¥²¤Dphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailed.php’œùj’‘_ñäNphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailedSubscriber.phpNœùjNæõ¤Fphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinished.phpœùjÇGD¤Pphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinishedSubscriber.phpRœùjR½Á“\¤?phpunit/Event/Events/Test/HookMethod/BeforeTestMethodCalled.php,œùj,êy )¤Iphpunit/Event/Events/Test/HookMethod/BeforeTestMethodCalledSubscriber.phpDœùjD¿þƾ¤@phpunit/Event/Events/Test/HookMethod/BeforeTestMethodErrored.phpªœùjª8ÏU¤Jphpunit/Event/Events/Test/HookMethod/BeforeTestMethodErroredSubscriber.phpFœùjF¦ó„0¤?phpunit/Event/Events/Test/HookMethod/BeforeTestMethodFailed.php¨œùj¨S2YÔ¤Iphpunit/Event/Events/Test/HookMethod/BeforeTestMethodFailedSubscriber.phpDœùjD}&°ö¤Aphpunit/Event/Events/Test/HookMethod/BeforeTestMethodFinished.phpœùjíiÔÔ¤Kphpunit/Event/Events/Test/HookMethod/BeforeTestMethodFinishedSubscriber.phpHœùjHx—ŠS¤<phpunit/Event/Events/Test/HookMethod/PostConditionCalled.php,œùj,×±_ݤFphpunit/Event/Events/Test/HookMethod/PostConditionCalledSubscriber.php>œùj>b*¤=phpunit/Event/Events/Test/HookMethod/PostConditionErrored.phpªœùjª^À´‚¤Gphpunit/Event/Events/Test/HookMethod/PostConditionErroredSubscriber.php@œùj@qhÀ÷¤<phpunit/Event/Events/Test/HookMethod/PostConditionFailed.php¨œùj¨¨º›©¤Fphpunit/Event/Events/Test/HookMethod/PostConditionFailedSubscriber.php>œùj>åàœ¤>phpunit/Event/Events/Test/HookMethod/PostConditionFinished.phpœùj{æA¤Hphpunit/Event/Events/Test/HookMethod/PostConditionFinishedSubscriber.phpBœùjBWXF“¤;phpunit/Event/Events/Test/HookMethod/PreConditionCalled.php*œùj*EÝé¤Ephpunit/Event/Events/Test/HookMethod/PreConditionCalledSubscriber.php<œùj<u8O&¤<phpunit/Event/Events/Test/HookMethod/PreConditionErrored.php¨œùj¨8“à¤Fphpunit/Event/Events/Test/HookMethod/PreConditionErroredSubscriber.php>œùj>‘§¤;phpunit/Event/Events/Test/HookMethod/PreConditionFailed.php¦œùj¦b¤Ephpunit/Event/Events/Test/HookMethod/PreConditionFailedSubscriber.php<œùj<>Äw¤=phpunit/Event/Events/Test/HookMethod/PreConditionFinished.phpœùjb>â¤Gphpunit/Event/Events/Test/HookMethod/PreConditionFinishedSubscriber.php@œùj@¡µX¤3phpunit/Event/Events/Test/Issue/ConsideredRisky.phpYœùjYQOìP¤=phpunit/Event/Events/Test/Issue/ConsideredRiskySubscriber.php6œùj6S%LT¤8phpunit/Event/Events/Test/Issue/DeprecationTriggered.phpÝœùjÝÖ¸å¤Bphpunit/Event/Events/Test/Issue/DeprecationTriggeredSubscriber.php@œùj@ö†“¤2phpunit/Event/Events/Test/Issue/ErrorTriggered.php? +œùj? +Ñ™åv¤<phpunit/Event/Events/Test/Issue/ErrorTriggeredSubscriber.php4œùj4R¹Â5¤3phpunit/Event/Events/Test/Issue/NoticeTriggered.php{ œùj{ ¶ñ·¤=phpunit/Event/Events/Test/Issue/NoticeTriggeredSubscriber.php6œùj6'T$ž¤;phpunit/Event/Events/Test/Issue/PhpDeprecationTriggered.php¨ œùj¨ —D¤Ephpunit/Event/Events/Test/Issue/PhpDeprecationTriggeredSubscriber.phpFœùjFˆs†¤6phpunit/Event/Events/Test/Issue/PhpNoticeTriggered.php‚ œùj‚ Ý]'¤@phpunit/Event/Events/Test/Issue/PhpNoticeTriggeredSubscriber.php<œùj<M¥s¤7phpunit/Event/Events/Test/Issue/PhpWarningTriggered.php„ œùj„ ‰ùϤAphpunit/Event/Events/Test/Issue/PhpWarningTriggeredSubscriber.php>œùj>« +d¤?phpunit/Event/Events/Test/Issue/PhpunitDeprecationTriggered.phpΜùjÎ"à¤Iphpunit/Event/Events/Test/Issue/PhpunitDeprecationTriggeredSubscriber.phpNœùjNlp®¤9phpunit/Event/Events/Test/Issue/PhpunitErrorTriggered.phpÛœùjÛ>¢£°¤Cphpunit/Event/Events/Test/Issue/PhpunitErrorTriggeredSubscriber.phpBœùjB°Ÿ³;¤:phpunit/Event/Events/Test/Issue/PhpunitNoticeTriggered.phpÝœùjÝ¡*!¤Dphpunit/Event/Events/Test/Issue/PhpunitNoticeTriggeredSubscriber.phpDœùjD +—¤;phpunit/Event/Events/Test/Issue/PhpunitWarningTriggered.php$œùj$žÿ—ð¤Ephpunit/Event/Events/Test/Issue/PhpunitWarningTriggeredSubscriber.phpFœùjF¶²â¤4phpunit/Event/Events/Test/Issue/WarningTriggered.php} œùj}  ÇYܤ>phpunit/Event/Events/Test/Issue/WarningTriggeredSubscriber.php8œùj8£®Z{¤@phpunit/Event/Events/Test/Lifecycle/DataProviderMethodCalled.php´œùj´ƒ“¥ô¤Jphpunit/Event/Events/Test/Lifecycle/DataProviderMethodCalledSubscriber.phpHœùjHë~-r¤Bphpunit/Event/Events/Test/Lifecycle/DataProviderMethodFinished.php…œùj…®|ƒå¤Lphpunit/Event/Events/Test/Lifecycle/DataProviderMethodFinishedSubscriber.phpLœùjL Ç?¤0phpunit/Event/Events/Test/Lifecycle/Finished.phpœùjRä¿ø¤:phpunit/Event/Events/Test/Lifecycle/FinishedSubscriber.php(œùj(.͵P¤:phpunit/Event/Events/Test/Lifecycle/PreparationErrored.php}œùj}øL<î¤Dphpunit/Event/Events/Test/Lifecycle/PreparationErroredSubscriber.php<œùj<‰ê¯€¤9phpunit/Event/Events/Test/Lifecycle/PreparationFailed.php{œùj{C°¤Cphpunit/Event/Events/Test/Lifecycle/PreparationFailedSubscriber.php:œùj:ØÌ"»¤:phpunit/Event/Events/Test/Lifecycle/PreparationStarted.phpœùjøw]ƤDphpunit/Event/Events/Test/Lifecycle/PreparationStartedSubscriber.php<œùj<&Uep¤0phpunit/Event/Events/Test/Lifecycle/Prepared.phpìœùjìÖŸ_’¤:phpunit/Event/Events/Test/Lifecycle/PreparedSubscriber.php(œùj(ħK”¤-phpunit/Event/Events/Test/Outcome/Errored.phpœùj.€¤7phpunit/Event/Events/Test/Outcome/ErroredSubscriber.php&œùj&èd3¤,phpunit/Event/Events/Test/Outcome/Failed.php& œùj& úÑ¿¤6phpunit/Event/Events/Test/Outcome/FailedSubscriber.php$œùj$À\*¤6phpunit/Event/Events/Test/Outcome/MarkedIncomplete.php’œùj’$$¤@phpunit/Event/Events/Test/Outcome/MarkedIncompleteSubscriber.php8œùj8 +6‹¤,phpunit/Event/Events/Test/Outcome/Passed.phpèœùjè +ž¹¤6phpunit/Event/Events/Test/Outcome/PassedSubscriber.php$œùj$ÂÐ:y¤-phpunit/Event/Events/Test/Outcome/Skipped.php"œùj"Äî¿r¤7phpunit/Event/Events/Test/Outcome/SkippedSubscriber.php&œùj&{ªdz¤5phpunit/Event/Events/Test/PrintedUnexpectedOutput.php™œùj™hùFƒ¤?phpunit/Event/Events/Test/PrintedUnexpectedOutputSubscriber.phpFœùjF¾4¾­¤:phpunit/Event/Events/Test/TestDouble/MockObjectCreated.phpyœùjyÔ}Ÿ¤Dphpunit/Event/Events/Test/TestDouble/MockObjectCreatedSubscriber.php:œùj:E¨'á¤Uphpunit/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreated.phpÏœùjÏÂgHǤ_phpunit/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreatedSubscriber.phppœùjp-¤Aphpunit/Event/Events/Test/TestDouble/PartialMockObjectCreated.php˜œùj˜þ¬Þ¤Kphpunit/Event/Events/Test/TestDouble/PartialMockObjectCreatedSubscriber.phpHœùjHøþ¡£¤8phpunit/Event/Events/Test/TestDouble/TestStubCreated.phpuœùjuᵓ³¤Bphpunit/Event/Events/Test/TestDouble/TestStubCreatedSubscriber.php6œùj6íà ¤Sphpunit/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreated.phpËœùj˧†)ï¤]phpunit/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreatedSubscriber.phplœùjlŠªR¤5phpunit/Event/Events/TestRunner/BootstrapFinished.php‚œùj‚ƒ…R…¤?phpunit/Event/Events/TestRunner/BootstrapFinishedSubscriber.phpFœùjF€2¸=¤7phpunit/Event/Events/TestRunner/ChildProcessErrored.phpœùjOlš¤Aphpunit/Event/Events/TestRunner/ChildProcessErroredSubscriber.phpJœùjJ@$$¤8phpunit/Event/Events/TestRunner/ChildProcessFinished.phpWœùjW §—M¤Bphpunit/Event/Events/TestRunner/ChildProcessFinishedSubscriber.phpLœùjL`¨&¤7phpunit/Event/Events/TestRunner/ChildProcessStarted.phpœùj’CØ¥¤Aphpunit/Event/Events/TestRunner/ChildProcessStartedSubscriber.phpJœùjJ"4¤.phpunit/Event/Events/TestRunner/Configured.phpœùjÈ dã¤8phpunit/Event/Events/TestRunner/ConfiguredSubscriber.php8œùj8ÍL¿Ï¤8phpunit/Event/Events/TestRunner/DeprecationTriggered.phpŒœùjŒr[å¤Bphpunit/Event/Events/TestRunner/DeprecationTriggeredSubscriber.phpLœùjLöñ`2¤5phpunit/Event/Events/TestRunner/EventFacadeSealed.phpœùjœ-Šg¤?phpunit/Event/Events/TestRunner/EventFacadeSealedSubscriber.phpFœùjF$¬v^¤4phpunit/Event/Events/TestRunner/ExecutionAborted.php"œùj"ÚnÒë¤>phpunit/Event/Events/TestRunner/ExecutionAbortedSubscriber.phpDœùjD²sl|¤5phpunit/Event/Events/TestRunner/ExecutionFinished.php$œùj$úVÚפ?phpunit/Event/Events/TestRunner/ExecutionFinishedSubscriber.phpFœùjFÓ¾ñ¤4phpunit/Event/Events/TestRunner/ExecutionStarted.phprœùjr‹eiå¤>phpunit/Event/Events/TestRunner/ExecutionStartedSubscriber.phpDœùjDÿ.¤9phpunit/Event/Events/TestRunner/ExtensionBootstrapped.phpלùj×k2E¤Cphpunit/Event/Events/TestRunner/ExtensionBootstrappedSubscriber.phpNœùjNÃ¥³¤;phpunit/Event/Events/TestRunner/ExtensionLoadedFromPhar.phpØœùjØ,O]¤Ephpunit/Event/Events/TestRunner/ExtensionLoadedFromPharSubscriber.phpRœùjRA‹Æ¾¤,phpunit/Event/Events/TestRunner/Finished.phpœùjS•Þ¤6phpunit/Event/Events/TestRunner/FinishedSubscriber.php4œùj4[Ixé¤=phpunit/Event/Events/TestRunner/GarbageCollectionDisabled.php5œùj5ºH·'¤Gphpunit/Event/Events/TestRunner/GarbageCollectionDisabledSubscriber.phpVœùjVy ÃW¤<phpunit/Event/Events/TestRunner/GarbageCollectionEnabled.php3œùj3æò¤Fphpunit/Event/Events/TestRunner/GarbageCollectionEnabledSubscriber.phpTœùjTyÄ +¤>phpunit/Event/Events/TestRunner/GarbageCollectionTriggered.php7œùj7èÔ5s¤Hphpunit/Event/Events/TestRunner/GarbageCollectionTriggeredSubscriber.phpXœùjX€Jz¤3phpunit/Event/Events/TestRunner/NoticeTriggered.phpöœùjöt»Ke¤=phpunit/Event/Events/TestRunner/NoticeTriggeredSubscriber.phpBœùjB¾Ðò¤+phpunit/Event/Events/TestRunner/Started.phpœùj©ÚŸõ¤5phpunit/Event/Events/TestRunner/StartedSubscriber.php2œùj2}ÃRp¤Iphpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinished.phpœùjڹˤSphpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinishedSubscriber.phpnœùjnöÏLû¤Hphpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStarted.phpBœùjBlœÅ¤Rphpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStartedSubscriber.phplœùjlêÙ§Ó¤4phpunit/Event/Events/TestRunner/WarningTriggered.php„œùj„€áÿj¤>phpunit/Event/Events/TestRunner/WarningTriggeredSubscriber.phpDœùjDʉú±¤+phpunit/Event/Events/TestSuite/Filtered.phpƒœùjƒÞª"¡¤5phpunit/Event/Events/TestSuite/FilteredSubscriber.php2œùj2™?¾Ë¤+phpunit/Event/Events/TestSuite/Finished.php¡œùj¡#æ(]¤5phpunit/Event/Events/TestSuite/FinishedSubscriber.php2œùj2JVˆ8¤)phpunit/Event/Events/TestSuite/Loaded.phpœùj +›þ¤3phpunit/Event/Events/TestSuite/LoadedSubscriber.php.œùj.˜š)¤*phpunit/Event/Events/TestSuite/Skipped.phpœùjI»C¤4phpunit/Event/Events/TestSuite/SkippedSubscriber.php0œùj0èǤ)phpunit/Event/Events/TestSuite/Sorted.phpŸœùjŸ$Ïžª¤3phpunit/Event/Events/TestSuite/SortedSubscriber.php.œùj.ÝIN"¤*phpunit/Event/Events/TestSuite/Started.phpŸœùjŸøT[/¤4phpunit/Event/Events/TestSuite/StartedSubscriber.php0œùj0¿Ý.¤9phpunit/Event/Exception/EventAlreadyAssignedException.php œùj 0•ɤ8phpunit/Event/Exception/EventFacadeIsSealedException.php +œùj +J ؤ%phpunit/Event/Exception/Exception.php½œùj½/7rr¤4phpunit/Event/Exception/InvalidArgumentException.phpùœùjùÛ䀤1phpunit/Event/Exception/InvalidEventException.phpœùjE>¯¤6phpunit/Event/Exception/InvalidSubscriberException.phpœùjSÜg¤$phpunit/Event/Exception/MapError.phpöœùjöÕ÷äR¤8phpunit/Event/Exception/NoComparisonFailureException.phpœùjâ{k ¤>phpunit/Event/Exception/NoDataSetFromDataProviderException.php'œùj'@~à¤8phpunit/Event/Exception/NoPreviousThrowableException.php +œùj +Ùú¦~¤@phpunit/Event/Exception/NoTestCaseObjectOnCallStackException.phpùœùjùxs§Ù¤,phpunit/Event/Exception/RuntimeException.phpéœùjéLƤDphpunit/Event/Exception/SubscriberTypeAlreadyRegisteredException.phpœùjį¨K¤1phpunit/Event/Exception/UnknownEventException.phpœùjšÜ}ê¤5phpunit/Event/Exception/UnknownEventTypeException.phpœùj/<ˆ¡¤6phpunit/Event/Exception/UnknownSubscriberException.phpœùj ²Éˤ:phpunit/Event/Exception/UnknownSubscriberTypeException.php œùj &'ý*¤phpunit/Event/Facade.phpO$œùjO$¶©°¤phpunit/Event/Subscriber.php£œùj£dlkû¤phpunit/Event/Tracer.phpîœùjî€Úm¤phpunit/Event/TypeMap.php&œùj&j}J¤#phpunit/Event/Value/ClassMethod.phpÏœùjÏc0œ¤)phpunit/Event/Value/ComparisonFailure.php9œùj9°é,e¤0phpunit/Event/Value/ComparisonFailureBuilder.php^œùj^Õ?`Ÿ¤/phpunit/Event/Value/Runtime/OperatingSystem.phpœùjq¢¼9¤#phpunit/Event/Value/Runtime/PHP.php2 œùj2 wun<¤'phpunit/Event/Value/Runtime/PHPUnit.phpÌœùjÌ\Á)¤'phpunit/Event/Value/Runtime/Runtime.php"œùj")ƒ'Y¤*phpunit/Event/Value/Telemetry/Duration.phpÑ œùjÑ ëØ`†¤8phpunit/Event/Value/Telemetry/GarbageCollectorStatus.phpL +œùjL +ÎMDs¤@phpunit/Event/Value/Telemetry/GarbageCollectorStatusProvider.phppœùjpr Ù¤(phpunit/Event/Value/Telemetry/HRTime.php œùj mÖž¥¤&phpunit/Event/Value/Telemetry/Info.phpï +œùjï +Jb¤-phpunit/Event/Value/Telemetry/MemoryMeter.php¤œùj¤'ìä}¤-phpunit/Event/Value/Telemetry/MemoryUsage.php^œùj^Übi¤*phpunit/Event/Value/Telemetry/Snapshot.phpóœùjóÈJF*¤+phpunit/Event/Value/Telemetry/StopWatch.phpLœùjLQØ¡6¤(phpunit/Event/Value/Telemetry/System.phpœùjæ5†$¤Fphpunit/Event/Value/Telemetry/SystemGarbageCollectorStatusProvider.phpRœùjRÃRH¤3phpunit/Event/Value/Telemetry/SystemMemoryMeter.phpçœùjç>ÿ¤1phpunit/Event/Value/Telemetry/SystemStopWatch.phpcœùjcý‚÷H¤;phpunit/Event/Value/Telemetry/SystemStopWatchWithOffset.php+œùj+ã=Dó¤'phpunit/Event/Value/Test/Issue/Code.php œùj Õ9 ¤/phpunit/Event/Value/Test/Issue/IssueTrigger.php œùj =xü¤!phpunit/Event/Value/Test/Phpt.phpœùj3{ÞY¤!phpunit/Event/Value/Test/Test.php8œùj8u¾uä¤+phpunit/Event/Value/Test/TestCollection.php"œùj"¨>Ƥ3phpunit/Event/Value/Test/TestCollectionIterator.php}œùj}þ™`¤:phpunit/Event/Value/Test/TestData/DataFromDataProvider.phpÅœùjÅöÆ¥¤<phpunit/Event/Value/Test/TestData/DataFromTestDependency.php°œùj°8åçˤ.phpunit/Event/Value/Test/TestData/TestData.phpÄœùjÄ æ·¤8phpunit/Event/Value/Test/TestData/TestDataCollection.phpœùj'¬ ¤@phpunit/Event/Value/Test/TestData/TestDataCollectionIterator.php—œùj—&Ûê¤$phpunit/Event/Value/Test/TestDox.php`œùj`Ûš¤+phpunit/Event/Value/Test/TestDoxBuilder.phpÇœùjÇRçò^¤'phpunit/Event/Value/Test/TestMethod.phpŸ œùjŸ cþPE¤.phpunit/Event/Value/Test/TestMethodBuilder.php4 +œùj4 +1Á¤+phpunit/Event/Value/TestSuite/TestSuite.phpÜùjÃX|W¶¤2phpunit/Event/Value/TestSuite/TestSuiteBuilder.phpl œùjl •š÷¤7phpunit/Event/Value/TestSuite/TestSuiteForTestClass.phpšœùjšxB¤Hphpunit/Event/Value/TestSuite/TestSuiteForTestMethodWithDataProvider.php>œùj>Ê‹ [¤3phpunit/Event/Value/TestSuite/TestSuiteWithName.phpDœùjDjW;¤!phpunit/Event/Value/Throwable.php‚ œùj‚ Ád¬ü¤(phpunit/Event/Value/ThrowableBuilder.php‹œùj‹CΓ¤phpunit/Exception.php½œùj½ÐA-¤phpunit/Framework/Assert.phpþ\œùjþ\<ä¤&phpunit/Framework/Assert/Functions.phpÕœùjÕŸºû¤&phpunit/Framework/Attributes/After.phpΜùjÎw§¤+phpunit/Framework/Attributes/AfterClass.phpÓœùjÓ9Á ±¤Dphpunit/Framework/Attributes/AllowMockObjectsWithoutExpectations.php7œùj75>%¤.phpunit/Framework/Attributes/BackupGlobals.phpéœùjém4B·¤7phpunit/Framework/Attributes/BackupStaticProperties.phpòœùjòy !„¤'phpunit/Framework/Attributes/Before.phpÏœùjÏŠNÌ2¤,phpunit/Framework/Attributes/BeforeClass.phpÔœùjÔ· Gå¤,phpunit/Framework/Attributes/CoversClass.php„œùj„T^ù§¤=phpunit/Framework/Attributes/CoversClassesThatExtendClass.php•œùj•ÚæšŽ¤Dphpunit/Framework/Attributes/CoversClassesThatImplementInterface.php¸œùj¸£Ã¤/phpunit/Framework/Attributes/CoversFunction.php¨œùj¨u®ôK¤-phpunit/Framework/Attributes/CoversMethod.phpÅœùjÅþ¨So¤0phpunit/Framework/Attributes/CoversNamespace.php”œùj”wQdʤ.phpunit/Framework/Attributes/CoversNothing.php!œùj!z3Ф,phpunit/Framework/Attributes/CoversTrait.php„œùj„ã®¶¤-phpunit/Framework/Attributes/DataProvider.php‘œùj‘•¾Œ¤4phpunit/Framework/Attributes/DataProviderClosure.phpþœùjþ<',«¤5phpunit/Framework/Attributes/DataProviderExternal.phpÆœùjÆGÓU¤(phpunit/Framework/Attributes/Depends.php”œùj”¶6"¤0phpunit/Framework/Attributes/DependsExternal.phpÉœùjÉ·¶Q¤>phpunit/Framework/Attributes/DependsExternalUsingDeepClone.phpלùj׌QU,¤Aphpunit/Framework/Attributes/DependsExternalUsingShallowClone.phpÚœùjÚÃuI¤/phpunit/Framework/Attributes/DependsOnClass.phpˆœùjˆ£‡Ó¤=phpunit/Framework/Attributes/DependsOnClassUsingDeepClone.php–œùj–•#kû¤@phpunit/Framework/Attributes/DependsOnClassUsingShallowClone.php™œùj™fùÕ¤6phpunit/Framework/Attributes/DependsUsingDeepClone.php¢œùj¢«&…á¤9phpunit/Framework/Attributes/DependsUsingShallowClone.php¥œùj¥r@P¤Kphpunit/Framework/Attributes/DisableReturnValueGenerationForTestDoubles.php#œùj#Y¿tE¤9phpunit/Framework/Attributes/DoesNotPerformAssertions.php,œùj,a¡¤@phpunit/Framework/Attributes/ExcludeGlobalVariableFromBackup.phpþœùjþ ¡ým¤@phpunit/Framework/Attributes/ExcludeStaticPropertyFromBackup.phpœùj…çðò¤&phpunit/Framework/Attributes/Group.php‚œùj‚à㟤3phpunit/Framework/Attributes/IgnoreDeprecations.phpËœùjËç¾ؤ:phpunit/Framework/Attributes/IgnorePhpunitDeprecations.php‰œùj‰Ç}±ý¤6phpunit/Framework/Attributes/IgnorePhpunitWarnings.php´œùj´Uܫˤ&phpunit/Framework/Attributes/Large.phpþœùjþ¤'phpunit/Framework/Attributes/Medium.phpÿœùjÿ`4à¤.phpunit/Framework/Attributes/PostCondition.phpÖœùjÖ)[.¤-phpunit/Framework/Attributes/PreCondition.phpÕœùjÕ•(y¤4phpunit/Framework/Attributes/PreserveGlobalState.phpïœùjïrm¿c¤<phpunit/Framework/Attributes/RequiresEnvironmentVariable.php$œùj$žfX¤1phpunit/Framework/Attributes/RequiresFunction.phpÅœùjÅžXê¤/phpunit/Framework/Attributes/RequiresMethod.phpâœùjâ0ÐÏš¤8phpunit/Framework/Attributes/RequiresOperatingSystem.phpÔœùjÔÑü’Ö¤>phpunit/Framework/Attributes/RequiresOperatingSystemFamily.phpöœùjöê?Á‡¤,phpunit/Framework/Attributes/RequiresPhp.phpÏœùjÏǯo¤5phpunit/Framework/Attributes/RequiresPhpExtension.phpFœùjF;9°£¤0phpunit/Framework/Attributes/RequiresPhpunit.phpÓœùjÓãïc“¤9phpunit/Framework/Attributes/RequiresPhpunitExtension.phpœùjrÙ㎤0phpunit/Framework/Attributes/RequiresSetting.phpºœùjºª_p¿¤5phpunit/Framework/Attributes/RunInSeparateProcess.phpœùjÕ}³¤<phpunit/Framework/Attributes/RunTestsInSeparateProcesses.phpœùjú£Hz¤&phpunit/Framework/Attributes/Small.phpþœùjþ˜ +´w¤%phpunit/Framework/Attributes/Test.phpþœùjþ77d‹¤(phpunit/Framework/Attributes/TestDox.phpiœùjiéXL¤1phpunit/Framework/Attributes/TestDoxFormatter.php‚œùj‚axÇŤ9phpunit/Framework/Attributes/TestDoxFormatterExternal.php·œùj·EîŤ)phpunit/Framework/Attributes/TestWith.php€œùj€2Míw¤-phpunit/Framework/Attributes/TestWithJson.phpœùj– á¤'phpunit/Framework/Attributes/Ticket.phpƒœùjƒ„,D¤*phpunit/Framework/Attributes/UsesClass.php‚œùj‚Ä3­¤;phpunit/Framework/Attributes/UsesClassesThatExtendClass.php“œùj“”<¤Bphpunit/Framework/Attributes/UsesClassesThatImplementInterface.php¶œùj¶ÿ·¹´¤-phpunit/Framework/Attributes/UsesFunction.php¦œùj¦=Yï¤+phpunit/Framework/Attributes/UsesMethod.phpÜùjÃ,Ap´¤.phpunit/Framework/Attributes/UsesNamespace.php’œùj’ξë¤*phpunit/Framework/Attributes/UsesTrait.php‚œùj‚²4K¼¤8phpunit/Framework/Attributes/WithEnvironmentVariable.phpÅœùjÅèÇ£e¤4phpunit/Framework/Attributes/WithoutErrorHandler.php œùj ñO½¤6phpunit/Framework/Constraint/Array/ArrayComparison.php:œùj:!´á¤2phpunit/Framework/Constraint/Array/ArrayHasKey.phpyœùjy8ÓÆ£¤5phpunit/Framework/Constraint/Array/ArraysAreEqual.phpœùjß§-¤9phpunit/Framework/Constraint/Array/ArraysAreIdentical.phpðœùjð=-ªG¤-phpunit/Framework/Constraint/Array/IsList.phpRœùjRì!„=¤0phpunit/Framework/Constraint/Boolean/IsFalse.php`œùj`, µá¤/phpunit/Framework/Constraint/Boolean/IsTrue.php]œùj]?6þͤ)phpunit/Framework/Constraint/Callback.phpúœùjú J¢c¤2phpunit/Framework/Constraint/Cardinality/Count.phpY œùjY º™/¤8phpunit/Framework/Constraint/Cardinality/GreaterThan.php(œùj( ¥ ¯¤4phpunit/Framework/Constraint/Cardinality/IsEmpty.phpŒœùjŒ[c[¤5phpunit/Framework/Constraint/Cardinality/LessThan.php"œùj"¡°%¤5phpunit/Framework/Constraint/Cardinality/SameSize.phpûœùjû +™08¤+phpunit/Framework/Constraint/Constraint.php‘#œùj‘#ãn]¤1phpunit/Framework/Constraint/Equality/IsEqual.phpc +œùjc + 3ÃÖ¤?phpunit/Framework/Constraint/Equality/IsEqualCanonicalizing.php^ +œùj^ +šðY‚¤=phpunit/Framework/Constraint/Equality/IsEqualIgnoringCase.phpd +œùjd +kîͤ:phpunit/Framework/Constraint/Equality/IsEqualWithDelta.php¸ œùj¸ ;y6ê¤4phpunit/Framework/Constraint/Exception/Exception.phpéœùjéX}íÿ¤8phpunit/Framework/Constraint/Exception/ExceptionCode.php0œùj0~ѤGphpunit/Framework/Constraint/Exception/ExceptionMessageIsOrContains.php$œùj$x›¤ñ¤Sphpunit/Framework/Constraint/Exception/ExceptionMessageMatchesRegularExpression.php·œùj·7Ë«F¤;phpunit/Framework/Constraint/Filesystem/DirectoryExists.phpùœùjù-pˆ¤6phpunit/Framework/Constraint/Filesystem/FileExists.phpôœùjôÿ+ð÷¤6phpunit/Framework/Constraint/Filesystem/IsReadable.phpôœùjô“A†¤6phpunit/Framework/Constraint/Filesystem/IsWritable.phpôœùjôöÆùB¤+phpunit/Framework/Constraint/IsAnything.phpAœùjAkÒš6¤,phpunit/Framework/Constraint/IsIdentical.phpæ œùjæ rÚª¤,phpunit/Framework/Constraint/JsonMatches.php +œùj +9~¬8¤.phpunit/Framework/Constraint/Math/IsFinite.phpzœùjzÔŠø¤0phpunit/Framework/Constraint/Math/IsInfinite.php‚œùj‚íC²¤+phpunit/Framework/Constraint/Math/IsNan.phpnœùjnÇx¤4phpunit/Framework/Constraint/Object/ObjectEquals.phpOœùjOŽírL¤9phpunit/Framework/Constraint/Object/ObjectHasProperty.phpuœùju÷e¥¤8phpunit/Framework/Constraint/Operator/BinaryOperator.php œùj X‹¤4phpunit/Framework/Constraint/Operator/LogicalAnd.phpYœùjYÿ‡ý¤4phpunit/Framework/Constraint/Operator/LogicalNot.phpü œùjü âèRf¤3phpunit/Framework/Constraint/Operator/LogicalOr.php1œùj1¾ ä¤4phpunit/Framework/Constraint/Operator/LogicalXor.phpœùjx{F¤2phpunit/Framework/Constraint/Operator/Operator.php'œùj'áJÂ%¤7phpunit/Framework/Constraint/Operator/UnaryOperator.phpœùj5D ¤.phpunit/Framework/Constraint/String/IsJson.phpò œùjò î–±¤9phpunit/Framework/Constraint/String/RegularExpression.php¡œùj¡£Uޤ6phpunit/Framework/Constraint/String/StringContains.php?œùj?𶩤¤6phpunit/Framework/Constraint/String/StringEndsWith.phpðœùjð@%õ-¤Mphpunit/Framework/Constraint/String/StringEqualsStringIgnoringLineEndings.php7œùj7[…J¤Fphpunit/Framework/Constraint/String/StringMatchesFormatDescription.phpÀœùjÀöo¤8phpunit/Framework/Constraint/String/StringStartsWith.phpøœùjø™.ÿ¤@phpunit/Framework/Constraint/Traversable/TraversableContains.phpKœùjK#Ǧ¤Ephpunit/Framework/Constraint/Traversable/TraversableContainsEqual.php!œùj!×b/¤Iphpunit/Framework/Constraint/Traversable/TraversableContainsIdentical.phpòœùjòíµÍ#¤Dphpunit/Framework/Constraint/Traversable/TraversableContainsOnly.phpH œùjH DsÖå¤2phpunit/Framework/Constraint/Type/IsInstanceOf.phpÊœùjÊ9 ;>¤,phpunit/Framework/Constraint/Type/IsNull.php\œùj\a#‡ ¤,phpunit/Framework/Constraint/Type/IsType.phpâ œùjâ ÃÈÚ°¤+phpunit/Framework/DataProviderTestSuite.php@ œùj@ E­‹ø¤4phpunit/Framework/Exception/AssertionFailedError.phpþœùjþÏ5/¤4phpunit/Framework/Exception/EmptyStringException.phpCœùjC‹ÖšÍ¤<phpunit/Framework/Exception/ErrorLogNotWritableException.php¹œùj¹_}¤)phpunit/Framework/Exception/Exception.php› +œùj› +²,Õú¤:phpunit/Framework/Exception/ExpectationFailedException.phpΜùjÎÞ]û»¤>phpunit/Framework/Exception/GeneratorNotSupportedException.php:œùj:™ j{¤9phpunit/Framework/Exception/Incomplete/IncompleteTest.php,œùj,_Kª¤>phpunit/Framework/Exception/Incomplete/IncompleteTestError.phpkœùjk÷›øè¤8phpunit/Framework/Exception/InvalidArgumentException.php;œùj;÷ñ‹)¤<phpunit/Framework/Exception/InvalidDataProviderException.phpÉœùjÉ¥¾ '¤:phpunit/Framework/Exception/InvalidDependencyException.phpoœùjoi¾Ôí¤9phpunit/Framework/Exception/NoChildTestSuiteException.php9œùj94´Ý¤Nphpunit/Framework/Exception/ObjectEquals/ActualValueIsNotAnObjectException.php­œùj­·òW÷¤`phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotAcceptParameterTypeException.phpWœùjWŒ‹–½¤bphpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php>œùj>{ý–¤gphpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareExactlyOneParameterException.phpHœùjH°t ²¤aphpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareParameterTypeException.phpFœùjFñ †9¤Rphpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotExistException.phpœùjÝ/]¤8phpunit/Framework/Exception/PhptAssertionFailedError.phpÜùjÃèèy¤9phpunit/Framework/Exception/ProcessIsolationException.php9œùj9,ÿä3phpunit/Framework/Exception/Skipped/SkippedTest.php)œùj)Àó¤=phpunit/Framework/Exception/Skipped/SkippedTestSuiteError.phpjœùjjwÜŠ¤Cphpunit/Framework/Exception/Skipped/SkippedWithMessageException.phppœùjpX&º>¤@phpunit/Framework/Exception/UnknownClassOrInterfaceException.phpöœùjöH nw¤:phpunit/Framework/Exception/UnknownNativeTypeException.phpçœùjçœ%]¤.phpunit/Framework/ExecutionOrderDependency.phpœùjëלð¤3phpunit/Framework/MockObject/ConfigurableMethod.phpïœùjïÌ^ÉP¤Aphpunit/Framework/MockObject/Exception/BadMethodCallException.phpoœùjoäÛ!¤Hphpunit/Framework/MockObject/Exception/CannotUseOnlyMethodsException.phptœùjt™¬ +¤4phpunit/Framework/MockObject/Exception/Exception.php,œùj,÷Rœ?¤Kphpunit/Framework/MockObject/Exception/IncompatibleReturnValueException.phpåœùjå2íK]¤Hphpunit/Framework/MockObject/Exception/MatchBuilderNotFoundException.php.œùj.ú¤´a¤Lphpunit/Framework/MockObject/Exception/MatcherAlreadyRegisteredException.php&œùj&æÝLphpunit/Framework/MockObject/Exception/MethodCannotBeConfiguredException.phpˆœùjˆ7À„3¤Ophpunit/Framework/MockObject/Exception/MethodNameAlreadyConfiguredException.phpòœùjò<Ú¬>¤Kphpunit/Framework/MockObject/Exception/MethodNameNotConfiguredException.phpêœùjêªYi¤Uphpunit/Framework/MockObject/Exception/MethodParametersAlreadyConfiguredException.phpûœùjû¥s¤Hphpunit/Framework/MockObject/Exception/NeverReturningMethodException.phpeœùje]M6…¤Qphpunit/Framework/MockObject/Exception/NoMoreParameterSetsConfiguredException.phpòœùjò°C½Ì¤Pphpunit/Framework/MockObject/Exception/NoMoreReturnValuesConfiguredException.phpלùj×H]²ò¤Lphpunit/Framework/MockObject/Exception/ReturnValueNotConfiguredException.php¨œùj¨2’×V¤;phpunit/Framework/MockObject/Exception/RuntimeException.phpcœùjcõ€= ¤Dphpunit/Framework/MockObject/Exception/TestDoubleSealedException.phpœùjmy®¤7phpunit/Framework/MockObject/Generator/DoubledClass.phpœùj8¢Àó¤8phpunit/Framework/MockObject/Generator/DoubledMethod.php*œùj*$r¤;phpunit/Framework/MockObject/Generator/DoubledMethodSet.phpÚœùjÚ#0¤Nphpunit/Framework/MockObject/Generator/Exception/ClassIsAnonymousException.phpLœùjLæ¾Ñ¤Pphpunit/Framework/MockObject/Generator/Exception/ClassIsEnumerationException.phpJœùjJ `@ ¤Jphpunit/Framework/MockObject/Generator/Exception/ClassIsFinalException.phpFœùjFÔƒ¤Mphpunit/Framework/MockObject/Generator/Exception/DuplicateMethodException.phpFœùjFÂAé¤>phpunit/Framework/MockObject/Generator/Exception/Exception.phpnœùjn½q~•¤Nphpunit/Framework/MockObject/Generator/Exception/InvalidClassNameException.phpqœùjqÿ ©Œ¤Ophpunit/Framework/MockObject/Generator/Exception/InvalidMethodNameException.php<œùj<×ÓªÙ¤Ophpunit/Framework/MockObject/Generator/Exception/MethodNamedMethodException.phpÜùjÃW²6¶¤Nphpunit/Framework/MockObject/Generator/Exception/NameAlreadyInUseException.phpiœùjiØ´¤Hphpunit/Framework/MockObject/Generator/Exception/ReflectionException.php…œùj…"è¤Ephpunit/Framework/MockObject/Generator/Exception/RuntimeException.php‚œùj‚„Ãø¤Nphpunit/Framework/MockObject/Generator/Exception/UnknownInterfaceException.php;œùj;¹:yá¤Iphpunit/Framework/MockObject/Generator/Exception/UnknownTypeException.php-œùj-¨‰V¤4phpunit/Framework/MockObject/Generator/Generator.phpÄeœùjÄer¬'ƒ¤9phpunit/Framework/MockObject/Generator/HookedProperty.phpRœùjRÓ¢žØ¤Bphpunit/Framework/MockObject/Generator/HookedPropertyGenerator.php’œùj’Ãã©k¤9phpunit/Framework/MockObject/Generator/TemplateLoader.phpÙœùjÙˆHU!¤@phpunit/Framework/MockObject/Generator/templates/deprecation.tpl;œùj;O5øs¤Cphpunit/Framework/MockObject/Generator/templates/doubled_method.tplCœùjC¡÷Mé¤Jphpunit/Framework/MockObject/Generator/templates/doubled_static_method.tplîœùjî 4éR¤Aphpunit/Framework/MockObject/Generator/templates/intersection.tplLœùjL®Ž-X¤Fphpunit/Framework/MockObject/Generator/templates/test_double_class.tpl[œùj[üj½Ð¤,phpunit/Framework/MockObject/MockBuilder.php œùj ”Q€ö¤Iphpunit/Framework/MockObject/Runtime/AbstractInvocationImplementation.php¹"œùj¹"{j¤?phpunit/Framework/MockObject/Runtime/Api/DoubledCloneMethod.phpœùj¥•J%¤3phpunit/Framework/MockObject/Runtime/Api/Method.php)œùj)ü Šž¤:phpunit/Framework/MockObject/Runtime/Api/MockObjectApi.php?œùj?á$rÕ¤?phpunit/Framework/MockObject/Runtime/Api/ProxiedCloneMethod.php7œùj7‰˜Â˜¤4phpunit/Framework/MockObject/Runtime/Api/StubApi.phpoœùjo× h¤<phpunit/Framework/MockObject/Runtime/Api/TestDoubleState.phpL œùjL n뵤Cphpunit/Framework/MockObject/Runtime/Interface/InvocationMocker.phpœùjÒ˜Çw¤Dphpunit/Framework/MockObject/Runtime/Interface/InvocationStubber.php œùj h›„O¤=phpunit/Framework/MockObject/Runtime/Interface/MockObject.php‚œùj‚…6¨A¤Ephpunit/Framework/MockObject/Runtime/Interface/MockObjectInternal.php?œùj?ŠU@6¤7phpunit/Framework/MockObject/Runtime/Interface/Stub.php‰œùj‰cvã ¤?phpunit/Framework/MockObject/Runtime/Interface/StubInternal.php9œùj9 {Æå¤3phpunit/Framework/MockObject/Runtime/Invocation.phpQ œùjQ ¤€~º¤:phpunit/Framework/MockObject/Runtime/InvocationHandler.php™œùj™Áù-¤Gphpunit/Framework/MockObject/Runtime/InvocationMockerImplementation.phpœùj‘Ûò‚¤Hphpunit/Framework/MockObject/Runtime/InvocationStubberImplementation.php§œùj§’Óü¤0phpunit/Framework/MockObject/Runtime/Matcher.phpÚœùjÚÁfy¤=phpunit/Framework/MockObject/Runtime/MethodNameConstraint.php_œùj_=;¼¤Ephpunit/Framework/MockObject/Runtime/PropertyHook/PropertyGetHook.phpœùj»Æ6̤Bphpunit/Framework/MockObject/Runtime/PropertyHook/PropertyHook.php5œùj5NE5Ò¤Ephpunit/Framework/MockObject/Runtime/PropertyHook/PropertySetHook.phpœùj`²>n¤=phpunit/Framework/MockObject/Runtime/ReturnValueGenerator.phpÛœùjÛ9'¤=phpunit/Framework/MockObject/Runtime/Rule/AnyInvokedCount.phpƒœùjƒ/d²k¤;phpunit/Framework/MockObject/Runtime/Rule/AnyParameters.php/œùj/ÿpv¤=phpunit/Framework/MockObject/Runtime/Rule/InvocationOrder.php7œùj7=€Ä˜¤Aphpunit/Framework/MockObject/Runtime/Rule/InvokedAtLeastCount.php*œùj*䙆³¤@phpunit/Framework/MockObject/Runtime/Rule/InvokedAtLeastOnce.phpGœùjGãfËs¤@phpunit/Framework/MockObject/Runtime/Rule/InvokedAtMostCount.phpUœùjUÅq‰*¤:phpunit/Framework/MockObject/Runtime/Rule/InvokedCount.phpO +œùjO +&h1•¤8phpunit/Framework/MockObject/Runtime/Rule/MethodName.php»œùj»E–z[¤Bphpunit/Framework/MockObject/Runtime/Rule/OrderedParameterSets.phpH +œùjH +;ã÷¤8phpunit/Framework/MockObject/Runtime/Rule/Parameters.php›œùj›¬Є¤<phpunit/Framework/MockObject/Runtime/Rule/ParametersRule.phpëœùjëv®Y¤Dphpunit/Framework/MockObject/Runtime/Rule/UnorderedParameterSets.php" œùj" ¬dýï¤>phpunit/Framework/MockObject/Runtime/Stub/ConsecutiveCalls.php œùj ËdRY¤7phpunit/Framework/MockObject/Runtime/Stub/Exception.php¦œùj¦áëK¶¤<phpunit/Framework/MockObject/Runtime/Stub/ReturnArgument.phpŸœùjŸrjc¤<phpunit/Framework/MockObject/Runtime/Stub/ReturnCallback.phpÔœùjÔ2à¶Q¤=phpunit/Framework/MockObject/Runtime/Stub/ReturnReference.phpfœùjf¦ÿ¬Ó¤8phpunit/Framework/MockObject/Runtime/Stub/ReturnSelf.phpEœùjE“”DѤ8phpunit/Framework/MockObject/Runtime/Stub/ReturnStub.phpTœùjTå{ÈŠ¤<phpunit/Framework/MockObject/Runtime/Stub/ReturnValueMap.phplœùjl$}S¤2phpunit/Framework/MockObject/Runtime/Stub/Stub.phpéœùjéŽÓ±Ê¤2phpunit/Framework/MockObject/TestDoubleBuilder.php²œùj²ÿÓæR¤0phpunit/Framework/MockObject/TestStubBuilder.phpˆ œùjˆ )Ǥ phpunit/Framework/NativeType.php&œùj&|Ñgç¤!phpunit/Framework/Reorderable.phpøœùjø€¶çö¤$phpunit/Framework/SelfDescribing.phpyœùjy;Å;¤phpunit/Framework/Test.phpãœùjã­ñ9¤!phpunit/Framework/TestBuilder.php )œùj )„v”¤phpunit/Framework/TestCase.php)œùj)ŠÖ8†¤<phpunit/Framework/TestRunner/ChildProcessResultProcessor.php‘œùj‘ì™S=¤:phpunit/Framework/TestRunner/SeparateProcessTestRunner.phpûœùjû%„¾!¤+phpunit/Framework/TestRunner/TestRunner.phpÕ,œùjÕ,DŸ]Á¤1phpunit/Framework/TestRunner/templates/method.tplzœùjzµÚÿá¤$phpunit/Framework/TestSize/Known.phpØœùjد½R¤$phpunit/Framework/TestSize/Large.phpbœùjb;qç¤%phpunit/Framework/TestSize/Medium.phpdœùjdTA¦Ñ¤$phpunit/Framework/TestSize/Small.phpVœùjVX♤'phpunit/Framework/TestSize/TestSize.php¤œùj¤ÅìHѤ&phpunit/Framework/TestSize/Unknown.phpçœùjçfÚœ¤,phpunit/Framework/TestStatus/Deprecation.php3œùj3‡mÐ|¤&phpunit/Framework/TestStatus/Error.php!œùj!ÊXP>¤(phpunit/Framework/TestStatus/Failure.php'œùj'µgö%¤+phpunit/Framework/TestStatus/Incomplete.php0œùj0Üqöq¤&phpunit/Framework/TestStatus/Known.phpŸœùjŸ‘–¤'phpunit/Framework/TestStatus/Notice.php$œùj$«¥!H¤&phpunit/Framework/TestStatus/Risky.php!œùj!t E¤(phpunit/Framework/TestStatus/Skipped.php'œùj'Ž<¤(phpunit/Framework/TestStatus/Success.php'œùj'Þa&¥¤+phpunit/Framework/TestStatus/TestStatus.phpÀœùjÀ+ u¤(phpunit/Framework/TestStatus/Unknown.php-œùj-FuXN¤(phpunit/Framework/TestStatus/Warning.php'œùj'Ž=â¤phpunit/Framework/TestSuite.phpKœùjK‰O·j¤'phpunit/Framework/TestSuiteIterator.phpçœùjç%Nî¤phpunit/Logging/EventLogger.phpIœùjIcïµ¾¤(phpunit/Logging/JUnit/JunitXmlLogger.phpÞ3œùjÞ3¯ÿgˤ/phpunit/Logging/JUnit/Subscriber/Subscriber.php=œùj=ôýxÛ¤:phpunit/Logging/JUnit/Subscriber/TestErroredSubscriber.php}œùj}£Šá¤9phpunit/Logging/JUnit/Subscriber/TestFailedSubscriber.phpwœùjw†€¤;phpunit/Logging/JUnit/Subscriber/TestFinishedSubscriber.phpƒœùjƒ"^—¤Cphpunit/Logging/JUnit/Subscriber/TestMarkedIncompleteSubscriber.php³œùj³5ÝTY¤Ephpunit/Logging/JUnit/Subscriber/TestPreparationErroredSubscriber.php¹œùj¹ñDy‰¤Dphpunit/Logging/JUnit/Subscriber/TestPreparationFailedSubscriber.php³œùj³ºÉ£Å¤Ephpunit/Logging/JUnit/Subscriber/TestPreparationStartedSubscriber.php¿œùj¿$†‘2¤;phpunit/Logging/JUnit/Subscriber/TestPreparedSubscriber.php}œùj}ñý»‡¤Jphpunit/Logging/JUnit/Subscriber/TestPrintedUnexpectedOutputSubscriber.phpyœùjy÷Öú¤Jphpunit/Logging/JUnit/Subscriber/TestRunnerExecutionFinishedSubscriber.phpQœùjQ2õ÷÷¤:phpunit/Logging/JUnit/Subscriber/TestSkippedSubscriber.php}œùj}¿I©¤@phpunit/Logging/JUnit/Subscriber/TestSuiteFinishedSubscriber.php-œùj- Cö¶¤?phpunit/Logging/JUnit/Subscriber/TestSuiteSkippedSubscriber.php-œùj-* S¤?phpunit/Logging/JUnit/Subscriber/TestSuiteStartedSubscriber.php-œùj-}‰£€¤Pphpunit/Logging/OpenTestReporting/Exception/CannotOpenUriForWritingException.phpÅœùjÅΗip¤9phpunit/Logging/OpenTestReporting/Exception/Exception.php`œùj`Tç>i¤2phpunit/Logging/OpenTestReporting/OtrXmlLogger.php´dœùj´džŒ¤,phpunit/Logging/OpenTestReporting/Status.php³œùj³|Ü"£¤Uphpunit/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodErroredSubscriber.php,œùj,wÖ¤Tphpunit/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodFailedSubscriber.php%œùj%ë£õ¤Wphpunit/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodErroredSubscriber.php8œùj8–£¤Vphpunit/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodFailedSubscriber.php1œùj1r¤™¤;phpunit/Logging/OpenTestReporting/Subscriber/Subscriber.phpgœùjg†€!{¤Fphpunit/Logging/OpenTestReporting/Subscriber/TestAbortedSubscriber.phpÀœùjÀþsE¤Nphpunit/Logging/OpenTestReporting/Subscriber/TestConsideredRiskySubscriber.phpaœùjaæ!n¤Sphpunit/Logging/OpenTestReporting/Subscriber/TestDeprecationTriggeredSubscriber.phpœùjD¢ýë¤Mphpunit/Logging/OpenTestReporting/Subscriber/TestErrorTriggeredSubscriber.php[œùj['S@¤Fphpunit/Logging/OpenTestReporting/Subscriber/TestErroredSubscriber.php•œùj•RO(¤Ephpunit/Logging/OpenTestReporting/Subscriber/TestFailedSubscriber.phpœùj#ݤGphpunit/Logging/OpenTestReporting/Subscriber/TestFinishedSubscriber.php•œùj•Hœ¤Nphpunit/Logging/OpenTestReporting/Subscriber/TestNoticeTriggeredSubscriber.phpaœùjav){¤Vphpunit/Logging/OpenTestReporting/Subscriber/TestPhpDeprecationTriggeredSubscriber.php‘œùj‘ðŽ÷¤Qphpunit/Logging/OpenTestReporting/Subscriber/TestPhpNoticeTriggeredSubscriber.phpsœùjsÆJN?¤Rphpunit/Logging/OpenTestReporting/Subscriber/TestPhpWarningTriggeredSubscriber.phpyœùjyÍý“¤Zphpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitDeprecationTriggeredSubscriber.php©œùj©ÏÔõù¤Tphpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitErrorTriggeredSubscriber.php…œùj…Rfœñ¤Uphpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitNoticeTriggeredSubscriber.php‹œùj‹çKNy¤Vphpunit/Logging/OpenTestReporting/Subscriber/TestPhpunitWarningTriggeredSubscriber.php‘œùj‘&1´®¤Qphpunit/Logging/OpenTestReporting/Subscriber/TestPreparationErroredSubscriber.phpÍœùjͦ£Ø¾¤Pphpunit/Logging/OpenTestReporting/Subscriber/TestPreparationFailedSubscriber.phpÈœùjÈu„µ¤Gphpunit/Logging/OpenTestReporting/Subscriber/TestPreparedSubscriber.php›œùj›ÙÁ7²¤Vphpunit/Logging/OpenTestReporting/Subscriber/TestPrintedUnexpectedOutputSubscriber.php‘œùj‘]¨=¤Mphpunit/Logging/OpenTestReporting/Subscriber/TestRunnerFinishedSubscriber.phpÑœùjÑùów…¤Lphpunit/Logging/OpenTestReporting/Subscriber/TestRunnerStartedSubscriber.php©œùj©Òy¡Æ¤Fphpunit/Logging/OpenTestReporting/Subscriber/TestSkippedSubscriber.php•œùj•iÏIr¤Lphpunit/Logging/OpenTestReporting/Subscriber/TestSuiteFinishedSubscriber.php©œùj©¡ÐɤKphpunit/Logging/OpenTestReporting/Subscriber/TestSuiteSkippedSubscriber.php©œùj©@*E¤Kphpunit/Logging/OpenTestReporting/Subscriber/TestSuiteStartedSubscriber.php©œùj©­E@p¤Ophpunit/Logging/OpenTestReporting/Subscriber/TestWarningTriggeredSubscriber.phpgœùjg¦m»ø¤2phpunit/Logging/TeamCity/Subscriber/Subscriber.phpIœùjIŒt¶“¤Ephpunit/Logging/TeamCity/Subscriber/TestConsideredRiskySubscriber.php³œùj³åÎF¤=phpunit/Logging/TeamCity/Subscriber/TestErroredSubscriber.phpƒœùjƒ¯y»ˆ¤<phpunit/Logging/TeamCity/Subscriber/TestFailedSubscriber.php}œùj}°ôå¤>phpunit/Logging/TeamCity/Subscriber/TestFinishedSubscriber.php‰œùj‰ÍT¸›¤Fphpunit/Logging/TeamCity/Subscriber/TestMarkedIncompleteSubscriber.php¹œùj¹¾T»b¤Hphpunit/Logging/TeamCity/Subscriber/TestPreparationErroredSubscriber.php¿œùj¿!s«ï¤Gphpunit/Logging/TeamCity/Subscriber/TestPreparationFailedSubscriber.php¹œùj¹…¹Ž¤Hphpunit/Logging/TeamCity/Subscriber/TestPreparationStartedSubscriber.phpÅœùjÅ}å'ì¤>phpunit/Logging/TeamCity/Subscriber/TestPreparedSubscriber.phpœùj' ÑC¤Mphpunit/Logging/TeamCity/Subscriber/TestRunnerExecutionFinishedSubscriber.phpWœùjWã)Ê®¤=phpunit/Logging/TeamCity/Subscriber/TestSkippedSubscriber.phpƒœùjƒÁNÇH¤Wphpunit/Logging/TeamCity/Subscriber/TestSuiteBeforeFirstTestMethodErroredSubscriber.phpœùjïʹj¤Vphpunit/Logging/TeamCity/Subscriber/TestSuiteBeforeFirstTestMethodFailedSubscriber.phpüœùjüÍ>®¤Cphpunit/Logging/TeamCity/Subscriber/TestSuiteFinishedSubscriber.php9œùj9¬(s³¤Bphpunit/Logging/TeamCity/Subscriber/TestSuiteSkippedSubscriber.php—œùj—5²B;¤Bphpunit/Logging/TeamCity/Subscriber/TestSuiteStartedSubscriber.php3œùj3±Ò“¤+phpunit/Logging/TeamCity/TeamCityLogger.php?5œùj?5GD,ø¤(phpunit/Logging/TestDox/HtmlRenderer.phpÐ œùjÐ ß|Gþ¤*phpunit/Logging/TestDox/NamePrettifier.php†0œùj†0{¦w¤-phpunit/Logging/TestDox/PlainTextRenderer.phpœùj%Ca¤<phpunit/Logging/TestDox/TestResult/Subscriber/Subscriber.phpfœùjf7kC¤Ophpunit/Logging/TestDox/TestResult/Subscriber/TestConsideredRiskySubscriber.phpPœùjP»J'ž¤Gphpunit/Logging/TestDox/TestResult/Subscriber/TestErroredSubscriber.php œùj t8¤Fphpunit/Logging/TestDox/TestResult/Subscriber/TestFailedSubscriber.phpœùjñä;À¤Hphpunit/Logging/TestDox/TestResult/Subscriber/TestFinishedSubscriber.phpŠœùjŠMÉ~£¤Pphpunit/Logging/TestDox/TestResult/Subscriber/TestMarkedIncompleteSubscriber.phpVœùjV]ùó¤Fphpunit/Logging/TestDox/TestResult/Subscriber/TestPassedSubscriber.phpœùjÔBº¤Hphpunit/Logging/TestDox/TestResult/Subscriber/TestPreparedSubscriber.php&œùj&ÚÈé¤Gphpunit/Logging/TestDox/TestResult/Subscriber/TestSkippedSubscriber.php œùj ´Õj¤Tphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.phpnœùjnQ¤Ophpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredNoticeSubscriber.phpPœùjP°ÔÃ)¤Wphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php€œùj€˜]¤Rphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.phpbœùjbae¤Sphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.phphœùjh¢QF¤[phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php˜œùj˜^õ¤Uphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.phptœùjt‘Gâ°¤Wphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php€œùj€îk½<¤Pphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredWarningSubscriber.phpVœùjVxÝB\¤1phpunit/Logging/TestDox/TestResult/TestResult.phpfœùjf阵 ¤;phpunit/Logging/TestDox/TestResult/TestResultCollection.phpsœùjs¹Ì¤Cphpunit/Logging/TestDox/TestResult/TestResultCollectionIterator.php¼œùj¼'4%~¤:phpunit/Logging/TestDox/TestResult/TestResultCollector.php£*œùj£*Äø^¤phpunit/Metadata/After.php9œùj9àwÀ¤phpunit/Metadata/AfterClass.phpCœùjCU÷¤8phpunit/Metadata/AllowMockObjectsWithoutExpectations.phpbœùjbI)¨¤%phpunit/Metadata/Api/CodeCoverage.phpÑœùjÑß;ñý¤%phpunit/Metadata/Api/DataProvider.php<3œùj<3T‡®¤%phpunit/Metadata/Api/Dependencies.php†œùj†Š6Á¾¤phpunit/Metadata/Api/Groups.phpJœùjJ%“PU¤$phpunit/Metadata/Api/HookMethods.phpœùjÙE¤%phpunit/Metadata/Api/ProvidedData.phpûœùjûO „®¤%phpunit/Metadata/Api/Requirements.php¾œùj¾ÈÿÙŒ¤"phpunit/Metadata/BackupGlobals.phpFœùjF´r0õ¤+phpunit/Metadata/BackupStaticProperties.phpXœùjXX\½w¤phpunit/Metadata/Before.php;œùj;®‘Y¦¤ phpunit/Metadata/BeforeClass.phpEœùjE{‰¸¤ phpunit/Metadata/CoversClass.phpßœùjßš0 ¤1phpunit/Metadata/CoversClassesThatExtendClass.phpœùj@bã¤8phpunit/Metadata/CoversClassesThatImplementInterface.php+œùj+}¡¯¤#phpunit/Metadata/CoversFunction.phpœùj‹&7¤!phpunit/Metadata/CoversMethod.php!œùj!³Â8¶¤$phpunit/Metadata/CoversNamespace.phpóœùjóX‘»»¤"phpunit/Metadata/CoversNothing.php6œùj6I¥Õ¤ phpunit/Metadata/CoversTrait.phpßœùjß“³’¤!phpunit/Metadata/DataProvider.phpœùjú®#‡¤(phpunit/Metadata/DataProviderClosure.phpXœùjX8 CŸ¤#phpunit/Metadata/DependsOnClass.phpGœùjGASáH¤$phpunit/Metadata/DependsOnMethod.php‰œùj‰B.T†¤?phpunit/Metadata/DisableReturnValueGenerationForTestDoubles.phppœùjp‘ ¤-phpunit/Metadata/DoesNotPerformAssertions.phpLœùjL{¯T¤(phpunit/Metadata/Exception/Exception.phpÀœùjÀälñ¤8phpunit/Metadata/Exception/InvalidAttributeException.phpwœùjwÒo‡¤Aphpunit/Metadata/Exception/InvalidVersionRequirementException.phpœùj-µ[D¤<phpunit/Metadata/Exception/NoVersionRequirementException.phpœùjgÌ®¤4phpunit/Metadata/ExcludeGlobalVariableFromBackup.phpRœùjR)§™[¤4phpunit/Metadata/ExcludeStaticPropertyFromBackup.phpUœùjU„Ø£¤phpunit/Metadata/Group.phpßœùjßï 4i¤'phpunit/Metadata/IgnoreDeprecations.php&œùj&ˆ†!F¤.phpunit/Metadata/IgnorePhpunitDeprecations.phpªœùjª(\¤*phpunit/Metadata/IgnorePhpunitWarnings.php,œùj,ßÎo¤phpunit/Metadata/Level.php¿œùj¿8VB¤phpunit/Metadata/Metadata.phpæzœùjæz±úOܤ'phpunit/Metadata/MetadataCollection.php8œùj8«(m¤/phpunit/Metadata/MetadataCollectionIterator.php/œùj/2¸†Ž¤+phpunit/Metadata/Parser/AttributeParser.phpeˆœùjeˆ +\ÌD¤)phpunit/Metadata/Parser/CachingParser.php¯ +œùj¯ + ®t¤"phpunit/Metadata/Parser/Parser.php3œùj3dÝË$¤$phpunit/Metadata/Parser/Registry.phpœùjç˜wR¤"phpunit/Metadata/PostCondition.phpIœùjIù¤sG¤!phpunit/Metadata/PreCondition.phpGœùjG†&›È¤(phpunit/Metadata/PreserveGlobalState.phpRœùjR-¶Ü˜¤0phpunit/Metadata/RequiresEnvironmentVariable.phpmœùjm¼A&Ò¤%phpunit/Metadata/RequiresFunction.php +œùj +õ |^¤#phpunit/Metadata/RequiresMethod.php%œùj%V¢´¤,phpunit/Metadata/RequiresOperatingSystem.php-œùj-¥_ã¤2phpunit/Metadata/RequiresOperatingSystemFamily.phpcœùjcµÏ§H¤ phpunit/Metadata/RequiresPhp.phpÜùjà ã~P¤)phpunit/Metadata/RequiresPhpExtension.phpžœùjžÝ7ùJ¤$phpunit/Metadata/RequiresPhpunit.phpËœùjËo_³¤-phpunit/Metadata/RequiresPhpunitExtension.phpeœùjeŒÒ-ž¤$phpunit/Metadata/RequiresSetting.phpþœùjþÇ£lú¤)phpunit/Metadata/RunInSeparateProcess.phpDœùjDÿŸi‹¤0phpunit/Metadata/RunTestsInSeparateProcesses.phpRœùjRYß­s¤phpunit/Metadata/Test.php$œùj$1Ñ¡¤phpunit/Metadata/TestDox.phpÀœùjÀW½*¤%phpunit/Metadata/TestDoxFormatter.php)œùj)v߃¤phpunit/Metadata/TestWith.phpòœùjòÀNñ¤phpunit/Metadata/UsesClass.phpÛœùjÛB3Ô¤/phpunit/Metadata/UsesClassesThatExtendClass.phpýœùjý§ZlI¤6phpunit/Metadata/UsesClassesThatImplementInterface.php'œùj'ð,¤!phpunit/Metadata/UsesFunction.phpœùjB€h‹¤phpunit/Metadata/UsesMethod.phpœùjê¤"phpunit/Metadata/UsesNamespace.phpëœùjë^öo¤phpunit/Metadata/UsesTrait.phpÛœùjÛr@AĤ2phpunit/Metadata/Version/ComparisonRequirement.php¨œùj¨2ßB¤2phpunit/Metadata/Version/ConstraintRequirement.phpžœùjž^.8¤(phpunit/Metadata/Version/Requirement.phpþœùjþ¢âI¿¤,phpunit/Metadata/WithEnvironmentVariable.php +œùj +.zu¤(phpunit/Metadata/WithoutErrorHandler.phpBœùjB%€W­¤.phpunit/Runner/BackedUpEnvironmentVariable.php«œùj«Ô#{°¤$phpunit/Runner/Baseline/Baseline.phpœùjŸ!Ù¤Aphpunit/Runner/Baseline/Exception/CannotLoadBaselineException.php~œùj~=)Sb¤Bphpunit/Runner/Baseline/Exception/CannotWriteBaselineException.phpœùj¶ 4ɤBphpunit/Runner/Baseline/Exception/FileDoesNotHaveLineException.php1œùj1ü3€¤%phpunit/Runner/Baseline/Generator.phpñœùjñ–öÖ¤!phpunit/Runner/Baseline/Issue.php) œùj) Û<ɤ"phpunit/Runner/Baseline/Reader.phpÖ œùjÖ ´ÿÀ{¤2phpunit/Runner/Baseline/RelativePathCalculator.phpÎ +œùjÎ +íËe¥¤1phpunit/Runner/Baseline/Subscriber/Subscriber.phpHœùjHÐ43¤Iphpunit/Runner/Baseline/Subscriber/TestTriggeredDeprecationSubscriber.phpûœùjûü_E¤Dphpunit/Runner/Baseline/Subscriber/TestTriggeredNoticeSubscriber.phpâœùjâjâĤLphpunit/Runner/Baseline/Subscriber/TestTriggeredPhpDeprecationSubscriber.php +œùj +Âk°±¤Gphpunit/Runner/Baseline/Subscriber/TestTriggeredPhpNoticeSubscriber.phpñœùjñÒîL¤Hphpunit/Runner/Baseline/Subscriber/TestTriggeredPhpWarningSubscriber.phpöœùjö´MФEphpunit/Runner/Baseline/Subscriber/TestTriggeredWarningSubscriber.phpçœùjçàQ̽¤"phpunit/Runner/Baseline/Writer.phpj œùjj öý†q¤phpunit/Runner/CodeCoverage.php·?œùj·?ßr_Τ3phpunit/Runner/CodeCoverageInitializationStatus.phpTœùjT‰52q¤1phpunit/Runner/DeprecationCollector/Collector.phpZœùjZì–c¤.phpunit/Runner/DeprecationCollector/Facade.phpôœùjô&¨ I¤<phpunit/Runner/DeprecationCollector/InIsolationCollector.php"œùj"óß}Ȥ=phpunit/Runner/DeprecationCollector/Subscriber/Subscriber.php&œùj&˜¬\¤Iphpunit/Runner/DeprecationCollector/Subscriber/TestPreparedSubscriber.php/œùj/Kd€I¤Uphpunit/Runner/DeprecationCollector/Subscriber/TestTriggeredDeprecationSubscriber.php}œùj}Yò¤phpunit/Runner/ErrorHandler.php[@œùj[@2ô&a¤8phpunit/Runner/Exception/ClassCannotBeFoundException.php%œùj%uëX¤@phpunit/Runner/Exception/ClassDoesNotExtendTestCaseException.phpQœùjQκYÀ¤5phpunit/Runner/Exception/ClassIsAbstractException.php'œùj'ƒìT¤<phpunit/Runner/Exception/CodeCoverageFileExistsException.phpkœùjk ƒÙŸ¤;phpunit/Runner/Exception/DirectoryDoesNotExistException.php+œùj+EH¾-¤+phpunit/Runner/Exception/ErrorException.phpDœùjDi}Ť&phpunit/Runner/Exception/Exception.phpœùjúYŠK¤6phpunit/Runner/Exception/FileDoesNotExistException.phpþœùjþdfH!¤2phpunit/Runner/Exception/InvalidOrderException.phpaœùja[Èt%¤;phpunit/Runner/Exception/ParameterDoesNotExistException.phpœùjZ­Ÿh¤&phpunit/Runner/Extension/Extension.php…œùj…sƲ¤2phpunit/Runner/Extension/ExtensionBootstrapper.phpá œùjá .îÑL¤,phpunit/Runner/Extension/ExtensionFacade.php" +œùj" +ŸXç¤#phpunit/Runner/Extension/Facade.phpðœùjð1N¤0phpunit/Runner/Extension/ParameterCollection.phpLœùjLpýñ(¤'phpunit/Runner/Extension/PharLoader.phpœùj¢Ã†s¤4phpunit/Runner/Filter/ExcludeGroupFilterIterator.phpQœùjQúFßݤ3phpunit/Runner/Filter/ExcludeNameFilterIterator.php£œùj£BêÕ¤!phpunit/Runner/Filter/Factory.phpõ œùjõ Ä1 ¤-phpunit/Runner/Filter/GroupFilterIterator.phpœùjphpunit/Runner/ResultCache/Subscriber/TestFailedSubscriber.phpœùjÜú…†¤@phpunit/Runner/ResultCache/Subscriber/TestFinishedSubscriber.phpÉœùjÉíÎg¤Hphpunit/Runner/ResultCache/Subscriber/TestMarkedIncompleteSubscriber.phpZœùjZŸÞ¦v¤@phpunit/Runner/ResultCache/Subscriber/TestPreparedSubscriber.php*œùj*yѤ?phpunit/Runner/ResultCache/Subscriber/TestSkippedSubscriber.phpÜùjÃà.“ͤEphpunit/Runner/ResultCache/Subscriber/TestSuiteFinishedSubscriber.php8œùj8Ê×/ý¤Dphpunit/Runner/ResultCache/Subscriber/TestSuiteStartedSubscriber.php2œùj2ª/ªÂ¤"phpunit/Runner/ShutdownHandler.phpxœùjxLäªT¤'phpunit/Runner/TestResult/Collector.phpwMœùjwMXŠÜa¤$phpunit/Runner/TestResult/Facade.php¼ œùj¼ U„ûM¤#phpunit/Runner/TestResult/Issue.phpà œùjà „9×=¤)phpunit/Runner/TestResult/PassedTests.phpÏ œùjÏ Ì 8¤Nphpunit/Runner/TestResult/Subscriber/AfterTestClassMethodErroredSubscriber.php˜œùj˜8)xº¤Mphpunit/Runner/TestResult/Subscriber/AfterTestClassMethodFailedSubscriber.php’œùj’-ÀQR¤Ophpunit/Runner/TestResult/Subscriber/BeforeTestClassMethodErroredSubscriber.php¢œùj¢U½E2¤Nphpunit/Runner/TestResult/Subscriber/BeforeTestClassMethodFailedSubscriber.phpœœùjœ[Æ=„¤Fphpunit/Runner/TestResult/Subscriber/ChildProcessErroredSubscriber.phpVœùjV-4g­¤Cphpunit/Runner/TestResult/Subscriber/ExecutionStartedSubscriber.php˜œùj˜XUÕ¤3phpunit/Runner/TestResult/Subscriber/Subscriber.php`œùj`T¹1{¤Fphpunit/Runner/TestResult/Subscriber/TestConsideredRiskySubscriber.php\œùj\-ï½4¤>phpunit/Runner/TestResult/Subscriber/TestErroredSubscriber.php,œùj,ÿ;¦Ô¤=phpunit/Runner/TestResult/Subscriber/TestFailedSubscriber.php&œùj&×0ˤ?phpunit/Runner/TestResult/Subscriber/TestFinishedSubscriber.php2œùj2޻݃¤Gphpunit/Runner/TestResult/Subscriber/TestMarkedIncompleteSubscriber.phpbœùjbC•¬¿¤?phpunit/Runner/TestResult/Subscriber/TestPreparedSubscriber.php,œùj,<Ú¸G¤Qphpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredDeprecationSubscriber.php’œùj’šÅÍ<¤Lphpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredNoticeSubscriber.phptœùjt‚½U"¤Mphpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredWarningSubscriber.phpzœùjzÚ+d¤>phpunit/Runner/TestResult/Subscriber/TestSkippedSubscriber.php,œùj,Û$ñ¤Dphpunit/Runner/TestResult/Subscriber/TestSuiteFinishedSubscriber.phpFœùjF2Šá¼¤Cphpunit/Runner/TestResult/Subscriber/TestSuiteSkippedSubscriber.php@œùj@OU&¤Cphpunit/Runner/TestResult/Subscriber/TestSuiteStartedSubscriber.php@œùj@ƒˆi¤Kphpunit/Runner/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.phpzœùjz°|?¤Ephpunit/Runner/TestResult/Subscriber/TestTriggeredErrorSubscriber.phpVœùjV¶‘Fphpunit/Runner/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php\œùj\¡AU‹¤Nphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.phpŒœùjŒB.XÞ¤Iphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.phpnœùjnE…@¤Jphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.phptœùjt’ÈS̤Rphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php¤œùj¤ù‘à/¤Lphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php€œùj€Ò)i2¤Mphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php†œùj† lÆä¤Nphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.phpŒœùjŒ,,ˆŒ¤Gphpunit/Runner/TestResult/Subscriber/TestTriggeredWarningSubscriber.phpbœùjbÍ8Ux¤(phpunit/Runner/TestResult/TestResult.phpÇJœùjÇJ-ÄY/¤"phpunit/Runner/TestSuiteLoader.php»œùj»eo­¤"phpunit/Runner/TestSuiteSorter.phpØ"œùjØ"Z`xb¤phpunit/Runner/Version.php0œùj0x×°ñ¤phpunit/TextUI/Application.phpPkœùjPkÒÙõ¤"phpunit/TextUI/Command/Command.phpHœùjH"Fò ¤9phpunit/TextUI/Command/Commands/AtLeastVersionCommand.php5œùj5zд¤@phpunit/TextUI/Command/Commands/CheckPhpConfigurationCommand.phpÑœùjѲn2ö¤@phpunit/TextUI/Command/Commands/GenerateConfigurationCommand.php# œùj# ã2® ¤5phpunit/TextUI/Command/Commands/ListGroupsCommand.php3œùj3^ؤ8phpunit/TextUI/Command/Commands/ListTestFilesCommand.phpלùj×eêj%¤9phpunit/TextUI/Command/Commands/ListTestSuitesCommand.php¦ +œùj¦ +*¶h¸¤:phpunit/TextUI/Command/Commands/ListTestsAsTextCommand.php$œùj$ŒeÏš¤9phpunit/TextUI/Command/Commands/ListTestsAsXmlCommand.phpgœùjg à+¤?phpunit/TextUI/Command/Commands/MigrateConfigurationCommand.phpœùj¦—£#¤3phpunit/TextUI/Command/Commands/ShowHelpCommand.phpšœùjšÿ§x¤6phpunit/TextUI/Command/Commands/ShowVersionCommand.phpÇœùjÇ!n˜¤7phpunit/TextUI/Command/Commands/VersionCheckCommand.php] œùj] `}¤@phpunit/TextUI/Command/Commands/WarmCodeCoverageCacheCommand.phpÅ œùjÅ Ái¤!phpunit/TextUI/Command/Result.phpÍœùjÍP,0Ф0phpunit/TextUI/Configuration/BootstrapLoader.phpr œùjr b,š£¤(phpunit/TextUI/Configuration/Builder.phpäœùjäß• 5¤,phpunit/TextUI/Configuration/Cli/Builder.php|‰œùj|‰àU/¤2phpunit/TextUI/Configuration/Cli/Configuration.php’ œùj’ Gý c¤.phpunit/TextUI/Configuration/Cli/Exception.php[œùj[¨æÎ'¤?phpunit/TextUI/Configuration/Cli/XmlConfigurationFileFinder.phpÌœùjÌDý±ü¤;phpunit/TextUI/Configuration/CodeCoverageFilterRegistry.phpÍœùjͯñr¤.phpunit/TextUI/Configuration/Configuration.phpÉœùjÉ?Y¼¤Ophpunit/TextUI/Configuration/Exception/BootstrapScriptDoesNotExistException.php6œùj6Ö4Y¤Cphpunit/TextUI/Configuration/Exception/BootstrapScriptException.php€œùj€{™’Ö¤Dphpunit/TextUI/Configuration/Exception/CannotFindSchemaException.php’œùj’¸«¢O¤Sphpunit/TextUI/Configuration/Exception/CodeCoverageReportNotConfiguredException.phpœùj©ÙVF¤Nphpunit/TextUI/Configuration/Exception/ConfigurationCannotBeBuiltException.php‹œùj‹6¯Õ¤4phpunit/TextUI/Configuration/Exception/Exception.php3œùj3¿l´p¤Gphpunit/TextUI/Configuration/Exception/FilterNotConfiguredException.php„œùj„´]Ü9¤Hphpunit/TextUI/Configuration/Exception/LoggingNotConfiguredException.php…œùj…N†¤>phpunit/TextUI/Configuration/Exception/NoBaselineException.php{œùj{%Iû¤?phpunit/TextUI/Configuration/Exception/NoBootstrapException.php|œùj|eIÂæ¤Dphpunit/TextUI/Configuration/Exception/NoCacheDirectoryException.phpœùjÍAФGphpunit/TextUI/Configuration/Exception/NoConfigurationFileException.php„œùj„¡Þ@À¤Lphpunit/TextUI/Configuration/Exception/NoCoverageCacheDirectoryException.php‰œùj‰æGt½¤Cphpunit/TextUI/Configuration/Exception/NoCustomCssFileException.php€œùj€¾ÝòΤFphpunit/TextUI/Configuration/Exception/NoDefaultTestSuiteException.phpƒœùjƒàÐÿ¤Hphpunit/TextUI/Configuration/Exception/NoHtmlCoverageTargetException.php…œùj…”.©ï¤Lphpunit/TextUI/Configuration/Exception/NoPharExtensionDirectoryException.php‰œùj‰™jà ¤Cphpunit/TextUI/Configuration/Exception/NoTestFilesFileException.php€œùj€ˆõ-õ¤\phpunit/TextUI/Configuration/Exception/SpecificDeprecationToStopOnNotConfiguredException.php™œùj™ì+̇¤'phpunit/TextUI/Configuration/Merger.php¡·œùj¡·°tÓA¤+phpunit/TextUI/Configuration/PhpHandler.php0œùj0~ö¡¤)phpunit/TextUI/Configuration/Registry.phpÔœùjÔWæö¤-phpunit/TextUI/Configuration/SourceFilter.phpëœùjëÜ‚q¶¤-phpunit/TextUI/Configuration/SourceMapper.phpmœùjmž¹d¤1phpunit/TextUI/Configuration/TestSuiteBuilder.phpœùjÍìwx¤/phpunit/TextUI/Configuration/Value/Constant.php-œùj-9ⵤ9phpunit/TextUI/Configuration/Value/ConstantCollection.phpŽœùjŽš8ṳ̂Aphpunit/TextUI/Configuration/Value/ConstantCollectionIterator.phpYœùjYÜžBϤ0phpunit/TextUI/Configuration/Value/Directory.php‰œùj‰nÏØ%¤:phpunit/TextUI/Configuration/Value/DirectoryCollection.phpýœùjýÛv|¤Bphpunit/TextUI/Configuration/Value/DirectoryCollectionIterator.phpjœùjjž'6¤9phpunit/TextUI/Configuration/Value/ExtensionBootstrap.phpœùjž„¤Cphpunit/TextUI/Configuration/Value/ExtensionBootstrapCollection.php«œùj«ŒžI¤Kphpunit/TextUI/Configuration/Value/ExtensionBootstrapCollectionIterator.phpÇœùjÇDÒ9Ƥ+phpunit/TextUI/Configuration/Value/File.phpœùj EÁð¤5phpunit/TextUI/Configuration/Value/FileCollection.phpŸœùjŸ%- ä=phpunit/TextUI/Configuration/Value/FileCollectionIterator.php-œùj-(À¤6phpunit/TextUI/Configuration/Value/FilterDirectory.phpQœùjQ!ý#ê¤@phpunit/TextUI/Configuration/Value/FilterDirectoryCollection.php3œùj3ÍJ ±¤Hphpunit/TextUI/Configuration/Value/FilterDirectoryCollectionIterator.phpˆœùjˆÐÙa¿¤1phpunit/TextUI/Configuration/Value/FilterFile.phpœùjãL½¤;phpunit/TextUI/Configuration/Value/FilterFileCollection.phpÏœùjÏnׄ5¤Cphpunit/TextUI/Configuration/Value/FilterFileCollectionIterator.phpKœùjK‹‰ƒß¤,phpunit/TextUI/Configuration/Value/Group.php…œùj…šVÛ_¤6phpunit/TextUI/Configuration/Value/GroupCollection.php"œùj"5ÓnÛ¤>phpunit/TextUI/Configuration/Value/GroupCollectionIterator.php8œùj8<’ °¤1phpunit/TextUI/Configuration/Value/IniSetting.php œùj ­E¨Õ¤;phpunit/TextUI/Configuration/Value/IniSettingCollection.php°œùj°ˆÝn¤Cphpunit/TextUI/Configuration/Value/IniSettingCollectionIterator.phpoœùjo_»`n¤*phpunit/TextUI/Configuration/Value/Php.phpîœùjîö¦«¤-phpunit/TextUI/Configuration/Value/Source.phpÄœùjijÑr¤4phpunit/TextUI/Configuration/Value/TestDirectory.php‰œùj‰©TϤ>phpunit/TextUI/Configuration/Value/TestDirectoryCollection.phpœùj:Àë…¤Fphpunit/TextUI/Configuration/Value/TestDirectoryCollectionIterator.php~œùj~ŸÐ…¤/phpunit/TextUI/Configuration/Value/TestFile.phpLœùjLø—ìú¤9phpunit/TextUI/Configuration/Value/TestFileCollection.php¿œùj¿Æo¤Aphpunit/TextUI/Configuration/Value/TestFileCollectionIterator.phpAœùjAPÙ6¤0phpunit/TextUI/Configuration/Value/TestSuite.phpŠœùjŠùÇ»¤:phpunit/TextUI/Configuration/Value/TestSuiteCollection.phpôœùjô‘d΋¤Bphpunit/TextUI/Configuration/Value/TestSuiteCollectionIterator.phpdœùjd͸“¤/phpunit/TextUI/Configuration/Value/Variable.php«œùj«'z§3¤9phpunit/TextUI/Configuration/Value/VariableCollection.phpŽœùjŽP]y¤Aphpunit/TextUI/Configuration/Value/VariableCollectionIterator.phpYœùjY1cQH¤>phpunit/TextUI/Configuration/Xml/CodeCoverage/CodeCoverage.php€œùj€ &¤?phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Clover.php&œùj&á+­¤Bphpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Cobertura.php)œùj)±‹ZŤ?phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Crap4j.phpËœùjËâÌñ¤=phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Html.phpœùjá±Û”¤Cphpunit/TextUI/Configuration/Xml/CodeCoverage/Report/OpenClover.php*œùj*Õ ´/¤<phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Php.php#œùj#Hô3¤=phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Text.phpΜùjÎVÉ^ƒ¤<phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Xml.php÷œùj÷xf„¤2phpunit/TextUI/Configuration/Xml/Configuration.php2 œùj2 ’”¤9phpunit/TextUI/Configuration/Xml/DefaultConfiguration.php[ œùj[ X`ì¤.phpunit/TextUI/Configuration/Xml/Exception.php_œùj_+øg3¤.phpunit/TextUI/Configuration/Xml/Generator.phpÏœùjÏb․+phpunit/TextUI/Configuration/Xml/Groups.php½œùj½mu’¤@phpunit/TextUI/Configuration/Xml/LoadedFromFileConfiguration.phpƒœùjƒaAÇr¤+phpunit/TextUI/Configuration/Xml/Loader.php臭ùjï©€Ó¤2phpunit/TextUI/Configuration/Xml/Logging/Junit.phpœùjOÙ¤4phpunit/TextUI/Configuration/Xml/Logging/Logging.php œùj Y8Œ•¤0phpunit/TextUI/Configuration/Xml/Logging/Otr.phpœùj±4.€¤5phpunit/TextUI/Configuration/Xml/Logging/TeamCity.phpœùj&Sk¤9phpunit/TextUI/Configuration/Xml/Logging/TestDox/Html.php œùj *IòŒ¤9phpunit/TextUI/Configuration/Xml/Logging/TestDox/Text.php œùj ¬l¦¤?phpunit/TextUI/Configuration/Xml/Migration/MigrationBuilder.phpƒœùjƒÌ/ü¤Aphpunit/TextUI/Configuration/Xml/Migration/MigrationException.phpvœùjvÛ[–r¤Iphpunit/TextUI/Configuration/Xml/Migration/Migrations/ConvertLogTypes.phpœùj< ëÙ¤Pphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageCloverToReport.phpËœùj˳b5z¤Pphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageCrap4jToReport.phpœùjˆæ“¤Nphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageHtmlToReport.phpœùjl;^©¤Mphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoveragePhpToReport.php¹œùj¹™c'ǤNphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageTextToReport.phpœùjí*LФMphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageXmlToReport.php¾œùj¾gºŠú¤Zphpunit/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCacheDirectoryAttribute.phpМùjÐi¬"¤Rphpunit/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCoverageElement.phpUœùjU Fc¤Nphpunit/TextUI/Configuration/Xml/Migration/Migrations/LogToReportMigration.php¬ œùj¬ CÜkí¤Cphpunit/TextUI/Configuration/Xml/Migration/Migrations/Migration.php_œùj_*ÉŸ,¤ephpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php(œùj(‘,«¤Zphpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromRootToCoverage.phpùœùjù["ý¤Yphpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveCoverageDirectoriesToSource.phpœùj*Vº¹¤Yphpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistExcludesToCoverage.php6 œùj6 !„À¤Yphpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistIncludesToCoverage.phpiœùji)ì⣤sphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute.phpœùj«ëܤhphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutTodoAnnotatedTestsAttribute.phpáœùjáP’ƒÅ¤Xphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheResultFileAttribute.php±œùj± 1§¤Tphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheTokensAttribute.php¥œùj¥1ªú¤`phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveConversionToExceptionsAttributes.php€œùj€¨:o¤fphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementCacheDirectoryAttribute.phpýœùjý¤ï¯ª¤mphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementProcessUncoveredFilesAttribute.phpœùj ì€>¤Kphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveEmptyFilter.phpîœùjîåRµƒ¤Iphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveListeners.php›œùj›Í'6ï¤Hphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveLogTypes.phpÝœùj݇tRO¤Ophpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveLoggingElements.php(œùj('—¤Vphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveNoInteractionAttribute.php«œùj«n'°.¤Qphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemovePrinterAttributes.phpœùj]ï2/¤xphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute.phpœùj¿ÕW¤Tphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestDoxGroupsElement.phpªœùjªô×´š¤Yphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestSuiteLoaderAttributes.php;œùj;)ó†¤Pphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveVerboseAttribute.php™œùj™Õª”±¤_phpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameBackupStaticAttributesAttribute.php˜œùj˜Ž"Zù¤fphpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameBeStrictAboutCoversAnnotationAttribute.phpœùjÂuÀˤ^phpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameForceCoversAnnotationAttribute.php–œùj–ƒ–¢U¤kphpunit/TextUI/Configuration/Xml/Migration/Migrations/ReplaceRestrictDeprecationsWithIgnoreDeprecations.php‰œùj‰t¯³7¤Nphpunit/TextUI/Configuration/Xml/Migration/Migrations/UpdateSchemaLocation.phpÙœùjÙ.P¦Ó¤7phpunit/TextUI/Configuration/Xml/Migration/Migrator.phpá œùjá Å[œùj>ý+ ¤,phpunit/TextUI/Configuration/Xml/PHPUnit.php™Cœùj™Crâq°¤Ophpunit/TextUI/Configuration/Xml/SchemaDetector/FailedSchemaDetectionResult.php}œùj}|¥€¤Iphpunit/TextUI/Configuration/Xml/SchemaDetector/SchemaDetectionResult.phpœùj(ù¯¤Bphpunit/TextUI/Configuration/Xml/SchemaDetector/SchemaDetector.phpoœùjoÐc€ª¤Sphpunit/TextUI/Configuration/Xml/SchemaDetector/SuccessfulSchemaDetectionResult.phpFœùjFkÚÎw¤1phpunit/TextUI/Configuration/Xml/SchemaFinder.phpyœùjy)}š3¤4phpunit/TextUI/Configuration/Xml/TestSuiteMapper.php<œùj<`gý£¤?phpunit/TextUI/Configuration/Xml/Validator/ValidationResult.phpoœùjof²1¤8phpunit/TextUI/Configuration/Xml/Validator/Validator.phpùœùjùI‹ö`¤6phpunit/TextUI/Exception/CannotOpenSocketException.phpœùjzçá¤&phpunit/TextUI/Exception/Exception.php$œùj$昤3phpunit/TextUI/Exception/InvalidSocketException.phpœùjÊI +¤-phpunit/TextUI/Exception/RuntimeException.phpGœùjG¾n V¤;phpunit/TextUI/Exception/TestDirectoryNotFoundException.phpœùjH˲P¤6phpunit/TextUI/Exception/TestFileNotFoundException.phpþœùjþ=ƒ|¤phpunit/TextUI/Help.phpšEœùjšE þ ¤Aphpunit/TextUI/Output/Default/ProgressPrinter/ProgressPrinter.php<4œùj<4áÏ:Ö¤cphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/BeforeTestClassMethodErroredSubscriber.phpºœùjºPÏDפZphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/ChildProcessErroredSubscriber.phptœùjt¸ O=¤Gphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/Subscriber.php¦œùj¦%¢¹ß¤Zphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestConsideredRiskySubscriber.phptœùjtÜb¤Rphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestErroredSubscriber.phpJœùjJxmÇ¢¤Qphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFailedSubscriber.php>œùj>Y'¹‡¤Sphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFinishedSubscriber.phpJœùjJzJ–é¤[phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestMarkedIncompleteSubscriber.phpzœùjzÂjø\¤Sphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestPreparedSubscriber.phpJœùjJùû¤aphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestRunnerExecutionStartedSubscriber.php˜œùj˜ê¥j ¤Rphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.phpDœùjD…訚¤Wphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestSuiteSkippedSubscriber.phptœùjt‘¨—e¤_phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredDeprecationSubscriber.php˜œùj˜d¿Vé¤Yphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredErrorSubscriber.phptœùjty´‘ѤZphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredNoticeSubscriber.phpzœùjz­[¾Ó¤bphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpDeprecationSubscriber.phpªœùjªA ”¤]phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpNoticeSubscriber.phpŒœùjŒ¸•‚è¤^phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpWarningSubscriber.php’œùj’¦Ú+¤fphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php¼œùj¼?ï>f¤aphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitNoticeSubscriber.phpžœùjžØMä¤bphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitWarningSubscriber.phpªœùjªëuý¤[phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredWarningSubscriber.php€œùj€ë Ý´¤/phpunit/TextUI/Output/Default/ResultPrinter.phpÄSœùjÄSçmOÛ¤9phpunit/TextUI/Output/Default/UnexpectedOutputPrinter.phpØœùjØqp‘ ¤ phpunit/TextUI/Output/Facade.php{#œùj{#2XO¤0phpunit/TextUI/Output/Printer/DefaultPrinter.phpˆ œùjˆ ¯"$¤-phpunit/TextUI/Output/Printer/NullPrinter.php§œùj§&W„þ¤)phpunit/TextUI/Output/Printer/Printer.php\œùj\gD“ߤ(phpunit/TextUI/Output/SummaryPrinter.phpÍœùjÍ”‰e¿¤/phpunit/TextUI/Output/TestDox/ResultPrinter.phpù1œùjù1Y¨¦Ç¤*phpunit/TextUI/ShellExitCodeCalculator.phpFœùjFöë©å¤phpunit/TextUI/TestRunner.phpלùj×m/$ؤ+phpunit/TextUI/TestSuiteFilterProcessor.phpF +œùjF +œî5¶¤phpunit/Util/Color.phpœùj‘ÜФ$phpunit/Util/Exception/Exception.php"œùj"ð‘Ò¤4phpunit/Util/Exception/InvalidDirectoryException.phpœùj ¦ç3¤/phpunit/Util/Exception/InvalidJsonException.php\œùj\÷nt¤:phpunit/Util/Exception/InvalidVersionOperatorException.phpœùjp2ïÙ¤.phpunit/Util/Exception/PhpProcessException.phpmœùjmZž|¤'phpunit/Util/Exception/XmlException.phpfœùjfÎ;´Q¤phpunit/Util/ExcludeList.php‘œùj‘{"Þ¤phpunit/Util/Exporter.phpœùj¶a®z¤phpunit/Util/Filesystem.phpRœùjRñ]â_¤phpunit/Util/Filter.php¦œùj¦óu¤phpunit/Util/GlobalState.php•(œùj•(åCL¤"phpunit/Util/GlobalStateResult.phpÒœùjÒˆyøN¤ phpunit/Util/Http/Downloader.phptœùjt.Ø=ä#phpunit/Util/Http/PhpDownloader.php œùj KÃ>Ƥphpunit/Util/Json.php œùj â¢o¤phpunit/Util/PHP/Job.php œùj QPðޤphpunit/Util/PHP/JobRunner.phpø*œùjø*ôä%¤&phpunit/Util/PHP/JobRunnerRegistry.phpÊœùjÊ ü鯤phpunit/Util/PHP/Result.php~œùj~šsœB¤phpunit/Util/Reflection.phpu œùju .ˤphpunit/Util/Sanitizer.phpÙœùjÙ&‘;Õ¤phpunit/Util/Test.phpˆœùjˆšnàÛ¤(phpunit/Util/ThrowableToStringMapper.php´œùj´Øø½Í¤*phpunit/Util/VersionComparisonOperator.phpœùjÞ⫤phpunit/Util/Xml/Loader.phpÇ œùjÇ »?Y=¤phpunit/Util/Xml/Xml.php…œùj…¾dü¤sbom.xmlk$œùjk$~w€q¤schema/10.0.xsd=œùj=|H¤schema/10.1.xsd«Bœùj«BÜ­r—¤schema/10.2.xsdQEœùjQE¸çÿn¤schema/10.3.xsdFœùjF›¶3&¤schema/10.4.xsdGFœùjGF?”ñÁ¤schema/10.5.xsdÛGœùjÛGÔaÈI¤schema/11.0.xsdTFœùjTF÷É?z¤schema/11.1.xsd®Hœùj®H!Êgè¤schema/11.2.xsd Hœùj HëÍæ¤schema/11.3.xsdyIœùjyI“ô¹¤schema/11.4.xsd#Iœùj#Iî0$”¤schema/11.5.xsdKœùjKsÄH±¤schema/12.0.xsdzIœùjzIfªGj¤schema/12.1.xsdÛJœùjÛJŠºb¤schema/12.2.xsdÒLœùjÒLs$˜¢¤schema/12.3.xsdMœùjMÊ—>º¤schema/12.4.xsdMœùjMÛ¢ýð¤schema/12.5.xsdXNœùjXNç#õ¤schema/13.0.xsd²Nœùj²NßÑ­R¤schema/8.5.xsdÓBœùjÓB2A[­¤schema/9.0.xsd4Bœùj4B•¨7w¤schema/9.1.xsdÕBœùjÕBßq'8¤schema/9.2.xsdÜBœùjÜBc·Á-¤schema/9.3.xsd¼Eœùj¼E¿ùq¤schema/9.4.xsd +Fœùj +FDOFI¤schema/9.5.xsdDFœùjDFûùs|¤schema/9.6.xsdRFœùjRFAêg¤sebastian-cli-parser/LICENSEûœùjû¬D¤sebastian-cli-parser/Parser.phpÇœùjÇÌ’f’¤<sebastian-cli-parser/exceptions/AmbiguousOptionException.phpÝœùjÝ+Mó…¤-sebastian-cli-parser/exceptions/Exception.phpyœùjy>€±¤Gsebastian-cli-parser/exceptions/OptionDoesNotAllowArgumentException.phpcœùjcŠRjY¤Jsebastian-cli-parser/exceptions/RequiredOptionArgumentMissingException.phplœùjlzQ¢¤:sebastian-cli-parser/exceptions/UnknownOptionException.phpvœùjvëÛÿä¤(sebastian-comparator/ArrayComparator.phpäœùjä5ò;„¤*sebastian-comparator/ClosureComparator.phpî œùjî ¨§\I¤#sebastian-comparator/Comparator.php®œùj®žª«¤*sebastian-comparator/ComparisonFailure.phpÉ œùjÉ Üq)<¤*sebastian-comparator/DOMNodeComparator.phpé œùjé ë—P¤/sebastian-comparator/DateIntervalComparator.phpÉ œùjÉ <3¤+sebastian-comparator/DateTimeComparator.php… œùj… y=á¤.sebastian-comparator/EnumerationComparator.php¾œùj¾ëY\|¤,sebastian-comparator/ExceptionComparator.phppœùjp0CW¤ sebastian-comparator/Factory.php‡œùj‡²M5w¤sebastian-comparator/LICENSEûœùjû9fo¤-sebastian-comparator/MockObjectComparator.phpÿœùjÿ©~¤)sebastian-comparator/NumberComparator.phpœùjWÚî¤*sebastian-comparator/NumericComparator.phpùœùjùÓæ¤)sebastian-comparator/ObjectComparator.php› œùj› Ù(9¤+sebastian-comparator/ResourceComparator.php„œùj„8OÃT¤)sebastian-comparator/ScalarComparator.phpÙœùjÙBqK¤3sebastian-comparator/SplObjectStorageComparator.php=œùj=nîþ¢¤'sebastian-comparator/TypeComparator.php”œùj”@k<„¤-sebastian-comparator/exceptions/Exception.phpøœùjø)d¹J¤4sebastian-comparator/exceptions/RuntimeException.phpœùj¨âµï¤#sebastian-complexity/Calculator.php +œùj +ä}V¤.sebastian-complexity/Complexity/Complexity.php œùj w¸Š¤8sebastian-complexity/Complexity/ComplexityCollection.php8 +œùj8 +íµÔD¤@sebastian-complexity/Complexity/ComplexityCollectionIterator.phpRœùjR+ÂVù¤,sebastian-complexity/Exception/Exception.phpzœùjzȬˤ3sebastian-complexity/Exception/RuntimeException.php‘œùj‘¼Ìé¤sebastian-complexity/LICENSEûœùjû¬D¤=sebastian-complexity/Visitor/ComplexityCalculatingVisitor.php< œùj< [»aï¤Gsebastian-complexity/Visitor/CyclomaticComplexityCalculatingVisitor.phphœùjh¨µŸ®¤sebastian-diff/Chunk.php„œùj„³Á $¤sebastian-diff/Diff.phpHœùjHƒ¯€æ¤sebastian-diff/Differ.php~œùj~oýB¤3sebastian-diff/Exception/ConfigurationException.phpQœùjQ ®¶T¤&sebastian-diff/Exception/Exception.phpnœùjnšÀ/\¤sebastian-diff/LICENSEûœùjû9fo¤sebastian-diff/Line.php<œùj<ïa ¤5sebastian-diff/LongestCommonSubsequenceCalculator.php>œùj>eñG ¤Dsebastian-diff/MemoryEfficientLongestCommonSubsequenceCalculator.php4 œùj4 *H%¤4sebastian-diff/Output/AbstractChunkOutputBuilder.php(œùj(—ž¤/sebastian-diff/Output/DiffOnlyOutputBuilder.phpÕœùjÕ|í +¤4sebastian-diff/Output/DiffOutputBuilderInterface.phpœùjpmö¤8sebastian-diff/Output/StrictUnifiedDiffOutputBuilder.php&1œùj&1>9 R¤2sebastian-diff/Output/UnifiedDiffOutputBuilder.php¼!œùj¼!^²H ¤sebastian-diff/Parser.phpÆ œùjÆ | ·™¤Bsebastian-diff/TimeEfficientLongestCommonSubsequenceCalculator.php1 œùj1 ƒ“5 ¤!sebastian-environment/Console.php‰œùj‰Èx³o¤sebastian-environment/Host.phpšœùjšX2l˜¤sebastian-environment/LICENSEûœùjû§ú»÷¤!sebastian-environment/Runtime.php±-œùj±-éÏ9¢¤sebastian-exporter/Exporter.php’=œùj’=µ×0¤sebastian-exporter/LICENSEûœùjû9fo¤sebastian-git-state/Builder.php œùj W8vפ(sebastian-git-state/GitCommandRunner.php÷œùj÷wÓ¨¤sebastian-git-state/LICENSEöœùjöö^⧤*sebastian-git-state/ShellCommandRunner.php´œùj´#~Ãɤ8sebastian-git-state/ShellCommandRunnerImplementation.php œùj ȶn¤sebastian-git-state/State.php¹œùj¹Ä»K§¤'sebastian-global-state/CodeExporter.php™ œùj™ l¤¤&sebastian-global-state/ExcludeList.php œùj Vÿeu¤sebastian-global-state/LICENSEûœùjûe´È3¤#sebastian-global-state/Restorer.phphœùjhÏ^o(¤#sebastian-global-state/Snapshot.phpS-œùjS-»¯âȤ/sebastian-global-state/exceptions/Exception.php}œùj}¶µâ´¤6sebastian-global-state/exceptions/RuntimeException.php”œùj”#Ú™¤#sebastian-lines-of-code/Counter.phpäœùjäõd²®¤/sebastian-lines-of-code/Exception/Exception.php~œùj~%>²ú¤>sebastian-lines-of-code/Exception/IllogicalValuesException.php®œùj®Êårÿ¤6sebastian-lines-of-code/Exception/RuntimeException.php•œùj•Ñ)Ϲ¤sebastian-lines-of-code/LICENSEûœùjû¬D¤/sebastian-lines-of-code/LineCountingVisitor.php5 œùj5 "kÞ¤'sebastian-lines-of-code/LinesOfCode.php| œùj| LSèý¤*sebastian-object-enumerator/Enumerator.phpOœùjO'ßìX¤.sebastian-object-reflector/ObjectReflector.phpûœùjûŸŸMl¤'sebastian-recursion-context/Context.phpXœùjX·:uë¤#sebastian-recursion-context/LICENSEûœùjû9fo¤sebastian-type/LICENSEûœùjû¢ºj¤sebastian-type/Parameter.php¦œùj¦ÓòR7¤#sebastian-type/ReflectionMapper.php©œùj©G™Ü¤sebastian-type/TypeName.php= œùj= `Y/m¤&sebastian-type/exception/Exception.phpäœùjä}¥«¤-sebastian-type/exception/RuntimeException.phpûœùjûÃu†¤$sebastian-type/type/CallableType.php´œùj´wRt\¤!sebastian-type/type/FalseType.phpœùj³X ]¤)sebastian-type/type/GenericObjectType.phpyœùjy‰#¸„¤(sebastian-type/type/IntersectionType.phpJ œùjJ VÜD¤$sebastian-type/type/IterableType.phpIœùjIZ«ŸÀ¤!sebastian-type/type/MixedType.php­œùj­ jÿ¦¤!sebastian-type/type/NeverType.php7œùj7}‘š¤ sebastian-type/type/NullType.php§œùj§#² n¤"sebastian-type/type/ObjectType.phpiœùjica¤"sebastian-type/type/SimpleType.phpPœùjPgË·»¤"sebastian-type/type/StaticType.php"œùj"Oaг¤ sebastian-type/type/TrueType.php½œùj½,šiú¤sebastian-type/type/Type.phpÍœùjÍøe¤!sebastian-type/type/UnionType.php& œùj& _€â[¤#sebastian-type/type/UnknownType.phpŸœùjŸyWk=¤ sebastian-type/type/VoidType.php3œùj3õó¤sebastian-version/LICENSEûœùjû+ƒz¤sebastian-version/Version.php +œùj +ÎZ¦¤$staabm-side-effects-detector/LICENSE-œùj-ßâj-¤+staabm-side-effects-detector/SideEffect.phpFœùjFpפ4staabm-side-effects-detector/SideEffectsDetector.phpÒ$œùjÒ$ÅÌÅ©¤1staabm-side-effects-detector/functionMetadata.phpŸsœùjŸsÔä!s¤theseer-tokenizer/Exception.phprœùjrÊÂmœ¤theseer-tokenizer/LICENSEüœùjüïR (¤"theseer-tokenizer/NamespaceUri.phpsœùjs¯c岤+theseer-tokenizer/NamespaceUriException.php}œùj}aÕ“¤theseer-tokenizer/Token.php—œùj—K•`¤%theseer-tokenizer/TokenCollection.phptœùjtê»Ñ¤.theseer-tokenizer/TokenCollectionException.php€œùj€5ɤtheseer-tokenizer/Tokenizer.php‚ œùj‚ b䕤#theseer-tokenizer/XMLSerializer.phpZ œùjZ ”N5ô¤{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "578bcff86e8d339d23358037997560dd", + "packages": [ + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.7.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" + }, + "time": "2025-12-06T11:56:16+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "14.1.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "655533a65696bbc4231cd8027af150dadc40ec88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/655533a65696bbc4231cd8027af150dadc40ec88", + "reference": "655533a65696bbc4231cd8027af150dadc40ec88", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.7.0", + "php": ">=8.4", + "phpunit/php-text-template": "^6.0", + "sebastian/complexity": "^6.0", + "sebastian/environment": "^9.2", + "sebastian/git-state": "^1.0", + "sebastian/lines-of-code": "^5.0", + "sebastian/version": "^7.0", + "theseer/tokenizer": "^2.0.1" + }, + "require-dev": { + "phpunit/phpunit": "^13.1" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "14.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/14.1.9" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2026-05-16T05:16:14+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6e5aa1fb0a95b1703d83e721299ee18bb4e2de50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6e5aa1fb0a95b1703d83e721299ee18bb4e2de50", + "reference": "6e5aa1fb0a95b1703d83e721299ee18bb4e2de50", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:33:26+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "42e5c5cae0c65df12d1b1a3ab52bf3f50f244d88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/42e5c5cae0c65df12d1b1a3ab52bf3f50f244d88", + "reference": "42e5c5cae0c65df12d1b1a3ab52bf3f50f244d88", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^13.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-invoker", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:34:47+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "a47af19f93f76aa3368303d752aa5272ca3299f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/a47af19f93f76aa3368303d752aa5272ca3299f4", + "reference": "a47af19f93f76aa3368303d752aa5272ca3299f4", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-text-template", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:36:37+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "9.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "a0e12065831f6ab0d83120dc61513eb8d9a966f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/a0e12065831f6ab0d83120dc61513eb8d9a966f6", + "reference": "a0e12065831f6ab0d83120dc61513eb8d9a966f6", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/9.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-timer", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:37:53+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "48a4654fa5e48c1c81214e9930048a572d4b23ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/48a4654fa5e48c1c81214e9930048a572d4b23ca", + "reference": "48a4654fa5e48c1c81214e9930048a572d4b23ca", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:39:44+00:00" + }, + { + "name": "sebastian/comparator", + "version": "8.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "ce999bf08b2c387a5423fe56961c32eed3f88089" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/ce999bf08b2c387a5423fe56961c32eed3f88089", + "reference": "ce999bf08b2c387a5423fe56961c32eed3f88089", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.4", + "sebastian/diff": "^8.3", + "sebastian/exporter": "^8.0.3" + }, + "require-dev": { + "phpunit/phpunit": "^13.1.10" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/8.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2026-05-21T04:46:40+00:00" + }, + { + "name": "sebastian/complexity", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "c5651c795c98093480df79350cb050813fc7a2f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c5651c795c98093480df79350cb050813fc7a2f3", + "reference": "c5651c795c98093480df79350cb050813fc7a2f3", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/complexity", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:41:32+00:00" + }, + { + "name": "sebastian/diff", + "version": "8.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b36d33b6e796513de7cb7df053afb3f55eefcd47" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b36d33b6e796513de7cb7df053afb3f55eefcd47", + "reference": "b36d33b6e796513de7cb7df053afb3f55eefcd47", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0", + "symfony/process": "^7.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/8.3.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/diff", + "type": "tidelift" + } + ], + "time": "2026-05-15T04:58:09+00:00" + }, + { + "name": "sebastian/environment", + "version": "9.3.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "6c9e487c9eb706a8d258102a1c0b0a3e53e86c2e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6c9e487c9eb706a8d258102a1c0b0a3e53e86c2e", + "reference": "6c9e487c9eb706a8d258102a1c0b0a3e53e86c2e", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.1.11" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/9.3.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" + } + ], + "time": "2026-05-25T13:41:38+00:00" + }, + { + "name": "sebastian/exporter", + "version": "8.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "c0d29a945f8cf82f300a05e69874508e307ca4c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c0d29a945f8cf82f300a05e69874508e307ca4c6", + "reference": "c0d29a945f8cf82f300a05e69874508e307ca4c6", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.4", + "sebastian/recursion-context": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^13.1.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/8.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" + } + ], + "time": "2026-05-21T11:50:56+00:00" + }, + { + "name": "sebastian/git-state", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/git-state.git", + "reference": "792a952e0eba55b6960a48aeceb9f371aad1f76b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/git-state/zipball/792a952e0eba55b6960a48aeceb9f371aad1f76b", + "reference": "792a952e0eba55b6960a48aeceb9f371aad1f76b", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for describing the state of a Git checkout", + "homepage": "https://github.com/sebastianbergmann/git-state", + "support": { + "issues": "https://github.com/sebastianbergmann/git-state/issues", + "security": "https://github.com/sebastianbergmann/git-state/security/policy", + "source": "https://github.com/sebastianbergmann/git-state/tree/1.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/git-state", + "type": "tidelift" + } + ], + "time": "2026-03-21T12:54:28+00:00" + }, + { + "name": "sebastian/global-state", + "version": "9.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e52e3dc22441e6218c710afe72c3042f8fc41ea7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e52e3dc22441e6218c710afe72c3042f8fc41ea7", + "reference": "e52e3dc22441e6218c710afe72c3042f8fc41ea7", + "shasum": "" + }, + "require": { + "php": ">=8.4", + "sebastian/object-reflector": "^6.0", + "sebastian/recursion-context": "^8.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/9.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:45:13+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d2cff273a90c79b0eb590baa682d4b5c318bdbb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d2cff273a90c79b0eb590baa682d4b5c318bdbb7", + "reference": "d2cff273a90c79b0eb590baa682d4b5c318bdbb7", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.7.0", + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.1.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/lines-of-code", + "type": "tidelift" + } + ], + "time": "2026-05-19T16:23:37+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "b39ab125fd9a7434b0ecbc4202eebce11a98cfc5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/b39ab125fd9a7434b0ecbc4202eebce11a98cfc5", + "reference": "b39ab125fd9a7434b0ecbc4202eebce11a98cfc5", + "shasum": "" + }, + "require": { + "php": ">=8.4", + "sebastian/object-reflector": "^6.0", + "sebastian/recursion-context": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/8.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/object-enumerator", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:46:36+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "3ca042c2c60b0eab094f8a1b6a7093f4d4c72200" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/3ca042c2c60b0eab094f8a1b6a7093f4d4c72200", + "reference": "3ca042c2c60b0eab094f8a1b6a7093f4d4c72200", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/object-reflector", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:47:13+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "74c5af21f6a5833e91767ca068c4d3dfec15317e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/74c5af21f6a5833e91767ca068c4d3dfec15317e", + "reference": "74c5af21f6a5833e91767ca068c4d3dfec15317e", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/8.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:51:28+00:00" + }, + { + "name": "sebastian/type", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "fee0309275847fefd7636167085e379c1dbf6990" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fee0309275847fefd7636167085e379c1dbf6990", + "reference": "fee0309275847fefd7636167085e379c1dbf6990", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "require-dev": { + "phpunit/phpunit": "^13.1.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" + } + ], + "time": "2026-05-20T06:49:11+00:00" + }, + { + "name": "sebastian/version", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "ad37a5552c8e2b88572249fdc19b6da7792e021b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/ad37a5552c8e2b88572249fdc19b6da7792e021b", + "reference": "ad37a5552c8e2b88572249fdc19b6da7792e021b", + "shasum": "" + }, + "require": { + "php": ">=8.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/version", + "type": "tidelift" + } + ], + "time": "2026-02-06T04:52:52+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^8.1" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2025-12-08T11:19:18+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": ">=8.4.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*" + }, + "platform-dev": {}, + "platform-overrides": { + "php": "8.4.1" + }, + "plugin-api-version": "2.9.0" +} +phpunit/phpunit: 13.1.13 +myclabs/deep-copy: 1.13.4 +nikic/php-parser: v5.7.0 +phar-io/manifest: 2.0.4 +phar-io/version: 3.2.1 +phpunit/php-code-coverage: 14.1.9 +phpunit/php-file-iterator: 7.0.0 +phpunit/php-invoker: 7.0.0 +phpunit/php-text-template: 6.0.0 +phpunit/php-timer: 9.0.0 +sebastian/cli-parser: 5.0.0 +sebastian/comparator: 8.2.1 +sebastian/complexity: 6.0.0 +sebastian/diff: 8.3.0 +sebastian/environment: 9.3.2 +sebastian/exporter: 8.1.0 +sebastian/git-state: 1.0.0 +sebastian/global-state: 9.0.0 +sebastian/lines-of-code: 5.0.1 +sebastian/object-enumerator: 8.0.0 +sebastian/object-reflector: 6.0.0 +sebastian/recursion-context: 8.0.0 +sebastian/type: 7.0.1 +sebastian/version: 7.0.0 +staabm/side-effects-detector: 1.0.5 +theseer/tokenizer: 2.0.1 + Filter, 'matcher' => Matcher] pairs. + */ + private $filters = []; + /** + * Type Filters to apply. + * + * @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs. + */ + private $typeFilters = []; + /** + * @var bool + */ + private $skipUncloneable = \false; + /** + * @var bool + */ + private $useCloneMethod; + /** + * @param bool $useCloneMethod If set to true, when an object implements the __clone() function, it will be used + * instead of the regular deep cloning. + */ + public function __construct($useCloneMethod = \false) + { + $this->useCloneMethod = $useCloneMethod; + $this->addTypeFilter(new ArrayObjectFilter($this), new TypeMatcher(ArrayObject::class)); + $this->addTypeFilter(new DateIntervalFilter(), new TypeMatcher(DateInterval::class)); + $this->addTypeFilter(new DatePeriodFilter(), new TypeMatcher(DatePeriod::class)); + $this->addTypeFilter(new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class)); + } + /** + * If enabled, will not throw an exception when coming across an uncloneable property. + * + * @param $skipUncloneable + * + * @return $this + */ + public function skipUncloneable($skipUncloneable = \true) + { + $this->skipUncloneable = $skipUncloneable; + return $this; + } + /** + * Deep copies the given object. + * + * @template TObject + * + * @param TObject $object + * + * @return TObject + */ + public function copy($object) + { + $this->hashMap = []; + return $this->recursiveCopy($object); + } + public function addFilter(Filter $filter, Matcher $matcher) + { + $this->filters[] = ['matcher' => $matcher, 'filter' => $filter]; + } + public function prependFilter(Filter $filter, Matcher $matcher) + { + array_unshift($this->filters, ['matcher' => $matcher, 'filter' => $filter]); + } + public function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher) + { + $this->typeFilters[] = ['matcher' => $matcher, 'filter' => $filter]; + } + public function prependTypeFilter(TypeFilter $filter, TypeMatcher $matcher) + { + array_unshift($this->typeFilters, ['matcher' => $matcher, 'filter' => $filter]); + } + private function recursiveCopy($var) + { + // Matches Type Filter + if ($filter = $this->getFirstMatchedTypeFilter($this->typeFilters, $var)) { + return $filter->apply($var); + } + // Resource + if (is_resource($var)) { + return $var; + } + // Array + if (is_array($var)) { + return $this->copyArray($var); + } + // Scalar + if (!is_object($var)) { + return $var; + } + // Enum + if (\PHP_VERSION_ID >= 80100 && enum_exists(get_class($var))) { + return $var; + } + // Object + return $this->copyObject($var); + } + /** + * Copy an array + * @param array $array + * @return array + */ + private function copyArray(array $array) + { + foreach ($array as $key => $value) { + $array[$key] = $this->recursiveCopy($value); + } + return $array; + } + /** + * Copies an object. + * + * @param object $object + * + * @throws CloneException + * + * @return object + */ + private function copyObject($object) + { + $objectHash = spl_object_hash($object); + if (isset($this->hashMap[$objectHash])) { + return $this->hashMap[$objectHash]; + } + $reflectedObject = new ReflectionObject($object); + $isCloneable = $reflectedObject->isCloneable(); + if (\false === $isCloneable) { + if ($this->skipUncloneable) { + $this->hashMap[$objectHash] = $object; + return $object; + } + throw new CloneException(sprintf('The class "%s" is not cloneable.', $reflectedObject->getName())); + } + $newObject = clone $object; + $this->hashMap[$objectHash] = $newObject; + if ($this->useCloneMethod && $reflectedObject->hasMethod('__clone')) { + return $newObject; + } + if ($newObject instanceof DateTimeInterface || $newObject instanceof DateTimeZone) { + return $newObject; + } + foreach (ReflectionHelper::getProperties($reflectedObject) as $property) { + $this->copyObjectProperty($newObject, $property); + } + return $newObject; + } + private function copyObjectProperty($object, ReflectionProperty $property) + { + // Ignore static properties + if ($property->isStatic()) { + return; + } + // Ignore readonly properties + if (method_exists($property, 'isReadOnly') && $property->isReadOnly()) { + return; + } + // Apply the filters + foreach ($this->filters as $item) { + /** @var Matcher $matcher */ + $matcher = $item['matcher']; + /** @var Filter $filter */ + $filter = $item['filter']; + if ($matcher->matches($object, $property->getName())) { + $filter->apply($object, $property->getName(), function ($object) { + return $this->recursiveCopy($object); + }); + if ($filter instanceof ChainableFilter) { + continue; + } + // If a filter matches, we stop processing this property + return; + } + } + if (\PHP_VERSION_ID < 80100) { + $property->setAccessible(\true); + } + // Ignore uninitialized properties (for PHP >7.4) + if (method_exists($property, 'isInitialized') && !$property->isInitialized($object)) { + return; + } + $propertyValue = $property->getValue($object); + // Copy the property + $property->setValue($object, $this->recursiveCopy($propertyValue)); + } + /** + * Returns first filter that matches variable, `null` if no such filter found. + * + * @param array $filterRecords Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and + * 'matcher' with value of type {@see TypeMatcher} + * @param mixed $var + * + * @return TypeFilter|null + */ + private function getFirstMatchedTypeFilter(array $filterRecords, $var) + { + $matched = $this->first($filterRecords, function (array $record) use ($var) { + /* @var TypeMatcher $matcher */ + $matcher = $record['matcher']; + return $matcher->matches($var); + }); + return isset($matched) ? $matched['filter'] : null; + } + /** + * Returns first element that matches predicate, `null` if no such element found. + * + * @param array $elements Array of ['filter' => Filter, 'matcher' => Matcher] pairs. + * @param callable $predicate Predicate arguments are: element. + * + * @return array|null Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and 'matcher' + * with value of type {@see TypeMatcher} or `null`. + */ + private function first(array $elements, callable $predicate) + { + foreach ($elements as $element) { + if (call_user_func($predicate, $element)) { + return $element; + } + } + return null; + } +} +filter = $filter; + } + public function apply($object, $property, $objectCopier) + { + $this->filter->apply($object, $property, $objectCopier); + } +} +setAccessible(\true); + } + $oldCollection = $reflectionProperty->getValue($object); + $newCollection = $oldCollection->map(function ($item) use ($objectCopier) { + return $objectCopier($item); + }); + $reflectionProperty->setValue($object, $newCollection); + } +} +setAccessible(\true); + } + $reflectionProperty->setValue($object, new ArrayCollection()); + } +} +__load(); + } +} +callback = $callable; + } + /** + * Replaces the object property by the result of the callback called with the object property. + * + * {@inheritdoc} + */ + public function apply($object, $property, $objectCopier) + { + $reflectionProperty = ReflectionHelper::getProperty($object, $property); + if (\PHP_VERSION_ID < 80100) { + $reflectionProperty->setAccessible(\true); + } + $value = call_user_func($this->callback, $reflectionProperty->getValue($object)); + $reflectionProperty->setValue($object, $value); + } +} +setAccessible(\true); + } + $reflectionProperty->setValue($object, null); + } +} +class = $class; + $this->property = $property; + } + /** + * Matches a specific property of a specific class. + * + * {@inheritdoc} + */ + public function matches($object, $property) + { + return $object instanceof $this->class && $property == $this->property; + } +} +property = $property; + } + /** + * Matches a property by its name. + * + * {@inheritdoc} + */ + public function matches($object, $property) + { + return $property == $this->property; + } +} +propertyType = $propertyType; + } + /** + * {@inheritdoc} + */ + public function matches($object, $property) + { + try { + $reflectionProperty = ReflectionHelper::getProperty($object, $property); + } catch (ReflectionException $exception) { + return \false; + } + if (\PHP_VERSION_ID < 80100) { + $reflectionProperty->setAccessible(\true); + } + // Uninitialized properties (for PHP >7.4) + if (method_exists($reflectionProperty, 'isInitialized') && !$reflectionProperty->isInitialized($object)) { + // null instanceof $this->propertyType + return \false; + } + return $reflectionProperty->getValue($object) instanceof $this->propertyType; + } +} +getProperties() does not return private properties from ancestor classes. + * + * @author muratyaman@gmail.com + * @see http://php.net/manual/en/reflectionclass.getproperties.php + * + * @param ReflectionClass $ref + * + * @return ReflectionProperty[] + */ + public static function getProperties(ReflectionClass $ref) + { + $props = $ref->getProperties(); + $propsArr = array(); + foreach ($props as $prop) { + $propertyName = $prop->getName(); + $propsArr[$propertyName] = $prop; + } + if ($parentClass = $ref->getParentClass()) { + $parentPropsArr = self::getProperties($parentClass); + foreach ($propsArr as $key => $property) { + $parentPropsArr[$key] = $property; + } + return $parentPropsArr; + } + return $propsArr; + } + /** + * Retrieves property by name from object and all its ancestors. + * + * @param object|string $object + * @param string $name + * + * @throws PropertyException + * @throws ReflectionException + * + * @return ReflectionProperty + */ + public static function getProperty($object, $name) + { + $reflection = is_object($object) ? new ReflectionObject($object) : new ReflectionClass($object); + if ($reflection->hasProperty($name)) { + return $reflection->getProperty($name); + } + if ($parentClass = $reflection->getParentClass()) { + return self::getProperty($parentClass->getName(), $name); + } + throw new PropertyException(sprintf('The class "%s" doesn\'t have a property with the given name: "%s".', is_object($object) ? get_class($object) : $object, $name)); + } +} + $propertyValue) { + $copy->{$propertyName} = $propertyValue; + } + return $copy; + } +} += 80200 && $element->include_end_date) { + $options |= DatePeriod::INCLUDE_END_DATE; + } + if (!$element->include_start_date) { + $options |= DatePeriod::EXCLUDE_START_DATE; + } + if ($element->getEndDate()) { + return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $element->getEndDate(), $options); + } + if (\PHP_VERSION_ID >= 70217) { + $recurrences = $element->getRecurrences(); + } else { + $recurrences = $element->recurrences - $element->include_start_date; + } + return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $recurrences, $options); + } +} +callback = $callable; + } + /** + * {@inheritdoc} + */ + public function apply($element) + { + return call_user_func($this->callback, $element); + } +} +copier = $copier; + } + /** + * {@inheritdoc} + */ + public function apply($arrayObject) + { + $clone = clone $arrayObject; + foreach ($arrayObject->getArrayCopy() as $k => $v) { + $clone->offsetSet($k, $this->copier->copy($v)); + } + return $clone; + } +} +copier = $copier; + } + /** + * {@inheritdoc} + */ + public function apply($element) + { + $newElement = clone $element; + $copy = $this->createCopyClosure(); + return $copy($newElement); + } + private function createCopyClosure() + { + $copier = $this->copier; + $copy = function (SplDoublyLinkedList $list) use ($copier) { + // Replace each element in the list with a deep copy of itself + for ($i = 1; $i <= $list->count(); $i++) { + $copy = $copier->recursiveCopy($list->shift()); + $list->push($copy); + } + return $list; + }; + return Closure::bind($copy, null, DeepCopy::class); + } +} +type = $type; + } + /** + * @param mixed $element + * + * @return boolean + */ + public function matches($element) + { + return is_object($element) ? is_a($element, $this->type) : gettype($element) === $this->type; + } +} +copy($value); + } +} +The MIT License (MIT) + +Copyright (c) 2013 My C-Sense + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +BSD 3-Clause License + +Copyright (c) 2011, Nikita Popov +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + protected array $attributes = []; + /** @var list */ + protected array $constants = []; + /** @var list */ + protected array $attributeGroups = []; + /** @var Identifier|Node\Name|Node\ComplexType|null */ + protected ?Node $type = null; + /** + * Creates a class constant builder + * + * @param string|Identifier $name Name + * @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value + */ + public function __construct($name, $value) + { + $this->constants = [new Const_($name, BuilderHelpers::normalizeValue($value))]; + } + /** + * Add another constant to const group + * + * @param string|Identifier $name Name + * @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value + * + * @return $this The builder instance (for fluid interface) + */ + public function addConst($name, $value) + { + $this->constants[] = new Const_($name, BuilderHelpers::normalizeValue($value)); + return $this; + } + /** + * Makes the constant public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC); + return $this; + } + /** + * Makes the constant protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED); + return $this; + } + /** + * Makes the constant private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE); + return $this; + } + /** + * Makes the constant final. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeFinal() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL); + return $this; + } + /** + * Sets doc comment for the constant. + * + * @param PhpParser\Comment\Doc|string $docComment Doc comment to set + * + * @return $this The builder instance (for fluid interface) + */ + public function setDocComment($docComment) + { + $this->attributes = ['comments' => [BuilderHelpers::normalizeDocComment($docComment)]]; + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Sets the constant type. + * + * @param string|Node\Name|Identifier|Node\ComplexType $type + * + * @return $this + */ + public function setType($type) + { + $this->type = BuilderHelpers::normalizeType($type); + return $this; + } + /** + * Returns the built class node. + * + * @return Stmt\ClassConst The built constant node + */ + public function getNode(): PhpParser\Node + { + return new Stmt\ClassConst($this->constants, $this->flags, $this->attributes, $this->attributeGroups, $this->type); + } +} + */ + protected array $implements = []; + protected int $flags = 0; + /** @var list */ + protected array $uses = []; + /** @var list */ + protected array $constants = []; + /** @var list */ + protected array $properties = []; + /** @var list */ + protected array $methods = []; + /** @var list */ + protected array $attributeGroups = []; + /** + * Creates a class builder. + * + * @param string $name Name of the class + */ + public function __construct(string $name) + { + $this->name = $name; + } + /** + * Extends a class. + * + * @param Name|string $class Name of class to extend + * + * @return $this The builder instance (for fluid interface) + */ + public function extend($class) + { + $this->extends = BuilderHelpers::normalizeName($class); + return $this; + } + /** + * Implements one or more interfaces. + * + * @param Name|string ...$interfaces Names of interfaces to implement + * + * @return $this The builder instance (for fluid interface) + */ + public function implement(...$interfaces) + { + foreach ($interfaces as $interface) { + $this->implements[] = BuilderHelpers::normalizeName($interface); + } + return $this; + } + /** + * Makes the class abstract. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeAbstract() + { + $this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::ABSTRACT); + return $this; + } + /** + * Makes the class final. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeFinal() + { + $this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::FINAL); + return $this; + } + /** + * Makes the class readonly. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeReadonly() + { + $this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::READONLY); + return $this; + } + /** + * Adds a statement. + * + * @param Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $stmt = BuilderHelpers::normalizeNode($stmt); + if ($stmt instanceof Stmt\Property) { + $this->properties[] = $stmt; + } elseif ($stmt instanceof Stmt\ClassMethod) { + $this->methods[] = $stmt; + } elseif ($stmt instanceof Stmt\TraitUse) { + $this->uses[] = $stmt; + } elseif ($stmt instanceof Stmt\ClassConst) { + $this->constants[] = $stmt; + } else { + throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType())); + } + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built class node. + * + * @return Stmt\Class_ The built class node + */ + public function getNode(): PhpParser\Node + { + return new Stmt\Class_($this->name, ['flags' => $this->flags, 'extends' => $this->extends, 'implements' => $this->implements, 'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} + */ + protected array $attributes = []; + /** + * Adds a statement. + * + * @param PhpParser\Node\Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + abstract public function addStmt($stmt); + /** + * Adds multiple statements. + * + * @param (PhpParser\Node\Stmt|PhpParser\Builder)[] $stmts The statements to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmts(array $stmts) + { + foreach ($stmts as $stmt) { + $this->addStmt($stmt); + } + return $this; + } + /** + * Sets doc comment for the declaration. + * + * @param PhpParser\Comment\Doc|string $docComment Doc comment to set + * + * @return $this The builder instance (for fluid interface) + */ + public function setDocComment($docComment) + { + $this->attributes['comments'] = [BuilderHelpers::normalizeDocComment($docComment)]; + return $this; + } +} + */ + protected array $attributes = []; + /** @var list */ + protected array $attributeGroups = []; + /** + * Creates an enum case builder. + * + * @param string|Identifier $name Name + */ + public function __construct($name) + { + $this->name = $name; + } + /** + * Sets the value. + * + * @param Node\Expr|string|int $value + * + * @return $this + */ + public function setValue($value) + { + $this->value = BuilderHelpers::normalizeValue($value); + return $this; + } + /** + * Sets doc comment for the constant. + * + * @param PhpParser\Comment\Doc|string $docComment Doc comment to set + * + * @return $this The builder instance (for fluid interface) + */ + public function setDocComment($docComment) + { + $this->attributes = ['comments' => [BuilderHelpers::normalizeDocComment($docComment)]]; + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built enum case node. + * + * @return Stmt\EnumCase The built constant node + */ + public function getNode(): PhpParser\Node + { + return new Stmt\EnumCase($this->name, $this->value, $this->attributeGroups, $this->attributes); + } +} + */ + protected array $implements = []; + /** @var list */ + protected array $uses = []; + /** @var list */ + protected array $enumCases = []; + /** @var list */ + protected array $constants = []; + /** @var list */ + protected array $methods = []; + /** @var list */ + protected array $attributeGroups = []; + /** + * Creates an enum builder. + * + * @param string $name Name of the enum + */ + public function __construct(string $name) + { + $this->name = $name; + } + /** + * Sets the scalar type. + * + * @param string|Identifier $scalarType + * + * @return $this + */ + public function setScalarType($scalarType) + { + $this->scalarType = BuilderHelpers::normalizeType($scalarType); + return $this; + } + /** + * Implements one or more interfaces. + * + * @param Name|string ...$interfaces Names of interfaces to implement + * + * @return $this The builder instance (for fluid interface) + */ + public function implement(...$interfaces) + { + foreach ($interfaces as $interface) { + $this->implements[] = BuilderHelpers::normalizeName($interface); + } + return $this; + } + /** + * Adds a statement. + * + * @param Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $stmt = BuilderHelpers::normalizeNode($stmt); + if ($stmt instanceof Stmt\EnumCase) { + $this->enumCases[] = $stmt; + } elseif ($stmt instanceof Stmt\ClassMethod) { + $this->methods[] = $stmt; + } elseif ($stmt instanceof Stmt\TraitUse) { + $this->uses[] = $stmt; + } elseif ($stmt instanceof Stmt\ClassConst) { + $this->constants[] = $stmt; + } else { + throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType())); + } + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built class node. + * + * @return Stmt\Enum_ The built enum node + */ + public function getNode(): PhpParser\Node + { + return new Stmt\Enum_($this->name, ['scalarType' => $this->scalarType, 'implements' => $this->implements, 'stmts' => array_merge($this->uses, $this->enumCases, $this->constants, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} +returnByRef = \true; + return $this; + } + /** + * Adds a parameter. + * + * @param Node\Param|Param $param The parameter to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addParam($param) + { + $param = BuilderHelpers::normalizeNode($param); + if (!$param instanceof Node\Param) { + throw new \LogicException(sprintf('Expected parameter node, got "%s"', $param->getType())); + } + $this->params[] = $param; + return $this; + } + /** + * Adds multiple parameters. + * + * @param (Node\Param|Param)[] $params The parameters to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addParams(array $params) + { + foreach ($params as $param) { + $this->addParam($param); + } + return $this; + } + /** + * Sets the return type for PHP 7. + * + * @param string|Node\Name|Node\Identifier|Node\ComplexType $type + * + * @return $this The builder instance (for fluid interface) + */ + public function setReturnType($type) + { + $this->returnType = BuilderHelpers::normalizeType($type); + return $this; + } +} + */ + protected array $stmts = []; + /** @var list */ + protected array $attributeGroups = []; + /** + * Creates a function builder. + * + * @param string $name Name of the function + */ + public function __construct(string $name) + { + $this->name = $name; + } + /** + * Adds a statement. + * + * @param Node|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built function node. + * + * @return Stmt\Function_ The built function node + */ + public function getNode(): Node + { + return new Stmt\Function_($this->name, ['byRef' => $this->returnByRef, 'params' => $this->params, 'returnType' => $this->returnType, 'stmts' => $this->stmts, 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} + */ + protected array $extends = []; + /** @var list */ + protected array $constants = []; + /** @var list */ + protected array $methods = []; + /** @var list */ + protected array $attributeGroups = []; + /** + * Creates an interface builder. + * + * @param string $name Name of the interface + */ + public function __construct(string $name) + { + $this->name = $name; + } + /** + * Extends one or more interfaces. + * + * @param Name|string ...$interfaces Names of interfaces to extend + * + * @return $this The builder instance (for fluid interface) + */ + public function extend(...$interfaces) + { + foreach ($interfaces as $interface) { + $this->extends[] = BuilderHelpers::normalizeName($interface); + } + return $this; + } + /** + * Adds a statement. + * + * @param Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $stmt = BuilderHelpers::normalizeNode($stmt); + if ($stmt instanceof Stmt\ClassConst) { + $this->constants[] = $stmt; + } elseif ($stmt instanceof Stmt\ClassMethod) { + // we erase all statements in the body of an interface method + $stmt->stmts = null; + $this->methods[] = $stmt; + } else { + throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType())); + } + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built interface node. + * + * @return Stmt\Interface_ The built interface node + */ + public function getNode(): PhpParser\Node + { + return new Stmt\Interface_($this->name, ['extends' => $this->extends, 'stmts' => array_merge($this->constants, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} +|null */ + protected ?array $stmts = []; + /** @var list */ + protected array $attributeGroups = []; + /** + * Creates a method builder. + * + * @param string $name Name of the method + */ + public function __construct(string $name) + { + $this->name = $name; + } + /** + * Makes the method public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC); + return $this; + } + /** + * Makes the method protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED); + return $this; + } + /** + * Makes the method private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE); + return $this; + } + /** + * Makes the method static. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeStatic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC); + return $this; + } + /** + * Makes the method abstract. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeAbstract() + { + if (!empty($this->stmts)) { + throw new \LogicException('Cannot make method with statements abstract'); + } + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::ABSTRACT); + $this->stmts = null; + // abstract methods don't have statements + return $this; + } + /** + * Makes the method final. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeFinal() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL); + return $this; + } + /** + * Adds a statement. + * + * @param Node|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + if (null === $this->stmts) { + throw new \LogicException('Cannot add statements to an abstract method'); + } + $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built method node. + * + * @return Stmt\ClassMethod The built method node + */ + public function getNode(): Node + { + return new Stmt\ClassMethod($this->name, ['flags' => $this->flags, 'byRef' => $this->returnByRef, 'params' => $this->params, 'returnType' => $this->returnType, 'stmts' => $this->stmts, 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} +name = null !== $name ? BuilderHelpers::normalizeName($name) : null; + } + /** + * Adds a statement. + * + * @param Node|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); + return $this; + } + /** + * Returns the built node. + * + * @return Stmt\Namespace_ The built node + */ + public function getNode(): Node + { + return new Stmt\Namespace_($this->name, $this->stmts, $this->attributes); + } +} + */ + protected array $attributeGroups = []; + /** + * Creates a parameter builder. + * + * @param string $name Name of the parameter + */ + public function __construct(string $name) + { + $this->name = $name; + } + /** + * Sets default value for the parameter. + * + * @param mixed $value Default value to use + * + * @return $this The builder instance (for fluid interface) + */ + public function setDefault($value) + { + $this->default = BuilderHelpers::normalizeValue($value); + return $this; + } + /** + * Sets type for the parameter. + * + * @param string|Node\Name|Node\Identifier|Node\ComplexType $type Parameter type + * + * @return $this The builder instance (for fluid interface) + */ + public function setType($type) + { + $this->type = BuilderHelpers::normalizeType($type); + if ($this->type == 'void') { + throw new \LogicException('Parameter type cannot be void'); + } + return $this; + } + /** + * Make the parameter accept the value by reference. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeByRef() + { + $this->byRef = \true; + return $this; + } + /** + * Make the parameter variadic + * + * @return $this The builder instance (for fluid interface) + */ + public function makeVariadic() + { + $this->variadic = \true; + return $this; + } + /** + * Makes the (promoted) parameter public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC); + return $this; + } + /** + * Makes the (promoted) parameter protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED); + return $this; + } + /** + * Makes the (promoted) parameter private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE); + return $this; + } + /** + * Makes the (promoted) parameter readonly. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeReadonly() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY); + return $this; + } + /** + * Gives the promoted property private(set) visibility. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivateSet() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE_SET); + return $this; + } + /** + * Gives the promoted property protected(set) visibility. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtectedSet() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED_SET); + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built parameter node. + * + * @return Node\Param The built parameter node + */ + public function getNode(): Node + { + return new Node\Param(new Node\Expr\Variable($this->name), $this->default, $this->type, $this->byRef, $this->variadic, [], $this->flags, $this->attributeGroups); + } +} + */ + protected array $attributes = []; + /** @var null|Identifier|Name|ComplexType */ + protected ?Node $type = null; + /** @var list */ + protected array $attributeGroups = []; + /** @var list */ + protected array $hooks = []; + /** + * Creates a property builder. + * + * @param string $name Name of the property + */ + public function __construct(string $name) + { + $this->name = $name; + } + /** + * Makes the property public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC); + return $this; + } + /** + * Makes the property protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED); + return $this; + } + /** + * Makes the property private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE); + return $this; + } + /** + * Makes the property static. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeStatic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC); + return $this; + } + /** + * Makes the property readonly. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeReadonly() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY); + return $this; + } + /** + * Makes the property abstract. Requires at least one property hook to be specified as well. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeAbstract() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::ABSTRACT); + return $this; + } + /** + * Makes the property final. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeFinal() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL); + return $this; + } + /** + * Gives the property private(set) visibility. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivateSet() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE_SET); + return $this; + } + /** + * Gives the property protected(set) visibility. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtectedSet() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED_SET); + return $this; + } + /** + * Sets default value for the property. + * + * @param mixed $value Default value to use + * + * @return $this The builder instance (for fluid interface) + */ + public function setDefault($value) + { + $this->default = BuilderHelpers::normalizeValue($value); + return $this; + } + /** + * Sets doc comment for the property. + * + * @param PhpParser\Comment\Doc|string $docComment Doc comment to set + * + * @return $this The builder instance (for fluid interface) + */ + public function setDocComment($docComment) + { + $this->attributes = ['comments' => [BuilderHelpers::normalizeDocComment($docComment)]]; + return $this; + } + /** + * Sets the property type for PHP 7.4+. + * + * @param string|Name|Identifier|ComplexType $type + * + * @return $this + */ + public function setType($type) + { + $this->type = BuilderHelpers::normalizeType($type); + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Adds a property hook. + * + * @return $this The builder instance (for fluid interface) + */ + public function addHook(Node\PropertyHook $hook) + { + $this->hooks[] = $hook; + return $this; + } + /** + * Returns the built class node. + * + * @return Stmt\Property The built property node + */ + public function getNode(): PhpParser\Node + { + if ($this->flags & Modifiers::ABSTRACT && !$this->hooks) { + throw new PhpParser\Error('Only hooked properties may be declared abstract'); + } + return new Stmt\Property($this->flags !== 0 ? $this->flags : Modifiers::PUBLIC, [new Node\PropertyItem($this->name, $this->default)], $this->attributes, $this->type, $this->attributeGroups, $this->hooks); + } +} +and($trait); + } + } + /** + * Adds used trait. + * + * @param Node\Name|string $trait Trait name + * + * @return $this The builder instance (for fluid interface) + */ + public function and($trait) + { + $this->traits[] = BuilderHelpers::normalizeName($trait); + return $this; + } + /** + * Adds trait adaptation. + * + * @param Stmt\TraitUseAdaptation|Builder\TraitUseAdaptation $adaptation Trait adaptation + * + * @return $this The builder instance (for fluid interface) + */ + public function with($adaptation) + { + $adaptation = BuilderHelpers::normalizeNode($adaptation); + if (!$adaptation instanceof Stmt\TraitUseAdaptation) { + throw new \LogicException('Adaptation must have type TraitUseAdaptation'); + } + $this->adaptations[] = $adaptation; + return $this; + } + /** + * Returns the built node. + * + * @return Node The built node + */ + public function getNode(): Node + { + return new Stmt\TraitUse($this->traits, $this->adaptations); + } +} +type = self::TYPE_UNDEFINED; + $this->trait = is_null($trait) ? null : BuilderHelpers::normalizeName($trait); + $this->method = BuilderHelpers::normalizeIdentifier($method); + } + /** + * Sets alias of method. + * + * @param Node\Identifier|string $alias Alias for adapted method + * + * @return $this The builder instance (for fluid interface) + */ + public function as($alias) + { + if ($this->type === self::TYPE_UNDEFINED) { + $this->type = self::TYPE_ALIAS; + } + if ($this->type !== self::TYPE_ALIAS) { + throw new \LogicException('Cannot set alias for not alias adaptation buider'); + } + $this->alias = BuilderHelpers::normalizeIdentifier($alias); + return $this; + } + /** + * Sets adapted method public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->setModifier(Modifiers::PUBLIC); + return $this; + } + /** + * Sets adapted method protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->setModifier(Modifiers::PROTECTED); + return $this; + } + /** + * Sets adapted method private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->setModifier(Modifiers::PRIVATE); + return $this; + } + /** + * Adds overwritten traits. + * + * @param Node\Name|string ...$traits Traits for overwrite + * + * @return $this The builder instance (for fluid interface) + */ + public function insteadof(...$traits) + { + if ($this->type === self::TYPE_UNDEFINED) { + if (is_null($this->trait)) { + throw new \LogicException('Precedence adaptation must have trait'); + } + $this->type = self::TYPE_PRECEDENCE; + } + if ($this->type !== self::TYPE_PRECEDENCE) { + throw new \LogicException('Cannot add overwritten traits for not precedence adaptation buider'); + } + foreach ($traits as $trait) { + $this->insteadof[] = BuilderHelpers::normalizeName($trait); + } + return $this; + } + protected function setModifier(int $modifier): void + { + if ($this->type === self::TYPE_UNDEFINED) { + $this->type = self::TYPE_ALIAS; + } + if ($this->type !== self::TYPE_ALIAS) { + throw new \LogicException('Cannot set access modifier for not alias adaptation buider'); + } + if (is_null($this->modifier)) { + $this->modifier = $modifier; + } else { + throw new \LogicException('Multiple access type modifiers are not allowed'); + } + } + /** + * Returns the built node. + * + * @return Node The built node + */ + public function getNode(): Node + { + switch ($this->type) { + case self::TYPE_ALIAS: + return new Stmt\TraitUseAdaptation\Alias($this->trait, $this->method, $this->modifier, $this->alias); + case self::TYPE_PRECEDENCE: + return new Stmt\TraitUseAdaptation\Precedence($this->trait, $this->method, $this->insteadof); + default: + throw new \LogicException('Type of adaptation is not defined'); + } + } +} + */ + protected array $uses = []; + /** @var list */ + protected array $constants = []; + /** @var list */ + protected array $properties = []; + /** @var list */ + protected array $methods = []; + /** @var list */ + protected array $attributeGroups = []; + /** + * Creates an interface builder. + * + * @param string $name Name of the interface + */ + public function __construct(string $name) + { + $this->name = $name; + } + /** + * Adds a statement. + * + * @param Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $stmt = BuilderHelpers::normalizeNode($stmt); + if ($stmt instanceof Stmt\Property) { + $this->properties[] = $stmt; + } elseif ($stmt instanceof Stmt\ClassMethod) { + $this->methods[] = $stmt; + } elseif ($stmt instanceof Stmt\TraitUse) { + $this->uses[] = $stmt; + } elseif ($stmt instanceof Stmt\ClassConst) { + $this->constants[] = $stmt; + } else { + throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType())); + } + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built trait node. + * + * @return Stmt\Trait_ The built interface node + */ + public function getNode(): PhpParser\Node + { + return new Stmt\Trait_($this->name, ['stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} +name = BuilderHelpers::normalizeName($name); + $this->type = $type; + } + /** + * Sets alias for used name. + * + * @param string $alias Alias to use (last component of full name by default) + * + * @return $this The builder instance (for fluid interface) + */ + public function as(string $alias) + { + $this->alias = $alias; + return $this; + } + /** + * Returns the built node. + * + * @return Stmt\Use_ The built node + */ + public function getNode(): Node + { + return new Stmt\Use_([new Node\UseItem($this->name, $this->alias)], $this->type); + } +} +args($args)); + } + /** + * Creates a namespace builder. + * + * @param null|string|Node\Name $name Name of the namespace + * + * @return Builder\Namespace_ The created namespace builder + */ + public function namespace($name): Builder\Namespace_ + { + return new Builder\Namespace_($name); + } + /** + * Creates a class builder. + * + * @param string $name Name of the class + * + * @return Builder\Class_ The created class builder + */ + public function class(string $name): Builder\Class_ + { + return new Builder\Class_($name); + } + /** + * Creates an interface builder. + * + * @param string $name Name of the interface + * + * @return Builder\Interface_ The created interface builder + */ + public function interface(string $name): Builder\Interface_ + { + return new Builder\Interface_($name); + } + /** + * Creates a trait builder. + * + * @param string $name Name of the trait + * + * @return Builder\Trait_ The created trait builder + */ + public function trait(string $name): Builder\Trait_ + { + return new Builder\Trait_($name); + } + /** + * Creates an enum builder. + * + * @param string $name Name of the enum + * + * @return Builder\Enum_ The created enum builder + */ + public function enum(string $name): Builder\Enum_ + { + return new Builder\Enum_($name); + } + /** + * Creates a trait use builder. + * + * @param Node\Name|string ...$traits Trait names + * + * @return Builder\TraitUse The created trait use builder + */ + public function useTrait(...$traits): Builder\TraitUse + { + return new Builder\TraitUse(...$traits); + } + /** + * Creates a trait use adaptation builder. + * + * @param Node\Name|string|null $trait Trait name + * @param Node\Identifier|string $method Method name + * + * @return Builder\TraitUseAdaptation The created trait use adaptation builder + */ + public function traitUseAdaptation($trait, $method = null): Builder\TraitUseAdaptation + { + if ($method === null) { + $method = $trait; + $trait = null; + } + return new Builder\TraitUseAdaptation($trait, $method); + } + /** + * Creates a method builder. + * + * @param string $name Name of the method + * + * @return Builder\Method The created method builder + */ + public function method(string $name): Builder\Method + { + return new Builder\Method($name); + } + /** + * Creates a parameter builder. + * + * @param string $name Name of the parameter + * + * @return Builder\Param The created parameter builder + */ + public function param(string $name): Builder\Param + { + return new Builder\Param($name); + } + /** + * Creates a property builder. + * + * @param string $name Name of the property + * + * @return Builder\Property The created property builder + */ + public function property(string $name): Builder\Property + { + return new Builder\Property($name); + } + /** + * Creates a function builder. + * + * @param string $name Name of the function + * + * @return Builder\Function_ The created function builder + */ + public function function(string $name): Builder\Function_ + { + return new Builder\Function_($name); + } + /** + * Creates a namespace/class use builder. + * + * @param Node\Name|string $name Name of the entity (namespace or class) to alias + * + * @return Builder\Use_ The created use builder + */ + public function use($name): Builder\Use_ + { + return new Builder\Use_($name, Use_::TYPE_NORMAL); + } + /** + * Creates a function use builder. + * + * @param Node\Name|string $name Name of the function to alias + * + * @return Builder\Use_ The created use function builder + */ + public function useFunction($name): Builder\Use_ + { + return new Builder\Use_($name, Use_::TYPE_FUNCTION); + } + /** + * Creates a constant use builder. + * + * @param Node\Name|string $name Name of the const to alias + * + * @return Builder\Use_ The created use const builder + */ + public function useConst($name): Builder\Use_ + { + return new Builder\Use_($name, Use_::TYPE_CONSTANT); + } + /** + * Creates a class constant builder. + * + * @param string|Identifier $name Name + * @param Node\Expr|bool|null|int|float|string|array $value Value + * + * @return Builder\ClassConst The created use const builder + */ + public function classConst($name, $value): Builder\ClassConst + { + return new Builder\ClassConst($name, $value); + } + /** + * Creates an enum case builder. + * + * @param string|Identifier $name Name + * + * @return Builder\EnumCase The created use const builder + */ + public function enumCase($name): Builder\EnumCase + { + return new Builder\EnumCase($name); + } + /** + * Creates node a for a literal value. + * + * @param Expr|bool|null|int|float|string|array|\UnitEnum $value $value + */ + public function val($value): Expr + { + return BuilderHelpers::normalizeValue($value); + } + /** + * Creates variable node. + * + * @param string|Expr $name Name + */ + public function var($name): Expr\Variable + { + if (!\is_string($name) && !$name instanceof Expr) { + throw new \LogicException('Variable name must be string or Expr'); + } + return new Expr\Variable($name); + } + /** + * Normalizes an argument list. + * + * Creates Arg nodes for all arguments and converts literal values to expressions. + * + * @param array $args List of arguments to normalize + * + * @return list + */ + public function args(array $args): array + { + $normalizedArgs = []; + foreach ($args as $key => $arg) { + if (!$arg instanceof Arg) { + $arg = new Arg(BuilderHelpers::normalizeValue($arg)); + } + if (\is_string($key)) { + $arg->name = BuilderHelpers::normalizeIdentifier($key); + } + $normalizedArgs[] = $arg; + } + return $normalizedArgs; + } + /** + * Creates a function call node. + * + * @param string|Name|Expr $name Function name + * @param array $args Function arguments + */ + public function funcCall($name, array $args = []): Expr\FuncCall + { + return new Expr\FuncCall(BuilderHelpers::normalizeNameOrExpr($name), $this->args($args)); + } + /** + * Creates a method call node. + * + * @param Expr $var Variable the method is called on + * @param string|Identifier|Expr $name Method name + * @param array $args Method arguments + */ + public function methodCall(Expr $var, $name, array $args = []): Expr\MethodCall + { + return new Expr\MethodCall($var, BuilderHelpers::normalizeIdentifierOrExpr($name), $this->args($args)); + } + /** + * Creates a static method call node. + * + * @param string|Name|Expr $class Class name + * @param string|Identifier|Expr $name Method name + * @param array $args Method arguments + */ + public function staticCall($class, $name, array $args = []): Expr\StaticCall + { + return new Expr\StaticCall(BuilderHelpers::normalizeNameOrExpr($class), BuilderHelpers::normalizeIdentifierOrExpr($name), $this->args($args)); + } + /** + * Creates an object creation node. + * + * @param string|Name|Expr $class Class name + * @param array $args Constructor arguments + */ + public function new($class, array $args = []): Expr\New_ + { + return new Expr\New_(BuilderHelpers::normalizeNameOrExpr($class), $this->args($args)); + } + /** + * Creates a constant fetch node. + * + * @param string|Name $name Constant name + */ + public function constFetch($name): Expr\ConstFetch + { + return new Expr\ConstFetch(BuilderHelpers::normalizeName($name)); + } + /** + * Creates a property fetch node. + * + * @param Expr $var Variable holding object + * @param string|Identifier|Expr $name Property name + */ + public function propertyFetch(Expr $var, $name): Expr\PropertyFetch + { + return new Expr\PropertyFetch($var, BuilderHelpers::normalizeIdentifierOrExpr($name)); + } + /** + * Creates a class constant fetch node. + * + * @param string|Name|Expr $class Class name + * @param string|Identifier|Expr $name Constant name + */ + public function classConstFetch($class, $name): Expr\ClassConstFetch + { + return new Expr\ClassConstFetch(BuilderHelpers::normalizeNameOrExpr($class), BuilderHelpers::normalizeIdentifierOrExpr($name)); + } + /** + * Creates nested Concat nodes from a list of expressions. + * + * @param Expr|string ...$exprs Expressions or literal strings + */ + public function concat(...$exprs): Concat + { + $numExprs = count($exprs); + if ($numExprs < 2) { + throw new \LogicException('Expected at least two expressions'); + } + $lastConcat = $this->normalizeStringExpr($exprs[0]); + for ($i = 1; $i < $numExprs; $i++) { + $lastConcat = new Concat($lastConcat, $this->normalizeStringExpr($exprs[$i])); + } + return $lastConcat; + } + /** + * @param string|Expr $expr + */ + private function normalizeStringExpr($expr): Expr + { + if ($expr instanceof Expr) { + return $expr; + } + if (\is_string($expr)) { + return new String_($expr); + } + throw new \LogicException('Expected string or Expr'); + } +} +getNode(); + } + if ($node instanceof Node) { + return $node; + } + throw new \LogicException('Expected node or builder object'); + } + /** + * Normalizes a node to a statement. + * + * Expressions are wrapped in a Stmt\Expression node. + * + * @param Node|Builder $node The node to normalize + * + * @return Stmt The normalized statement node + */ + public static function normalizeStmt($node): Stmt + { + $node = self::normalizeNode($node); + if ($node instanceof Stmt) { + return $node; + } + if ($node instanceof Expr) { + return new Stmt\Expression($node); + } + throw new \LogicException('Expected statement or expression node'); + } + /** + * Normalizes strings to Identifier. + * + * @param string|Identifier $name The identifier to normalize + * + * @return Identifier The normalized identifier + */ + public static function normalizeIdentifier($name): Identifier + { + if ($name instanceof Identifier) { + return $name; + } + if (\is_string($name)) { + return new Identifier($name); + } + throw new \LogicException('Expected string or instance of Node\Identifier'); + } + /** + * Normalizes strings to Identifier, also allowing expressions. + * + * @param string|Identifier|Expr $name The identifier to normalize + * + * @return Identifier|Expr The normalized identifier or expression + */ + public static function normalizeIdentifierOrExpr($name) + { + if ($name instanceof Identifier || $name instanceof Expr) { + return $name; + } + if (\is_string($name)) { + return new Identifier($name); + } + throw new \LogicException('Expected string or instance of Node\Identifier or Node\Expr'); + } + /** + * Normalizes a name: Converts string names to Name nodes. + * + * @param Name|string $name The name to normalize + * + * @return Name The normalized name + */ + public static function normalizeName($name): Name + { + if ($name instanceof Name) { + return $name; + } + if (is_string($name)) { + if (!$name) { + throw new \LogicException('Name cannot be empty'); + } + if ($name[0] === '\\') { + return new Name\FullyQualified(substr($name, 1)); + } + if (0 === strpos($name, 'namespace\\')) { + return new Name\Relative(substr($name, strlen('namespace\\'))); + } + return new Name($name); + } + throw new \LogicException('Name must be a string or an instance of Node\Name'); + } + /** + * Normalizes a name: Converts string names to Name nodes, while also allowing expressions. + * + * @param Expr|Name|string $name The name to normalize + * + * @return Name|Expr The normalized name or expression + */ + public static function normalizeNameOrExpr($name) + { + if ($name instanceof Expr) { + return $name; + } + if (!is_string($name) && !$name instanceof Name) { + throw new \LogicException('Name must be a string or an instance of Node\Name or Node\Expr'); + } + return self::normalizeName($name); + } + /** + * Normalizes a type: Converts plain-text type names into proper AST representation. + * + * In particular, builtin types become Identifiers, custom types become Names and nullables + * are wrapped in NullableType nodes. + * + * @param string|Name|Identifier|ComplexType $type The type to normalize + * + * @return Name|Identifier|ComplexType The normalized type + */ + public static function normalizeType($type) + { + if (!is_string($type)) { + if (!$type instanceof Name && !$type instanceof Identifier && !$type instanceof ComplexType) { + throw new \LogicException('Type must be a string, or an instance of Name, Identifier or ComplexType'); + } + return $type; + } + $nullable = \false; + if (strlen($type) > 0 && $type[0] === '?') { + $nullable = \true; + $type = substr($type, 1); + } + $builtinTypes = ['array', 'callable', 'bool', 'int', 'float', 'string', 'iterable', 'void', 'object', 'null', 'false', 'mixed', 'never', 'true']; + $lowerType = strtolower($type); + if (in_array($lowerType, $builtinTypes)) { + $type = new Identifier($lowerType); + } else { + $type = self::normalizeName($type); + } + $notNullableTypes = ['void', 'mixed', 'never']; + if ($nullable && in_array((string) $type, $notNullableTypes)) { + throw new \LogicException(sprintf('%s type cannot be nullable', $type)); + } + return $nullable ? new NullableType($type) : $type; + } + /** + * Normalizes a value: Converts nulls, booleans, integers, + * floats, strings and arrays into their respective nodes + * + * @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value The value to normalize + * + * @return Expr The normalized value + */ + public static function normalizeValue($value): Expr + { + if ($value instanceof Node\Expr) { + return $value; + } + if (is_null($value)) { + return new Expr\ConstFetch(new Name('null')); + } + if (is_bool($value)) { + return new Expr\ConstFetch(new Name($value ? 'true' : 'false')); + } + if (is_int($value)) { + return new Scalar\Int_($value); + } + if (is_float($value)) { + return new Scalar\Float_($value); + } + if (is_string($value)) { + return new Scalar\String_($value); + } + if (is_array($value)) { + $items = []; + $lastKey = -1; + foreach ($value as $itemKey => $itemValue) { + // for consecutive, numeric keys don't generate keys + if (null !== $lastKey && ++$lastKey === $itemKey) { + $items[] = new Node\ArrayItem(self::normalizeValue($itemValue)); + } else { + $lastKey = null; + $items[] = new Node\ArrayItem(self::normalizeValue($itemValue), self::normalizeValue($itemKey)); + } + } + return new Expr\Array_($items); + } + if ($value instanceof \UnitEnum) { + return new Expr\ClassConstFetch(new FullyQualified(\get_class($value)), new Identifier($value->name)); + } + throw new \LogicException('Invalid value'); + } + /** + * Normalizes a doc comment: Converts plain strings to PhpParser\Comment\Doc. + * + * @param Comment\Doc|string $docComment The doc comment to normalize + * + * @return Comment\Doc The normalized doc comment + */ + public static function normalizeDocComment($docComment): Comment\Doc + { + if ($docComment instanceof Comment\Doc) { + return $docComment; + } + if (is_string($docComment)) { + return new Comment\Doc($docComment); + } + throw new \LogicException('Doc comment must be a string or an instance of PhpParser\Comment\Doc'); + } + /** + * Normalizes a attribute: Converts attribute to the Attribute Group if needed. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return Node\AttributeGroup The Attribute Group + */ + public static function normalizeAttribute($attribute): Node\AttributeGroup + { + if ($attribute instanceof Node\AttributeGroup) { + return $attribute; + } + if (!$attribute instanceof Node\Attribute) { + throw new \LogicException('Attribute must be an instance of PhpParser\Node\Attribute or PhpParser\Node\AttributeGroup'); + } + return new Node\AttributeGroup([$attribute]); + } + /** + * Adds a modifier and returns new modifier bitmask. + * + * @param int $modifiers Existing modifiers + * @param int $modifier Modifier to set + * + * @return int New modifiers + */ + public static function addModifier(int $modifiers, int $modifier): int + { + Modifiers::verifyModifier($modifiers, $modifier); + return $modifiers | $modifier; + } + /** + * Adds a modifier and returns new modifier bitmask. + * @return int New modifiers + */ + public static function addClassModifier(int $existingModifiers, int $modifierToSet): int + { + Modifiers::verifyClassModifier($existingModifiers, $modifierToSet); + return $existingModifiers | $modifierToSet; + } +} +text = $text; + $this->startLine = $startLine; + $this->startFilePos = $startFilePos; + $this->startTokenPos = $startTokenPos; + $this->endLine = $endLine; + $this->endFilePos = $endFilePos; + $this->endTokenPos = $endTokenPos; + } + /** + * Gets the comment text. + * + * @return string The comment text (including comment delimiters like /*) + */ + public function getText(): string + { + return $this->text; + } + /** + * Gets the line number the comment started on. + * + * @return int Line number (or -1 if not available) + * @phpstan-return -1|positive-int + */ + public function getStartLine(): int + { + return $this->startLine; + } + /** + * Gets the file offset the comment started on. + * + * @return int File offset (or -1 if not available) + */ + public function getStartFilePos(): int + { + return $this->startFilePos; + } + /** + * Gets the token offset the comment started on. + * + * @return int Token offset (or -1 if not available) + */ + public function getStartTokenPos(): int + { + return $this->startTokenPos; + } + /** + * Gets the line number the comment ends on. + * + * @return int Line number (or -1 if not available) + * @phpstan-return -1|positive-int + */ + public function getEndLine(): int + { + return $this->endLine; + } + /** + * Gets the file offset the comment ends on. + * + * @return int File offset (or -1 if not available) + */ + public function getEndFilePos(): int + { + return $this->endFilePos; + } + /** + * Gets the token offset the comment ends on. + * + * @return int Token offset (or -1 if not available) + */ + public function getEndTokenPos(): int + { + return $this->endTokenPos; + } + /** + * Gets the comment text. + * + * @return string The comment text (including comment delimiters like /*) + */ + public function __toString(): string + { + return $this->text; + } + /** + * Gets the reformatted comment text. + * + * "Reformatted" here means that we try to clean up the whitespace at the + * starts of the lines. This is necessary because we receive the comments + * without leading whitespace on the first line, but with leading whitespace + * on all subsequent lines. + * + * Additionally, this normalizes CRLF newlines to LF newlines. + */ + public function getReformattedText(): string + { + $text = str_replace("\r\n", "\n", $this->text); + $newlinePos = strpos($text, "\n"); + if (\false === $newlinePos) { + // Single line comments don't need further processing + return $text; + } + if (preg_match('(^.*(?:\n\s+\*.*)+$)', $text)) { + // Multi line comment of the type + // + // /* + // * Some text. + // * Some more text. + // */ + // + // is handled by replacing the whitespace sequences before the * by a single space + return preg_replace('(^\s+\*)m', ' *', $text); + } + if (preg_match('(^/\*\*?\s*\n)', $text) && preg_match('(\n(\s*)\*/$)', $text, $matches)) { + // Multi line comment of the type + // + // /* + // Some text. + // Some more text. + // */ + // + // is handled by removing the whitespace sequence on the line before the closing + // */ on all lines. So if the last line is " */", then " " is removed at the + // start of all lines. + return preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $text); + } + if (preg_match('(^/\*\*?\s*(?!\s))', $text, $matches)) { + // Multi line comment of the type + // + // /* Some text. + // Some more text. + // Indented text. + // Even more text. */ + // + // is handled by removing the difference between the shortest whitespace prefix on all + // lines and the length of the "/* " opening sequence. + $prefixLen = $this->getShortestWhitespacePrefixLen(substr($text, $newlinePos + 1)); + $removeLen = $prefixLen - strlen($matches[0]); + return preg_replace('(^\s{' . $removeLen . '})m', '', $text); + } + // No idea how to format this comment, so simply return as is + return $text; + } + /** + * Get length of shortest whitespace prefix (at the start of a line). + * + * If there is a line with no prefix whitespace, 0 is a valid return value. + * + * @param string $str String to check + * @return int Length in characters. Tabs count as single characters. + */ + private function getShortestWhitespacePrefixLen(string $str): int + { + $lines = explode("\n", $str); + $shortestPrefixLen = \PHP_INT_MAX; + foreach ($lines as $line) { + preg_match('(^\s*)', $line, $matches); + $prefixLen = strlen($matches[0]); + if ($prefixLen < $shortestPrefixLen) { + $shortestPrefixLen = $prefixLen; + } + } + return $shortestPrefixLen; + } + /** + * @return array{nodeType:string, text:mixed, line:mixed, filePos:mixed} + */ + public function jsonSerialize(): array + { + // Technically not a node, but we make it look like one anyway + $type = $this instanceof Comment\Doc ? 'Comment_Doc' : 'Comment'; + return [ + 'nodeType' => $type, + 'text' => $this->text, + // TODO: Rename these to include "start". + 'line' => $this->startLine, + 'filePos' => $this->startFilePos, + 'tokenPos' => $this->startTokenPos, + 'endLine' => $this->endLine, + 'endFilePos' => $this->endFilePos, + 'endTokenPos' => $this->endTokenPos, + ]; + } +} +fallbackEvaluator = $fallbackEvaluator ?? function (Expr $expr) { + throw new ConstExprEvaluationException("Expression of type {$expr->getType()} cannot be evaluated"); + }; + } + /** + * Silently evaluates a constant expression into a PHP value. + * + * Thrown Errors, warnings or notices will be converted into a ConstExprEvaluationException. + * The original source of the exception is available through getPrevious(). + * + * If some part of the expression cannot be evaluated, the fallback evaluator passed to the + * constructor will be invoked. By default, if no fallback is provided, an exception of type + * ConstExprEvaluationException is thrown. + * + * See class doc comment for caveats and limitations. + * + * @param Expr $expr Constant expression to evaluate + * @return mixed Result of evaluation + * + * @throws ConstExprEvaluationException if the expression cannot be evaluated or an error occurred + */ + public function evaluateSilently(Expr $expr) + { + set_error_handler(function ($num, $str, $file, $line) { + throw new \ErrorException($str, 0, $num, $file, $line); + }); + try { + return $this->evaluate($expr); + } catch (\Throwable $e) { + if (!$e instanceof ConstExprEvaluationException) { + $e = new ConstExprEvaluationException("An error occurred during constant expression evaluation", 0, $e); + } + throw $e; + } finally { + restore_error_handler(); + } + } + /** + * Directly evaluates a constant expression into a PHP value. + * + * May generate Error exceptions, warnings or notices. Use evaluateSilently() to convert these + * into a ConstExprEvaluationException. + * + * If some part of the expression cannot be evaluated, the fallback evaluator passed to the + * constructor will be invoked. By default, if no fallback is provided, an exception of type + * ConstExprEvaluationException is thrown. + * + * See class doc comment for caveats and limitations. + * + * @param Expr $expr Constant expression to evaluate + * @return mixed Result of evaluation + * + * @throws ConstExprEvaluationException if the expression cannot be evaluated + */ + public function evaluateDirectly(Expr $expr) + { + return $this->evaluate($expr); + } + /** @return mixed */ + private function evaluate(Expr $expr) + { + if ($expr instanceof Scalar\Int_ || $expr instanceof Scalar\Float_ || $expr instanceof Scalar\String_) { + return $expr->value; + } + if ($expr instanceof Expr\Array_) { + return $this->evaluateArray($expr); + } + // Unary operators + if ($expr instanceof Expr\UnaryPlus) { + return +$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\UnaryMinus) { + return -$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\BooleanNot) { + return !$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\BitwiseNot) { + return ~$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\BinaryOp) { + return $this->evaluateBinaryOp($expr); + } + if ($expr instanceof Expr\Ternary) { + return $this->evaluateTernary($expr); + } + if ($expr instanceof Expr\ArrayDimFetch && null !== $expr->dim) { + return $this->evaluate($expr->var)[$this->evaluate($expr->dim)]; + } + if ($expr instanceof Expr\ConstFetch) { + return $this->evaluateConstFetch($expr); + } + return ($this->fallbackEvaluator)($expr); + } + private function evaluateArray(Expr\Array_ $expr): array + { + $array = []; + foreach ($expr->items as $item) { + if (null !== $item->key) { + $array[$this->evaluate($item->key)] = $this->evaluate($item->value); + } elseif ($item->unpack) { + $array = array_merge($array, $this->evaluate($item->value)); + } else { + $array[] = $this->evaluate($item->value); + } + } + return $array; + } + /** @return mixed */ + private function evaluateTernary(Expr\Ternary $expr) + { + if (null === $expr->if) { + return $this->evaluate($expr->cond) ?: $this->evaluate($expr->else); + } + return $this->evaluate($expr->cond) ? $this->evaluate($expr->if) : $this->evaluate($expr->else); + } + /** @return mixed */ + private function evaluateBinaryOp(Expr\BinaryOp $expr) + { + if ($expr instanceof Expr\BinaryOp\Coalesce && $expr->left instanceof Expr\ArrayDimFetch) { + // This needs to be special cased to respect BP_VAR_IS fetch semantics + return $this->evaluate($expr->left->var)[$this->evaluate($expr->left->dim)] ?? $this->evaluate($expr->right); + } + // The evaluate() calls are repeated in each branch, because some of the operators are + // short-circuiting and evaluating the RHS in advance may be illegal in that case + $l = $expr->left; + $r = $expr->right; + switch ($expr->getOperatorSigil()) { + case '&': + return $this->evaluate($l) & $this->evaluate($r); + case '|': + return $this->evaluate($l) | $this->evaluate($r); + case '^': + return $this->evaluate($l) ^ $this->evaluate($r); + case '&&': + return $this->evaluate($l) && $this->evaluate($r); + case '||': + return $this->evaluate($l) || $this->evaluate($r); + case '??': + return $this->evaluate($l) ?? $this->evaluate($r); + case '.': + return $this->evaluate($l) . $this->evaluate($r); + case '/': + return $this->evaluate($l) / $this->evaluate($r); + case '==': + return $this->evaluate($l) == $this->evaluate($r); + case '>': + return $this->evaluate($l) > $this->evaluate($r); + case '>=': + return $this->evaluate($l) >= $this->evaluate($r); + case '===': + return $this->evaluate($l) === $this->evaluate($r); + case 'and': + return $this->evaluate($l) and $this->evaluate($r); + case 'or': + return $this->evaluate($l) or $this->evaluate($r); + case 'xor': + return $this->evaluate($l) xor $this->evaluate($r); + case '-': + return $this->evaluate($l) - $this->evaluate($r); + case '%': + return $this->evaluate($l) % $this->evaluate($r); + case '*': + return $this->evaluate($l) * $this->evaluate($r); + case '!=': + return $this->evaluate($l) != $this->evaluate($r); + case '!==': + return $this->evaluate($l) !== $this->evaluate($r); + case '+': + return $this->evaluate($l) + $this->evaluate($r); + case '**': + return $this->evaluate($l) ** $this->evaluate($r); + case '<<': + return $this->evaluate($l) << $this->evaluate($r); + case '>>': + return $this->evaluate($l) >> $this->evaluate($r); + case '<': + return $this->evaluate($l) < $this->evaluate($r); + case '<=': + return $this->evaluate($l) <= $this->evaluate($r); + case '<=>': + return $this->evaluate($l) <=> $this->evaluate($r); + case '|>': + $lval = $this->evaluate($l); + return $this->evaluate($r)($lval); + } + throw new \Exception('Should not happen'); + } + /** @return mixed */ + private function evaluateConstFetch(Expr\ConstFetch $expr) + { + $name = $expr->name->toLowerString(); + switch ($name) { + case 'null': + return null; + case 'false': + return \false; + case 'true': + return \true; + } + return ($this->fallbackEvaluator)($expr); + } +} + */ + protected array $attributes; + /** + * Creates an Exception signifying a parse error. + * + * @param string $message Error message + * @param array $attributes Attributes of node/token where error occurred + */ + public function __construct(string $message, array $attributes = []) + { + $this->rawMessage = $message; + $this->attributes = $attributes; + $this->updateMessage(); + } + /** + * Gets the error message + * + * @return string Error message + */ + public function getRawMessage(): string + { + return $this->rawMessage; + } + /** + * Gets the line the error starts in. + * + * @return int Error start line + * @phpstan-return -1|positive-int + */ + public function getStartLine(): int + { + return $this->attributes['startLine'] ?? -1; + } + /** + * Gets the line the error ends in. + * + * @return int Error end line + * @phpstan-return -1|positive-int + */ + public function getEndLine(): int + { + return $this->attributes['endLine'] ?? -1; + } + /** + * Gets the attributes of the node/token the error occurred at. + * + * @return array + */ + public function getAttributes(): array + { + return $this->attributes; + } + /** + * Sets the attributes of the node/token the error occurred at. + * + * @param array $attributes + */ + public function setAttributes(array $attributes): void + { + $this->attributes = $attributes; + $this->updateMessage(); + } + /** + * Sets the line of the PHP file the error occurred in. + * + * @param string $message Error message + */ + public function setRawMessage(string $message): void + { + $this->rawMessage = $message; + $this->updateMessage(); + } + /** + * Sets the line the error starts in. + * + * @param int $line Error start line + */ + public function setStartLine(int $line): void + { + $this->attributes['startLine'] = $line; + $this->updateMessage(); + } + /** + * Returns whether the error has start and end column information. + * + * For column information enable the startFilePos and endFilePos in the lexer options. + */ + public function hasColumnInfo(): bool + { + return isset($this->attributes['startFilePos'], $this->attributes['endFilePos']); + } + /** + * Gets the start column (1-based) into the line where the error started. + * + * @param string $code Source code of the file + */ + public function getStartColumn(string $code): int + { + if (!$this->hasColumnInfo()) { + throw new \RuntimeException('Error does not have column information'); + } + return $this->toColumn($code, $this->attributes['startFilePos']); + } + /** + * Gets the end column (1-based) into the line where the error ended. + * + * @param string $code Source code of the file + */ + public function getEndColumn(string $code): int + { + if (!$this->hasColumnInfo()) { + throw new \RuntimeException('Error does not have column information'); + } + return $this->toColumn($code, $this->attributes['endFilePos']); + } + /** + * Formats message including line and column information. + * + * @param string $code Source code associated with the error, for calculation of the columns + * + * @return string Formatted message + */ + public function getMessageWithColumnInfo(string $code): string + { + return sprintf('%s from %d:%d to %d:%d', $this->getRawMessage(), $this->getStartLine(), $this->getStartColumn($code), $this->getEndLine(), $this->getEndColumn($code)); + } + /** + * Converts a file offset into a column. + * + * @param string $code Source code that $pos indexes into + * @param int $pos 0-based position in $code + * + * @return int 1-based column (relative to start of line) + */ + private function toColumn(string $code, int $pos): int + { + if ($pos > strlen($code)) { + throw new \RuntimeException('Invalid position information'); + } + $lineStartPos = strrpos($code, "\n", $pos - strlen($code)); + if (\false === $lineStartPos) { + $lineStartPos = -1; + } + return $pos - $lineStartPos; + } + /** + * Updates the exception message after a change to rawMessage or rawLine. + */ + protected function updateMessage(): void + { + $this->message = $this->rawMessage; + if (-1 === $this->getStartLine()) { + $this->message .= ' on unknown line'; + } else { + $this->message .= ' on line ' . $this->getStartLine(); + } + } +} +errors[] = $error; + } + /** + * Get collected errors. + * + * @return Error[] + */ + public function getErrors(): array + { + return $this->errors; + } + /** + * Check whether there are any errors. + */ + public function hasErrors(): bool + { + return !empty($this->errors); + } + /** + * Reset/clear collected errors. + */ + public function clearErrors(): void + { + $this->errors = []; + } +} +type = $type; + $this->old = $old; + $this->new = $new; + } +} +isEqual = $isEqual; + } + /** + * Calculate diff (edit script) from $old to $new. + * + * @param T[] $old Original array + * @param T[] $new New array + * + * @return DiffElem[] Diff (edit script) + */ + public function diff(array $old, array $new): array + { + $old = \array_values($old); + $new = \array_values($new); + list($trace, $x, $y) = $this->calculateTrace($old, $new); + return $this->extractDiff($trace, $x, $y, $old, $new); + } + /** + * Calculate diff, including "replace" operations. + * + * If a sequence of remove operations is followed by the same number of add operations, these + * will be coalesced into replace operations. + * + * @param T[] $old Original array + * @param T[] $new New array + * + * @return DiffElem[] Diff (edit script), including replace operations + */ + public function diffWithReplacements(array $old, array $new): array + { + return $this->coalesceReplacements($this->diff($old, $new)); + } + /** + * @param T[] $old + * @param T[] $new + * @return array{array>, int, int} + */ + private function calculateTrace(array $old, array $new): array + { + $n = \count($old); + $m = \count($new); + $max = $n + $m; + $v = [1 => 0]; + $trace = []; + for ($d = 0; $d <= $max; $d++) { + $trace[] = $v; + for ($k = -$d; $k <= $d; $k += 2) { + if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { + $x = $v[$k + 1]; + } else { + $x = $v[$k - 1] + 1; + } + $y = $x - $k; + while ($x < $n && $y < $m && ($this->isEqual)($old[$x], $new[$y])) { + $x++; + $y++; + } + $v[$k] = $x; + if ($x >= $n && $y >= $m) { + return [$trace, $x, $y]; + } + } + } + throw new \Exception('Should not happen'); + } + /** + * @param array> $trace + * @param T[] $old + * @param T[] $new + * @return DiffElem[] + */ + private function extractDiff(array $trace, int $x, int $y, array $old, array $new): array + { + $result = []; + for ($d = \count($trace) - 1; $d >= 0; $d--) { + $v = $trace[$d]; + $k = $x - $y; + if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { + $prevK = $k + 1; + } else { + $prevK = $k - 1; + } + $prevX = $v[$prevK]; + $prevY = $prevX - $prevK; + while ($x > $prevX && $y > $prevY) { + $result[] = new DiffElem(DiffElem::TYPE_KEEP, $old[$x - 1], $new[$y - 1]); + $x--; + $y--; + } + if ($d === 0) { + break; + } + while ($x > $prevX) { + $result[] = new DiffElem(DiffElem::TYPE_REMOVE, $old[$x - 1], null); + $x--; + } + while ($y > $prevY) { + $result[] = new DiffElem(DiffElem::TYPE_ADD, null, $new[$y - 1]); + $y--; + } + } + return array_reverse($result); + } + /** + * Coalesce equal-length sequences of remove+add into a replace operation. + * + * @param DiffElem[] $diff + * @return DiffElem[] + */ + private function coalesceReplacements(array $diff): array + { + $newDiff = []; + $c = \count($diff); + for ($i = 0; $i < $c; $i++) { + $diffType = $diff[$i]->type; + if ($diffType !== DiffElem::TYPE_REMOVE) { + $newDiff[] = $diff[$i]; + continue; + } + $j = $i; + while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) { + $j++; + } + $k = $j; + while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) { + $k++; + } + if ($j - $i === $k - $j) { + $len = $j - $i; + for ($n = 0; $n < $len; $n++) { + $newDiff[] = new DiffElem(DiffElem::TYPE_REPLACE, $diff[$i + $n]->old, $diff[$j + $n]->new); + } + } else { + for (; $i < $k; $i++) { + $newDiff[] = $diff[$i]; + } + } + $i = $k - 1; + } + return $newDiff; + } +} + $attributes Attributes + */ + public function __construct(array $attrGroups, int $flags, array $args, ?Node\Name $extends, array $implements, array $stmts, array $attributes) + { + parent::__construct($attributes); + $this->attrGroups = $attrGroups; + $this->flags = $flags; + $this->args = $args; + $this->extends = $extends; + $this->implements = $implements; + $this->stmts = $stmts; + } + public static function fromNewNode(Expr\New_ $newNode): self + { + $class = $newNode->class; + assert($class instanceof Node\Stmt\Class_); + // We don't assert that $class->name is null here, to allow consumers to assign unique names + // to anonymous classes for their own purposes. We simplify ignore the name here. + return new self($class->attrGroups, $class->flags, $newNode->args, $class->extends, $class->implements, $class->stmts, $newNode->getAttributes()); + } + public function getType(): string + { + return 'Expr_PrintableNewAnonClass'; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'flags', 'args', 'extends', 'implements', 'stmts']; + } +} += 80000) { + class TokenPolyfill extends \PhpToken + { + } + return; +} +/** + * This is a polyfill for the PhpToken class introduced in PHP 8.0. We do not actually polyfill + * PhpToken, because composer might end up picking a different polyfill implementation, which does + * not meet our requirements. + * + * @internal + */ +class TokenPolyfill +{ + /** @var int The ID of the token. Either a T_* constant of a character code < 256. */ + public int $id; + /** @var string The textual content of the token. */ + public string $text; + /** @var int The 1-based starting line of the token (or -1 if unknown). */ + public int $line; + /** @var int The 0-based starting position of the token (or -1 if unknown). */ + public int $pos; + /** @var array Tokens ignored by the PHP parser. */ + private const IGNORABLE_TOKENS = [\T_WHITESPACE => \true, \T_COMMENT => \true, \T_DOC_COMMENT => \true, \T_OPEN_TAG => \true]; + /** @var array Tokens that may be part of a T_NAME_* identifier. */ + private static array $identifierTokens; + /** + * Create a Token with the given ID and text, as well optional line and position information. + */ + final public function __construct(int $id, string $text, int $line = -1, int $pos = -1) + { + $this->id = $id; + $this->text = $text; + $this->line = $line; + $this->pos = $pos; + } + /** + * Get the name of the token. For single-char tokens this will be the token character. + * Otherwise it will be a T_* style name, or null if the token ID is unknown. + */ + public function getTokenName(): ?string + { + if ($this->id < 256) { + return \chr($this->id); + } + $name = token_name($this->id); + return $name === 'UNKNOWN' ? null : $name; + } + /** + * Check whether the token is of the given kind. The kind may be either an integer that matches + * the token ID, a string that matches the token text, or an array of integers/strings. In the + * latter case, the function returns true if any of the kinds in the array match. + * + * @param int|string|(int|string)[] $kind + */ + public function is($kind): bool + { + if (\is_int($kind)) { + return $this->id === $kind; + } + if (\is_string($kind)) { + return $this->text === $kind; + } + if (\is_array($kind)) { + foreach ($kind as $entry) { + if (\is_int($entry)) { + if ($this->id === $entry) { + return \true; + } + } elseif (\is_string($entry)) { + if ($this->text === $entry) { + return \true; + } + } else { + throw new \TypeError('Argument #1 ($kind) must only have elements of type string|int, ' . gettype($entry) . ' given'); + } + } + return \false; + } + throw new \TypeError('Argument #1 ($kind) must be of type string|int|array, ' . gettype($kind) . ' given'); + } + /** + * Check whether this token would be ignored by the PHP parser. Returns true for T_WHITESPACE, + * T_COMMENT, T_DOC_COMMENT and T_OPEN_TAG, and false for everything else. + */ + public function isIgnorable(): bool + { + return isset(self::IGNORABLE_TOKENS[$this->id]); + } + /** + * Return the textual content of the token. + */ + public function __toString(): string + { + return $this->text; + } + /** + * Tokenize the given source code and return an array of tokens. + * + * This performs certain canonicalizations to match the PHP 8.0 token format: + * * Bad characters are represented using T_BAD_CHARACTER rather than omitted. + * * T_COMMENT does not include trailing newlines, instead the newline is part of a following + * T_WHITESPACE token. + * * Namespaced names are represented using T_NAME_* tokens. + * + * @return static[] + */ + public static function tokenize(string $code, int $flags = 0): array + { + self::init(); + $tokens = []; + $line = 1; + $pos = 0; + $origTokens = \token_get_all($code, $flags); + $numTokens = \count($origTokens); + for ($i = 0; $i < $numTokens; $i++) { + $token = $origTokens[$i]; + if (\is_string($token)) { + if (\strlen($token) === 2) { + // b" and B" are tokenized as single-char tokens, even though they aren't. + $tokens[] = new static(\ord('"'), $token, $line, $pos); + $pos += 2; + } else { + $tokens[] = new static(\ord($token), $token, $line, $pos); + $pos++; + } + } else { + $id = $token[0]; + $text = $token[1]; + // Emulate PHP 8.0 comment format, which does not include trailing whitespace anymore. + if ($id === \T_COMMENT && \substr($text, 0, 2) !== '/*' && \preg_match('/(\r\n|\n|\r)$/D', $text, $matches)) { + $trailingNewline = $matches[0]; + $text = \substr($text, 0, -\strlen($trailingNewline)); + $tokens[] = new static($id, $text, $line, $pos); + $pos += \strlen($text); + if ($i + 1 < $numTokens && $origTokens[$i + 1][0] === \T_WHITESPACE) { + // Move trailing newline into following T_WHITESPACE token, if it already exists. + $origTokens[$i + 1][1] = $trailingNewline . $origTokens[$i + 1][1]; + $origTokens[$i + 1][2]--; + } else { + // Otherwise, we need to create a new T_WHITESPACE token. + $tokens[] = new static(\T_WHITESPACE, $trailingNewline, $line, $pos); + $line++; + $pos += \strlen($trailingNewline); + } + continue; + } + // Emulate PHP 8.0 T_NAME_* tokens, by combining sequences of T_NS_SEPARATOR and + // T_STRING into a single token. + if ($id === \T_NS_SEPARATOR || isset(self::$identifierTokens[$id])) { + $newText = $text; + $lastWasSeparator = $id === \T_NS_SEPARATOR; + for ($j = $i + 1; $j < $numTokens; $j++) { + if ($lastWasSeparator) { + if (!isset(self::$identifierTokens[$origTokens[$j][0]])) { + break; + } + $lastWasSeparator = \false; + } else { + if ($origTokens[$j][0] !== \T_NS_SEPARATOR) { + break; + } + $lastWasSeparator = \true; + } + $newText .= $origTokens[$j][1]; + } + if ($lastWasSeparator) { + // Trailing separator is not part of the name. + $j--; + $newText = \substr($newText, 0, -1); + } + if ($j > $i + 1) { + if ($id === \T_NS_SEPARATOR) { + $id = \T_NAME_FULLY_QUALIFIED; + } elseif ($id === \T_NAMESPACE) { + $id = \T_NAME_RELATIVE; + } else { + $id = \T_NAME_QUALIFIED; + } + $tokens[] = new static($id, $newText, $line, $pos); + $pos += \strlen($newText); + $i = $j - 1; + continue; + } + } + $tokens[] = new static($id, $text, $line, $pos); + $line += \substr_count($text, "\n"); + $pos += \strlen($text); + } + } + return $tokens; + } + /** Initialize private static state needed by tokenize(). */ + private static function init(): void + { + if (isset(self::$identifierTokens)) { + return; + } + // Based on semi_reserved production. + self::$identifierTokens = \array_fill_keys([\T_STRING, \T_STATIC, \T_ABSTRACT, \T_FINAL, \T_PRIVATE, \T_PROTECTED, \T_PUBLIC, \T_READONLY, \T_INCLUDE, \T_INCLUDE_ONCE, \T_EVAL, \T_REQUIRE, \T_REQUIRE_ONCE, \T_LOGICAL_OR, \T_LOGICAL_XOR, \T_LOGICAL_AND, \T_INSTANCEOF, \T_NEW, \T_CLONE, \T_EXIT, \T_IF, \T_ELSEIF, \T_ELSE, \T_ENDIF, \T_ECHO, \T_DO, \T_WHILE, \T_ENDWHILE, \T_FOR, \T_ENDFOR, \T_FOREACH, \T_ENDFOREACH, \T_DECLARE, \T_ENDDECLARE, \T_AS, \T_TRY, \T_CATCH, \T_FINALLY, \T_THROW, \T_USE, \T_INSTEADOF, \T_GLOBAL, \T_VAR, \T_UNSET, \T_ISSET, \T_EMPTY, \T_CONTINUE, \T_GOTO, \T_FUNCTION, \T_CONST, \T_RETURN, \T_PRINT, \T_YIELD, \T_LIST, \T_SWITCH, \T_ENDSWITCH, \T_CASE, \T_DEFAULT, \T_BREAK, \T_ARRAY, \T_CALLABLE, \T_EXTENDS, \T_IMPLEMENTS, \T_NAMESPACE, \T_TRAIT, \T_INTERFACE, \T_CLASS, \T_CLASS_C, \T_TRAIT_C, \T_FUNC_C, \T_METHOD_C, \T_LINE, \T_FILE, \T_DIR, \T_NS_C, \T_HALT_COMPILER, \T_FN, \T_MATCH], \true); + } +} +tokens = $tokens; + $this->indentMap = $this->calcIndentMap($tabWidth); + } + /** + * Whether the given position is immediately surrounded by parenthesis. + * + * @param int $startPos Start position + * @param int $endPos End position + */ + public function haveParens(int $startPos, int $endPos): bool + { + return $this->haveTokenImmediatelyBefore($startPos, '(') && $this->haveTokenImmediatelyAfter($endPos, ')'); + } + /** + * Whether the given position is immediately surrounded by braces. + * + * @param int $startPos Start position + * @param int $endPos End position + */ + public function haveBraces(int $startPos, int $endPos): bool + { + return ($this->haveTokenImmediatelyBefore($startPos, '{') || $this->haveTokenImmediatelyBefore($startPos, \T_CURLY_OPEN)) && $this->haveTokenImmediatelyAfter($endPos, '}'); + } + /** + * Check whether the position is directly preceded by a certain token type. + * + * During this check whitespace and comments are skipped. + * + * @param int $pos Position before which the token should occur + * @param int|string $expectedTokenType Token to check for + * + * @return bool Whether the expected token was found + */ + public function haveTokenImmediatelyBefore(int $pos, $expectedTokenType): bool + { + $tokens = $this->tokens; + $pos--; + for (; $pos >= 0; $pos--) { + $token = $tokens[$pos]; + if ($token->is($expectedTokenType)) { + return \true; + } + if (!$token->isIgnorable()) { + break; + } + } + return \false; + } + /** + * Check whether the position is directly followed by a certain token type. + * + * During this check whitespace and comments are skipped. + * + * @param int $pos Position after which the token should occur + * @param int|string $expectedTokenType Token to check for + * + * @return bool Whether the expected token was found + */ + public function haveTokenImmediatelyAfter(int $pos, $expectedTokenType): bool + { + $tokens = $this->tokens; + $pos++; + for ($c = \count($tokens); $pos < $c; $pos++) { + $token = $tokens[$pos]; + if ($token->is($expectedTokenType)) { + return \true; + } + if (!$token->isIgnorable()) { + break; + } + } + return \false; + } + /** @param int|string|(int|string)[] $skipTokenType */ + public function skipLeft(int $pos, $skipTokenType): int + { + $tokens = $this->tokens; + $pos = $this->skipLeftWhitespace($pos); + if ($skipTokenType === \T_WHITESPACE) { + return $pos; + } + if (!$tokens[$pos]->is($skipTokenType)) { + // Shouldn't happen. The skip token MUST be there + throw new \Exception('Encountered unexpected token'); + } + $pos--; + return $this->skipLeftWhitespace($pos); + } + /** @param int|string|(int|string)[] $skipTokenType */ + public function skipRight(int $pos, $skipTokenType): int + { + $tokens = $this->tokens; + $pos = $this->skipRightWhitespace($pos); + if ($skipTokenType === \T_WHITESPACE) { + return $pos; + } + if (!$tokens[$pos]->is($skipTokenType)) { + // Shouldn't happen. The skip token MUST be there + throw new \Exception('Encountered unexpected token'); + } + $pos++; + return $this->skipRightWhitespace($pos); + } + /** + * Return first non-whitespace token position smaller or equal to passed position. + * + * @param int $pos Token position + * @return int Non-whitespace token position + */ + public function skipLeftWhitespace(int $pos): int + { + $tokens = $this->tokens; + for (; $pos >= 0; $pos--) { + if (!$tokens[$pos]->isIgnorable()) { + break; + } + } + return $pos; + } + /** + * Return first non-whitespace position greater or equal to passed position. + * + * @param int $pos Token position + * @return int Non-whitespace token position + */ + public function skipRightWhitespace(int $pos): int + { + $tokens = $this->tokens; + for ($count = \count($tokens); $pos < $count; $pos++) { + if (!$tokens[$pos]->isIgnorable()) { + break; + } + } + return $pos; + } + /** @param int|string|(int|string)[] $findTokenType */ + public function findRight(int $pos, $findTokenType): int + { + $tokens = $this->tokens; + for ($count = \count($tokens); $pos < $count; $pos++) { + if ($tokens[$pos]->is($findTokenType)) { + return $pos; + } + } + return -1; + } + /** + * Whether the given position range contains a certain token type. + * + * @param int $startPos Starting position (inclusive) + * @param int $endPos Ending position (exclusive) + * @param int|string $tokenType Token type to look for + * @return bool Whether the token occurs in the given range + */ + public function haveTokenInRange(int $startPos, int $endPos, $tokenType): bool + { + $tokens = $this->tokens; + for ($pos = $startPos; $pos < $endPos; $pos++) { + if ($tokens[$pos]->is($tokenType)) { + return \true; + } + } + return \false; + } + public function haveTagInRange(int $startPos, int $endPos): bool + { + return $this->haveTokenInRange($startPos, $endPos, \T_OPEN_TAG) || $this->haveTokenInRange($startPos, $endPos, \T_CLOSE_TAG); + } + /** + * Get indentation before token position. + * + * @param int $pos Token position + * + * @return int Indentation depth (in spaces) + */ + public function getIndentationBefore(int $pos): int + { + return $this->indentMap[$pos]; + } + /** + * Get the code corresponding to a token offset range, optionally adjusted for indentation. + * + * @param int $from Token start position (inclusive) + * @param int $to Token end position (exclusive) + * @param int $indent By how much the code should be indented (can be negative as well) + * + * @return string Code corresponding to token range, adjusted for indentation + */ + public function getTokenCode(int $from, int $to, int $indent): string + { + $tokens = $this->tokens; + $result = ''; + for ($pos = $from; $pos < $to; $pos++) { + $token = $tokens[$pos]; + $id = $token->id; + $text = $token->text; + if ($id === \T_CONSTANT_ENCAPSED_STRING || $id === \T_ENCAPSED_AND_WHITESPACE) { + $result .= $text; + } else if ($indent < 0) { + $result .= str_replace("\n" . str_repeat(" ", -$indent), "\n", $text); + } elseif ($indent > 0) { + $result .= str_replace("\n", "\n" . str_repeat(" ", $indent), $text); + } else { + $result .= $text; + } + } + return $result; + } + /** + * Precalculate the indentation at every token position. + * + * @return int[] Token position to indentation map + */ + private function calcIndentMap(int $tabWidth): array + { + $indentMap = []; + $indent = 0; + foreach ($this->tokens as $i => $token) { + $indentMap[] = $indent; + if ($token->id === \T_WHITESPACE) { + $content = $token->text; + $newlinePos = \strrpos($content, "\n"); + if (\false !== $newlinePos) { + $indent = $this->getIndent(\substr($content, $newlinePos + 1), $tabWidth); + } elseif ($i === 1 && $this->tokens[0]->id === \T_OPEN_TAG && $this->tokens[0]->text[\strlen($this->tokens[0]->text) - 1] === "\n") { + // Special case: Newline at the end of opening tag followed by whitespace. + $indent = $this->getIndent($content, $tabWidth); + } + } + } + // Add a sentinel for one past end of the file + $indentMap[] = $indent; + return $indentMap; + } + private function getIndent(string $ws, int $tabWidth): int + { + $spaces = \substr_count($ws, " "); + $tabs = \substr_count($ws, "\t"); + assert(\strlen($ws) === $spaces + $tabs); + return $spaces + $tabs * $tabWidth; + } +} +[] Node type to reflection class map */ + private array $reflectionClassCache; + /** @return mixed */ + public function decode(string $json) + { + $value = json_decode($json, \true); + if (json_last_error()) { + throw new \RuntimeException('JSON decoding error: ' . json_last_error_msg()); + } + return $this->decodeRecursive($value); + } + /** + * @param mixed $value + * @return mixed + */ + private function decodeRecursive($value) + { + if (\is_array($value)) { + if (isset($value['nodeType'])) { + if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc') { + return $this->decodeComment($value); + } + return $this->decodeNode($value); + } + return $this->decodeArray($value); + } + return $value; + } + private function decodeArray(array $array): array + { + $decodedArray = []; + foreach ($array as $key => $value) { + $decodedArray[$key] = $this->decodeRecursive($value); + } + return $decodedArray; + } + private function decodeNode(array $value): Node + { + $nodeType = $value['nodeType']; + if (!\is_string($nodeType)) { + throw new \RuntimeException('Node type must be a string'); + } + $reflectionClass = $this->reflectionClassFromNodeType($nodeType); + $node = $reflectionClass->newInstanceWithoutConstructor(); + if (isset($value['attributes'])) { + if (!\is_array($value['attributes'])) { + throw new \RuntimeException('Attributes must be an array'); + } + $node->setAttributes($this->decodeArray($value['attributes'])); + } + foreach ($value as $name => $subNode) { + if ($name === 'nodeType' || $name === 'attributes') { + continue; + } + $node->{$name} = $this->decodeRecursive($subNode); + } + return $node; + } + private function decodeComment(array $value): Comment + { + $className = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class; + if (!isset($value['text'])) { + throw new \RuntimeException('Comment must have text'); + } + return new $className($value['text'], $value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1, $value['endLine'] ?? -1, $value['endFilePos'] ?? -1, $value['endTokenPos'] ?? -1); + } + /** @return \ReflectionClass */ + private function reflectionClassFromNodeType(string $nodeType): \ReflectionClass + { + if (!isset($this->reflectionClassCache[$nodeType])) { + $className = $this->classNameFromNodeType($nodeType); + $this->reflectionClassCache[$nodeType] = new \ReflectionClass($className); + } + return $this->reflectionClassCache[$nodeType]; + } + /** @return class-string */ + private function classNameFromNodeType(string $nodeType): string + { + $className = 'PhpParser\Node\\' . strtr($nodeType, '_', '\\'); + if (class_exists($className)) { + return $className; + } + $className .= '_'; + if (class_exists($className)) { + return $className; + } + throw new \RuntimeException("Unknown node type \"{$nodeType}\""); + } +} +postprocessTokens($tokens, $errorHandler); + if (\false !== $scream) { + ini_set('xdebug.scream', $scream); + } + return $tokens; + } + private function handleInvalidCharacter(Token $token, ErrorHandler $errorHandler): void + { + $chr = $token->text; + if ($chr === "\x00") { + // PHP cuts error message after null byte, so need special case + $errorMsg = 'Unexpected null byte'; + } else { + $errorMsg = sprintf('Unexpected character "%s" (ASCII %d)', $chr, ord($chr)); + } + $errorHandler->handleError(new Error($errorMsg, ['startLine' => $token->line, 'endLine' => $token->line, 'startFilePos' => $token->pos, 'endFilePos' => $token->pos])); + } + private function isUnterminatedComment(Token $token): bool + { + return $token->is([\T_COMMENT, \T_DOC_COMMENT]) && substr($token->text, 0, 2) === '/*' && substr($token->text, -2) !== '*/'; + } + /** + * @param list $tokens + */ + protected function postprocessTokens(array &$tokens, ErrorHandler $errorHandler): void + { + // This function reports errors (bad characters and unterminated comments) in the token + // array, and performs certain canonicalizations: + // * Use PHP 8.1 T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG and + // T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG tokens used to disambiguate intersection types. + // * Add a sentinel token with ID 0. + $numTokens = \count($tokens); + if ($numTokens === 0) { + // Empty input edge case: Just add the sentinel token. + $tokens[] = new Token(0, "\x00", 1, 0); + return; + } + for ($i = 0; $i < $numTokens; $i++) { + $token = $tokens[$i]; + if ($token->id === \T_BAD_CHARACTER) { + $this->handleInvalidCharacter($token, $errorHandler); + } + if ($token->id === \ord('&')) { + $next = $i + 1; + while (isset($tokens[$next]) && $tokens[$next]->id === \T_WHITESPACE) { + $next++; + } + $followedByVarOrVarArg = isset($tokens[$next]) && $tokens[$next]->is([\T_VARIABLE, \T_ELLIPSIS]); + $token->id = $followedByVarOrVarArg ? \T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG : \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG; + } + } + // Check for unterminated comment + $lastToken = $tokens[$numTokens - 1]; + if ($this->isUnterminatedComment($lastToken)) { + $errorHandler->handleError(new Error('Unterminated comment', ['startLine' => $lastToken->line, 'endLine' => $lastToken->getEndLine(), 'startFilePos' => $lastToken->pos, 'endFilePos' => $lastToken->getEndPos()])); + } + // Add sentinel token. + $tokens[] = new Token(0, "\x00", $lastToken->getEndLine(), $lastToken->getEndPos()); + } +} + */ + private array $emulators = []; + private PhpVersion $targetPhpVersion; + private PhpVersion $hostPhpVersion; + /** + * @param PhpVersion|null $phpVersion PHP version to emulate. Defaults to newest supported. + */ + public function __construct(?PhpVersion $phpVersion = null) + { + $this->targetPhpVersion = $phpVersion ?? PhpVersion::getNewestSupported(); + $this->hostPhpVersion = PhpVersion::getHostVersion(); + $emulators = [new MatchTokenEmulator(), new NullsafeTokenEmulator(), new AttributeEmulator(), new EnumTokenEmulator(), new ReadonlyTokenEmulator(), new ExplicitOctalEmulator(), new ReadonlyFunctionTokenEmulator(), new PropertyTokenEmulator(), new AsymmetricVisibilityTokenEmulator(), new PipeOperatorEmulator(), new VoidCastEmulator()]; + // Collect emulators that are relevant for the PHP version we're running + // and the PHP version we're targeting for emulation. + foreach ($emulators as $emulator) { + $emulatorPhpVersion = $emulator->getPhpVersion(); + if ($this->isForwardEmulationNeeded($emulatorPhpVersion)) { + $this->emulators[] = $emulator; + } elseif ($this->isReverseEmulationNeeded($emulatorPhpVersion)) { + $this->emulators[] = new ReverseEmulator($emulator); + } + } + } + public function tokenize(string $code, ?ErrorHandler $errorHandler = null): array + { + $emulators = array_filter($this->emulators, function ($emulator) use ($code) { + return $emulator->isEmulationNeeded($code); + }); + if (empty($emulators)) { + // Nothing to emulate, yay + return parent::tokenize($code, $errorHandler); + } + if ($errorHandler === null) { + $errorHandler = new ErrorHandler\Throwing(); + } + $this->patches = []; + foreach ($emulators as $emulator) { + $code = $emulator->preprocessCode($code, $this->patches); + } + $collector = new ErrorHandler\Collecting(); + $tokens = parent::tokenize($code, $collector); + $this->sortPatches(); + $tokens = $this->fixupTokens($tokens); + $errors = $collector->getErrors(); + if (!empty($errors)) { + $this->fixupErrors($errors); + foreach ($errors as $error) { + $errorHandler->handleError($error); + } + } + foreach ($emulators as $emulator) { + $tokens = $emulator->emulate($code, $tokens); + } + return $tokens; + } + private function isForwardEmulationNeeded(PhpVersion $emulatorPhpVersion): bool + { + return $this->hostPhpVersion->older($emulatorPhpVersion) && $this->targetPhpVersion->newerOrEqual($emulatorPhpVersion); + } + private function isReverseEmulationNeeded(PhpVersion $emulatorPhpVersion): bool + { + return $this->hostPhpVersion->newerOrEqual($emulatorPhpVersion) && $this->targetPhpVersion->older($emulatorPhpVersion); + } + private function sortPatches(): void + { + // Patches may be contributed by different emulators. + // Make sure they are sorted by increasing patch position. + usort($this->patches, function ($p1, $p2) { + return $p1[0] <=> $p2[0]; + }); + } + /** + * @param list $tokens + * @return list + */ + private function fixupTokens(array $tokens): array + { + if (\count($this->patches) === 0) { + return $tokens; + } + // Load first patch + $patchIdx = 0; + list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; + // We use a manual loop over the tokens, because we modify the array on the fly + $posDelta = 0; + $lineDelta = 0; + for ($i = 0, $c = \count($tokens); $i < $c; $i++) { + $token = $tokens[$i]; + $pos = $token->pos; + $token->pos += $posDelta; + $token->line += $lineDelta; + $localPosDelta = 0; + $len = \strlen($token->text); + while ($patchPos >= $pos && $patchPos < $pos + $len) { + $patchTextLen = \strlen($patchText); + if ($patchType === 'remove') { + if ($patchPos === $pos && $patchTextLen === $len) { + // Remove token entirely + array_splice($tokens, $i, 1, []); + $i--; + $c--; + } else { + // Remove from token string + $token->text = substr_replace($token->text, '', $patchPos - $pos + $localPosDelta, $patchTextLen); + $localPosDelta -= $patchTextLen; + } + $lineDelta -= \substr_count($patchText, "\n"); + } elseif ($patchType === 'add') { + // Insert into the token string + $token->text = substr_replace($token->text, $patchText, $patchPos - $pos + $localPosDelta, 0); + $localPosDelta += $patchTextLen; + $lineDelta += \substr_count($patchText, "\n"); + } elseif ($patchType === 'replace') { + // Replace inside the token string + $token->text = substr_replace($token->text, $patchText, $patchPos - $pos + $localPosDelta, $patchTextLen); + } else { + assert(\false); + } + // Fetch the next patch + $patchIdx++; + if ($patchIdx >= \count($this->patches)) { + // No more patches. However, we still need to adjust position. + $patchPos = \PHP_INT_MAX; + break; + } + list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; + } + $posDelta += $localPosDelta; + } + return $tokens; + } + /** + * Fixup line and position information in errors. + * + * @param Error[] $errors + */ + private function fixupErrors(array $errors): void + { + foreach ($errors as $error) { + $attrs = $error->getAttributes(); + $posDelta = 0; + $lineDelta = 0; + foreach ($this->patches as $patch) { + list($patchPos, $patchType, $patchText) = $patch; + if ($patchPos >= $attrs['startFilePos']) { + // No longer relevant + break; + } + if ($patchType === 'add') { + $posDelta += strlen($patchText); + $lineDelta += substr_count($patchText, "\n"); + } elseif ($patchType === 'remove') { + $posDelta -= strlen($patchText); + $lineDelta -= substr_count($patchText, "\n"); + } + } + $attrs['startFilePos'] += $posDelta; + $attrs['endFilePos'] += $posDelta; + $attrs['startLine'] += $lineDelta; + $attrs['endLine'] += $lineDelta; + $error->setAttributes($attrs); + } + } +} + \T_PUBLIC_SET, \T_PROTECTED => \T_PROTECTED_SET, \T_PRIVATE => \T_PRIVATE_SET]; + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { + $token = $tokens[$i]; + if (isset($map[$token->id]) && $i + 3 < $c && $tokens[$i + 1]->text === '(' && $tokens[$i + 2]->id === \T_STRING && \strtolower($tokens[$i + 2]->text) === 'set' && $tokens[$i + 3]->text === ')' && $this->isKeywordContext($tokens, $i)) { + array_splice($tokens, $i, 4, [new Token($map[$token->id], $token->text . '(' . $tokens[$i + 2]->text . ')', $token->line, $token->pos)]); + $c -= 3; + } + } + return $tokens; + } + public function reverseEmulate(string $code, array $tokens): array + { + $reverseMap = [\T_PUBLIC_SET => \T_PUBLIC, \T_PROTECTED_SET => \T_PROTECTED, \T_PRIVATE_SET => \T_PRIVATE]; + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { + $token = $tokens[$i]; + if (isset($reverseMap[$token->id]) && \preg_match('/(public|protected|private)\((set)\)/i', $token->text, $matches)) { + [, $modifier, $set] = $matches; + $modifierLen = \strlen($modifier); + array_splice($tokens, $i, 1, [new Token($reverseMap[$token->id], $modifier, $token->line, $token->pos), new Token(\ord('('), '(', $token->line, $token->pos + $modifierLen), new Token(\T_STRING, $set, $token->line, $token->pos + $modifierLen + 1), new Token(\ord(')'), ')', $token->line, $token->pos + $modifierLen + 4)]); + $i += 3; + $c += 3; + } + } + return $tokens; + } + /** @param Token[] $tokens */ + protected function isKeywordContext(array $tokens, int $pos): bool + { + $prevToken = $this->getPreviousNonSpaceToken($tokens, $pos); + if ($prevToken === null) { + return \false; + } + return $prevToken->id !== \T_OBJECT_OPERATOR && $prevToken->id !== \T_NULLSAFE_OBJECT_OPERATOR; + } + /** @param Token[] $tokens */ + private function getPreviousNonSpaceToken(array $tokens, int $start): ?Token + { + for ($i = $start - 1; $i >= 0; --$i) { + if ($tokens[$i]->id === \T_WHITESPACE) { + continue; + } + return $tokens[$i]; + } + return null; + } +} +text === '#' && isset($tokens[$i + 1]) && $tokens[$i + 1]->text === '[') { + array_splice($tokens, $i, 2, [new Token(\T_ATTRIBUTE, '#[', $token->line, $token->pos)]); + $c--; + continue; + } + } + return $tokens; + } + public function reverseEmulate(string $code, array $tokens): array + { + // TODO + return $tokens; + } + public function preprocessCode(string $code, array &$patches): string + { + $pos = 0; + while (\false !== $pos = strpos($code, '#[', $pos)) { + // Replace #[ with %[ + $code[$pos] = '%'; + $patches[] = [$pos, 'replace', '#']; + $pos += 2; + } + return $code; + } +} +id === \T_WHITESPACE && $tokens[$pos + 2]->id === \T_STRING; + } +} +id == \T_LNUMBER && $token->text === '0' && isset($tokens[$i + 1]) && $tokens[$i + 1]->id == \T_STRING && preg_match('/[oO][0-7]+(?:_[0-7]+)*/', $tokens[$i + 1]->text)) { + $tokenKind = $this->resolveIntegerOrFloatToken($tokens[$i + 1]->text); + array_splice($tokens, $i, 2, [new Token($tokenKind, '0' . $tokens[$i + 1]->text, $token->line, $token->pos)]); + $c--; + } + } + return $tokens; + } + private function resolveIntegerOrFloatToken(string $str): int + { + $str = substr($str, 1); + $str = str_replace('_', '', $str); + $num = octdec($str); + return is_float($num) ? \T_DNUMBER : \T_LNUMBER; + } + public function reverseEmulate(string $code, array $tokens): array + { + // Explicit octals were not legal code previously, don't bother. + return $tokens; + } +} +getKeywordString()) !== \false; + } + /** @param Token[] $tokens */ + protected function isKeywordContext(array $tokens, int $pos): bool + { + $prevToken = $this->getPreviousNonSpaceToken($tokens, $pos); + if ($prevToken === null) { + return \false; + } + return $prevToken->id !== \T_OBJECT_OPERATOR && $prevToken->id !== \T_NULLSAFE_OBJECT_OPERATOR; + } + public function emulate(string $code, array $tokens): array + { + $keywordString = $this->getKeywordString(); + foreach ($tokens as $i => $token) { + if ($token->id === \T_STRING && strtolower($token->text) === $keywordString && $this->isKeywordContext($tokens, $i)) { + $token->id = $this->getKeywordToken(); + } + } + return $tokens; + } + /** @param Token[] $tokens */ + private function getPreviousNonSpaceToken(array $tokens, int $start): ?Token + { + for ($i = $start - 1; $i >= 0; --$i) { + if ($tokens[$i]->id === \T_WHITESPACE) { + continue; + } + return $tokens[$i]; + } + return null; + } + public function reverseEmulate(string $code, array $tokens): array + { + $keywordToken = $this->getKeywordToken(); + foreach ($tokens as $token) { + if ($token->id === $keywordToken) { + $token->id = \T_STRING; + } + } + return $tokens; + } +} +') !== \false; + } + public function emulate(string $code, array $tokens): array + { + // We need to manually iterate and manage a count because we'll change + // the tokens array on the way + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { + $token = $tokens[$i]; + if ($token->text === '?' && isset($tokens[$i + 1]) && $tokens[$i + 1]->id === \T_OBJECT_OPERATOR) { + array_splice($tokens, $i, 2, [new Token(\T_NULLSAFE_OBJECT_OPERATOR, '?->', $token->line, $token->pos)]); + $c--; + continue; + } + // Handle ?-> inside encapsed string. + if ($token->id === \T_ENCAPSED_AND_WHITESPACE && isset($tokens[$i - 1]) && $tokens[$i - 1]->id === \T_VARIABLE && preg_match('/^\?->([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)/', $token->text, $matches)) { + $replacement = [new Token(\T_NULLSAFE_OBJECT_OPERATOR, '?->', $token->line, $token->pos), new Token(\T_STRING, $matches[1], $token->line, $token->pos + 3)]; + $matchLen = \strlen($matches[0]); + if ($matchLen !== \strlen($token->text)) { + $replacement[] = new Token(\T_ENCAPSED_AND_WHITESPACE, \substr($token->text, $matchLen), $token->line, $token->pos + $matchLen); + } + array_splice($tokens, $i, 1, $replacement); + $c += \count($replacement) - 1; + continue; + } + } + return $tokens; + } + public function reverseEmulate(string $code, array $tokens): array + { + // ?-> was not valid code previously, don't bother. + return $tokens; + } +} +') !== \false; + } + public function emulate(string $code, array $tokens): array + { + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { + $token = $tokens[$i]; + if ($token->text === '|' && isset($tokens[$i + 1]) && $tokens[$i + 1]->text === '>') { + array_splice($tokens, $i, 2, [new Token(\T_PIPE, '|>', $token->line, $token->pos)]); + $c--; + } + } + return $tokens; + } + public function reverseEmulate(string $code, array $tokens): array + { + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { + $token = $tokens[$i]; + if ($token->id === \T_PIPE) { + array_splice($tokens, $i, 1, [new Token(\ord('|'), '|', $token->line, $token->pos), new Token(\ord('>'), '>', $token->line, $token->pos + 1)]); + $i++; + $c++; + } + } + return $tokens; + } +} +text === '(' || $tokens[$pos + 1]->id === \T_WHITESPACE && isset($tokens[$pos + 2]) && $tokens[$pos + 2]->text === '(')); + } +} +emulator = $emulator; + } + public function getPhpVersion(): PhpVersion + { + return $this->emulator->getPhpVersion(); + } + public function isEmulationNeeded(string $code): bool + { + return $this->emulator->isEmulationNeeded($code); + } + public function emulate(string $code, array $tokens): array + { + return $this->emulator->reverseEmulate($code, $tokens); + } + public function reverseEmulate(string $code, array $tokens): array + { + return $this->emulator->emulate($code, $tokens); + } + public function preprocessCode(string $code, array &$patches): string + { + return $code; + } +} +text !== '(') { + continue; + } + $numTokens = 1; + $text = '('; + $j = $i + 1; + if ($j < $c && $tokens[$j]->id === \T_WHITESPACE && preg_match('/[ \t]+/', $tokens[$j]->text)) { + $text .= $tokens[$j]->text; + $numTokens++; + $j++; + } + if ($j >= $c || $tokens[$j]->id !== \T_STRING || \strtolower($tokens[$j]->text) !== 'void') { + continue; + } + $text .= $tokens[$j]->text; + $numTokens++; + $k = $j + 1; + if ($k < $c && $tokens[$k]->id === \T_WHITESPACE && preg_match('/[ \t]+/', $tokens[$k]->text)) { + $text .= $tokens[$k]->text; + $numTokens++; + $k++; + } + if ($k >= $c || $tokens[$k]->text !== ')') { + continue; + } + $text .= ')'; + $numTokens++; + array_splice($tokens, $i, $numTokens, [new Token(\T_VOID_CAST, $text, $token->line, $token->pos)]); + $c -= $numTokens - 1; + } + return $tokens; + } + public function reverseEmulate(string $code, array $tokens): array + { + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { + $token = $tokens[$i]; + if ($token->id !== \T_VOID_CAST) { + continue; + } + if (!preg_match('/^\(([ \t]*)(void)([ \t]*)\)$/i', $token->text, $match)) { + throw new \LogicException('Unexpected T_VOID_CAST contents'); + } + $newTokens = []; + $pos = $token->pos; + $newTokens[] = new Token(\ord('('), '(', $token->line, $pos); + $pos++; + if ($match[1] !== '') { + $newTokens[] = new Token(\T_WHITESPACE, $match[1], $token->line, $pos); + $pos += \strlen($match[1]); + } + $newTokens[] = new Token(\T_STRING, $match[2], $token->line, $pos); + $pos += \strlen($match[2]); + if ($match[3] !== '') { + $newTokens[] = new Token(\T_WHITESPACE, $match[3], $token->line, $pos); + $pos += \strlen($match[3]); + } + $newTokens[] = new Token(\ord(')'), ')', $token->line, $pos); + array_splice($tokens, $i, 1, $newTokens); + $i += \count($newTokens) - 1; + $c += \count($newTokens) - 1; + } + return $tokens; + } +} + 'public', self::PROTECTED => 'protected', self::PRIVATE => 'private', self::STATIC => 'static', self::ABSTRACT => 'abstract', self::FINAL => 'final', self::READONLY => 'readonly', self::PUBLIC_SET => 'public(set)', self::PROTECTED_SET => 'protected(set)', self::PRIVATE_SET => 'private(set)']; + public static function toString(int $modifier): string + { + if (!isset(self::TO_STRING_MAP[$modifier])) { + throw new \InvalidArgumentException("Unknown modifier {$modifier}"); + } + return self::TO_STRING_MAP[$modifier]; + } + private static function isValidModifier(int $modifier): bool + { + $isPow2 = ($modifier & $modifier - 1) == 0 && $modifier != 0; + return $isPow2 && $modifier <= self::PRIVATE_SET; + } + /** + * @internal + */ + public static function verifyClassModifier(int $a, int $b): void + { + assert(self::isValidModifier($b)); + if (($a & $b) != 0) { + throw new Error('Multiple ' . self::toString($b) . ' modifiers are not allowed'); + } + if ($a & 48 && $b & 48) { + throw new Error('Cannot use the final modifier on an abstract class'); + } + } + /** + * @internal + */ + public static function verifyModifier(int $a, int $b): void + { + assert(self::isValidModifier($b)); + if ($a & Modifiers::VISIBILITY_MASK && $b & Modifiers::VISIBILITY_MASK || $a & Modifiers::VISIBILITY_SET_MASK && $b & Modifiers::VISIBILITY_SET_MASK) { + throw new Error('Multiple access type modifiers are not allowed'); + } + if (($a & $b) != 0) { + throw new Error('Multiple ' . self::toString($b) . ' modifiers are not allowed'); + } + if ($a & 48 && $b & 48) { + throw new Error('Cannot use the final modifier on an abstract class member'); + } + } +} + [aliasName => originalName]] */ + protected array $aliases = []; + /** @var Name[][] Same as $aliases but preserving original case */ + protected array $origAliases = []; + /** @var ErrorHandler Error handler */ + protected ErrorHandler $errorHandler; + /** + * Create a name context. + * + * @param ErrorHandler $errorHandler Error handling used to report errors + */ + public function __construct(ErrorHandler $errorHandler) + { + $this->errorHandler = $errorHandler; + } + /** + * Start a new namespace. + * + * This also resets the alias table. + * + * @param Name|null $namespace Null is the global namespace + */ + public function startNamespace(?Name $namespace = null): void + { + $this->namespace = $namespace; + $this->origAliases = $this->aliases = [Stmt\Use_::TYPE_NORMAL => [], Stmt\Use_::TYPE_FUNCTION => [], Stmt\Use_::TYPE_CONSTANT => []]; + } + /** + * Add an alias / import. + * + * @param Name $name Original name + * @param string $aliasName Aliased name + * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_* + * @param array $errorAttrs Attributes to use to report an error + */ + public function addAlias(Name $name, string $aliasName, int $type, array $errorAttrs = []): void + { + // Constant names are case sensitive, everything else case insensitive + if ($type === Stmt\Use_::TYPE_CONSTANT) { + $aliasLookupName = $aliasName; + } else { + $aliasLookupName = strtolower($aliasName); + } + if (isset($this->aliases[$type][$aliasLookupName])) { + $typeStringMap = [Stmt\Use_::TYPE_NORMAL => '', Stmt\Use_::TYPE_FUNCTION => 'function ', Stmt\Use_::TYPE_CONSTANT => 'const ']; + $this->errorHandler->handleError(new Error(sprintf('Cannot use %s%s as %s because the name is already in use', $typeStringMap[$type], $name, $aliasName), $errorAttrs)); + return; + } + $this->aliases[$type][$aliasLookupName] = $name; + $this->origAliases[$type][$aliasName] = $name; + } + /** + * Get current namespace. + * + * @return null|Name Namespace (or null if global namespace) + */ + public function getNamespace(): ?Name + { + return $this->namespace; + } + /** + * Get resolved name. + * + * @param Name $name Name to resolve + * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_{FUNCTION|CONSTANT} + * + * @return null|Name Resolved name, or null if static resolution is not possible + */ + public function getResolvedName(Name $name, int $type): ?Name + { + // don't resolve special class names + if ($type === Stmt\Use_::TYPE_NORMAL && $name->isSpecialClassName()) { + if (!$name->isUnqualified()) { + $this->errorHandler->handleError(new Error(sprintf("'\\%s' is an invalid class name", $name->toString()), $name->getAttributes())); + } + return $name; + } + // fully qualified names are already resolved + if ($name->isFullyQualified()) { + return $name; + } + // Try to resolve aliases + if (null !== $resolvedName = $this->resolveAlias($name, $type)) { + return $resolvedName; + } + if ($type !== Stmt\Use_::TYPE_NORMAL && $name->isUnqualified()) { + if (null === $this->namespace) { + // outside of a namespace unaliased unqualified is same as fully qualified + return new FullyQualified($name, $name->getAttributes()); + } + // Cannot resolve statically + return null; + } + // if no alias exists prepend current namespace + return FullyQualified::concat($this->namespace, $name, $name->getAttributes()); + } + /** + * Get resolved class name. + * + * @param Name $name Class ame to resolve + * + * @return Name Resolved name + */ + public function getResolvedClassName(Name $name): Name + { + return $this->getResolvedName($name, Stmt\Use_::TYPE_NORMAL); + } + /** + * Get possible ways of writing a fully qualified name (e.g., by making use of aliases). + * + * @param string $name Fully-qualified name (without leading namespace separator) + * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_* + * + * @return Name[] Possible representations of the name + */ + public function getPossibleNames(string $name, int $type): array + { + $lcName = strtolower($name); + if ($type === Stmt\Use_::TYPE_NORMAL) { + // self, parent and static must always be unqualified + if ($lcName === "self" || $lcName === "parent" || $lcName === "static") { + return [new Name($name)]; + } + } + // Collect possible ways to write this name, starting with the fully-qualified name + $possibleNames = [new FullyQualified($name)]; + if (null !== $nsRelativeName = $this->getNamespaceRelativeName($name, $lcName, $type)) { + // Make sure there is no alias that makes the normally namespace-relative name + // into something else + if (null === $this->resolveAlias($nsRelativeName, $type)) { + $possibleNames[] = $nsRelativeName; + } + } + // Check for relevant namespace use statements + foreach ($this->origAliases[Stmt\Use_::TYPE_NORMAL] as $alias => $orig) { + $lcOrig = $orig->toLowerString(); + if (0 === strpos($lcName, $lcOrig . '\\')) { + $possibleNames[] = new Name($alias . substr($name, strlen($lcOrig))); + } + } + // Check for relevant type-specific use statements + foreach ($this->origAliases[$type] as $alias => $orig) { + if ($type === Stmt\Use_::TYPE_CONSTANT) { + // Constants are complicated-sensitive + $normalizedOrig = $this->normalizeConstName($orig->toString()); + if ($normalizedOrig === $this->normalizeConstName($name)) { + $possibleNames[] = new Name($alias); + } + } else if ($orig->toLowerString() === $lcName) { + $possibleNames[] = new Name($alias); + } + } + return $possibleNames; + } + /** + * Get shortest representation of this fully-qualified name. + * + * @param string $name Fully-qualified name (without leading namespace separator) + * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_* + * + * @return Name Shortest representation + */ + public function getShortName(string $name, int $type): Name + { + $possibleNames = $this->getPossibleNames($name, $type); + // Find shortest name + $shortestName = null; + $shortestLength = \INF; + foreach ($possibleNames as $possibleName) { + $length = strlen($possibleName->toCodeString()); + if ($length < $shortestLength) { + $shortestName = $possibleName; + $shortestLength = $length; + } + } + return $shortestName; + } + private function resolveAlias(Name $name, int $type): ?FullyQualified + { + $firstPart = $name->getFirst(); + if ($name->isQualified()) { + // resolve aliases for qualified names, always against class alias table + $checkName = strtolower($firstPart); + if (isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName])) { + $alias = $this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName]; + return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes()); + } + } elseif ($name->isUnqualified()) { + // constant aliases are case-sensitive, function aliases case-insensitive + $checkName = $type === Stmt\Use_::TYPE_CONSTANT ? $firstPart : strtolower($firstPart); + if (isset($this->aliases[$type][$checkName])) { + // resolve unqualified aliases + return new FullyQualified($this->aliases[$type][$checkName], $name->getAttributes()); + } + } + // No applicable aliases + return null; + } + private function getNamespaceRelativeName(string $name, string $lcName, int $type): ?Name + { + if (null === $this->namespace) { + return new Name($name); + } + if ($type === Stmt\Use_::TYPE_CONSTANT) { + // The constants true/false/null always resolve to the global symbols, even inside a + // namespace, so they may be used without qualification + if ($lcName === "true" || $lcName === "false" || $lcName === "null") { + return new Name($name); + } + } + $namespacePrefix = strtolower($this->namespace . '\\'); + if (0 === strpos($lcName, $namespacePrefix)) { + return new Name(substr($name, strlen($namespacePrefix))); + } + return null; + } + private function normalizeConstName(string $name): string + { + $nsSep = strrpos($name, '\\'); + if (\false === $nsSep) { + return $name; + } + // Constants have case-insensitive namespace and case-sensitive short-name + $ns = substr($name, 0, $nsSep); + $shortName = substr($name, $nsSep + 1); + return strtolower($ns) . '\\' . $shortName; + } +} + + */ + public function getAttributes(): array; + /** + * Replaces all the attributes of this node. + * + * @param array $attributes + */ + public function setAttributes(array $attributes): void; +} + $attributes Additional attributes + * @param Identifier|null $name Parameter name (for named parameters) + */ + public function __construct(Expr $value, bool $byRef = \false, bool $unpack = \false, array $attributes = [], ?Identifier $name = null) + { + $this->attributes = $attributes; + $this->name = $name; + $this->value = $value; + $this->byRef = $byRef; + $this->unpack = $unpack; + } + public function getSubNodeNames(): array + { + return ['name', 'value', 'byRef', 'unpack']; + } + public function getType(): string + { + return 'Arg'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $value, ?Expr $key = null, bool $byRef = \false, array $attributes = [], bool $unpack = \false) + { + $this->attributes = $attributes; + $this->key = $key; + $this->value = $value; + $this->byRef = $byRef; + $this->unpack = $unpack; + } + public function getSubNodeNames(): array + { + return ['key', 'value', 'byRef', 'unpack']; + } + public function getType(): string + { + return 'ArrayItem'; + } +} +// @deprecated compatibility alias +class_alias(ArrayItem::class, Expr\ArrayItem::class); + Attribute arguments */ + public array $args; + /** + * @param Node\Name $name Attribute name + * @param list $args Attribute arguments + * @param array $attributes Additional node attributes + */ + public function __construct(Name $name, array $args = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->name = $name; + $this->args = $args; + } + public function getSubNodeNames(): array + { + return ['name', 'args']; + } + public function getType(): string + { + return 'Attribute'; + } +} + $attributes Additional node attributes + */ + public function __construct(array $attrs, array $attributes = []) + { + $this->attributes = $attributes; + $this->attrs = $attrs; + } + public function getSubNodeNames(): array + { + return ['attrs']; + } + public function getType(): string + { + return 'AttributeGroup'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr\Variable $var, bool $byRef = \false, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->byRef = $byRef; + } + public function getSubNodeNames(): array + { + return ['var', 'byRef']; + } + public function getType(): string + { + return 'ClosureUse'; + } +} +// @deprecated compatibility alias +class_alias(ClosureUse::class, Expr\ClosureUse::class); + $attributes Additional attributes + */ + public function __construct($name, Expr $value, array $attributes = []) + { + $this->attributes = $attributes; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->value = $value; + } + public function getSubNodeNames(): array + { + return ['name', 'value']; + } + public function getType(): string + { + return 'Const'; + } +} +value pair node. + * + * @param string|Node\Identifier $key Key + * @param Node\Expr $value Value + * @param array $attributes Additional attributes + */ + public function __construct($key, Node\Expr $value, array $attributes = []) + { + $this->attributes = $attributes; + $this->key = \is_string($key) ? new Node\Identifier($key) : $key; + $this->value = $value; + } + public function getSubNodeNames(): array + { + return ['key', 'value']; + } + public function getType(): string + { + return 'DeclareItem'; + } +} +// @deprecated compatibility alias +class_alias(DeclareItem::class, Stmt\DeclareDeclare::class); + $attributes Additional attributes + */ + public function __construct(Expr $var, ?Expr $dim = null, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->dim = $dim; + } + public function getSubNodeNames(): array + { + return ['var', 'dim']; + } + public function getType(): string + { + return 'Expr_ArrayDimFetch'; + } +} + $attributes Additional attributes + */ + public function __construct(array $items = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->items = $items; + } + public function getSubNodeNames(): array + { + return ['items']; + } + public function getType(): string + { + return 'Expr_Array'; + } +} + false : Whether the closure is static + * 'byRef' => false : Whether to return by reference + * 'params' => array() : Parameters + * 'returnType' => null : Return type + * 'attrGroups' => array() : PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct(array $subNodes, array $attributes = []) + { + $this->attributes = $attributes; + $this->static = $subNodes['static'] ?? \false; + $this->byRef = $subNodes['byRef'] ?? \false; + $this->params = $subNodes['params'] ?? []; + $this->returnType = $subNodes['returnType'] ?? null; + $this->expr = $subNodes['expr']; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'static', 'byRef', 'params', 'returnType', 'expr']; + } + public function returnsByRef(): bool + { + return $this->byRef; + } + public function getParams(): array + { + return $this->params; + } + public function getReturnType() + { + return $this->returnType; + } + public function getAttrGroups(): array + { + return $this->attrGroups; + } + /** + * @return Node\Stmt\Return_[] + */ + public function getStmts(): array + { + return [new Node\Stmt\Return_($this->expr)]; + } + public function getType(): string + { + return 'Expr_ArrowFunction'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $var, Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['var', 'expr']; + } + public function getType(): string + { + return 'Expr_Assign'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $var, Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['var', 'expr']; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $var, Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['var', 'expr']; + } + public function getType(): string + { + return 'Expr_AssignRef'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $left, Expr $right, array $attributes = []) + { + $this->attributes = $attributes; + $this->left = $left; + $this->right = $right; + } + public function getSubNodeNames(): array + { + return ['left', 'right']; + } + /** + * Get the operator sigil for this binary operation. + * + * In the case there are multiple possible sigils for an operator, this method does not + * necessarily return the one used in the parsed code. + */ + abstract public function getOperatorSigil(): string; +} +'; + } + public function getType(): string + { + return 'Expr_BinaryOp_Greater'; + } +} +='; + } + public function getType(): string + { + return 'Expr_BinaryOp_GreaterOrEqual'; + } +} +'; + } + public function getType(): string + { + return 'Expr_BinaryOp_Pipe'; + } +} +>'; + } + public function getType(): string + { + return 'Expr_BinaryOp_ShiftRight'; + } +} +'; + } + public function getType(): string + { + return 'Expr_BinaryOp_Spaceship'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_BitwiseNot'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_BooleanNot'; + } +} + + */ + abstract public function getRawArgs(): array; + /** + * Returns whether this call expression is actually a first class callable. + */ + public function isFirstClassCallable(): bool + { + $rawArgs = $this->getRawArgs(); + return count($rawArgs) === 1 && current($rawArgs) instanceof VariadicPlaceholder; + } + /** + * Assert that this is not a first-class callable and return only ordinary Args. + * + * @return Arg[] + */ + public function getArgs(): array + { + assert(!$this->isFirstClassCallable()); + return $this->getRawArgs(); + } + /** + * Retrieves a specific argument from the raw arguments. + * + * Returns the named argument that matches the given `$name`, or the + * positional (unnamed) argument that exists at the given `$position`, + * otherwise, returns `null` for first-class callables or if no match is found. + */ + public function getArg(string $name, int $position): ?Arg + { + if ($this->isFirstClassCallable()) { + return null; + } + foreach ($this->getRawArgs() as $i => $arg) { + if ($arg->unpack) { + continue; + } + if ($arg->name !== null && $arg->name->toString() === $name || $arg->name === null && $i === $position) { + return $arg; + } + } + return null; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } +} + $attributes Additional attributes + */ + public function __construct(Node $class, $name, array $attributes = []) + { + $this->attributes = $attributes; + $this->class = $class; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames(): array + { + return ['class', 'name']; + } + public function getType(): string + { + return 'Expr_ClassConstFetch'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_Clone'; + } +} + false : Whether the closure is static + * 'byRef' => false : Whether to return by reference + * 'params' => array(): Parameters + * 'uses' => array(): use()s + * 'returnType' => null : Return type + * 'stmts' => array(): Statements + * 'attrGroups' => array(): PHP attributes groups + * @param array $attributes Additional attributes + */ + public function __construct(array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->static = $subNodes['static'] ?? \false; + $this->byRef = $subNodes['byRef'] ?? \false; + $this->params = $subNodes['params'] ?? []; + $this->uses = $subNodes['uses'] ?? []; + $this->returnType = $subNodes['returnType'] ?? null; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'static', 'byRef', 'params', 'uses', 'returnType', 'stmts']; + } + public function returnsByRef(): bool + { + return $this->byRef; + } + public function getParams(): array + { + return $this->params; + } + public function getReturnType() + { + return $this->returnType; + } + /** @return Node\Stmt[] */ + public function getStmts(): array + { + return $this->stmts; + } + public function getAttrGroups(): array + { + return $this->attrGroups; + } + public function getType(): string + { + return 'Expr_Closure'; + } +} + $attributes Additional attributes + */ + public function __construct(Name $name, array $attributes = []) + { + $this->attributes = $attributes; + $this->name = $name; + } + public function getSubNodeNames(): array + { + return ['name']; + } + public function getType(): string + { + return 'Expr_ConstFetch'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_Empty'; + } +} + $attributes Additional attributes + */ + public function __construct(array $attributes = []) + { + $this->attributes = $attributes; + } + public function getSubNodeNames(): array + { + return []; + } + public function getType(): string + { + return 'Expr_Error'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_ErrorSuppress'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_Eval'; + } +} + $attributes Additional attributes + */ + public function __construct(?Expr $expr = null, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_Exit'; + } +} + Arguments */ + public array $args; + /** + * Constructs a function call node. + * + * @param Node\Name|Expr $name Function name + * @param array $args Arguments + * @param array $attributes Additional attributes + */ + public function __construct(Node $name, array $args = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->name = $name; + $this->args = $args; + } + public function getSubNodeNames(): array + { + return ['name', 'args']; + } + public function getType(): string + { + return 'Expr_FuncCall'; + } + public function getRawArgs(): array + { + return $this->args; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, int $type, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + $this->type = $type; + } + public function getSubNodeNames(): array + { + return ['expr', 'type']; + } + public function getType(): string + { + return 'Expr_Include'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, Node $class, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + $this->class = $class; + } + public function getSubNodeNames(): array + { + return ['expr', 'class']; + } + public function getType(): string + { + return 'Expr_Instanceof'; + } +} + $attributes Additional attributes + */ + public function __construct(array $vars, array $attributes = []) + { + $this->attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames(): array + { + return ['vars']; + } + public function getType(): string + { + return 'Expr_Isset'; + } +} + $attributes Additional attributes + */ + public function __construct(array $items, array $attributes = []) + { + $this->attributes = $attributes; + $this->items = $items; + } + public function getSubNodeNames(): array + { + return ['items']; + } + public function getType(): string + { + return 'Expr_List'; + } +} + $attributes Additional attributes + */ + public function __construct(Node\Expr $cond, array $arms = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->cond = $cond; + $this->arms = $arms; + } + public function getSubNodeNames(): array + { + return ['cond', 'arms']; + } + public function getType(): string + { + return 'Expr_Match'; + } +} + Arguments */ + public array $args; + /** + * Constructs a function call node. + * + * @param Expr $var Variable holding object + * @param string|Identifier|Expr $name Method name + * @param array $args Arguments + * @param array $attributes Additional attributes + */ + public function __construct(Expr $var, $name, array $args = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->args = $args; + } + public function getSubNodeNames(): array + { + return ['var', 'name', 'args']; + } + public function getType(): string + { + return 'Expr_MethodCall'; + } + public function getRawArgs(): array + { + return $this->args; + } +} + Arguments */ + public array $args; + /** + * Constructs a function call node. + * + * @param Node\Name|Expr|Node\Stmt\Class_ $class Class name (or class node for anonymous classes) + * @param array $args Arguments + * @param array $attributes Additional attributes + */ + public function __construct(Node $class, array $args = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->class = $class; + $this->args = $args; + } + public function getSubNodeNames(): array + { + return ['class', 'args']; + } + public function getType(): string + { + return 'Expr_New'; + } + public function getRawArgs(): array + { + return $this->args; + } +} + Arguments */ + public array $args; + /** + * Constructs a nullsafe method call node. + * + * @param Expr $var Variable holding object + * @param string|Identifier|Expr $name Method name + * @param array $args Arguments + * @param array $attributes Additional attributes + */ + public function __construct(Expr $var, $name, array $args = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->args = $args; + } + public function getSubNodeNames(): array + { + return ['var', 'name', 'args']; + } + public function getType(): string + { + return 'Expr_NullsafeMethodCall'; + } + public function getRawArgs(): array + { + return $this->args; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $var, $name, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames(): array + { + return ['var', 'name']; + } + public function getType(): string + { + return 'Expr_NullsafePropertyFetch'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $var, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames(): array + { + return ['var']; + } + public function getType(): string + { + return 'Expr_PostDec'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $var, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames(): array + { + return ['var']; + } + public function getType(): string + { + return 'Expr_PostInc'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $var, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames(): array + { + return ['var']; + } + public function getType(): string + { + return 'Expr_PreDec'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $var, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames(): array + { + return ['var']; + } + public function getType(): string + { + return 'Expr_PreInc'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_Print'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $var, $name, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames(): array + { + return ['var', 'name']; + } + public function getType(): string + { + return 'Expr_PropertyFetch'; + } +} + $attributes Additional attributes + */ + public function __construct(array $parts, array $attributes = []) + { + $this->attributes = $attributes; + $this->parts = $parts; + } + public function getSubNodeNames(): array + { + return ['parts']; + } + public function getType(): string + { + return 'Expr_ShellExec'; + } +} + Arguments */ + public array $args; + /** + * Constructs a static method call node. + * + * @param Node\Name|Expr $class Class name + * @param string|Identifier|Expr $name Method name + * @param array $args Arguments + * @param array $attributes Additional attributes + */ + public function __construct(Node $class, $name, array $args = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->class = $class; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->args = $args; + } + public function getSubNodeNames(): array + { + return ['class', 'name', 'args']; + } + public function getType(): string + { + return 'Expr_StaticCall'; + } + public function getRawArgs(): array + { + return $this->args; + } +} + $attributes Additional attributes + */ + public function __construct(Node $class, $name, array $attributes = []) + { + $this->attributes = $attributes; + $this->class = $class; + $this->name = \is_string($name) ? new VarLikeIdentifier($name) : $name; + } + public function getSubNodeNames(): array + { + return ['class', 'name']; + } + public function getType(): string + { + return 'Expr_StaticPropertyFetch'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $cond, ?Expr $if, Expr $else, array $attributes = []) + { + $this->attributes = $attributes; + $this->cond = $cond; + $this->if = $if; + $this->else = $else; + } + public function getSubNodeNames(): array + { + return ['cond', 'if', 'else']; + } + public function getType(): string + { + return 'Expr_Ternary'; + } +} + $attributes Additional attributes + */ + public function __construct(Node\Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_Throw'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_UnaryMinus'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_UnaryPlus'; + } +} + $attributes Additional attributes + */ + public function __construct($name, array $attributes = []) + { + $this->attributes = $attributes; + $this->name = $name; + } + public function getSubNodeNames(): array + { + return ['name']; + } + public function getType(): string + { + return 'Expr_Variable'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Expr_YieldFrom'; + } +} + $attributes Additional attributes + */ + public function __construct(?Expr $value = null, ?Expr $key = null, array $attributes = []) + { + $this->attributes = $attributes; + $this->key = $key; + $this->value = $value; + } + public function getSubNodeNames(): array + { + return ['key', 'value']; + } + public function getType(): string + { + return 'Expr_Yield'; + } +} + */ + private static array $specialClassNames = ['self' => \true, 'parent' => \true, 'static' => \true]; + /** + * Constructs an identifier node. + * + * @param string $name Identifier as string + * @param array $attributes Additional attributes + */ + public function __construct(string $name, array $attributes = []) + { + if ($name === '') { + throw new \InvalidArgumentException('Identifier name cannot be empty'); + } + $this->attributes = $attributes; + $this->name = $name; + } + public function getSubNodeNames(): array + { + return ['name']; + } + /** + * Get identifier as string. + * + * @psalm-return non-empty-string + * @return string Identifier as string. + */ + public function toString(): string + { + return $this->name; + } + /** + * Get lowercased identifier as string. + * + * @psalm-return non-empty-string&lowercase-string + * @return string Lowercased identifier as string + */ + public function toLowerString(): string + { + return strtolower($this->name); + } + /** + * Checks whether the identifier is a special class name (self, parent or static). + * + * @return bool Whether identifier is a special class name + */ + public function isSpecialClassName(): bool + { + return isset(self::$specialClassNames[strtolower($this->name)]); + } + /** + * Get identifier as string. + * + * @psalm-return non-empty-string + * @return string Identifier as string + */ + public function __toString(): string + { + return $this->name; + } + public function getType(): string + { + return 'Identifier'; + } +} + $attributes Additional attributes + */ + public function __construct(string $value, array $attributes = []) + { + $this->attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames(): array + { + return ['value']; + } + public function getType(): string + { + return 'InterpolatedStringPart'; + } +} +// @deprecated compatibility alias +class_alias(InterpolatedStringPart::class, Scalar\EncapsedStringPart::class); + $attributes Additional attributes + */ + public function __construct(array $types, array $attributes = []) + { + $this->attributes = $attributes; + $this->types = $types; + } + public function getSubNodeNames(): array + { + return ['types']; + } + public function getType(): string + { + return 'IntersectionType'; + } +} + */ + public ?array $conds; + public Expr $body; + /** + * @param null|list $conds + */ + public function __construct(?array $conds, Node\Expr $body, array $attributes = []) + { + $this->conds = $conds; + $this->body = $body; + $this->attributes = $attributes; + } + public function getSubNodeNames(): array + { + return ['conds', 'body']; + } + public function getType(): string + { + return 'MatchArm'; + } +} + */ + private static array $specialClassNames = ['self' => \true, 'parent' => \true, 'static' => \true]; + /** + * Constructs a name node. + * + * @param string|string[]|self $name Name as string, part array or Name instance (copy ctor) + * @param array $attributes Additional attributes + */ + final public function __construct($name, array $attributes = []) + { + $this->attributes = $attributes; + $this->name = self::prepareName($name); + } + public function getSubNodeNames(): array + { + return ['name']; + } + /** + * Get parts of name (split by the namespace separator). + * + * @psalm-return non-empty-list + * @return string[] Parts of name + */ + public function getParts(): array + { + return \explode('\\', $this->name); + } + /** + * Gets the first part of the name, i.e. everything before the first namespace separator. + * + * @return string First part of the name + */ + public function getFirst(): string + { + if (\false !== $pos = \strpos($this->name, '\\')) { + return \substr($this->name, 0, $pos); + } + return $this->name; + } + /** + * Gets the last part of the name, i.e. everything after the last namespace separator. + * + * @return string Last part of the name + */ + public function getLast(): string + { + if (\false !== $pos = \strrpos($this->name, '\\')) { + return \substr($this->name, $pos + 1); + } + return $this->name; + } + /** + * Checks whether the name is unqualified. (E.g. Name) + * + * @return bool Whether the name is unqualified + */ + public function isUnqualified(): bool + { + return \false === \strpos($this->name, '\\'); + } + /** + * Checks whether the name is qualified. (E.g. Name\Name) + * + * @return bool Whether the name is qualified + */ + public function isQualified(): bool + { + return \false !== \strpos($this->name, '\\'); + } + /** + * Checks whether the name is fully qualified. (E.g. \Name) + * + * @return bool Whether the name is fully qualified + */ + public function isFullyQualified(): bool + { + return \false; + } + /** + * Checks whether the name is explicitly relative to the current namespace. (E.g. namespace\Name) + * + * @return bool Whether the name is relative + */ + public function isRelative(): bool + { + return \false; + } + /** + * Returns a string representation of the name itself, without taking the name type into + * account (e.g., not including a leading backslash for fully qualified names). + * + * @psalm-return non-empty-string + * @return string String representation + */ + public function toString(): string + { + return $this->name; + } + /** + * Returns a string representation of the name as it would occur in code (e.g., including + * leading backslash for fully qualified names. + * + * @psalm-return non-empty-string + * @return string String representation + */ + public function toCodeString(): string + { + return $this->toString(); + } + /** + * Returns lowercased string representation of the name, without taking the name type into + * account (e.g., no leading backslash for fully qualified names). + * + * @psalm-return non-empty-string&lowercase-string + * @return string Lowercased string representation + */ + public function toLowerString(): string + { + return strtolower($this->name); + } + /** + * Checks whether the identifier is a special class name (self, parent or static). + * + * @return bool Whether identifier is a special class name + */ + public function isSpecialClassName(): bool + { + return isset(self::$specialClassNames[strtolower($this->name)]); + } + /** + * Returns a string representation of the name by imploding the namespace parts with the + * namespace separator. + * + * @psalm-return non-empty-string + * @return string String representation + */ + public function __toString(): string + { + return $this->name; + } + /** + * Gets a slice of a name (similar to array_slice). + * + * This method returns a new instance of the same type as the original and with the same + * attributes. + * + * If the slice is empty, null is returned. The null value will be correctly handled in + * concatenations using concat(). + * + * Offset and length have the same meaning as in array_slice(). + * + * @param int $offset Offset to start the slice at (may be negative) + * @param int|null $length Length of the slice (may be negative) + * + * @return static|null Sliced name + */ + public function slice(int $offset, ?int $length = null) + { + if ($offset === 1 && $length === null) { + // Short-circuit the common case. + if (\false !== $pos = \strpos($this->name, '\\')) { + return new static(\substr($this->name, $pos + 1)); + } + return null; + } + $parts = \explode('\\', $this->name); + $numParts = \count($parts); + $realOffset = $offset < 0 ? $offset + $numParts : $offset; + if ($realOffset < 0 || $realOffset > $numParts) { + throw new \OutOfBoundsException(sprintf('Offset %d is out of bounds', $offset)); + } + if (null === $length) { + $realLength = $numParts - $realOffset; + } else { + $realLength = $length < 0 ? $length + $numParts - $realOffset : $length; + if ($realLength < 0 || $realLength > $numParts - $realOffset) { + throw new \OutOfBoundsException(sprintf('Length %d is out of bounds', $length)); + } + } + if ($realLength === 0) { + // Empty slice is represented as null + return null; + } + return new static(array_slice($parts, $realOffset, $realLength), $this->attributes); + } + /** + * Concatenate two names, yielding a new Name instance. + * + * The type of the generated instance depends on which class this method is called on, for + * example Name\FullyQualified::concat() will yield a Name\FullyQualified instance. + * + * If one of the arguments is null, a new instance of the other name will be returned. If both + * arguments are null, null will be returned. As such, writing + * Name::concat($namespace, $shortName) + * where $namespace is a Name node or null will work as expected. + * + * @param string|string[]|self|null $name1 The first name + * @param string|string[]|self|null $name2 The second name + * @param array $attributes Attributes to assign to concatenated name + * + * @return static|null Concatenated name + */ + public static function concat($name1, $name2, array $attributes = []) + { + if (null === $name1 && null === $name2) { + return null; + } + if (null === $name1) { + return new static($name2, $attributes); + } + if (null === $name2) { + return new static($name1, $attributes); + } else { + return new static(self::prepareName($name1) . '\\' . self::prepareName($name2), $attributes); + } + } + /** + * Prepares a (string, array or Name node) name for use in name changing methods by converting + * it to a string. + * + * @param string|string[]|self $name Name to prepare + * + * @psalm-return non-empty-string + * @return string Prepared name + */ + private static function prepareName($name): string + { + if (\is_string($name)) { + if ('' === $name) { + throw new \InvalidArgumentException('Name cannot be empty'); + } + return $name; + } + if (\is_array($name)) { + if (empty($name)) { + throw new \InvalidArgumentException('Name cannot be empty'); + } + return implode('\\', $name); + } + if ($name instanceof self) { + return $name->name; + } + throw new \InvalidArgumentException('Expected string, array of parts or Name instance'); + } + public function getType(): string + { + return 'Name'; + } +} +toString(); + } + public function getType(): string + { + return 'Name_FullyQualified'; + } +} +toString(); + } + public function getType(): string + { + return 'Name_Relative'; + } +} + $attributes Additional attributes + */ + public function __construct(Node $type, array $attributes = []) + { + $this->attributes = $attributes; + $this->type = $type; + } + public function getSubNodeNames(): array + { + return ['type']; + } + public function getType(): string + { + return 'NullableType'; + } +} + $attributes Additional attributes + * @param int $flags Optional visibility flags + * @param list $attrGroups PHP attribute groups + * @param PropertyHook[] $hooks Property hooks for promoted properties + */ + public function __construct(Expr $var, ?Expr $default = null, ?Node $type = null, bool $byRef = \false, bool $variadic = \false, array $attributes = [], int $flags = 0, array $attrGroups = [], array $hooks = []) + { + $this->attributes = $attributes; + $this->type = $type; + $this->byRef = $byRef; + $this->variadic = $variadic; + $this->var = $var; + $this->default = $default; + $this->flags = $flags; + $this->attrGroups = $attrGroups; + $this->hooks = $hooks; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'flags', 'type', 'byRef', 'variadic', 'var', 'default', 'hooks']; + } + public function getType(): string + { + return 'Param'; + } + /** + * Whether this parameter uses constructor property promotion. + */ + public function isPromoted(): bool + { + return $this->flags !== 0 || $this->hooks !== []; + } + public function isFinal(): bool + { + return (bool) ($this->flags & Modifiers::FINAL); + } + public function isPublic(): bool + { + $public = (bool) ($this->flags & Modifiers::PUBLIC); + if ($public) { + return \true; + } + if (!$this->isPromoted()) { + return \false; + } + return ($this->flags & Modifiers::VISIBILITY_MASK) === 0; + } + public function isProtected(): bool + { + return (bool) ($this->flags & Modifiers::PROTECTED); + } + public function isPrivate(): bool + { + return (bool) ($this->flags & Modifiers::PRIVATE); + } + public function isReadonly(): bool + { + return (bool) ($this->flags & Modifiers::READONLY); + } + /** + * Whether the promoted property has explicit public(set) visibility. + */ + public function isPublicSet(): bool + { + return (bool) ($this->flags & Modifiers::PUBLIC_SET); + } + /** + * Whether the promoted property has explicit protected(set) visibility. + */ + public function isProtectedSet(): bool + { + return (bool) ($this->flags & Modifiers::PROTECTED_SET); + } + /** + * Whether the promoted property has explicit private(set) visibility. + */ + public function isPrivateSet(): bool + { + return (bool) ($this->flags & Modifiers::PRIVATE_SET); + } +} + 0 : Flags + * 'byRef' => false : Whether hook returns by reference + * 'params' => array(): Parameters + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, $body, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->body = $body; + $this->flags = $subNodes['flags'] ?? 0; + $this->byRef = $subNodes['byRef'] ?? \false; + $this->params = $subNodes['params'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function returnsByRef(): bool + { + return $this->byRef; + } + public function getParams(): array + { + return $this->params; + } + public function getReturnType() + { + return null; + } + /** + * Whether the property hook is final. + */ + public function isFinal(): bool + { + return (bool) ($this->flags & Modifiers::FINAL); + } + public function getStmts(): ?array + { + if ($this->body instanceof Expr) { + $name = $this->name->toLowerString(); + if ($name === 'get') { + return [new Return_($this->body)]; + } + if ($name === 'set') { + if (!$this->hasAttribute('propertyName')) { + throw new \LogicException('Can only use getStmts() on a "set" hook if the "propertyName" attribute is set'); + } + $propName = $this->getAttribute('propertyName'); + $prop = new PropertyFetch(new Variable('this'), (string) $propName); + return [new Expression(new Assign($prop, $this->body))]; + } + throw new \LogicException('Unknown property hook "' . $name . '"'); + } + return $this->body; + } + public function getAttrGroups(): array + { + return $this->attrGroups; + } + public function getType(): string + { + return 'PropertyHook'; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'flags', 'byRef', 'name', 'params', 'body']; + } +} + $attributes Additional attributes + */ + public function __construct($name, ?Node\Expr $default = null, array $attributes = []) + { + $this->attributes = $attributes; + $this->name = \is_string($name) ? new Node\VarLikeIdentifier($name) : $name; + $this->default = $default; + } + public function getSubNodeNames(): array + { + return ['name', 'default']; + } + public function getType(): string + { + return 'PropertyItem'; + } +} +// @deprecated compatibility alias +class_alias(PropertyItem::class, Stmt\PropertyProperty::class); + $attributes Additional attributes + */ + public function __construct(float $value, array $attributes = []) + { + $this->attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames(): array + { + return ['value']; + } + /** + * @param mixed[] $attributes + */ + public static function fromString(string $str, array $attributes = []): Float_ + { + $attributes['rawValue'] = $str; + $float = self::parse($str); + return new Float_($float, $attributes); + } + /** + * @internal + * + * Parses a DNUMBER token like PHP would. + * + * @param string $str A string number + * + * @return float The parsed number + */ + public static function parse(string $str): float + { + $str = str_replace('_', '', $str); + // Check whether this is one of the special integer notations. + if ('0' === $str[0]) { + // hex + if ('x' === $str[1] || 'X' === $str[1]) { + return hexdec($str); + } + // bin + if ('b' === $str[1] || 'B' === $str[1]) { + return bindec($str); + } + // oct, but only if the string does not contain any of '.eE'. + if (\false === strpbrk($str, '.eE')) { + // substr($str, 0, strcspn($str, '89')) cuts the string at the first invalid digit + // (8 or 9) so that only the digits before that are used. + return octdec(substr($str, 0, strcspn($str, '89'))); + } + } + // dec + return (float) $str; + } + public function getType(): string + { + return 'Scalar_Float'; + } +} +// @deprecated compatibility alias +class_alias(Float_::class, DNumber::class); + $attributes Additional attributes + */ + public function __construct(int $value, array $attributes = []) + { + $this->attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames(): array + { + return ['value']; + } + /** + * Constructs an Int node from a string number literal. + * + * @param string $str String number literal (decimal, octal, hex or binary) + * @param array $attributes Additional attributes + * @param bool $allowInvalidOctal Whether to allow invalid octal numbers (PHP 5) + * + * @return Int_ The constructed LNumber, including kind attribute + */ + public static function fromString(string $str, array $attributes = [], bool $allowInvalidOctal = \false): Int_ + { + $attributes['rawValue'] = $str; + $str = str_replace('_', '', $str); + if ('0' !== $str[0] || '0' === $str) { + $attributes['kind'] = Int_::KIND_DEC; + return new Int_((int) $str, $attributes); + } + if ('x' === $str[1] || 'X' === $str[1]) { + $attributes['kind'] = Int_::KIND_HEX; + return new Int_(hexdec($str), $attributes); + } + if ('b' === $str[1] || 'B' === $str[1]) { + $attributes['kind'] = Int_::KIND_BIN; + return new Int_(bindec($str), $attributes); + } + if (!$allowInvalidOctal && strpbrk($str, '89')) { + throw new Error('Invalid numeric literal', $attributes); + } + // Strip optional explicit octal prefix. + if ('o' === $str[1] || 'O' === $str[1]) { + $str = substr($str, 2); + } + // use intval instead of octdec to get proper cutting behavior with malformed numbers + $attributes['kind'] = Int_::KIND_OCT; + return new Int_(intval($str, 8), $attributes); + } + public function getType(): string + { + return 'Scalar_Int'; + } +} +// @deprecated compatibility alias +class_alias(Int_::class, LNumber::class); + $attributes Additional attributes + */ + public function __construct(array $parts, array $attributes = []) + { + $this->attributes = $attributes; + $this->parts = $parts; + } + public function getSubNodeNames(): array + { + return ['parts']; + } + public function getType(): string + { + return 'Scalar_InterpolatedString'; + } +} +// @deprecated compatibility alias +class_alias(InterpolatedString::class, Encapsed::class); + $attributes Additional attributes + */ + public function __construct(array $attributes = []) + { + $this->attributes = $attributes; + } + public function getSubNodeNames(): array + { + return []; + } + /** + * Get name of magic constant. + * + * @return string Name of magic constant + */ + abstract public function getName(): string; +} + Escaped character to its decoded value */ + protected static array $replacements = ['\\' => '\\', '$' => '$', 'n' => "\n", 'r' => "\r", 't' => "\t", 'f' => "\f", 'v' => "\v", 'e' => "\x1b"]; + /** + * Constructs a string scalar node. + * + * @param string $value Value of the string + * @param array $attributes Additional attributes + */ + public function __construct(string $value, array $attributes = []) + { + $this->attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames(): array + { + return ['value']; + } + /** + * @param array $attributes + * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes + */ + public static function fromString(string $str, array $attributes = [], bool $parseUnicodeEscape = \true): self + { + $attributes['kind'] = $str[0] === "'" || $str[1] === "'" && ($str[0] === 'b' || $str[0] === 'B') ? Scalar\String_::KIND_SINGLE_QUOTED : Scalar\String_::KIND_DOUBLE_QUOTED; + $attributes['rawValue'] = $str; + $string = self::parse($str, $parseUnicodeEscape); + return new self($string, $attributes); + } + /** + * @internal + * + * Parses a string token. + * + * @param string $str String token content + * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes + * + * @return string The parsed string + */ + public static function parse(string $str, bool $parseUnicodeEscape = \true): string + { + $bLength = 0; + if ('b' === $str[0] || 'B' === $str[0]) { + $bLength = 1; + } + if ('\'' === $str[$bLength]) { + return str_replace(['\\\\', '\\\''], ['\\', '\''], substr($str, $bLength + 1, -1)); + } else { + return self::parseEscapeSequences(substr($str, $bLength + 1, -1), '"', $parseUnicodeEscape); + } + } + /** + * @internal + * + * Parses escape sequences in strings (all string types apart from single quoted). + * + * @param string $str String without quotes + * @param null|string $quote Quote type + * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes + * + * @return string String with escape sequences parsed + */ + public static function parseEscapeSequences(string $str, ?string $quote, bool $parseUnicodeEscape = \true): string + { + if (null !== $quote) { + $str = str_replace('\\' . $quote, $quote, $str); + } + $extra = ''; + if ($parseUnicodeEscape) { + $extra = '|u\{([0-9a-fA-F]+)\}'; + } + return preg_replace_callback('~\\\\([\\\\$nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}' . $extra . ')~', function ($matches) { + $str = $matches[1]; + if (isset(self::$replacements[$str])) { + return self::$replacements[$str]; + } + if ('x' === $str[0] || 'X' === $str[0]) { + return chr(hexdec(substr($str, 1))); + } + if ('u' === $str[0]) { + $dec = hexdec($matches[2]); + // If it overflowed to float, treat as INT_MAX, it will throw an error anyway. + return self::codePointToUtf8(\is_int($dec) ? $dec : \PHP_INT_MAX); + } else { + return chr(octdec($str) & 255); + } + }, $str); + } + /** + * Converts a Unicode code point to its UTF-8 encoded representation. + * + * @param int $num Code point + * + * @return string UTF-8 representation of code point + */ + private static function codePointToUtf8(int $num): string + { + if ($num <= 0x7f) { + return chr($num); + } + if ($num <= 0x7ff) { + return chr(($num >> 6) + 0xc0) . chr(($num & 0x3f) + 0x80); + } + if ($num <= 0xffff) { + return chr(($num >> 12) + 0xe0) . chr(($num >> 6 & 0x3f) + 0x80) . chr(($num & 0x3f) + 0x80); + } + if ($num <= 0x1fffff) { + return chr(($num >> 18) + 0xf0) . chr(($num >> 12 & 0x3f) + 0x80) . chr(($num >> 6 & 0x3f) + 0x80) . chr(($num & 0x3f) + 0x80); + } + throw new Error('Invalid UTF-8 codepoint escape sequence: Codepoint too large'); + } + public function getType(): string + { + return 'Scalar_String'; + } +} + $attributes Additional attributes + */ + public function __construct(Expr\Variable $var, ?Node\Expr $default = null, array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->default = $default; + } + public function getSubNodeNames(): array + { + return ['var', 'default']; + } + public function getType(): string + { + return 'StaticVar'; + } +} +// @deprecated compatibility alias +class_alias(StaticVar::class, Stmt\StaticVar::class); + $attributes Additional attributes + */ + public function __construct(array $stmts, array $attributes = []) + { + $this->attributes = $attributes; + $this->stmts = $stmts; + } + public function getType(): string + { + return 'Stmt_Block'; + } + public function getSubNodeNames(): array + { + return ['stmts']; + } +} + $attributes Additional attributes + */ + public function __construct(?Node\Expr $num = null, array $attributes = []) + { + $this->attributes = $attributes; + $this->num = $num; + } + public function getSubNodeNames(): array + { + return ['num']; + } + public function getType(): string + { + return 'Stmt_Break'; + } +} + $attributes Additional attributes + */ + public function __construct(?Node\Expr $cond, array $stmts = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames(): array + { + return ['cond', 'stmts']; + } + public function getType(): string + { + return 'Stmt_Case'; + } +} + $attributes Additional attributes + */ + public function __construct(array $types, ?Expr\Variable $var = null, array $stmts = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->types = $types; + $this->var = $var; + $this->stmts = $stmts; + } + public function getSubNodeNames(): array + { + return ['types', 'var', 'stmts']; + } + public function getType(): string + { + return 'Stmt_Catch'; + } +} + $attributes Additional attributes + * @param list $attrGroups PHP attribute groups + * @param null|Node\Identifier|Node\Name|Node\ComplexType $type Type declaration + */ + public function __construct(array $consts, int $flags = 0, array $attributes = [], array $attrGroups = [], ?Node $type = null) + { + $this->attributes = $attributes; + $this->flags = $flags; + $this->consts = $consts; + $this->attrGroups = $attrGroups; + $this->type = $type; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'flags', 'type', 'consts']; + } + /** + * Whether constant is explicitly or implicitly public. + */ + public function isPublic(): bool + { + return ($this->flags & Modifiers::PUBLIC) !== 0 || ($this->flags & Modifiers::VISIBILITY_MASK) === 0; + } + /** + * Whether constant is protected. + */ + public function isProtected(): bool + { + return (bool) ($this->flags & Modifiers::PROTECTED); + } + /** + * Whether constant is private. + */ + public function isPrivate(): bool + { + return (bool) ($this->flags & Modifiers::PRIVATE); + } + /** + * Whether constant is final. + */ + public function isFinal(): bool + { + return (bool) ($this->flags & Modifiers::FINAL); + } + public function getType(): string + { + return 'Stmt_ClassConst'; + } +} + + */ + public function getTraitUses(): array + { + $traitUses = []; + foreach ($this->stmts as $stmt) { + if ($stmt instanceof TraitUse) { + $traitUses[] = $stmt; + } + } + return $traitUses; + } + /** + * @return list + */ + public function getConstants(): array + { + $constants = []; + foreach ($this->stmts as $stmt) { + if ($stmt instanceof ClassConst) { + $constants[] = $stmt; + } + } + return $constants; + } + /** + * @return list + */ + public function getProperties(): array + { + $properties = []; + foreach ($this->stmts as $stmt) { + if ($stmt instanceof Property) { + $properties[] = $stmt; + } + } + return $properties; + } + /** + * Gets property with the given name defined directly in this class/interface/trait. + * + * @param string $name Name of the property + * + * @return Property|null Property node or null if the property does not exist + */ + public function getProperty(string $name): ?Property + { + foreach ($this->stmts as $stmt) { + if ($stmt instanceof Property) { + foreach ($stmt->props as $prop) { + if ($prop instanceof PropertyItem && $name === $prop->name->toString()) { + return $stmt; + } + } + } + } + return null; + } + /** + * Gets all methods defined directly in this class/interface/trait + * + * @return list + */ + public function getMethods(): array + { + $methods = []; + foreach ($this->stmts as $stmt) { + if ($stmt instanceof ClassMethod) { + $methods[] = $stmt; + } + } + return $methods; + } + /** + * Gets method with the given name defined directly in this class/interface/trait. + * + * @param string $name Name of the method (compared case-insensitively) + * + * @return ClassMethod|null Method node or null if the method does not exist + */ + public function getMethod(string $name): ?ClassMethod + { + $lowerName = strtolower($name); + foreach ($this->stmts as $stmt) { + if ($stmt instanceof ClassMethod && $lowerName === $stmt->name->toLowerString()) { + return $stmt; + } + } + return null; + } +} + */ + private static array $magicNames = ['__construct' => \true, '__destruct' => \true, '__call' => \true, '__callstatic' => \true, '__get' => \true, '__set' => \true, '__isset' => \true, '__unset' => \true, '__sleep' => \true, '__wakeup' => \true, '__tostring' => \true, '__set_state' => \true, '__clone' => \true, '__invoke' => \true, '__debuginfo' => \true, '__serialize' => \true, '__unserialize' => \true]; + /** + * Constructs a class method node. + * + * @param string|Node\Identifier $name Name + * @param array{ + * flags?: int, + * byRef?: bool, + * params?: Node\Param[], + * returnType?: null|Node\Identifier|Node\Name|Node\ComplexType, + * stmts?: Node\Stmt[]|null, + * attrGroups?: Node\AttributeGroup[], + * } $subNodes Array of the following optional subnodes: + * 'flags => 0 : Flags + * 'byRef' => false : Whether to return by reference + * 'params' => array() : Parameters + * 'returnType' => null : Return type + * 'stmts' => array() : Statements + * 'attrGroups' => array() : PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->flags = $subNodes['flags'] ?? $subNodes['type'] ?? 0; + $this->byRef = $subNodes['byRef'] ?? \false; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->params = $subNodes['params'] ?? []; + $this->returnType = $subNodes['returnType'] ?? null; + $this->stmts = array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'flags', 'byRef', 'name', 'params', 'returnType', 'stmts']; + } + public function returnsByRef(): bool + { + return $this->byRef; + } + public function getParams(): array + { + return $this->params; + } + public function getReturnType() + { + return $this->returnType; + } + public function getStmts(): ?array + { + return $this->stmts; + } + public function getAttrGroups(): array + { + return $this->attrGroups; + } + /** + * Whether the method is explicitly or implicitly public. + */ + public function isPublic(): bool + { + return ($this->flags & Modifiers::PUBLIC) !== 0 || ($this->flags & Modifiers::VISIBILITY_MASK) === 0; + } + /** + * Whether the method is protected. + */ + public function isProtected(): bool + { + return (bool) ($this->flags & Modifiers::PROTECTED); + } + /** + * Whether the method is private. + */ + public function isPrivate(): bool + { + return (bool) ($this->flags & Modifiers::PRIVATE); + } + /** + * Whether the method is abstract. + */ + public function isAbstract(): bool + { + return (bool) ($this->flags & Modifiers::ABSTRACT); + } + /** + * Whether the method is final. + */ + public function isFinal(): bool + { + return (bool) ($this->flags & Modifiers::FINAL); + } + /** + * Whether the method is static. + */ + public function isStatic(): bool + { + return (bool) ($this->flags & Modifiers::STATIC); + } + /** + * Whether the method is magic. + */ + public function isMagic(): bool + { + return isset(self::$magicNames[$this->name->toLowerString()]); + } + public function getType(): string + { + return 'Stmt_ClassMethod'; + } +} + 0 : Flags + * 'extends' => null : Name of extended class + * 'implements' => array(): Names of implemented interfaces + * 'stmts' => array(): Statements + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->flags = $subNodes['flags'] ?? $subNodes['type'] ?? 0; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->extends = $subNodes['extends'] ?? null; + $this->implements = $subNodes['implements'] ?? []; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'flags', 'name', 'extends', 'implements', 'stmts']; + } + /** + * Whether the class is explicitly abstract. + */ + public function isAbstract(): bool + { + return (bool) ($this->flags & Modifiers::ABSTRACT); + } + /** + * Whether the class is final. + */ + public function isFinal(): bool + { + return (bool) ($this->flags & Modifiers::FINAL); + } + public function isReadonly(): bool + { + return (bool) ($this->flags & Modifiers::READONLY); + } + /** + * Whether the class is anonymous. + */ + public function isAnonymous(): bool + { + return null === $this->name; + } + public function getType(): string + { + return 'Stmt_Class'; + } +} + $attributes Additional attributes + * @param list $attrGroups PHP attribute groups + */ + public function __construct(array $consts, array $attributes = [], array $attrGroups = []) + { + $this->attributes = $attributes; + $this->attrGroups = $attrGroups; + $this->consts = $consts; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'consts']; + } + public function getType(): string + { + return 'Stmt_Const'; + } +} + $attributes Additional attributes + */ + public function __construct(?Node\Expr $num = null, array $attributes = []) + { + $this->attributes = $attributes; + $this->num = $num; + } + public function getSubNodeNames(): array + { + return ['num']; + } + public function getType(): string + { + return 'Stmt_Continue'; + } +} + $attributes Additional attributes + */ + public function __construct(array $declares, ?array $stmts = null, array $attributes = []) + { + $this->attributes = $attributes; + $this->declares = $declares; + $this->stmts = $stmts; + } + public function getSubNodeNames(): array + { + return ['declares', 'stmts']; + } + public function getType(): string + { + return 'Stmt_Declare'; + } +} + $attributes Additional attributes + */ + public function __construct(Node\Expr $cond, array $stmts = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames(): array + { + return ['stmts', 'cond']; + } + public function getType(): string + { + return 'Stmt_Do'; + } +} + $attributes Additional attributes + */ + public function __construct(array $exprs, array $attributes = []) + { + $this->attributes = $attributes; + $this->exprs = $exprs; + } + public function getSubNodeNames(): array + { + return ['exprs']; + } + public function getType(): string + { + return 'Stmt_Echo'; + } +} + $attributes Additional attributes + */ + public function __construct(Node\Expr $cond, array $stmts = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames(): array + { + return ['cond', 'stmts']; + } + public function getType(): string + { + return 'Stmt_ElseIf'; + } +} + $attributes Additional attributes + */ + public function __construct(array $stmts = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->stmts = $stmts; + } + public function getSubNodeNames(): array + { + return ['stmts']; + } + public function getType(): string + { + return 'Stmt_Else'; + } +} + $attrGroups PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, ?Node\Expr $expr = null, array $attrGroups = [], array $attributes = []) + { + parent::__construct($attributes); + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->expr = $expr; + $this->attrGroups = $attrGroups; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'name', 'expr']; + } + public function getType(): string + { + return 'Stmt_EnumCase'; + } +} + null : Scalar type + * 'implements' => array() : Names of implemented interfaces + * 'stmts' => array() : Statements + * 'attrGroups' => array() : PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->scalarType = $subNodes['scalarType'] ?? null; + $this->implements = $subNodes['implements'] ?? []; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + parent::__construct($attributes); + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'name', 'scalarType', 'implements', 'stmts']; + } + public function getType(): string + { + return 'Stmt_Enum'; + } +} + $attributes Additional attributes + */ + public function __construct(Node\Expr $expr, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Stmt_Expression'; + } +} + $attributes Additional attributes + */ + public function __construct(array $stmts = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->stmts = $stmts; + } + public function getSubNodeNames(): array + { + return ['stmts']; + } + public function getType(): string + { + return 'Stmt_Finally'; + } +} + array(): Init expressions + * 'cond' => array(): Loop conditions + * 'loop' => array(): Loop expressions + * 'stmts' => array(): Statements + * @param array $attributes Additional attributes + */ + public function __construct(array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->init = $subNodes['init'] ?? []; + $this->cond = $subNodes['cond'] ?? []; + $this->loop = $subNodes['loop'] ?? []; + $this->stmts = $subNodes['stmts'] ?? []; + } + public function getSubNodeNames(): array + { + return ['init', 'cond', 'loop', 'stmts']; + } + public function getType(): string + { + return 'Stmt_For'; + } +} + null : Variable to assign key to + * 'byRef' => false : Whether to assign value by reference + * 'stmts' => array(): Statements + * @param array $attributes Additional attributes + */ + public function __construct(Node\Expr $expr, Node\Expr $valueVar, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + $this->keyVar = $subNodes['keyVar'] ?? null; + $this->byRef = $subNodes['byRef'] ?? \false; + $this->valueVar = $valueVar; + $this->stmts = $subNodes['stmts'] ?? []; + } + public function getSubNodeNames(): array + { + return ['expr', 'keyVar', 'byRef', 'valueVar', 'stmts']; + } + public function getType(): string + { + return 'Stmt_Foreach'; + } +} + false : Whether to return by reference + * 'params' => array(): Parameters + * 'returnType' => null : Return type + * 'stmts' => array(): Statements + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->byRef = $subNodes['byRef'] ?? \false; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->params = $subNodes['params'] ?? []; + $this->returnType = $subNodes['returnType'] ?? null; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'byRef', 'name', 'params', 'returnType', 'stmts']; + } + public function returnsByRef(): bool + { + return $this->byRef; + } + public function getParams(): array + { + return $this->params; + } + public function getReturnType() + { + return $this->returnType; + } + public function getAttrGroups(): array + { + return $this->attrGroups; + } + /** @return Node\Stmt[] */ + public function getStmts(): array + { + return $this->stmts; + } + public function getType(): string + { + return 'Stmt_Function'; + } +} + $attributes Additional attributes + */ + public function __construct(array $vars, array $attributes = []) + { + $this->attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames(): array + { + return ['vars']; + } + public function getType(): string + { + return 'Stmt_Global'; + } +} + $attributes Additional attributes + */ + public function __construct($name, array $attributes = []) + { + $this->attributes = $attributes; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames(): array + { + return ['name']; + } + public function getType(): string + { + return 'Stmt_Goto'; + } +} + $attributes Additional attributes + */ + public function __construct(Name $prefix, array $uses, int $type = Use_::TYPE_NORMAL, array $attributes = []) + { + $this->attributes = $attributes; + $this->type = $type; + $this->prefix = $prefix; + $this->uses = $uses; + } + public function getSubNodeNames(): array + { + return ['type', 'prefix', 'uses']; + } + public function getType(): string + { + return 'Stmt_GroupUse'; + } +} + $attributes Additional attributes + */ + public function __construct(string $remaining, array $attributes = []) + { + $this->attributes = $attributes; + $this->remaining = $remaining; + } + public function getSubNodeNames(): array + { + return ['remaining']; + } + public function getType(): string + { + return 'Stmt_HaltCompiler'; + } +} + array(): Statements + * 'elseifs' => array(): Elseif clauses + * 'else' => null : Else clause + * @param array $attributes Additional attributes + */ + public function __construct(Node\Expr $cond, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->cond = $cond; + $this->stmts = $subNodes['stmts'] ?? []; + $this->elseifs = $subNodes['elseifs'] ?? []; + $this->else = $subNodes['else'] ?? null; + } + public function getSubNodeNames(): array + { + return ['cond', 'stmts', 'elseifs', 'else']; + } + public function getType(): string + { + return 'Stmt_If'; + } +} + $attributes Additional attributes + */ + public function __construct(string $value, array $attributes = []) + { + $this->attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames(): array + { + return ['value']; + } + public function getType(): string + { + return 'Stmt_InlineHTML'; + } +} + array(): Name of extended interfaces + * 'stmts' => array(): Statements + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->extends = $subNodes['extends'] ?? []; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'name', 'extends', 'stmts']; + } + public function getType(): string + { + return 'Stmt_Interface'; + } +} + $attributes Additional attributes + */ + public function __construct($name, array $attributes = []) + { + $this->attributes = $attributes; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames(): array + { + return ['name']; + } + public function getType(): string + { + return 'Stmt_Label'; + } +} + $attributes Additional attributes + */ + public function __construct(?Node\Name $name = null, ?array $stmts = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->name = $name; + $this->stmts = $stmts; + } + public function getSubNodeNames(): array + { + return ['name', 'stmts']; + } + public function getType(): string + { + return 'Stmt_Namespace'; + } +} + $attributes Additional attributes + * @param null|Identifier|Name|ComplexType $type Type declaration + * @param Node\AttributeGroup[] $attrGroups PHP attribute groups + * @param Node\PropertyHook[] $hooks Property hooks + */ + public function __construct(int $flags, array $props, array $attributes = [], ?Node $type = null, array $attrGroups = [], array $hooks = []) + { + $this->attributes = $attributes; + $this->flags = $flags; + $this->props = $props; + $this->type = $type; + $this->attrGroups = $attrGroups; + $this->hooks = $hooks; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'flags', 'type', 'props', 'hooks']; + } + /** + * Whether the property is explicitly or implicitly public. + */ + public function isPublic(): bool + { + return ($this->flags & Modifiers::PUBLIC) !== 0 || ($this->flags & Modifiers::VISIBILITY_MASK) === 0; + } + /** + * Whether the property is protected. + */ + public function isProtected(): bool + { + return (bool) ($this->flags & Modifiers::PROTECTED); + } + /** + * Whether the property is private. + */ + public function isPrivate(): bool + { + return (bool) ($this->flags & Modifiers::PRIVATE); + } + /** + * Whether the property is static. + */ + public function isStatic(): bool + { + return (bool) ($this->flags & Modifiers::STATIC); + } + /** + * Whether the property is readonly. + */ + public function isReadonly(): bool + { + return (bool) ($this->flags & Modifiers::READONLY); + } + /** + * Whether the property is abstract. + */ + public function isAbstract(): bool + { + return (bool) ($this->flags & Modifiers::ABSTRACT); + } + /** + * Whether the property is final. + */ + public function isFinal(): bool + { + return (bool) ($this->flags & Modifiers::FINAL); + } + /** + * Whether the property has explicit public(set) visibility. + */ + public function isPublicSet(): bool + { + return (bool) ($this->flags & Modifiers::PUBLIC_SET); + } + /** + * Whether the property has explicit protected(set) visibility. + */ + public function isProtectedSet(): bool + { + return (bool) ($this->flags & Modifiers::PROTECTED_SET); + } + /** + * Whether the property has explicit private(set) visibility. + */ + public function isPrivateSet(): bool + { + return (bool) ($this->flags & Modifiers::PRIVATE_SET); + } + public function getType(): string + { + return 'Stmt_Property'; + } +} + $attributes Additional attributes + */ + public function __construct(?Node\Expr $expr = null, array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames(): array + { + return ['expr']; + } + public function getType(): string + { + return 'Stmt_Return'; + } +} + $attributes Additional attributes + */ + public function __construct(array $vars, array $attributes = []) + { + $this->attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames(): array + { + return ['vars']; + } + public function getType(): string + { + return 'Stmt_Static'; + } +} + $attributes Additional attributes + */ + public function __construct(Node\Expr $cond, array $cases, array $attributes = []) + { + $this->attributes = $attributes; + $this->cond = $cond; + $this->cases = $cases; + } + public function getSubNodeNames(): array + { + return ['cond', 'cases']; + } + public function getType(): string + { + return 'Stmt_Switch'; + } +} + $attributes Additional attributes + */ + public function __construct(array $traits, array $adaptations = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->traits = $traits; + $this->adaptations = $adaptations; + } + public function getSubNodeNames(): array + { + return ['traits', 'adaptations']; + } + public function getType(): string + { + return 'Stmt_TraitUse'; + } +} + $attributes Additional attributes + */ + public function __construct(?Node\Name $trait, $method, ?int $newModifier, $newName, array $attributes = []) + { + $this->attributes = $attributes; + $this->trait = $trait; + $this->method = \is_string($method) ? new Node\Identifier($method) : $method; + $this->newModifier = $newModifier; + $this->newName = \is_string($newName) ? new Node\Identifier($newName) : $newName; + } + public function getSubNodeNames(): array + { + return ['trait', 'method', 'newModifier', 'newName']; + } + public function getType(): string + { + return 'Stmt_TraitUseAdaptation_Alias'; + } +} + $attributes Additional attributes + */ + public function __construct(Node\Name $trait, $method, array $insteadof, array $attributes = []) + { + $this->attributes = $attributes; + $this->trait = $trait; + $this->method = \is_string($method) ? new Node\Identifier($method) : $method; + $this->insteadof = $insteadof; + } + public function getSubNodeNames(): array + { + return ['trait', 'method', 'insteadof']; + } + public function getType(): string + { + return 'Stmt_TraitUseAdaptation_Precedence'; + } +} + array(): Statements + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames(): array + { + return ['attrGroups', 'name', 'stmts']; + } + public function getType(): string + { + return 'Stmt_Trait'; + } +} + $attributes Additional attributes + */ + public function __construct(array $stmts, array $catches, ?Finally_ $finally = null, array $attributes = []) + { + $this->attributes = $attributes; + $this->stmts = $stmts; + $this->catches = $catches; + $this->finally = $finally; + } + public function getSubNodeNames(): array + { + return ['stmts', 'catches', 'finally']; + } + public function getType(): string + { + return 'Stmt_TryCatch'; + } +} + $attributes Additional attributes + */ + public function __construct(array $vars, array $attributes = []) + { + $this->attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames(): array + { + return ['vars']; + } + public function getType(): string + { + return 'Stmt_Unset'; + } +} + $attributes Additional attributes + */ + public function __construct(array $uses, int $type = self::TYPE_NORMAL, array $attributes = []) + { + $this->attributes = $attributes; + $this->type = $type; + $this->uses = $uses; + } + public function getSubNodeNames(): array + { + return ['type', 'uses']; + } + public function getType(): string + { + return 'Stmt_Use'; + } +} + $attributes Additional attributes + */ + public function __construct(Node\Expr $cond, array $stmts = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames(): array + { + return ['cond', 'stmts']; + } + public function getType(): string + { + return 'Stmt_While'; + } +} + $attributes Additional attributes + */ + public function __construct(array $types, array $attributes = []) + { + $this->attributes = $attributes; + $this->types = $types; + } + public function getSubNodeNames(): array + { + return ['types']; + } + public function getType(): string + { + return 'UnionType'; + } +} + $attributes Additional attributes + */ + public function __construct(Node\Name $name, $alias = null, int $type = Use_::TYPE_UNKNOWN, array $attributes = []) + { + $this->attributes = $attributes; + $this->type = $type; + $this->name = $name; + $this->alias = \is_string($alias) ? new Identifier($alias) : $alias; + } + public function getSubNodeNames(): array + { + return ['type', 'name', 'alias']; + } + /** + * Get alias. If not explicitly given this is the last component of the used name. + */ + public function getAlias(): Identifier + { + if (null !== $this->alias) { + return $this->alias; + } + return new Identifier($this->name->getLast()); + } + public function getType(): string + { + return 'UseItem'; + } +} +// @deprecated compatibility alias +class_alias(UseItem::class, Stmt\UseUse::class); + $attributes Additional attributes + */ + public function __construct(array $attributes = []) + { + $this->attributes = $attributes; + } + public function getType(): string + { + return 'VariadicPlaceholder'; + } + public function getSubNodeNames(): array + { + return []; + } +} + Attributes */ + protected array $attributes; + /** + * Creates a Node. + * + * @param array $attributes Array of attributes + */ + public function __construct(array $attributes = []) + { + $this->attributes = $attributes; + } + /** + * Gets line the node started in (alias of getStartLine). + * + * @return int Start line (or -1 if not available) + * @phpstan-return -1|positive-int + */ + public function getLine(): int + { + return $this->attributes['startLine'] ?? -1; + } + /** + * Gets line the node started in. + * + * Requires the 'startLine' attribute to be enabled in the lexer (enabled by default). + * + * @return int Start line (or -1 if not available) + * @phpstan-return -1|positive-int + */ + public function getStartLine(): int + { + return $this->attributes['startLine'] ?? -1; + } + /** + * Gets the line the node ended in. + * + * Requires the 'endLine' attribute to be enabled in the lexer (enabled by default). + * + * @return int End line (or -1 if not available) + * @phpstan-return -1|positive-int + */ + public function getEndLine(): int + { + return $this->attributes['endLine'] ?? -1; + } + /** + * Gets the token offset of the first token that is part of this node. + * + * The offset is an index into the array returned by Lexer::getTokens(). + * + * Requires the 'startTokenPos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int Token start position (or -1 if not available) + */ + public function getStartTokenPos(): int + { + return $this->attributes['startTokenPos'] ?? -1; + } + /** + * Gets the token offset of the last token that is part of this node. + * + * The offset is an index into the array returned by Lexer::getTokens(). + * + * Requires the 'endTokenPos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int Token end position (or -1 if not available) + */ + public function getEndTokenPos(): int + { + return $this->attributes['endTokenPos'] ?? -1; + } + /** + * Gets the file offset of the first character that is part of this node. + * + * Requires the 'startFilePos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int File start position (or -1 if not available) + */ + public function getStartFilePos(): int + { + return $this->attributes['startFilePos'] ?? -1; + } + /** + * Gets the file offset of the last character that is part of this node. + * + * Requires the 'endFilePos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int File end position (or -1 if not available) + */ + public function getEndFilePos(): int + { + return $this->attributes['endFilePos'] ?? -1; + } + /** + * Gets all comments directly preceding this node. + * + * The comments are also available through the "comments" attribute. + * + * @return Comment[] + */ + public function getComments(): array + { + return $this->attributes['comments'] ?? []; + } + /** + * Gets the doc comment of the node. + * + * @return null|Comment\Doc Doc comment object or null + */ + public function getDocComment(): ?Comment\Doc + { + $comments = $this->getComments(); + for ($i = count($comments) - 1; $i >= 0; $i--) { + $comment = $comments[$i]; + if ($comment instanceof Comment\Doc) { + return $comment; + } + } + return null; + } + /** + * Sets the doc comment of the node. + * + * This will either replace an existing doc comment or add it to the comments array. + * + * @param Comment\Doc $docComment Doc comment to set + */ + public function setDocComment(Comment\Doc $docComment): void + { + $comments = $this->getComments(); + for ($i = count($comments) - 1; $i >= 0; $i--) { + if ($comments[$i] instanceof Comment\Doc) { + // Replace existing doc comment. + $comments[$i] = $docComment; + $this->setAttribute('comments', $comments); + return; + } + } + // Append new doc comment. + $comments[] = $docComment; + $this->setAttribute('comments', $comments); + } + public function setAttribute(string $key, $value): void + { + $this->attributes[$key] = $value; + } + public function hasAttribute(string $key): bool + { + return array_key_exists($key, $this->attributes); + } + public function getAttribute(string $key, $default = null) + { + if (array_key_exists($key, $this->attributes)) { + return $this->attributes[$key]; + } + return $default; + } + public function getAttributes(): array + { + return $this->attributes; + } + public function setAttributes(array $attributes): void + { + $this->attributes = $attributes; + } + /** + * @return array + */ + public function jsonSerialize(): array + { + return ['nodeType' => $this->getType()] + get_object_vars($this); + } +} + \true, 'startLine' => \true, 'endLine' => \true, 'startFilePos' => \true, 'endFilePos' => \true, 'startTokenPos' => \true, 'endTokenPos' => \true]; + /** + * Constructs a NodeDumper. + * + * Supported options: + * * bool dumpComments: Whether comments should be dumped. + * * bool dumpPositions: Whether line/offset information should be dumped. To dump offset + * information, the code needs to be passed to dump(). + * * bool dumpOtherAttributes: Whether non-comment, non-position attributes should be dumped. + * + * @param array $options Options (see description) + */ + public function __construct(array $options = []) + { + $this->dumpComments = !empty($options['dumpComments']); + $this->dumpPositions = !empty($options['dumpPositions']); + $this->dumpOtherAttributes = !empty($options['dumpOtherAttributes']); + } + /** + * Dumps a node or array. + * + * @param array|Node $node Node or array to dump + * @param string|null $code Code corresponding to dumped AST. This only needs to be passed if + * the dumpPositions option is enabled and the dumping of node offsets + * is desired. + * + * @return string Dumped value + */ + public function dump($node, ?string $code = null): string + { + $this->code = $code; + $this->res = ''; + $this->nl = "\n"; + $this->dumpRecursive($node, \false); + return $this->res; + } + /** @param mixed $node */ + protected function dumpRecursive($node, bool $indent = \true): void + { + if ($indent) { + $this->nl .= " "; + } + if ($node instanceof Node) { + $this->res .= $node->getType(); + if ($this->dumpPositions && null !== $p = $this->dumpPosition($node)) { + $this->res .= $p; + } + $this->res .= '('; + foreach ($node->getSubNodeNames() as $key) { + $this->res .= "{$this->nl} " . $key . ': '; + $value = $node->{$key}; + if (\is_int($value)) { + if ('flags' === $key || 'newModifier' === $key) { + $this->res .= $this->dumpFlags($value); + continue; + } + if ('type' === $key && $node instanceof Include_) { + $this->res .= $this->dumpIncludeType($value); + continue; + } + if ('type' === $key && ($node instanceof Use_ || $node instanceof UseItem || $node instanceof GroupUse)) { + $this->res .= $this->dumpUseType($value); + continue; + } + } + $this->dumpRecursive($value); + } + if ($this->dumpComments && $comments = $node->getComments()) { + $this->res .= "{$this->nl} comments: "; + $this->dumpRecursive($comments); + } + if ($this->dumpOtherAttributes) { + foreach ($node->getAttributes() as $key => $value) { + if (isset(self::IGNORE_ATTRIBUTES[$key])) { + continue; + } + $this->res .= "{$this->nl} {$key}: "; + if (\is_int($value)) { + if ('kind' === $key) { + if ($node instanceof Int_) { + $this->res .= $this->dumpIntKind($value); + continue; + } + if ($node instanceof String_ || $node instanceof InterpolatedString) { + $this->res .= $this->dumpStringKind($value); + continue; + } + if ($node instanceof Array_) { + $this->res .= $this->dumpArrayKind($value); + continue; + } + if ($node instanceof List_) { + $this->res .= $this->dumpListKind($value); + continue; + } + } + } + $this->dumpRecursive($value); + } + } + $this->res .= "{$this->nl})"; + } elseif (\is_array($node)) { + $this->res .= 'array('; + foreach ($node as $key => $value) { + $this->res .= "{$this->nl} " . $key . ': '; + $this->dumpRecursive($value); + } + $this->res .= "{$this->nl})"; + } elseif ($node instanceof Comment) { + $this->res .= \str_replace("\n", $this->nl, $node->getReformattedText()); + } elseif (\is_string($node)) { + $this->res .= \str_replace("\n", $this->nl, $node); + } elseif (\is_int($node) || \is_float($node)) { + $this->res .= $node; + } elseif (null === $node) { + $this->res .= 'null'; + } elseif (\false === $node) { + $this->res .= 'false'; + } elseif (\true === $node) { + $this->res .= 'true'; + } else { + throw new \InvalidArgumentException('Can only dump nodes and arrays.'); + } + if ($indent) { + $this->nl = \substr($this->nl, 0, -4); + } + } + protected function dumpFlags(int $flags): string + { + $strs = []; + if ($flags & Modifiers::PUBLIC) { + $strs[] = 'PUBLIC'; + } + if ($flags & Modifiers::PROTECTED) { + $strs[] = 'PROTECTED'; + } + if ($flags & Modifiers::PRIVATE) { + $strs[] = 'PRIVATE'; + } + if ($flags & Modifiers::ABSTRACT) { + $strs[] = 'ABSTRACT'; + } + if ($flags & Modifiers::STATIC) { + $strs[] = 'STATIC'; + } + if ($flags & Modifiers::FINAL) { + $strs[] = 'FINAL'; + } + if ($flags & Modifiers::READONLY) { + $strs[] = 'READONLY'; + } + if ($flags & Modifiers::PUBLIC_SET) { + $strs[] = 'PUBLIC_SET'; + } + if ($flags & Modifiers::PROTECTED_SET) { + $strs[] = 'PROTECTED_SET'; + } + if ($flags & Modifiers::PRIVATE_SET) { + $strs[] = 'PRIVATE_SET'; + } + if ($strs) { + return implode(' | ', $strs) . ' (' . $flags . ')'; + } else { + return (string) $flags; + } + } + /** @param array $map */ + private function dumpEnum(int $value, array $map): string + { + if (!isset($map[$value])) { + return (string) $value; + } + return $map[$value] . ' (' . $value . ')'; + } + private function dumpIncludeType(int $type): string + { + return $this->dumpEnum($type, [Include_::TYPE_INCLUDE => 'TYPE_INCLUDE', Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE', Include_::TYPE_REQUIRE => 'TYPE_REQUIRE', Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQUIRE_ONCE']); + } + private function dumpUseType(int $type): string + { + return $this->dumpEnum($type, [Use_::TYPE_UNKNOWN => 'TYPE_UNKNOWN', Use_::TYPE_NORMAL => 'TYPE_NORMAL', Use_::TYPE_FUNCTION => 'TYPE_FUNCTION', Use_::TYPE_CONSTANT => 'TYPE_CONSTANT']); + } + private function dumpIntKind(int $kind): string + { + return $this->dumpEnum($kind, [Int_::KIND_BIN => 'KIND_BIN', Int_::KIND_OCT => 'KIND_OCT', Int_::KIND_DEC => 'KIND_DEC', Int_::KIND_HEX => 'KIND_HEX']); + } + private function dumpStringKind(int $kind): string + { + return $this->dumpEnum($kind, [String_::KIND_SINGLE_QUOTED => 'KIND_SINGLE_QUOTED', String_::KIND_DOUBLE_QUOTED => 'KIND_DOUBLE_QUOTED', String_::KIND_HEREDOC => 'KIND_HEREDOC', String_::KIND_NOWDOC => 'KIND_NOWDOC']); + } + private function dumpArrayKind(int $kind): string + { + return $this->dumpEnum($kind, [Array_::KIND_LONG => 'KIND_LONG', Array_::KIND_SHORT => 'KIND_SHORT']); + } + private function dumpListKind(int $kind): string + { + return $this->dumpEnum($kind, [List_::KIND_LIST => 'KIND_LIST', List_::KIND_ARRAY => 'KIND_ARRAY']); + } + /** + * Dump node position, if possible. + * + * @param Node $node Node for which to dump position + * + * @return string|null Dump of position, or null if position information not available + */ + protected function dumpPosition(Node $node): ?string + { + if (!$node->hasAttribute('startLine') || !$node->hasAttribute('endLine')) { + return null; + } + $start = $node->getStartLine(); + $end = $node->getEndLine(); + if ($node->hasAttribute('startFilePos') && $node->hasAttribute('endFilePos') && null !== $this->code) { + $start .= ':' . $this->toColumn($this->code, $node->getStartFilePos()); + $end .= ':' . $this->toColumn($this->code, $node->getEndFilePos()); + } + return "[{$start} - {$end}]"; + } + // Copied from Error class + private function toColumn(string $code, int $pos): int + { + if ($pos > strlen($code)) { + throw new \RuntimeException('Invalid position information'); + } + $lineStartPos = strrpos($code, "\n", $pos - strlen($code)); + if (\false === $lineStartPos) { + $lineStartPos = -1; + } + return $pos - $lineStartPos; + } +} +traverse($nodes); + return $visitor->getFoundNodes(); + } + /** + * Find all nodes that are instances of a certain class. + * @template TNode as Node + * + * @param Node|Node[] $nodes Single node or array of nodes to search in + * @param class-string $class Class name + * + * @return TNode[] Found nodes (all instances of $class) + */ + public function findInstanceOf($nodes, string $class): array + { + return $this->find($nodes, function ($node) use ($class) { + return $node instanceof $class; + }); + } + /** + * Find first node satisfying a filter callback. + * + * @param Node|Node[] $nodes Single node or array of nodes to search in + * @param callable $filter Filter callback: function(Node $node) : bool + * + * @return null|Node Found node (or null if none found) + */ + public function findFirst($nodes, callable $filter): ?Node + { + if ($nodes === []) { + return null; + } + if (!is_array($nodes)) { + $nodes = [$nodes]; + } + $visitor = new FirstFindingVisitor($filter); + $traverser = new NodeTraverser($visitor); + $traverser->traverse($nodes); + return $visitor->getFoundNode(); + } + /** + * Find first node that is an instance of a certain class. + * + * @template TNode as Node + * + * @param Node|Node[] $nodes Single node or array of nodes to search in + * @param class-string $class Class name + * + * @return null|TNode Found node, which is an instance of $class (or null if none found) + */ + public function findFirstInstanceOf($nodes, string $class): ?Node + { + return $this->findFirst($nodes, function ($node) use ($class) { + return $node instanceof $class; + }); + } +} + Visitors */ + protected array $visitors = []; + /** @var bool Whether traversal should be stopped */ + protected bool $stopTraversal; + /** + * Create a traverser with the given visitors. + * + * @param NodeVisitor ...$visitors Node visitors + */ + public function __construct(NodeVisitor ...$visitors) + { + $this->visitors = $visitors; + } + /** + * Adds a visitor. + * + * @param NodeVisitor $visitor Visitor to add + */ + public function addVisitor(NodeVisitor $visitor): void + { + $this->visitors[] = $visitor; + } + /** + * Removes an added visitor. + */ + public function removeVisitor(NodeVisitor $visitor): void + { + $index = array_search($visitor, $this->visitors); + if ($index !== \false) { + array_splice($this->visitors, $index, 1, []); + } + } + /** + * Traverses an array of nodes using the registered visitors. + * + * @param Node[] $nodes Array of nodes + * + * @return Node[] Traversed array of nodes + */ + public function traverse(array $nodes): array + { + $this->stopTraversal = \false; + foreach ($this->visitors as $visitor) { + if (null !== $return = $visitor->beforeTraverse($nodes)) { + $nodes = $return; + } + } + $nodes = $this->traverseArray($nodes); + for ($i = \count($this->visitors) - 1; $i >= 0; --$i) { + $visitor = $this->visitors[$i]; + if (null !== $return = $visitor->afterTraverse($nodes)) { + $nodes = $return; + } + } + return $nodes; + } + /** + * Recursively traverse a node. + * + * @param Node $node Node to traverse. + */ + protected function traverseNode(Node $node): void + { + foreach ($node->getSubNodeNames() as $name) { + $subNode = $node->{$name}; + if (\is_array($subNode)) { + $node->{$name} = $this->traverseArray($subNode); + if ($this->stopTraversal) { + break; + } + continue; + } + if (!$subNode instanceof Node) { + continue; + } + $traverseChildren = \true; + $visitorIndex = -1; + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->enterNode($subNode); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($subNode, $return); + $subNode = $node->{$name} = $return; + } elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) { + $traverseChildren = \false; + } elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) { + $traverseChildren = \false; + break; + } elseif (NodeVisitor::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) { + $node->{$name} = null; + continue 2; + } else { + throw new \LogicException('enterNode() returned invalid value of type ' . gettype($return)); + } + } + } + if ($traverseChildren) { + $this->traverseNode($subNode); + if ($this->stopTraversal) { + break; + } + } + for (; $visitorIndex >= 0; --$visitorIndex) { + $visitor = $this->visitors[$visitorIndex]; + $return = $visitor->leaveNode($subNode); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($subNode, $return); + $subNode = $node->{$name} = $return; + } elseif (NodeVisitor::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) { + $node->{$name} = null; + break; + } elseif (\is_array($return)) { + throw new \LogicException('leaveNode() may only return an array ' . 'if the parent structure is an array'); + } else { + throw new \LogicException('leaveNode() returned invalid value of type ' . gettype($return)); + } + } + } + } + } + /** + * Recursively traverse array (usually of nodes). + * + * @param Node[] $nodes Array to traverse + * + * @return Node[] Result of traversal (may be original array or changed one) + */ + protected function traverseArray(array $nodes): array + { + $doNodes = []; + foreach ($nodes as $i => $node) { + if (!$node instanceof Node) { + if (\is_array($node)) { + throw new \LogicException('Invalid node structure: Contains nested arrays'); + } + continue; + } + $traverseChildren = \true; + $visitorIndex = -1; + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->enterNode($node); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($node, $return); + $nodes[$i] = $node = $return; + } elseif (\is_array($return)) { + $doNodes[] = [$i, $return]; + continue 2; + } elseif (NodeVisitor::REMOVE_NODE === $return) { + $doNodes[] = [$i, []]; + continue 2; + } elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) { + $traverseChildren = \false; + } elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) { + $traverseChildren = \false; + break; + } elseif (NodeVisitor::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) { + throw new \LogicException('REPLACE_WITH_NULL can not be used if the parent structure is an array'); + } else { + throw new \LogicException('enterNode() returned invalid value of type ' . gettype($return)); + } + } + } + if ($traverseChildren) { + $this->traverseNode($node); + if ($this->stopTraversal) { + break; + } + } + for (; $visitorIndex >= 0; --$visitorIndex) { + $visitor = $this->visitors[$visitorIndex]; + $return = $visitor->leaveNode($node); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($node, $return); + $nodes[$i] = $node = $return; + } elseif (\is_array($return)) { + $doNodes[] = [$i, $return]; + break; + } elseif (NodeVisitor::REMOVE_NODE === $return) { + $doNodes[] = [$i, []]; + break; + } elseif (NodeVisitor::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) { + throw new \LogicException('REPLACE_WITH_NULL can not be used if the parent structure is an array'); + } else { + throw new \LogicException('leaveNode() returned invalid value of type ' . gettype($return)); + } + } + } + } + if (!empty($doNodes)) { + while (list($i, $replace) = array_pop($doNodes)) { + array_splice($nodes, $i, 1, $replace); + } + } + return $nodes; + } + private function ensureReplacementReasonable(Node $old, Node $new): void + { + if ($old instanceof Node\Stmt && $new instanceof Node\Expr) { + throw new \LogicException("Trying to replace statement ({$old->getType()}) " . "with expression ({$new->getType()}). Are you missing a " . "Stmt_Expression wrapper?"); + } + if ($old instanceof Node\Expr && $new instanceof Node\Stmt) { + throw new \LogicException("Trying to replace expression ({$old->getType()}) " . "with statement ({$new->getType()})"); + } + } +} + $node stays as-is + * * array (of Nodes) + * => The return value is merged into the parent array (at the position of the $node) + * * NodeVisitor::REMOVE_NODE + * => $node is removed from the parent array + * * NodeVisitor::REPLACE_WITH_NULL + * => $node is replaced with null + * * NodeVisitor::DONT_TRAVERSE_CHILDREN + * => Children of $node are not traversed. $node stays as-is + * * NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN + * => Further visitors for the current node are skipped, and its children are not + * traversed. $node stays as-is. + * * NodeVisitor::STOP_TRAVERSAL + * => Traversal is aborted. $node stays as-is + * * otherwise + * => $node is set to the return value + * + * @param Node $node Node + * + * @return null|int|Node|Node[] Replacement node (or special return value) + */ + public function enterNode(Node $node); + /** + * Called when leaving a node. + * + * Return value semantics: + * * null + * => $node stays as-is + * * NodeVisitor::REMOVE_NODE + * => $node is removed from the parent array + * * NodeVisitor::REPLACE_WITH_NULL + * => $node is replaced with null + * * NodeVisitor::STOP_TRAVERSAL + * => Traversal is aborted. $node stays as-is + * * array (of Nodes) + * => The return value is merged into the parent array (at the position of the $node) + * * otherwise + * => $node is set to the return value + * + * @param Node $node Node + * + * @return null|int|Node|Node[] Replacement node (or special return value) + */ + public function leaveNode(Node $node); + /** + * Called once after traversal. + * + * Return value semantics: + * * null: $nodes stays as-is + * * otherwise: $nodes is set to the return value + * + * @param Node[] $nodes Array of nodes + * + * @return null|Node[] Array of nodes + */ + public function afterTraverse(array $nodes); +} +setAttribute('origNode', $origNode); + return $node; + } +} + Token positions of comments */ + private array $commentPositions = []; + /** + * Create a comment annotation visitor. + * + * @param Token[] $tokens Token array + */ + public function __construct(array $tokens) + { + $this->tokens = $tokens; + // Collect positions of comments. We use this to avoid traversing parts of the AST where + // there are no comments. + foreach ($tokens as $i => $token) { + if ($token->id === \T_COMMENT || $token->id === \T_DOC_COMMENT) { + $this->commentPositions[] = $i; + } + } + } + public function enterNode(Node $node) + { + $nextCommentPos = current($this->commentPositions); + if ($nextCommentPos === \false) { + // No more comments. + return self::STOP_TRAVERSAL; + } + $oldPos = $this->pos; + $this->pos = $pos = $node->getStartTokenPos(); + if ($nextCommentPos > $oldPos && $nextCommentPos < $pos) { + $comments = []; + while (--$pos >= $oldPos) { + $token = $this->tokens[$pos]; + if ($token->id === \T_DOC_COMMENT) { + $comments[] = new Comment\Doc($token->text, $token->line, $token->pos, $pos, $token->getEndLine(), $token->getEndPos() - 1, $pos); + continue; + } + if ($token->id === \T_COMMENT) { + $comments[] = new Comment($token->text, $token->line, $token->pos, $pos, $token->getEndLine(), $token->getEndPos() - 1, $pos); + continue; + } + if ($token->id !== \T_WHITESPACE) { + break; + } + } + if (!empty($comments)) { + $node->setAttribute('comments', array_reverse($comments)); + } + do { + $nextCommentPos = next($this->commentPositions); + } while ($nextCommentPos !== \false && $nextCommentPos < $this->pos); + } + $endPos = $node->getEndTokenPos(); + if ($nextCommentPos > $endPos) { + // Skip children if there are no comments located inside this node. + $this->pos = $endPos; + return self::DONT_TRAVERSE_CHILDREN; + } + return null; + } +} + Found nodes */ + protected array $foundNodes; + public function __construct(callable $filterCallback) + { + $this->filterCallback = $filterCallback; + } + /** + * Get found nodes satisfying the filter callback. + * + * Nodes are returned in pre-order. + * + * @return list Found nodes + */ + public function getFoundNodes(): array + { + return $this->foundNodes; + } + public function beforeTraverse(array $nodes): ?array + { + $this->foundNodes = []; + return null; + } + public function enterNode(Node $node) + { + $filterCallback = $this->filterCallback; + if ($filterCallback($node)) { + $this->foundNodes[] = $node; + } + return null; + } +} +filterCallback = $filterCallback; + } + /** + * Get found node satisfying the filter callback. + * + * Returns null if no node satisfies the filter callback. + * + * @return null|Node Found node (or null if not found) + */ + public function getFoundNode(): ?Node + { + return $this->foundNode; + } + public function beforeTraverse(array $nodes): ?array + { + $this->foundNode = null; + return null; + } + public function enterNode(Node $node) + { + $filterCallback = $this->filterCallback; + if ($filterCallback($node)) { + $this->foundNode = $node; + return NodeVisitor::STOP_TRAVERSAL; + } + return null; + } +} +nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing()); + $this->preserveOriginalNames = $options['preserveOriginalNames'] ?? \false; + $this->replaceNodes = $options['replaceNodes'] ?? \true; + } + /** + * Get name resolution context. + */ + public function getNameContext(): NameContext + { + return $this->nameContext; + } + public function beforeTraverse(array $nodes): ?array + { + $this->nameContext->startNamespace(); + return null; + } + public function enterNode(Node $node) + { + if ($node instanceof Stmt\Namespace_) { + $this->nameContext->startNamespace($node->name); + } elseif ($node instanceof Stmt\Use_) { + foreach ($node->uses as $use) { + $this->addAlias($use, $node->type, null); + } + } elseif ($node instanceof Stmt\GroupUse) { + foreach ($node->uses as $use) { + $this->addAlias($use, $node->type, $node->prefix); + } + } elseif ($node instanceof Stmt\Class_) { + if (null !== $node->extends) { + $node->extends = $this->resolveClassName($node->extends); + } + foreach ($node->implements as &$interface) { + $interface = $this->resolveClassName($interface); + } + $this->resolveAttrGroups($node); + if (null !== $node->name) { + $this->addNamespacedName($node); + } else { + $node->namespacedName = null; + } + } elseif ($node instanceof Stmt\Interface_) { + foreach ($node->extends as &$interface) { + $interface = $this->resolveClassName($interface); + } + $this->resolveAttrGroups($node); + $this->addNamespacedName($node); + } elseif ($node instanceof Stmt\Enum_) { + foreach ($node->implements as &$interface) { + $interface = $this->resolveClassName($interface); + } + $this->resolveAttrGroups($node); + $this->addNamespacedName($node); + } elseif ($node instanceof Stmt\Trait_) { + $this->resolveAttrGroups($node); + $this->addNamespacedName($node); + } elseif ($node instanceof Stmt\Function_) { + $this->resolveSignature($node); + $this->resolveAttrGroups($node); + $this->addNamespacedName($node); + } elseif ($node instanceof Stmt\ClassMethod || $node instanceof Expr\Closure || $node instanceof Expr\ArrowFunction) { + $this->resolveSignature($node); + $this->resolveAttrGroups($node); + } elseif ($node instanceof Stmt\Property) { + if (null !== $node->type) { + $node->type = $this->resolveType($node->type); + } + $this->resolveAttrGroups($node); + } elseif ($node instanceof Node\PropertyHook) { + foreach ($node->params as $param) { + $param->type = $this->resolveType($param->type); + $this->resolveAttrGroups($param); + } + $this->resolveAttrGroups($node); + } elseif ($node instanceof Stmt\Const_) { + foreach ($node->consts as $const) { + $this->addNamespacedName($const); + } + $this->resolveAttrGroups($node); + } elseif ($node instanceof Stmt\ClassConst) { + if (null !== $node->type) { + $node->type = $this->resolveType($node->type); + } + $this->resolveAttrGroups($node); + } elseif ($node instanceof Stmt\EnumCase) { + $this->resolveAttrGroups($node); + } elseif ($node instanceof Expr\StaticCall || $node instanceof Expr\StaticPropertyFetch || $node instanceof Expr\ClassConstFetch || $node instanceof Expr\New_ || $node instanceof Expr\Instanceof_) { + if ($node->class instanceof Name) { + $node->class = $this->resolveClassName($node->class); + } + } elseif ($node instanceof Stmt\Catch_) { + foreach ($node->types as &$type) { + $type = $this->resolveClassName($type); + } + } elseif ($node instanceof Expr\FuncCall) { + if ($node->name instanceof Name) { + $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_FUNCTION); + } + } elseif ($node instanceof Expr\ConstFetch) { + $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_CONSTANT); + } elseif ($node instanceof Stmt\TraitUse) { + foreach ($node->traits as &$trait) { + $trait = $this->resolveClassName($trait); + } + foreach ($node->adaptations as $adaptation) { + if (null !== $adaptation->trait) { + $adaptation->trait = $this->resolveClassName($adaptation->trait); + } + if ($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) { + foreach ($adaptation->insteadof as &$insteadof) { + $insteadof = $this->resolveClassName($insteadof); + } + } + } + } + return null; + } + /** @param Stmt\Use_::TYPE_* $type */ + private function addAlias(Node\UseItem $use, int $type, ?Name $prefix = null): void + { + // Add prefix for group uses + $name = $prefix ? Name::concat($prefix, $use->name) : $use->name; + // Type is determined either by individual element or whole use declaration + $type |= $use->type; + $this->nameContext->addAlias($name, (string) $use->getAlias(), $type, $use->getAttributes()); + } + /** @param Stmt\Function_|Stmt\ClassMethod|Expr\Closure|Expr\ArrowFunction $node */ + private function resolveSignature($node): void + { + foreach ($node->params as $param) { + $param->type = $this->resolveType($param->type); + $this->resolveAttrGroups($param); + } + $node->returnType = $this->resolveType($node->returnType); + } + /** + * @template T of Node\Identifier|Name|Node\ComplexType|null + * @param T $node + * @return T + */ + private function resolveType(?Node $node): ?Node + { + if ($node instanceof Name) { + return $this->resolveClassName($node); + } + if ($node instanceof Node\NullableType) { + $node->type = $this->resolveType($node->type); + return $node; + } + if ($node instanceof Node\UnionType || $node instanceof Node\IntersectionType) { + foreach ($node->types as &$type) { + $type = $this->resolveType($type); + } + return $node; + } + return $node; + } + /** + * Resolve name, according to name resolver options. + * + * @param Name $name Function or constant name to resolve + * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_* + * + * @return Name Resolved name, or original name with attribute + */ + protected function resolveName(Name $name, int $type): Name + { + if (!$this->replaceNodes) { + $resolvedName = $this->nameContext->getResolvedName($name, $type); + if (null !== $resolvedName) { + $name->setAttribute('resolvedName', $resolvedName); + } else { + $name->setAttribute('namespacedName', FullyQualified::concat($this->nameContext->getNamespace(), $name, $name->getAttributes())); + } + return $name; + } + if ($this->preserveOriginalNames) { + // Save the original name + $originalName = $name; + $name = clone $originalName; + $name->setAttribute('originalName', $originalName); + } + $resolvedName = $this->nameContext->getResolvedName($name, $type); + if (null !== $resolvedName) { + return $resolvedName; + } + // unqualified names inside a namespace cannot be resolved at compile-time + // add the namespaced version of the name as an attribute + $name->setAttribute('namespacedName', FullyQualified::concat($this->nameContext->getNamespace(), $name, $name->getAttributes())); + return $name; + } + protected function resolveClassName(Name $name): Name + { + return $this->resolveName($name, Stmt\Use_::TYPE_NORMAL); + } + protected function addNamespacedName(Node $node): void + { + $node->namespacedName = Name::concat($this->nameContext->getNamespace(), (string) $node->name); + } + protected function resolveAttrGroups(Node $node): void + { + foreach ($node->attrGroups as $attrGroup) { + foreach ($attrGroup->attrs as $attr) { + $attr->name = $this->resolveClassName($attr->name); + } + } + } +} +$weakReferences=false on the child node, the parent node can be accessed through + * $node->getAttribute('parent'), the previous + * node can be accessed through $node->getAttribute('previous'), + * and the next node can be accessed through $node->getAttribute('next'). + * + * With $weakReferences=true attribute names are prefixed by "weak_", e.g. "weak_parent". + */ +final class NodeConnectingVisitor extends NodeVisitorAbstract +{ + /** + * @var Node[] + */ + private array $stack = []; + /** + * @var ?Node + */ + private $previous; + private bool $weakReferences; + public function __construct(bool $weakReferences = \false) + { + $this->weakReferences = $weakReferences; + } + public function beforeTraverse(array $nodes) + { + $this->stack = []; + $this->previous = null; + } + public function enterNode(Node $node) + { + if (!empty($this->stack)) { + $parent = $this->stack[count($this->stack) - 1]; + if ($this->weakReferences) { + $node->setAttribute('weak_parent', \WeakReference::create($parent)); + } else { + $node->setAttribute('parent', $parent); + } + } + if ($this->previous !== null) { + if ($this->weakReferences) { + if ($this->previous->getAttribute('weak_parent') === $node->getAttribute('weak_parent')) { + $node->setAttribute('weak_previous', \WeakReference::create($this->previous)); + $this->previous->setAttribute('weak_next', \WeakReference::create($node)); + } + } elseif ($this->previous->getAttribute('parent') === $node->getAttribute('parent')) { + $node->setAttribute('previous', $this->previous); + $this->previous->setAttribute('next', $node); + } + } + $this->stack[] = $node; + } + public function leaveNode(Node $node) + { + $this->previous = $node; + array_pop($this->stack); + } +} +$weakReferences=false on the child node, the parent node can be accessed through + * $node->getAttribute('parent'). + * + * With $weakReferences=true the attribute name is "weak_parent" instead. + */ +final class ParentConnectingVisitor extends NodeVisitorAbstract +{ + /** + * @var Node[] + */ + private array $stack = []; + private bool $weakReferences; + public function __construct(bool $weakReferences = \false) + { + $this->weakReferences = $weakReferences; + } + public function beforeTraverse(array $nodes) + { + $this->stack = []; + } + public function enterNode(Node $node) + { + if (!empty($this->stack)) { + $parent = $this->stack[count($this->stack) - 1]; + if ($this->weakReferences) { + $node->setAttribute('weak_parent', \WeakReference::create($parent)); + } else { + $node->setAttribute('parent', $parent); + } + } + $this->stack[] = $node; + } + public function leaveNode(Node $node) + { + array_pop($this->stack); + } +} +'", "T_IS_GREATER_OR_EQUAL", "T_SL", "T_SR", "'+'", "'-'", "'.'", "'*'", "'/'", "'%'", "'!'", "T_INSTANCEOF", "'~'", "T_INC", "T_DEC", "T_INT_CAST", "T_DOUBLE_CAST", "T_STRING_CAST", "T_ARRAY_CAST", "T_OBJECT_CAST", "T_BOOL_CAST", "T_UNSET_CAST", "'@'", "T_POW", "'['", "T_NEW", "T_CLONE", "T_EXIT", "T_IF", "T_ELSEIF", "T_ELSE", "T_ENDIF", "T_LNUMBER", "T_DNUMBER", "T_STRING", "T_STRING_VARNAME", "T_VARIABLE", "T_NUM_STRING", "T_INLINE_HTML", "T_ENCAPSED_AND_WHITESPACE", "T_CONSTANT_ENCAPSED_STRING", "T_ECHO", "T_DO", "T_WHILE", "T_ENDWHILE", "T_FOR", "T_ENDFOR", "T_FOREACH", "T_ENDFOREACH", "T_DECLARE", "T_ENDDECLARE", "T_AS", "T_SWITCH", "T_MATCH", "T_ENDSWITCH", "T_CASE", "T_DEFAULT", "T_BREAK", "T_CONTINUE", "T_GOTO", "T_FUNCTION", "T_FN", "T_CONST", "T_RETURN", "T_TRY", "T_CATCH", "T_FINALLY", "T_USE", "T_INSTEADOF", "T_GLOBAL", "T_STATIC", "T_ABSTRACT", "T_FINAL", "T_PRIVATE", "T_PROTECTED", "T_PUBLIC", "T_READONLY", "T_PUBLIC_SET", "T_PROTECTED_SET", "T_PRIVATE_SET", "T_VAR", "T_UNSET", "T_ISSET", "T_EMPTY", "T_HALT_COMPILER", "T_CLASS", "T_TRAIT", "T_INTERFACE", "T_ENUM", "T_EXTENDS", "T_IMPLEMENTS", "T_OBJECT_OPERATOR", "T_NULLSAFE_OBJECT_OPERATOR", "T_LIST", "T_ARRAY", "T_CALLABLE", "T_CLASS_C", "T_TRAIT_C", "T_METHOD_C", "T_FUNC_C", "T_PROPERTY_C", "T_LINE", "T_FILE", "T_START_HEREDOC", "T_END_HEREDOC", "T_DOLLAR_OPEN_CURLY_BRACES", "T_CURLY_OPEN", "T_PAAMAYIM_NEKUDOTAYIM", "T_NAMESPACE", "T_NS_C", "T_DIR", "T_NS_SEPARATOR", "T_ELLIPSIS", "T_NAME_FULLY_QUALIFIED", "T_NAME_QUALIFIED", "T_NAME_RELATIVE", "T_ATTRIBUTE", "';'", "']'", "'('", "')'", "'{'", "'}'", "'`'", "'\"'", "'\$'"); + protected array $tokenToSymbol = array(0, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 57, 171, 173, 172, 56, 173, 173, 166, 167, 54, 51, 9, 52, 53, 55, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 32, 164, 45, 17, 47, 31, 69, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 71, 173, 165, 37, 173, 170, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 168, 36, 169, 59, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35, 38, 39, 40, 41, 42, 43, 44, 46, 48, 49, 50, 58, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163); + protected array $action = array(133, 134, 135, 575, 136, 137, 1049, 766, 767, 768, 138, 41, 850, -341, 495, 1390, -32766, -32766, -32766, 1008, 841, 1145, 1146, 1147, 1141, 1140, 1139, 1148, 1142, 1143, 1144, -32766, -32766, -32766, -195, 760, 759, -32766, -194, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, -32767, 0, -32766, 3, 4, 769, 1145, 1146, 1147, 1141, 1140, 1139, 1148, 1142, 1143, 1144, 388, 389, 448, 272, 53, 391, 773, 774, 775, 776, 433, 5, 434, 571, 337, 39, 254, 29, 298, 830, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 806, 576, 807, 808, 809, 810, 798, 799, 353, 354, 801, 802, 787, 788, 789, 791, 792, 793, 364, 833, 834, 835, 836, 837, 577, -382, 306, -382, 794, 795, 578, 579, 244, 818, 816, 817, 829, 813, 814, 1313, 38, 580, 581, 812, 582, 583, 584, 585, 1325, 586, 587, 481, 482, -628, 496, 1009, 815, 588, 589, 140, 139, -628, 133, 134, 135, 575, 136, 137, 1085, 766, 767, 768, 138, 41, -32766, -341, 1046, 1041, 1040, 1039, 1045, 1042, 1043, 1044, -32766, -32766, -32766, -32767, -32767, -32767, -32767, 106, 107, 108, 109, 110, -195, 760, 759, 1058, -194, -32766, -32766, -32766, 149, -32766, 852, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 936, 303, 257, 769, -32766, -32766, -32766, 850, -32766, 297, -32766, -32766, -32766, -32766, -32766, 1371, 1355, 272, 53, 391, 773, 774, 775, 776, -625, -32766, 434, -32766, -32766, -32766, -32766, 730, -625, 830, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 806, 576, 807, 808, 809, 810, 798, 799, 353, 354, 801, 802, 787, 788, 789, 791, 792, 793, 364, 833, 834, 835, 836, 837, 577, -579, -275, 317, 794, 795, 578, 579, -577, 818, 816, 817, 829, 813, 814, 957, 926, 580, 581, 812, 582, 583, 584, 585, 144, 586, 587, 841, 336, -32766, -32766, -32766, 815, 588, 589, -628, 139, -628, 133, 134, 135, 575, 136, 137, 1082, 766, 767, 768, 138, 41, -32766, 1375, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 1374, 629, 388, 389, -32766, -32766, -32766, -32766, -32766, -579, -579, 1081, 433, 321, 760, 759, -577, -577, -32766, 1293, -32766, -32766, 111, 112, 113, -579, 282, 843, 851, 623, 1400, 936, -577, 1401, 769, 333, 938, -585, 114, -579, 725, 294, 298, 1119, -584, 349, -577, 752, 272, 53, 391, 773, 774, 775, 776, 145, 86, 434, 306, 336, 336, -625, 731, -625, 830, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 806, 576, 807, 808, 809, 810, 798, 799, 353, 354, 801, 802, 787, 788, 789, 791, 792, 793, 364, 833, 834, 835, 836, 837, 577, -576, 850, -578, 794, 795, 578, 579, 845, 818, 816, 817, 829, 813, 814, 727, 926, 580, 581, 812, 582, 583, 584, 585, 740, 586, 587, 243, 1055, -32766, -32766, -85, 815, 588, 589, 878, 152, 879, 133, 134, 135, 575, 136, 137, 1087, 766, 767, 768, 138, 41, 350, 961, 960, 1058, 1058, 1058, -32766, -32766, -32766, 841, -32766, 131, 977, 978, 400, 1055, 10, 979, -576, -576, -578, -578, 378, 760, 759, 936, 973, 290, 297, 297, -32766, 846, 936, 154, -576, 79, -578, 382, 849, 936, 1058, 336, 878, 769, 879, 938, -583, -85, -576, 725, -578, 959, 108, 109, 110, 1058, 732, 272, 53, 391, 773, 774, 775, 776, 290, 155, 434, 470, 471, 472, 735, 760, 759, 830, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 806, 576, 807, 808, 809, 810, 798, 799, 353, 354, 801, 802, 787, 788, 789, 791, 792, 793, 364, 833, 834, 835, 836, 837, 577, 926, 434, 847, 794, 795, 578, 579, 926, 818, 816, 817, 829, 813, 814, 926, 398, 580, 581, 812, 582, 583, 584, 585, 452, 586, 587, 157, 87, 88, 89, 453, 815, 588, 589, 454, 152, 790, 761, 762, 763, 764, 765, 158, 766, 767, 768, 803, 804, 40, 27, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 1134, 282, 1055, 455, -32766, 994, 1288, 1287, 1289, 725, 390, 389, 938, 114, 856, 1120, 725, 769, 159, 938, 433, 672, 23, 725, 1118, 691, 692, 1058, -32766, 153, 416, 770, 771, 772, 773, 774, 775, 776, -78, -619, 839, -619, -581, 386, 387, 392, 393, 830, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 806, 828, 807, 808, 809, 810, 798, 799, 800, 827, 801, 802, 787, 788, 789, 791, 792, 793, 832, 833, 834, 835, 836, 837, 838, 161, 663, 664, 794, 795, 796, 797, 36, 818, 816, 817, 829, 813, 814, -58, -57, 805, 811, 812, 819, 820, 822, 821, -87, 823, 824, -581, -581, 128, 129, 141, 815, 826, 825, 54, 55, 56, 57, 527, 58, 59, 142, -110, 148, 162, 60, 61, -110, 62, -110, 936, 163, 164, 165, 313, 166, -581, -110, -110, -110, -110, -110, -110, -110, -110, -110, -110, -110, 1293, -84, 953, -78, -73, -72, -71, -70, -69, -68, -67, -66, -65, 742, -46, 63, 64, -18, -575, 1286, 146, 65, 51, 66, 251, 252, 67, 68, 69, 70, 71, 72, 73, 74, 281, 31, 273, 47, 450, 528, 291, -357, 741, 1319, 1320, 529, 744, 850, 935, 151, 295, 1317, 45, 22, 530, 1284, 531, -309, 532, -305, 533, 286, 936, 534, 535, 287, 926, 292, 48, 49, 456, 385, 384, 293, 50, 536, 342, 296, 282, 1057, 376, 348, 850, 299, 300, -575, -575, 1279, 114, 307, 308, 701, 538, 539, 540, 150, 841, -32766, 1288, 1287, 1289, -575, 850, 294, 542, 543, 1402, 1305, 1306, 1307, 1308, 1310, 1302, 1303, 305, -575, 716, -110, -110, 130, 1309, 1304, -110, 593, 1288, 1287, 1289, 306, 13, 673, 75, -110, 1152, 678, 331, 332, 336, -154, -154, -154, -32766, 718, 694, -4, 936, 938, 926, 314, 478, 725, 506, 1324, -154, 705, -154, 679, -154, 695, -154, 974, 1326, -541, 306, 312, 311, 79, 849, 661, 383, 43, 320, 336, 37, 1252, 0, 0, 52, 0, 0, 977, 978, 0, 760, 759, 537, -32766, 0, 0, 0, 706, 0, 0, 912, 973, -110, -110, -110, 35, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, -531, 11, 707, 708, 31, 274, 30, 380, 955, 599, -613, 306, 627, 0, 938, 0, 850, 926, 725, -154, 1317, 1288, 1287, 1289, 44, -612, 749, 290, 750, 1194, 1196, 869, 309, 310, 917, 1018, 995, 1002, 992, 383, -575, 446, 1003, 915, 990, 1123, 304, 1126, 381, 1127, 977, 978, 1124, 1125, 1131, 537, 1279, 1314, 861, 330, 760, 759, 132, 541, 973, -110, -110, -110, 1341, 1359, 1393, 1293, 666, 542, 543, -611, 1305, 1306, 1307, 1308, 1310, 1302, 1303, -585, -584, -583, -582, 21, -525, 1309, 1304, 1, 32, 760, 759, 33, 938, -32766, -278, 77, 725, -4, -16, 1286, 332, 336, 42, -575, -575, 46, -32766, -32766, -32766, 76, -32766, 80, -32766, 81, -32766, 82, 83, -32766, 84, -575, 85, 147, -32766, -32766, -32766, 156, -32766, 160, -32766, -32766, 249, 379, 1286, -575, -32766, 430, 31, 273, 338, -32766, -32766, -32766, 365, -32766, 366, -32766, -32766, -32766, 850, 850, -32766, 367, 1317, 368, 369, -32766, -32766, -32766, 370, 371, 372, -32766, -32766, 373, 374, 375, 377, -32766, 430, 447, 570, 31, 274, -276, -275, 15, 16, 78, 17, -32766, 18, 20, 414, 850, -110, -110, 497, 1317, 1279, -110, 498, 505, 508, 509, 510, 511, 515, 516, -110, 517, 525, 604, 711, 1088, 1084, 1234, 543, -32766, 1305, 1306, 1307, 1308, 1310, 1302, 1303, 1315, 1086, 1083, -50, 1064, 1274, 1309, 1304, 1279, 1060, -280, -102, 14, 19, 306, 24, 77, 79, 415, 303, 413, 332, 336, 336, 618, 624, 543, 652, 1305, 1306, 1307, 1308, 1310, 1302, 1303, 717, 143, 1238, 1292, 1235, 1372, 1309, 1304, 726, 729, 733, -32766, 734, 736, 737, 738, 77, 1286, 419, 739, 743, 332, 336, 728, -32766, -32766, -32766, 746, -32766, 913, -32766, 1397, -32766, 1399, 872, -32766, 871, 967, 1010, 1398, -32766, -32766, -32766, 966, -32766, 964, -32766, -32766, 965, 968, 1286, 1267, -32766, 430, 946, 956, 944, -32766, -32766, -32766, 1000, -32766, 1001, -32766, -32766, -32766, 650, 1396, -32766, 1353, 1342, 1360, 1369, -32766, -32766, -32766, 1318, -32766, 336, -32766, -32766, 936, 0, 1286, 0, -32766, 430, 0, 0, 0, -32766, -32766, -32766, 0, -32766, 0, -32766, -32766, -32766, 0, 0, -32766, 0, 0, 936, 0, -32766, -32766, -32766, 0, -32766, 0, -32766, -32766, 0, 0, 1286, 0, -32766, 430, 0, 0, 0, -32766, -32766, -32766, 0, -32766, 0, -32766, -32766, -32766, 0, 0, -32766, 0, 0, 0, 501, -32766, -32766, -32766, 0, -32766, 0, -32766, -32766, 0, 0, 1286, 606, -32766, 430, 0, 0, 0, -32766, -32766, -32766, 0, -32766, 0, -32766, -32766, -32766, 926, 0, -32766, 2, 0, 0, 0, -32766, -32766, -32766, 0, 0, 0, -32766, -32766, 0, -253, -253, -253, -32766, 430, 0, 383, 926, 0, 0, 0, 0, 0, 0, 0, -32766, 0, 977, 978, 0, 0, 0, 537, -252, -252, -252, 0, 0, 0, 383, 912, 973, -110, -110, -110, 0, 0, 0, 0, 0, 977, 978, 0, 0, 0, 537, 0, 0, 0, 0, 0, 0, 0, 912, 973, -110, -110, -110, -32766, 0, 0, 0, 0, 938, 1286, 0, 0, 725, -253, 0, 0, -32766, -32766, -32766, 0, -32766, 0, -32766, 0, -32766, 0, 0, -32766, 0, 0, 0, 938, -32766, -32766, -32766, 725, -252, 0, -32766, -32766, 0, 0, 0, 0, -32766, 430, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -32766); + protected array $actionCheck = array(3, 4, 5, 6, 7, 8, 1, 10, 11, 12, 13, 14, 83, 9, 32, 86, 10, 11, 12, 32, 81, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 10, 11, 12, 9, 38, 39, 31, 9, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 31, 9, 9, 58, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 107, 108, 109, 72, 73, 74, 75, 76, 77, 78, 117, 9, 81, 86, 71, 152, 153, 9, 31, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 107, 163, 109, 127, 128, 129, 130, 15, 132, 133, 134, 135, 136, 137, 1, 9, 140, 141, 142, 143, 144, 145, 146, 151, 148, 149, 138, 139, 1, 168, 164, 155, 156, 157, 9, 159, 9, 3, 4, 5, 6, 7, 8, 167, 10, 11, 12, 13, 14, 117, 167, 119, 120, 121, 122, 123, 124, 125, 126, 10, 11, 12, 45, 46, 47, 48, 49, 50, 51, 52, 53, 167, 38, 39, 142, 167, 10, 11, 12, 9, 31, 1, 33, 34, 35, 36, 37, 38, 39, 1, 167, 9, 58, 10, 11, 12, 83, 31, 166, 33, 34, 35, 36, 37, 1, 1, 72, 73, 74, 75, 76, 77, 78, 1, 31, 81, 33, 34, 35, 36, 32, 9, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 71, 167, 9, 127, 128, 129, 130, 71, 132, 133, 134, 135, 136, 137, 1, 85, 140, 141, 142, 143, 144, 145, 146, 168, 148, 149, 81, 172, 10, 11, 12, 155, 156, 157, 165, 159, 167, 3, 4, 5, 6, 7, 8, 167, 10, 11, 12, 13, 14, 31, 1, 33, 34, 35, 10, 10, 11, 12, 9, 52, 107, 108, 10, 11, 12, 10, 11, 138, 139, 1, 117, 9, 38, 39, 138, 139, 31, 1, 33, 34, 54, 55, 56, 154, 58, 81, 164, 1, 81, 1, 154, 84, 58, 9, 164, 166, 70, 168, 168, 31, 31, 164, 166, 9, 168, 168, 72, 73, 74, 75, 76, 77, 78, 168, 168, 81, 163, 172, 172, 165, 32, 167, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 71, 83, 71, 127, 128, 129, 130, 161, 132, 133, 134, 135, 136, 137, 168, 85, 140, 141, 142, 143, 144, 145, 146, 168, 148, 149, 98, 117, 117, 117, 32, 155, 156, 157, 107, 159, 109, 3, 4, 5, 6, 7, 8, 167, 10, 11, 12, 13, 14, 9, 73, 74, 142, 142, 142, 10, 11, 12, 81, 141, 15, 118, 119, 107, 117, 109, 123, 138, 139, 138, 139, 9, 38, 39, 1, 132, 166, 166, 166, 117, 81, 1, 15, 154, 166, 154, 9, 160, 1, 142, 172, 107, 58, 109, 164, 166, 98, 168, 168, 168, 123, 51, 52, 53, 142, 32, 72, 73, 74, 75, 76, 77, 78, 166, 15, 81, 133, 134, 135, 32, 38, 39, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 85, 81, 161, 127, 128, 129, 130, 85, 132, 133, 134, 135, 136, 137, 85, 9, 140, 141, 142, 143, 144, 145, 146, 9, 148, 149, 15, 10, 11, 12, 9, 155, 156, 157, 9, 159, 3, 4, 5, 6, 7, 8, 15, 10, 11, 12, 13, 14, 31, 102, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 127, 58, 117, 9, 117, 164, 160, 161, 162, 168, 107, 108, 164, 70, 9, 169, 168, 58, 15, 164, 117, 76, 77, 168, 1, 76, 77, 142, 141, 102, 103, 72, 73, 74, 75, 76, 77, 78, 17, 165, 81, 167, 71, 107, 108, 107, 108, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 15, 112, 113, 127, 128, 129, 130, 15, 132, 133, 134, 135, 136, 137, 17, 17, 140, 141, 142, 143, 144, 145, 146, 32, 148, 149, 138, 139, 17, 17, 17, 155, 156, 157, 2, 3, 4, 5, 6, 7, 8, 17, 102, 17, 17, 13, 14, 107, 16, 109, 1, 17, 17, 17, 114, 17, 168, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 1, 32, 39, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 51, 52, 32, 71, 81, 32, 57, 71, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 32, 71, 72, 73, 74, 75, 32, 169, 32, 79, 80, 81, 32, 83, 32, 32, 38, 87, 88, 89, 90, 117, 92, 36, 94, 36, 96, 36, 1, 99, 100, 36, 85, 36, 104, 105, 106, 107, 108, 36, 110, 111, 36, 38, 58, 141, 116, 117, 83, 38, 38, 138, 139, 123, 70, 138, 139, 78, 128, 129, 130, 71, 81, 86, 160, 161, 162, 154, 83, 31, 140, 141, 84, 143, 144, 145, 146, 147, 148, 149, 150, 168, 81, 118, 119, 168, 156, 157, 123, 90, 160, 161, 162, 163, 98, 91, 166, 132, 83, 97, 170, 171, 172, 76, 77, 78, 141, 93, 95, 0, 1, 164, 85, 115, 98, 168, 98, 151, 91, 81, 93, 101, 95, 101, 97, 132, 151, 154, 163, 137, 136, 166, 160, 114, 107, 164, 136, 172, 168, 170, -1, -1, 71, -1, -1, 118, 119, -1, 38, 39, 123, 141, -1, -1, -1, 117, -1, -1, 131, 132, 133, 134, 135, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 154, 154, 141, 142, 71, 72, 154, 154, 159, 158, 166, 163, 158, -1, 164, -1, 83, 85, 168, 169, 87, 160, 161, 162, 164, 166, 164, 166, 164, 60, 61, 164, 138, 139, 164, 164, 164, 164, 164, 107, 71, 109, 164, 164, 164, 164, 114, 164, 154, 164, 118, 119, 164, 164, 164, 123, 123, 165, 165, 168, 38, 39, 168, 131, 132, 133, 134, 135, 165, 165, 165, 1, 165, 140, 141, 166, 143, 144, 145, 146, 147, 148, 149, 166, 166, 166, 166, 155, 166, 156, 157, 166, 166, 38, 39, 166, 164, 75, 167, 166, 168, 169, 32, 81, 171, 172, 166, 138, 139, 166, 88, 89, 90, 166, 92, 166, 94, 166, 96, 166, 166, 99, 166, 154, 166, 166, 104, 105, 106, 166, 75, 166, 110, 111, 166, 168, 81, 168, 116, 117, 71, 72, 166, 88, 89, 90, 166, 92, 166, 94, 128, 96, 83, 83, 99, 166, 87, 166, 166, 104, 105, 106, 166, 166, 166, 110, 111, 166, 166, 166, 166, 116, 117, 166, 166, 71, 72, 167, 167, 167, 167, 159, 167, 128, 167, 167, 167, 83, 118, 119, 167, 87, 123, 123, 167, 167, 167, 167, 167, 167, 167, 167, 132, 167, 167, 167, 167, 167, 167, 167, 141, 141, 143, 144, 145, 146, 147, 148, 149, 167, 167, 167, 32, 167, 167, 156, 157, 123, 167, 167, 167, 167, 167, 163, 167, 166, 166, 169, 167, 167, 171, 172, 172, 167, 167, 141, 167, 143, 144, 145, 146, 147, 148, 149, 167, 32, 167, 167, 167, 167, 156, 157, 168, 168, 168, 75, 168, 168, 168, 168, 166, 81, 169, 168, 168, 171, 172, 168, 88, 89, 90, 169, 92, 169, 94, 169, 96, 169, 169, 99, 169, 169, 169, 169, 104, 105, 106, 169, 75, 169, 110, 111, 169, 169, 81, 169, 116, 117, 169, 169, 169, 88, 89, 90, 169, 92, 169, 94, 128, 96, 169, 169, 99, 169, 169, 169, 169, 104, 105, 106, 171, 75, 172, 110, 111, 1, -1, 81, -1, 116, 117, -1, -1, -1, 88, 89, 90, -1, 92, -1, 94, 128, 96, -1, -1, 99, -1, -1, 1, -1, 104, 105, 106, -1, 75, -1, 110, 111, -1, -1, 81, -1, 116, 117, -1, -1, -1, 88, 89, 90, -1, 92, -1, 94, 128, 96, -1, -1, 99, -1, -1, -1, 103, 104, 105, 106, -1, 75, -1, 110, 111, -1, -1, 81, 82, 116, 117, -1, -1, -1, 88, 89, 90, -1, 92, -1, 94, 128, 96, 85, -1, 99, 166, -1, -1, -1, 104, 105, 106, -1, -1, -1, 110, 111, -1, 101, 102, 103, 116, 117, -1, 107, 85, -1, -1, -1, -1, -1, -1, -1, 128, -1, 118, 119, -1, -1, -1, 123, 101, 102, 103, -1, -1, -1, 107, 131, 132, 133, 134, 135, -1, -1, -1, -1, -1, 118, 119, -1, -1, -1, 123, -1, -1, -1, -1, -1, -1, -1, 131, 132, 133, 134, 135, 75, -1, -1, -1, -1, 164, 81, -1, -1, 168, 169, -1, -1, 88, 89, 90, -1, 92, -1, 94, -1, 96, -1, -1, 99, -1, -1, -1, 164, 104, 105, 106, 168, 169, -1, 110, 111, -1, -1, -1, -1, 116, 117, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 128); + protected array $actionBase = array(0, 155, -3, 313, 471, 471, 881, 963, 1365, 1388, 892, 134, 515, -61, 367, 524, 524, 801, 524, 209, 510, 283, 517, 517, 517, 920, 855, 628, 628, 855, 628, 1053, 1053, 1053, 1053, 1086, 1086, 1320, 1320, 1353, 1254, 1221, 1449, 1449, 1449, 1449, 1449, 1287, 1449, 1449, 1449, 1449, 1449, 1287, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 1449, 201, -13, 44, 365, 744, 1102, 1120, 1107, 1121, 1096, 1095, 1103, 1108, 1122, 1183, 1185, 837, 1186, 1187, 1182, 1188, 1110, 938, 1098, 1118, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 323, 482, 334, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 331, 964, 964, 21, 21, 21, 324, 1135, 1100, 1135, 1135, 1135, 1135, 1135, 1135, 1135, 1135, 297, 204, 1000, 187, 170, 170, 6, 6, 6, 6, 6, 692, 53, 1101, 819, 819, 138, 138, 138, 138, 542, 14, 347, 355, -41, 348, 232, 384, 384, 487, 487, 554, 554, 349, 349, 554, 554, 554, 399, 399, 399, 399, 208, 215, 366, 364, -7, 864, 224, 224, 224, 224, 864, 864, 864, 864, 829, 1190, 864, 1011, 1027, 864, 864, 368, 767, 767, 925, 305, 305, 305, 767, 421, -71, -71, 421, 380, -71, 225, 286, 556, 847, 572, 543, 556, 640, 771, 233, 148, 826, 605, 826, 1094, 831, 831, 802, 792, 921, 1140, 1123, 874, 1176, 876, 1178, 420, 9, 791, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1191, 519, 1094, 436, 1191, 1191, 1191, 519, 519, 519, 519, 519, 519, 519, 519, 805, 519, 519, 641, 436, 614, 618, 436, 860, 519, 877, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, -18, 201, 201, -13, 292, 292, 201, 216, 5, 292, 292, 292, 292, 201, 201, 201, 201, 605, 840, 882, 607, 435, 885, 29, 840, 840, 840, 4, 113, 25, 841, 843, 393, 835, 835, 835, 869, 956, 956, 835, 839, 835, 869, 835, 835, 956, 956, 879, 956, 146, 609, 373, 514, 616, 956, 272, 835, 835, 835, 835, 854, 956, 45, 68, 620, 835, 203, 191, 835, 835, 854, 848, 828, 846, 956, 956, 956, 854, 499, 846, 846, 846, 893, 895, 873, 822, 363, 341, 674, 127, 783, 822, 822, 835, 601, 873, 822, 873, 822, 880, 822, 822, 822, 873, 822, 839, 477, 822, 779, 786, 663, 74, 822, 51, 978, 980, 743, 982, 971, 984, 1038, 985, 987, 1125, 953, 999, 974, 989, 1039, 960, 957, 836, 763, 764, 878, 827, 951, 838, 838, 838, 948, 949, 838, 838, 838, 838, 838, 838, 838, 838, 763, 923, 884, 853, 1013, 765, 776, 1069, 820, 1145, 823, 1011, 978, 987, 789, 974, 989, 960, 957, 800, 799, 797, 798, 796, 795, 793, 794, 808, 1071, 1072, 990, 825, 778, 1049, 1020, 1143, 922, 1022, 1023, 1050, 1073, 898, 1083, 1147, 844, 1149, 1150, 924, 1028, 1126, 838, 940, 875, 934, 1027, 950, 763, 935, 1084, 1085, 1043, 824, 1054, 1058, 998, 870, 842, 936, 1152, 1029, 1032, 1033, 1127, 1129, 891, 1044, 962, 1059, 872, 1099, 1060, 1061, 1062, 1063, 1130, 1153, 1131, 890, 1132, 901, 858, 1041, 856, 1154, 504, 851, 857, 866, 1035, 536, 1007, 1136, 1134, 1155, 1064, 1065, 1067, 1159, 1161, 994, 902, 1046, 867, 1048, 1042, 903, 904, 606, 865, 1087, 845, 849, 859, 622, 672, 1164, 1165, 1167, 996, 830, 833, 905, 909, 1088, 832, 1092, 1170, 737, 910, 1171, 1070, 787, 788, 690, 750, 749, 790, 868, 1137, 883, 852, 850, 1034, 788, 834, 911, 1172, 912, 914, 916, 1068, 919, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 784, 784, 784, 784, 784, 784, 784, 784, 784, 628, 628, 628, 628, 784, 784, 784, 784, 784, 784, 784, 628, 784, 784, 784, 628, 628, 0, 0, 628, 0, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 784, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 612, 758, 758, 612, 612, 612, 612, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 612, 612, 0, 612, 612, 612, 612, 612, 612, 612, 612, 879, 758, 758, 758, 758, 305, 305, 305, 305, -96, -96, 758, 758, 380, 758, 380, 758, 758, 305, 305, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, 0, 0, 0, 436, -71, 758, 839, 839, 839, 839, 758, 758, 758, 758, -71, -71, 758, 414, 414, 758, 758, 0, 0, 0, 0, 0, 0, 0, 0, 436, 0, 0, 436, 0, 0, 839, 839, 758, 380, 879, 328, 758, 0, 0, 0, 0, 436, 839, 436, 519, -71, -71, 519, 519, 292, 201, 328, 596, 596, 596, 596, 0, 0, 605, 879, 879, 879, 879, 879, 879, 879, 879, 879, 879, 879, 839, 0, 879, 0, 839, 839, 839, 0, 0, 0, 0, 0, 0, 0, 0, 956, 0, 0, 0, 0, 0, 0, 0, 839, 0, 956, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 839, 0, 0, 0, 0, 0, 0, 0, 0, 0, 838, 870, 0, 0, 870, 0, 838, 838, 838, 0, 0, 0, 865, 832); + protected array $actionDefault = array(3, 32767, 32767, 32767, 102, 102, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 100, 32767, 631, 631, 631, 631, 32767, 32767, 257, 102, 32767, 32767, 500, 415, 415, 415, 32767, 32767, 32767, 573, 573, 573, 573, 573, 17, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 500, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 36, 7, 8, 10, 11, 49, 338, 100, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 102, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 624, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 403, 494, 504, 482, 483, 485, 486, 414, 574, 630, 344, 627, 342, 413, 146, 354, 343, 245, 261, 505, 262, 506, 509, 510, 218, 400, 150, 151, 446, 501, 448, 499, 503, 447, 420, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 418, 419, 502, 32767, 32767, 479, 478, 477, 444, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 102, 32767, 445, 449, 417, 452, 450, 451, 468, 469, 466, 467, 470, 32767, 323, 32767, 32767, 32767, 471, 472, 473, 474, 381, 379, 32767, 32767, 111, 323, 111, 32767, 32767, 459, 460, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 517, 567, 476, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 102, 32767, 32767, 32767, 100, 569, 441, 443, 537, 454, 455, 453, 421, 32767, 542, 32767, 102, 32767, 544, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 568, 32767, 575, 575, 32767, 530, 100, 196, 32767, 543, 196, 196, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 638, 530, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 32767, 196, 110, 32767, 32767, 32767, 100, 196, 196, 196, 196, 196, 196, 196, 196, 545, 196, 196, 191, 32767, 271, 273, 102, 592, 196, 547, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 530, 464, 139, 32767, 532, 139, 575, 456, 457, 458, 575, 575, 575, 319, 296, 32767, 32767, 32767, 32767, 32767, 545, 545, 100, 100, 100, 100, 32767, 32767, 32767, 32767, 111, 516, 99, 99, 99, 99, 99, 103, 101, 32767, 32767, 32767, 32767, 226, 32767, 101, 101, 99, 32767, 101, 101, 32767, 32767, 226, 228, 215, 230, 32767, 596, 597, 226, 101, 230, 230, 230, 250, 250, 519, 325, 101, 99, 101, 101, 198, 325, 325, 32767, 101, 519, 325, 519, 325, 200, 325, 325, 325, 519, 325, 32767, 101, 325, 217, 403, 99, 99, 325, 32767, 32767, 32767, 532, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 225, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 562, 32767, 580, 594, 462, 463, 465, 579, 577, 487, 488, 489, 490, 491, 492, 493, 496, 626, 32767, 536, 32767, 32767, 32767, 353, 32767, 636, 32767, 32767, 32767, 9, 74, 525, 42, 43, 51, 57, 551, 552, 553, 554, 548, 549, 555, 550, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 637, 32767, 575, 32767, 32767, 32767, 32767, 461, 557, 602, 32767, 32767, 576, 629, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 139, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 562, 32767, 137, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 558, 32767, 32767, 32767, 575, 32767, 32767, 32767, 32767, 321, 318, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 575, 32767, 32767, 32767, 32767, 32767, 298, 32767, 315, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 399, 532, 301, 303, 304, 32767, 32767, 32767, 32767, 375, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 153, 153, 3, 3, 356, 153, 153, 153, 356, 356, 153, 356, 356, 356, 153, 153, 153, 153, 153, 153, 283, 186, 265, 268, 250, 250, 153, 367, 153); + protected array $goto = array(202, 169, 202, 202, 202, 1056, 842, 712, 359, 670, 671, 598, 688, 689, 690, 748, 653, 655, 591, 929, 675, 930, 1090, 721, 699, 702, 1028, 710, 719, 1024, 171, 171, 171, 171, 226, 203, 199, 199, 181, 183, 221, 199, 199, 199, 199, 199, 1180, 200, 200, 200, 200, 200, 1180, 193, 194, 195, 196, 197, 198, 223, 221, 224, 550, 551, 431, 552, 555, 556, 557, 558, 559, 560, 561, 562, 172, 173, 174, 201, 175, 176, 177, 170, 178, 179, 180, 182, 220, 222, 225, 245, 248, 259, 260, 262, 263, 264, 265, 266, 267, 268, 269, 275, 276, 277, 278, 288, 289, 326, 327, 328, 437, 438, 439, 613, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 184, 242, 185, 194, 195, 196, 197, 198, 223, 204, 205, 206, 207, 246, 186, 187, 208, 188, 209, 205, 189, 247, 204, 168, 210, 211, 190, 212, 213, 214, 191, 215, 216, 192, 217, 218, 219, 285, 283, 285, 285, 870, 1089, 1091, 1094, 615, 255, 255, 255, 255, 255, 441, 677, 614, 1130, 884, 867, 436, 329, 323, 324, 345, 608, 440, 346, 442, 654, 724, 492, 521, 715, 896, 1128, 993, 883, 494, 253, 253, 253, 253, 250, 256, 489, 1361, 1362, 1386, 1386, 925, 920, 921, 934, 876, 922, 873, 923, 924, 874, 877, 363, 928, 881, 480, 480, 868, 880, 1386, 848, 474, 363, 363, 480, 1117, 1112, 1113, 1114, 1229, 351, 362, 362, 362, 362, 1389, 1389, 429, 363, 363, 1017, 902, 363, 989, 1403, 747, 360, 361, 566, 1026, 1021, 1056, 1285, 1285, 1285, 569, 352, 351, 363, 363, 605, 1056, 1285, 848, 1056, 848, 1056, 1056, 1137, 1138, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 1056, 357, 1261, 962, 637, 674, 1285, 1262, 1265, 963, 1266, 1285, 1285, 1285, 1285, 1376, 435, 1285, 628, 402, 1285, 1285, 1368, 1368, 1368, 1368, 1347, 574, 567, 1062, 1061, 1059, 1059, 958, 958, 697, 970, 1014, 942, 1051, 1067, 1068, 943, 565, 565, 565, 603, 513, 522, 514, 863, 676, 863, 565, 709, 520, 1176, 318, 567, 574, 600, 601, 319, 611, 617, 844, 633, 634, 1080, 8, 709, 9, 449, 709, 28, 1065, 1066, 467, 335, 316, 569, 698, 987, 987, 987, 987, 1363, 1364, 467, 639, 639, 981, 988, 609, 631, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1316, 1335, 1335, 863, 469, 682, 469, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 347, 258, 258, 626, 640, 643, 644, 645, 646, 667, 668, 669, 723, 632, 460, 860, 460, 460, 460, 1358, 1358, 1358, 553, 553, 1278, 985, 420, 720, 553, 1358, 553, 553, 553, 553, 553, 553, 553, 553, 451, 889, 568, 595, 568, 647, 649, 651, 568, 976, 595, 411, 405, 473, 886, 1276, 1370, 1370, 1370, 1370, 909, 866, 909, 909, 1036, 483, 612, 484, 485, 751, 563, 563, 563, 563, 894, 619, 1101, 1394, 1395, 412, 1332, 1332, 898, 490, 1151, 1354, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 279, 1105, 334, 334, 334, 998, 892, 0, 1280, 1047, 0, 0, 863, 0, 0, 460, 460, 460, 460, 460, 460, 460, 460, 460, 460, 460, 0, 0, 460, 1103, 554, 554, 0, 1356, 1356, 1103, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 621, 622, 417, 418, 947, 1166, 0, 686, 0, 687, 0, 422, 423, 424, 0, 700, 1033, 0, 425, 1281, 1282, 0, 1268, 355, 888, 0, 680, 1012, 858, 0, 0, 0, 882, 443, 0, 1268, 0, 897, 885, 1100, 1104, 0, 0, 0, 1275, 0, 443, 0, 1283, 1344, 1345, 996, 0, 0, 1063, 1063, 0, 0, 0, 681, 1074, 1070, 1071, 404, 407, 616, 620, 0, 0, 0, 0, 0, 0, 0, 986, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1149, 901, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1031, 1031); + protected array $gotoCheck = array(42, 42, 42, 42, 42, 73, 6, 73, 97, 86, 86, 48, 86, 86, 86, 48, 48, 48, 127, 65, 48, 65, 131, 9, 48, 48, 48, 48, 48, 48, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 23, 23, 23, 23, 15, 130, 130, 130, 134, 5, 5, 5, 5, 5, 66, 66, 8, 8, 35, 26, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 8, 84, 8, 8, 35, 8, 49, 35, 84, 5, 5, 5, 5, 5, 5, 185, 185, 185, 191, 191, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 157, 157, 27, 15, 191, 12, 159, 14, 14, 157, 15, 15, 15, 15, 159, 177, 24, 24, 24, 24, 191, 191, 43, 14, 14, 50, 45, 14, 50, 14, 50, 97, 97, 50, 50, 50, 73, 73, 73, 73, 14, 177, 177, 14, 14, 181, 73, 73, 12, 73, 12, 73, 73, 148, 148, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 188, 79, 79, 56, 56, 73, 79, 79, 79, 79, 73, 73, 73, 73, 190, 13, 73, 13, 62, 73, 73, 9, 9, 9, 9, 14, 76, 76, 119, 119, 89, 89, 9, 9, 89, 89, 103, 73, 89, 89, 89, 73, 19, 19, 19, 104, 163, 14, 163, 22, 64, 22, 19, 7, 163, 158, 76, 76, 76, 76, 76, 76, 76, 76, 7, 76, 76, 115, 46, 7, 46, 113, 7, 76, 120, 120, 19, 178, 178, 14, 117, 19, 19, 19, 19, 187, 187, 19, 108, 108, 19, 19, 2, 2, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 179, 179, 22, 83, 121, 83, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 29, 5, 5, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 80, 23, 18, 23, 23, 23, 134, 134, 134, 165, 165, 14, 93, 93, 93, 165, 134, 165, 165, 165, 165, 165, 165, 165, 165, 83, 39, 9, 9, 9, 85, 85, 85, 9, 92, 9, 28, 9, 9, 37, 169, 134, 134, 134, 134, 25, 25, 25, 25, 110, 9, 9, 9, 9, 99, 107, 107, 107, 107, 9, 107, 133, 9, 9, 31, 180, 180, 41, 160, 151, 134, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 24, 136, 24, 24, 24, 96, 9, -1, 20, 114, -1, -1, 22, -1, -1, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, -1, -1, 23, 134, 182, 182, -1, 134, 134, 134, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 17, 17, 82, 82, 17, 17, -1, 82, -1, 82, -1, 82, 82, 82, -1, 82, 17, -1, 82, 20, 20, -1, 20, 82, 17, -1, 17, 17, 20, -1, -1, -1, 17, 118, -1, 20, -1, 16, 16, 16, 16, -1, -1, -1, 17, -1, 118, -1, 20, 20, 20, 16, -1, -1, 118, 118, -1, -1, -1, 118, 118, 118, 118, 59, 59, 59, 59, -1, -1, -1, -1, -1, -1, -1, 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16, 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 107, 107); + protected array $gotoBase = array(0, 0, -339, 0, 0, 174, -7, 339, 171, 10, 0, 0, -69, -36, -78, -186, 130, 81, 114, 66, 117, 0, 62, 160, 240, 468, 178, 225, 118, 112, 0, 45, 0, 0, 0, -195, 0, 119, 0, 122, 0, 44, -1, 226, 0, 227, -387, 0, -715, 182, 241, 0, 0, 0, 0, 0, 256, 0, 0, 570, 0, 0, 269, 0, 102, 3, -63, 0, 0, 0, 0, 0, 0, -5, 0, 0, -31, 0, 0, -120, 110, 53, 54, 120, -286, -33, -724, 0, 0, 40, 0, 0, 124, 129, 0, 0, 61, -488, 0, 67, 0, 0, 0, 294, 295, 0, 0, 453, 141, 0, 100, 0, 0, 83, -3, 82, 0, 86, 318, 38, 78, 107, 0, 0, 0, 0, 0, 16, 0, 0, 168, 20, 0, 108, 163, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 43, 0, 0, 0, 0, 0, 193, 101, -38, 46, 0, 0, -166, 0, 195, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, -60, 42, 157, 251, 243, 297, 0, 0, -97, 0, 1, 263, 0, 276, -101, 0, 0); + protected array $gotoDefault = array(-32768, 526, 755, 7, 756, 951, 831, 840, 590, 544, 722, 356, 641, 432, 1352, 927, 1165, 610, 859, 1294, 1300, 468, 862, 340, 745, 939, 910, 911, 408, 395, 875, 406, 665, 642, 507, 895, 464, 887, 499, 890, 463, 899, 167, 428, 524, 903, 6, 906, 572, 937, 991, 396, 914, 397, 693, 916, 594, 918, 919, 403, 409, 410, 1170, 602, 638, 931, 261, 596, 932, 394, 933, 941, 399, 401, 703, 479, 518, 512, 421, 1132, 597, 625, 662, 457, 486, 636, 648, 635, 493, 444, 426, 339, 975, 983, 500, 477, 997, 358, 1005, 753, 1178, 656, 502, 1013, 657, 1020, 1023, 545, 546, 491, 1035, 271, 1038, 503, 1048, 26, 683, 1053, 1054, 684, 658, 1076, 659, 685, 660, 1078, 476, 592, 1179, 475, 1093, 1099, 465, 1102, 1340, 466, 1106, 270, 1109, 284, 427, 445, 1115, 1116, 12, 1122, 713, 714, 25, 280, 523, 1150, 704, -32768, -32768, -32768, -32768, 462, 1177, 461, 1249, 1251, 573, 504, 1269, 301, 1272, 696, 519, 1277, 458, 1343, 459, 547, 487, 325, 548, 1387, 315, 343, 322, 564, 302, 344, 549, 488, 1349, 1357, 341, 34, 1377, 1388, 607, 630); + protected array $ruleToNonTerminal = array(0, 1, 3, 3, 2, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 10, 11, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18, 21, 21, 22, 23, 23, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 29, 29, 30, 30, 32, 34, 34, 28, 36, 36, 33, 38, 38, 35, 35, 37, 37, 39, 39, 31, 40, 40, 41, 43, 44, 44, 45, 45, 46, 46, 48, 47, 47, 47, 47, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 25, 25, 50, 69, 69, 72, 72, 71, 70, 70, 63, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 80, 80, 26, 26, 27, 27, 27, 27, 27, 88, 88, 90, 90, 83, 83, 91, 91, 92, 92, 92, 84, 84, 87, 87, 85, 85, 93, 94, 94, 57, 57, 65, 65, 68, 68, 68, 67, 95, 95, 96, 58, 58, 58, 58, 97, 97, 98, 98, 99, 99, 100, 101, 101, 102, 102, 103, 103, 55, 55, 51, 51, 105, 53, 53, 106, 52, 52, 54, 54, 64, 64, 64, 64, 81, 81, 109, 109, 111, 111, 112, 112, 112, 112, 112, 112, 112, 112, 110, 110, 110, 115, 115, 115, 115, 89, 89, 118, 118, 118, 119, 119, 116, 116, 120, 120, 122, 122, 123, 123, 117, 124, 124, 121, 125, 125, 125, 125, 113, 113, 82, 82, 82, 20, 20, 20, 128, 128, 128, 128, 129, 129, 129, 127, 126, 126, 131, 131, 131, 130, 130, 60, 132, 132, 133, 61, 135, 135, 136, 136, 137, 137, 86, 138, 138, 138, 138, 138, 138, 138, 143, 143, 144, 144, 145, 145, 145, 145, 145, 146, 147, 147, 142, 142, 139, 139, 141, 141, 149, 149, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 140, 150, 150, 152, 151, 151, 153, 153, 114, 154, 154, 156, 156, 156, 155, 155, 62, 104, 157, 157, 56, 56, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 164, 165, 165, 166, 158, 158, 163, 163, 167, 168, 168, 169, 170, 171, 171, 171, 171, 19, 19, 73, 73, 73, 73, 159, 159, 159, 159, 173, 173, 162, 162, 162, 160, 160, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 180, 180, 180, 108, 182, 182, 182, 182, 161, 161, 161, 161, 161, 161, 161, 161, 59, 59, 176, 176, 176, 176, 176, 183, 183, 172, 172, 172, 172, 184, 184, 184, 184, 184, 184, 74, 74, 66, 66, 66, 66, 134, 134, 134, 134, 187, 186, 175, 175, 175, 175, 175, 175, 175, 174, 174, 174, 185, 185, 185, 185, 107, 181, 189, 189, 188, 188, 190, 190, 190, 190, 190, 190, 190, 190, 178, 178, 178, 178, 177, 192, 191, 191, 191, 191, 191, 191, 191, 191, 193, 193, 193, 193); + protected array $ruleToLength = array(1, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 2, 1, 3, 4, 1, 2, 0, 1, 1, 1, 1, 4, 3, 5, 4, 3, 4, 1, 3, 4, 1, 1, 8, 7, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 3, 1, 3, 1, 2, 2, 3, 1, 3, 2, 3, 1, 3, 3, 2, 0, 1, 1, 1, 1, 1, 3, 7, 10, 5, 7, 9, 5, 3, 3, 3, 3, 3, 3, 1, 2, 5, 7, 9, 6, 5, 6, 3, 2, 1, 1, 1, 1, 0, 2, 1, 3, 8, 0, 4, 2, 1, 3, 0, 1, 0, 1, 0, 1, 3, 1, 1, 1, 1, 1, 8, 9, 7, 8, 7, 6, 8, 0, 2, 0, 2, 1, 2, 1, 2, 1, 1, 1, 0, 2, 0, 2, 0, 2, 2, 1, 3, 1, 4, 1, 4, 1, 1, 4, 2, 1, 3, 3, 3, 4, 4, 5, 0, 2, 4, 3, 1, 1, 7, 0, 2, 1, 3, 3, 4, 1, 4, 0, 2, 5, 0, 2, 6, 0, 2, 0, 3, 1, 2, 1, 1, 2, 0, 1, 3, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 7, 9, 6, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 3, 3, 3, 3, 3, 1, 3, 3, 1, 1, 2, 1, 1, 0, 1, 0, 2, 2, 2, 4, 3, 2, 4, 4, 3, 3, 1, 3, 1, 1, 3, 2, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 3, 2, 0, 1, 5, 5, 6, 10, 3, 5, 1, 1, 3, 0, 2, 4, 5, 4, 4, 4, 3, 1, 1, 1, 1, 1, 1, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 3, 1, 1, 3, 0, 2, 0, 5, 8, 1, 3, 3, 0, 2, 2, 2, 3, 1, 0, 1, 1, 3, 3, 3, 4, 4, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 4, 4, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 2, 1, 2, 4, 2, 2, 8, 9, 8, 9, 9, 10, 9, 10, 8, 3, 2, 2, 1, 1, 0, 4, 2, 1, 3, 2, 1, 2, 2, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 3, 3, 4, 1, 1, 3, 1, 1, 1, 1, 1, 3, 2, 3, 0, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 4, 4, 1, 4, 4, 0, 1, 1, 1, 3, 3, 1, 4, 2, 2, 1, 3, 1, 4, 4, 3, 3, 3, 3, 1, 3, 1, 1, 3, 1, 1, 4, 1, 1, 1, 3, 1, 1, 2, 1, 3, 4, 3, 2, 0, 2, 2, 1, 2, 1, 1, 1, 4, 3, 3, 3, 3, 6, 3, 1, 1, 2, 1); + protected function initReduceCallbacks(): void + { + $this->reduceCallbacks = [0 => null, 1 => static function ($self, $stackPos) { + $self->semValue = $self->handleNamespaces($self->semStack[$stackPos - (1 - 1)]); + }, 2 => static function ($self, $stackPos) { + if ($self->semStack[$stackPos - (2 - 2)] !== null) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + } + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 3 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 4 => static function ($self, $stackPos) { + $nop = $self->maybeCreateZeroLengthNop($self->tokenPos); + if ($nop !== null) { + $self->semStack[$stackPos - (1 - 1)][] = $nop; + } + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 5 => null, 6 => null, 7 => null, 8 => null, 9 => null, 10 => null, 11 => null, 12 => null, 13 => null, 14 => null, 15 => null, 16 => null, 17 => null, 18 => null, 19 => null, 20 => null, 21 => null, 22 => null, 23 => null, 24 => null, 25 => null, 26 => null, 27 => null, 28 => null, 29 => null, 30 => null, 31 => null, 32 => null, 33 => null, 34 => null, 35 => null, 36 => null, 37 => null, 38 => null, 39 => null, 40 => null, 41 => null, 42 => null, 43 => null, 44 => null, 45 => null, 46 => null, 47 => null, 48 => null, 49 => null, 50 => null, 51 => null, 52 => null, 53 => null, 54 => null, 55 => null, 56 => null, 57 => null, 58 => null, 59 => null, 60 => null, 61 => null, 62 => null, 63 => null, 64 => null, 65 => null, 66 => null, 67 => null, 68 => null, 69 => null, 70 => null, 71 => null, 72 => null, 73 => null, 74 => null, 75 => null, 76 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + if ($self->semValue === "emitError(new Error('Cannot use "getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]))); + } + }, 77 => null, 78 => null, 79 => null, 80 => null, 81 => null, 82 => null, 83 => null, 84 => null, 85 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 86 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 87 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 88 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 89 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 90 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 91 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 92 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 93 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 94 => null, 95 => static function ($self, $stackPos) { + $self->semValue = new Name(substr($self->semStack[$stackPos - (1 - 1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 96 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable(substr($self->semStack[$stackPos - (1 - 1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 97 => static function ($self, $stackPos) { + /* nothing */ + }, 98 => static function ($self, $stackPos) { + /* nothing */ + }, 99 => static function ($self, $stackPos) { + /* nothing */ + }, 100 => static function ($self, $stackPos) { + $self->emitError(new Error('A trailing comma is not allowed here', $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]))); + }, 101 => null, 102 => null, 103 => static function ($self, $stackPos) { + $self->semValue = new Node\Attribute($self->semStack[$stackPos - (1 - 1)], [], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 104 => static function ($self, $stackPos) { + $self->semValue = new Node\Attribute($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 105 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 106 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 107 => static function ($self, $stackPos) { + $self->semValue = new Node\AttributeGroup($self->semStack[$stackPos - (4 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 108 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 109 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 110 => static function ($self, $stackPos) { + $self->semValue = []; + }, 111 => null, 112 => null, 113 => null, 114 => null, 115 => static function ($self, $stackPos) { + $self->semValue = new Stmt\HaltCompiler($self->handleHaltCompiler(), $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 116 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Namespace_($self->semStack[$stackPos - (3 - 2)], null, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON); + $self->checkNamespace($self->semValue); + }, 117 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Namespace_($self->semStack[$stackPos - (5 - 2)], $self->semStack[$stackPos - (5 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $self->checkNamespace($self->semValue); + }, 118 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Namespace_(null, $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $self->checkNamespace($self->semValue); + }, 119 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Use_($self->semStack[$stackPos - (3 - 2)], Stmt\Use_::TYPE_NORMAL, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 120 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Use_($self->semStack[$stackPos - (4 - 3)], $self->semStack[$stackPos - (4 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 121 => null, 122 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Const_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]), []); + }, 123 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Const_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (4 - 1)]); + $self->checkConstantAttributes($self->semValue); + }, 124 => static function ($self, $stackPos) { + $self->semValue = Stmt\Use_::TYPE_FUNCTION; + }, 125 => static function ($self, $stackPos) { + $self->semValue = Stmt\Use_::TYPE_CONSTANT; + }, 126 => static function ($self, $stackPos) { + $self->semValue = new Stmt\GroupUse($self->semStack[$stackPos - (8 - 3)], $self->semStack[$stackPos - (8 - 6)], $self->semStack[$stackPos - (8 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + }, 127 => static function ($self, $stackPos) { + $self->semValue = new Stmt\GroupUse($self->semStack[$stackPos - (7 - 2)], $self->semStack[$stackPos - (7 - 5)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + }, 128 => null, 129 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 130 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 131 => null, 132 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 133 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 134 => null, 135 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 136 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 137 => static function ($self, $stackPos) { + $self->semValue = new Node\UseItem($self->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkUseUse($self->semValue, $stackPos - (1 - 1)); + }, 138 => static function ($self, $stackPos) { + $self->semValue = new Node\UseItem($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkUseUse($self->semValue, $stackPos - (3 - 3)); + }, 139 => static function ($self, $stackPos) { + $self->semValue = new Node\UseItem($self->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkUseUse($self->semValue, $stackPos - (1 - 1)); + }, 140 => static function ($self, $stackPos) { + $self->semValue = new Node\UseItem($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkUseUse($self->semValue, $stackPos - (3 - 3)); + }, 141 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + $self->semValue->type = Stmt\Use_::TYPE_NORMAL; + }, 142 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue->type = $self->semStack[$stackPos - (2 - 1)]; + }, 143 => null, 144 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 145 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 146 => static function ($self, $stackPos) { + $self->semValue = new Node\Const_($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 147 => null, 148 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 149 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 150 => static function ($self, $stackPos) { + $self->semValue = new Node\Const_(new Node\Identifier($self->semStack[$stackPos - (3 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos - (3 - 1)])), $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 151 => static function ($self, $stackPos) { + $self->semValue = new Node\Const_(new Node\Identifier($self->semStack[$stackPos - (3 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos - (3 - 1)])), $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 152 => static function ($self, $stackPos) { + if ($self->semStack[$stackPos - (2 - 2)] !== null) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + } + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 153 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 154 => static function ($self, $stackPos) { + $nop = $self->maybeCreateZeroLengthNop($self->tokenPos); + if ($nop !== null) { + $self->semStack[$stackPos - (1 - 1)][] = $nop; + } + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 155 => null, 156 => null, 157 => null, 158 => static function ($self, $stackPos) { + throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 159 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Block($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 160 => static function ($self, $stackPos) { + $self->semValue = new Stmt\If_($self->semStack[$stackPos - (7 - 3)], ['stmts' => $self->semStack[$stackPos - (7 - 5)], 'elseifs' => $self->semStack[$stackPos - (7 - 6)], 'else' => $self->semStack[$stackPos - (7 - 7)]], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + }, 161 => static function ($self, $stackPos) { + $self->semValue = new Stmt\If_($self->semStack[$stackPos - (10 - 3)], ['stmts' => $self->semStack[$stackPos - (10 - 6)], 'elseifs' => $self->semStack[$stackPos - (10 - 7)], 'else' => $self->semStack[$stackPos - (10 - 8)]], $self->getAttributes($self->tokenStartStack[$stackPos - (10 - 1)], $self->tokenEndStack[$stackPos])); + }, 162 => static function ($self, $stackPos) { + $self->semValue = new Stmt\While_($self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 163 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Do_($self->semStack[$stackPos - (7 - 5)], $self->semStack[$stackPos - (7 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + }, 164 => static function ($self, $stackPos) { + $self->semValue = new Stmt\For_(['init' => $self->semStack[$stackPos - (9 - 3)], 'cond' => $self->semStack[$stackPos - (9 - 5)], 'loop' => $self->semStack[$stackPos - (9 - 7)], 'stmts' => $self->semStack[$stackPos - (9 - 9)]], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 165 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Switch_($self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 166 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Break_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 167 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Continue_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 168 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Return_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 169 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Global_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 170 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Static_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 171 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Echo_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 172 => static function ($self, $stackPos) { + $self->semValue = new Stmt\InlineHTML($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + $self->semValue->setAttribute('hasLeadingNewline', $self->inlineHtmlHasLeadingNewline($stackPos - (1 - 1))); + }, 173 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Expression($self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 174 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Unset_($self->semStack[$stackPos - (5 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 175 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos - (7 - 3)], $self->semStack[$stackPos - (7 - 5)][0], ['keyVar' => null, 'byRef' => $self->semStack[$stackPos - (7 - 5)][1], 'stmts' => $self->semStack[$stackPos - (7 - 7)]], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + }, 176 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos - (9 - 3)], $self->semStack[$stackPos - (9 - 7)][0], ['keyVar' => $self->semStack[$stackPos - (9 - 5)], 'byRef' => $self->semStack[$stackPos - (9 - 7)][1], 'stmts' => $self->semStack[$stackPos - (9 - 9)]], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 177 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos - (6 - 3)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (6 - 4)], $self->tokenEndStack[$stackPos - (6 - 4)])), ['stmts' => $self->semStack[$stackPos - (6 - 6)]], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])); + }, 178 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Declare_($self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 179 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TryCatch($self->semStack[$stackPos - (6 - 3)], $self->semStack[$stackPos - (6 - 5)], $self->semStack[$stackPos - (6 - 6)], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkTryCatch($self->semValue); + }, 180 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Goto_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 181 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Label($self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 182 => static function ($self, $stackPos) { + $self->semValue = null; + /* means: no statement */ + }, 183 => null, 184 => static function ($self, $stackPos) { + $self->semValue = $self->maybeCreateNop($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]); + }, 185 => static function ($self, $stackPos) { + if ($self->semStack[$stackPos - (1 - 1)] instanceof Stmt\Block) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]->stmts; + } else if ($self->semStack[$stackPos - (1 - 1)] === null) { + $self->semValue = []; + } else { + $self->semValue = [$self->semStack[$stackPos - (1 - 1)]]; + } + }, 186 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 187 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 188 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 189 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 190 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Catch_($self->semStack[$stackPos - (8 - 3)], $self->semStack[$stackPos - (8 - 4)], $self->semStack[$stackPos - (8 - 7)], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + }, 191 => static function ($self, $stackPos) { + $self->semValue = null; + }, 192 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Finally_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 193 => null, 194 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 195 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 196 => static function ($self, $stackPos) { + $self->semValue = \false; + }, 197 => static function ($self, $stackPos) { + $self->semValue = \true; + }, 198 => static function ($self, $stackPos) { + $self->semValue = \false; + }, 199 => static function ($self, $stackPos) { + $self->semValue = \true; + }, 200 => static function ($self, $stackPos) { + $self->semValue = \false; + }, 201 => static function ($self, $stackPos) { + $self->semValue = \true; + }, 202 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 203 => static function ($self, $stackPos) { + $self->semValue = []; + }, 204 => null, 205 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 206 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 207 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 208 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Function_($self->semStack[$stackPos - (8 - 3)], ['byRef' => $self->semStack[$stackPos - (8 - 2)], 'params' => $self->semStack[$stackPos - (8 - 5)], 'returnType' => $self->semStack[$stackPos - (8 - 7)], 'stmts' => $self->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + }, 209 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Function_($self->semStack[$stackPos - (9 - 4)], ['byRef' => $self->semStack[$stackPos - (9 - 3)], 'params' => $self->semStack[$stackPos - (9 - 6)], 'returnType' => $self->semStack[$stackPos - (9 - 8)], 'stmts' => $self->semStack[$stackPos - (9 - 9)], 'attrGroups' => $self->semStack[$stackPos - (9 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 210 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Class_($self->semStack[$stackPos - (7 - 2)], ['type' => $self->semStack[$stackPos - (7 - 1)], 'extends' => $self->semStack[$stackPos - (7 - 3)], 'implements' => $self->semStack[$stackPos - (7 - 4)], 'stmts' => $self->semStack[$stackPos - (7 - 6)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkClass($self->semValue, $stackPos - (7 - 2)); + }, 211 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Class_($self->semStack[$stackPos - (8 - 3)], ['type' => $self->semStack[$stackPos - (8 - 2)], 'extends' => $self->semStack[$stackPos - (8 - 4)], 'implements' => $self->semStack[$stackPos - (8 - 5)], 'stmts' => $self->semStack[$stackPos - (8 - 7)], 'attrGroups' => $self->semStack[$stackPos - (8 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkClass($self->semValue, $stackPos - (8 - 3)); + }, 212 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Interface_($self->semStack[$stackPos - (7 - 3)], ['extends' => $self->semStack[$stackPos - (7 - 4)], 'stmts' => $self->semStack[$stackPos - (7 - 6)], 'attrGroups' => $self->semStack[$stackPos - (7 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkInterface($self->semValue, $stackPos - (7 - 3)); + }, 213 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Trait_($self->semStack[$stackPos - (6 - 3)], ['stmts' => $self->semStack[$stackPos - (6 - 5)], 'attrGroups' => $self->semStack[$stackPos - (6 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])); + }, 214 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Enum_($self->semStack[$stackPos - (8 - 3)], ['scalarType' => $self->semStack[$stackPos - (8 - 4)], 'implements' => $self->semStack[$stackPos - (8 - 5)], 'stmts' => $self->semStack[$stackPos - (8 - 7)], 'attrGroups' => $self->semStack[$stackPos - (8 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkEnum($self->semValue, $stackPos - (8 - 3)); + }, 215 => static function ($self, $stackPos) { + $self->semValue = null; + }, 216 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 217 => static function ($self, $stackPos) { + $self->semValue = null; + }, 218 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 219 => static function ($self, $stackPos) { + $self->semValue = 0; + }, 220 => null, 221 => null, 222 => static function ($self, $stackPos) { + $self->checkClassModifier($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $self->semValue = $self->semStack[$stackPos - (2 - 1)] | $self->semStack[$stackPos - (2 - 2)]; + }, 223 => static function ($self, $stackPos) { + $self->semValue = Modifiers::ABSTRACT; + }, 224 => static function ($self, $stackPos) { + $self->semValue = Modifiers::FINAL; + }, 225 => static function ($self, $stackPos) { + $self->semValue = Modifiers::READONLY; + }, 226 => static function ($self, $stackPos) { + $self->semValue = null; + }, 227 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 228 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 229 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 230 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 231 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 232 => null, 233 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 234 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 235 => null, 236 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 237 => null, 238 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 239 => static function ($self, $stackPos) { + if ($self->semStack[$stackPos - (1 - 1)] instanceof Stmt\Block) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]->stmts; + } else if ($self->semStack[$stackPos - (1 - 1)] === null) { + $self->semValue = []; + } else { + $self->semValue = [$self->semStack[$stackPos - (1 - 1)]]; + } + }, 240 => static function ($self, $stackPos) { + $self->semValue = null; + }, 241 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 242 => null, 243 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 244 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 245 => static function ($self, $stackPos) { + $self->semValue = new Node\DeclareItem($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 246 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 247 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 3)]; + }, 248 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 249 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (5 - 3)]; + }, 250 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 251 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 252 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Case_($self->semStack[$stackPos - (4 - 2)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 253 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Case_(null, $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 254 => null, 255 => null, 256 => static function ($self, $stackPos) { + $self->semValue = new Expr\Match_($self->semStack[$stackPos - (7 - 3)], $self->semStack[$stackPos - (7 - 6)], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + }, 257 => static function ($self, $stackPos) { + $self->semValue = []; + }, 258 => null, 259 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 260 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 261 => static function ($self, $stackPos) { + $self->semValue = new Node\MatchArm($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 262 => static function ($self, $stackPos) { + $self->semValue = new Node\MatchArm(null, $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 263 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 264 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 265 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 266 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 267 => static function ($self, $stackPos) { + $self->semValue = new Stmt\ElseIf_($self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 268 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 269 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 270 => static function ($self, $stackPos) { + $self->semValue = new Stmt\ElseIf_($self->semStack[$stackPos - (6 - 3)], $self->semStack[$stackPos - (6 - 6)], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])); + $self->fixupAlternativeElse($self->semValue); + }, 271 => static function ($self, $stackPos) { + $self->semValue = null; + }, 272 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Else_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 273 => static function ($self, $stackPos) { + $self->semValue = null; + }, 274 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Else_($self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + $self->fixupAlternativeElse($self->semValue); + }, 275 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)], \false); + }, 276 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (2 - 2)], \true); + }, 277 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)], \false); + }, 278 => static function ($self, $stackPos) { + $self->semValue = array($self->fixupArrayDestructuring($self->semStack[$stackPos - (1 - 1)]), \false); + }, 279 => null, 280 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 281 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 282 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 283 => static function ($self, $stackPos) { + $self->semValue = 0; + }, 284 => static function ($self, $stackPos) { + $self->checkModifier($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $self->semValue = $self->semStack[$stackPos - (2 - 1)] | $self->semStack[$stackPos - (2 - 2)]; + }, 285 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PUBLIC; + }, 286 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PROTECTED; + }, 287 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PRIVATE; + }, 288 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PUBLIC_SET; + }, 289 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PROTECTED_SET; + }, 290 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PRIVATE_SET; + }, 291 => static function ($self, $stackPos) { + $self->semValue = Modifiers::READONLY; + }, 292 => static function ($self, $stackPos) { + $self->semValue = Modifiers::FINAL; + }, 293 => static function ($self, $stackPos) { + $self->semValue = new Node\Param($self->semStack[$stackPos - (7 - 6)], null, $self->semStack[$stackPos - (7 - 3)], $self->semStack[$stackPos - (7 - 4)], $self->semStack[$stackPos - (7 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (7 - 2)], $self->semStack[$stackPos - (7 - 1)], $self->semStack[$stackPos - (7 - 7)]); + $self->checkParam($self->semValue); + $self->addPropertyNameToHooks($self->semValue); + }, 294 => static function ($self, $stackPos) { + $self->semValue = new Node\Param($self->semStack[$stackPos - (9 - 6)], $self->semStack[$stackPos - (9 - 8)], $self->semStack[$stackPos - (9 - 3)], $self->semStack[$stackPos - (9 - 4)], $self->semStack[$stackPos - (9 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (9 - 2)], $self->semStack[$stackPos - (9 - 1)], $self->semStack[$stackPos - (9 - 9)]); + $self->checkParam($self->semValue); + $self->addPropertyNameToHooks($self->semValue); + }, 295 => static function ($self, $stackPos) { + $self->semValue = new Node\Param(new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])), null, $self->semStack[$stackPos - (6 - 3)], $self->semStack[$stackPos - (6 - 4)], $self->semStack[$stackPos - (6 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (6 - 2)], $self->semStack[$stackPos - (6 - 1)]); + }, 296 => null, 297 => static function ($self, $stackPos) { + $self->semValue = new Node\NullableType($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 298 => static function ($self, $stackPos) { + $self->semValue = new Node\UnionType($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 299 => null, 300 => null, 301 => static function ($self, $stackPos) { + $self->semValue = new Node\Name('static', $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 302 => static function ($self, $stackPos) { + $self->semValue = $self->handleBuiltinTypes($self->semStack[$stackPos - (1 - 1)]); + }, 303 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier('array', $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 304 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier('callable', $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 305 => null, 306 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 307 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)]); + }, 308 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 309 => null, 310 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 311 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)]); + }, 312 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 313 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)]); + }, 314 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 315 => static function ($self, $stackPos) { + $self->semValue = new Node\IntersectionType($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 316 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)]); + }, 317 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 318 => static function ($self, $stackPos) { + $self->semValue = new Node\IntersectionType($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 319 => null, 320 => static function ($self, $stackPos) { + $self->semValue = new Node\NullableType($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 321 => static function ($self, $stackPos) { + $self->semValue = new Node\UnionType($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 322 => null, 323 => static function ($self, $stackPos) { + $self->semValue = null; + }, 324 => null, 325 => static function ($self, $stackPos) { + $self->semValue = null; + }, 326 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 327 => static function ($self, $stackPos) { + $self->semValue = null; + }, 328 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 329 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 330 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 2)]); + }, 331 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 332 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 333 => static function ($self, $stackPos) { + $self->semValue = array(new Node\Arg($self->semStack[$stackPos - (4 - 2)], \false, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos]))); + }, 334 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 2)]); + }, 335 => static function ($self, $stackPos) { + $self->semValue = array(new Node\Arg($self->semStack[$stackPos - (3 - 1)], \false, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos - (3 - 1)])), $self->semStack[$stackPos - (3 - 3)]); + }, 336 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 337 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 338 => static function ($self, $stackPos) { + $self->semValue = new Node\VariadicPlaceholder($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 339 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 340 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 341 => static function ($self, $stackPos) { + $self->semValue = new Node\Arg($self->semStack[$stackPos - (2 - 2)], \true, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 342 => static function ($self, $stackPos) { + $self->semValue = new Node\Arg($self->semStack[$stackPos - (2 - 2)], \false, \true, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 343 => static function ($self, $stackPos) { + $self->semValue = new Node\Arg($self->semStack[$stackPos - (3 - 3)], \false, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (3 - 1)]); + }, 344 => static function ($self, $stackPos) { + $self->semValue = new Node\Arg($self->semStack[$stackPos - (1 - 1)], \false, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 345 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 346 => null, 347 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 348 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 349 => null, 350 => null, 351 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 352 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 353 => static function ($self, $stackPos) { + $self->semValue = new Node\StaticVar($self->semStack[$stackPos - (1 - 1)], null, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 354 => static function ($self, $stackPos) { + $self->semValue = new Node\StaticVar($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 355 => static function ($self, $stackPos) { + if ($self->semStack[$stackPos - (2 - 2)] !== null) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + } else { + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + } + }, 356 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 357 => static function ($self, $stackPos) { + $nop = $self->maybeCreateZeroLengthNop($self->tokenPos); + if ($nop !== null) { + $self->semStack[$stackPos - (1 - 1)][] = $nop; + } + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 358 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Property($self->semStack[$stackPos - (5 - 2)], $self->semStack[$stackPos - (5 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 1)]); + }, 359 => static function ($self, $stackPos) { + $self->semValue = new Stmt\ClassConst($self->semStack[$stackPos - (5 - 4)], $self->semStack[$stackPos - (5 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (5 - 1)]); + $self->checkClassConst($self->semValue, $stackPos - (5 - 2)); + }, 360 => static function ($self, $stackPos) { + $self->semValue = new Stmt\ClassConst($self->semStack[$stackPos - (6 - 5)], $self->semStack[$stackPos - (6 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (6 - 1)], $self->semStack[$stackPos - (6 - 4)]); + $self->checkClassConst($self->semValue, $stackPos - (6 - 2)); + }, 361 => static function ($self, $stackPos) { + $self->semValue = new Stmt\ClassMethod($self->semStack[$stackPos - (10 - 5)], ['type' => $self->semStack[$stackPos - (10 - 2)], 'byRef' => $self->semStack[$stackPos - (10 - 4)], 'params' => $self->semStack[$stackPos - (10 - 7)], 'returnType' => $self->semStack[$stackPos - (10 - 9)], 'stmts' => $self->semStack[$stackPos - (10 - 10)], 'attrGroups' => $self->semStack[$stackPos - (10 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (10 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkClassMethod($self->semValue, $stackPos - (10 - 2)); + }, 362 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUse($self->semStack[$stackPos - (3 - 2)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 363 => static function ($self, $stackPos) { + $self->semValue = new Stmt\EnumCase($self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 4)], $self->semStack[$stackPos - (5 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 364 => static function ($self, $stackPos) { + $self->semValue = null; + /* will be skipped */ + }, 365 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 366 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 367 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 368 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 369 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUseAdaptation\Precedence($self->semStack[$stackPos - (4 - 1)][0], $self->semStack[$stackPos - (4 - 1)][1], $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 370 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos - (5 - 1)][0], $self->semStack[$stackPos - (5 - 1)][1], $self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 371 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos - (4 - 1)][0], $self->semStack[$stackPos - (4 - 1)][1], $self->semStack[$stackPos - (4 - 3)], null, $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 372 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos - (4 - 1)][0], $self->semStack[$stackPos - (4 - 1)][1], null, $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 373 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos - (4 - 1)][0], $self->semStack[$stackPos - (4 - 1)][1], null, $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 374 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)]); + }, 375 => null, 376 => static function ($self, $stackPos) { + $self->semValue = array(null, $self->semStack[$stackPos - (1 - 1)]); + }, 377 => static function ($self, $stackPos) { + $self->semValue = null; + }, 378 => null, 379 => null, 380 => static function ($self, $stackPos) { + $self->semValue = 0; + }, 381 => static function ($self, $stackPos) { + $self->semValue = 0; + }, 382 => null, 383 => null, 384 => static function ($self, $stackPos) { + $self->checkModifier($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $self->semValue = $self->semStack[$stackPos - (2 - 1)] | $self->semStack[$stackPos - (2 - 2)]; + }, 385 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PUBLIC; + }, 386 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PROTECTED; + }, 387 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PRIVATE; + }, 388 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PUBLIC_SET; + }, 389 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PROTECTED_SET; + }, 390 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PRIVATE_SET; + }, 391 => static function ($self, $stackPos) { + $self->semValue = Modifiers::STATIC; + }, 392 => static function ($self, $stackPos) { + $self->semValue = Modifiers::ABSTRACT; + }, 393 => static function ($self, $stackPos) { + $self->semValue = Modifiers::FINAL; + }, 394 => static function ($self, $stackPos) { + $self->semValue = Modifiers::READONLY; + }, 395 => null, 396 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 397 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 398 => static function ($self, $stackPos) { + $self->semValue = new Node\VarLikeIdentifier(substr($self->semStack[$stackPos - (1 - 1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 399 => static function ($self, $stackPos) { + $self->semValue = new Node\PropertyItem($self->semStack[$stackPos - (1 - 1)], null, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 400 => static function ($self, $stackPos) { + $self->semValue = new Node\PropertyItem($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 401 => static function ($self, $stackPos) { + $self->semValue = []; + }, 402 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 403 => static function ($self, $stackPos) { + $self->semValue = []; + }, 404 => static function ($self, $stackPos) { + $self->semValue = new Node\PropertyHook($self->semStack[$stackPos - (5 - 4)], $self->semStack[$stackPos - (5 - 5)], ['flags' => $self->semStack[$stackPos - (5 - 2)], 'byRef' => $self->semStack[$stackPos - (5 - 3)], 'params' => [], 'attrGroups' => $self->semStack[$stackPos - (5 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkPropertyHook($self->semValue, null); + }, 405 => static function ($self, $stackPos) { + $self->semValue = new Node\PropertyHook($self->semStack[$stackPos - (8 - 4)], $self->semStack[$stackPos - (8 - 8)], ['flags' => $self->semStack[$stackPos - (8 - 2)], 'byRef' => $self->semStack[$stackPos - (8 - 3)], 'params' => $self->semStack[$stackPos - (8 - 6)], 'attrGroups' => $self->semStack[$stackPos - (8 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkPropertyHook($self->semValue, $stackPos - (8 - 5)); + }, 406 => static function ($self, $stackPos) { + $self->semValue = null; + }, 407 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 408 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 409 => static function ($self, $stackPos) { + $self->semValue = 0; + }, 410 => static function ($self, $stackPos) { + $self->checkPropertyHookModifiers($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $self->semValue = $self->semStack[$stackPos - (2 - 1)] | $self->semStack[$stackPos - (2 - 2)]; + }, 411 => null, 412 => null, 413 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 414 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 415 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 416 => null, 417 => null, 418 => static function ($self, $stackPos) { + $self->semValue = new Expr\Assign($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 419 => static function ($self, $stackPos) { + $self->semValue = new Expr\Assign($self->fixupArrayDestructuring($self->semStack[$stackPos - (3 - 1)]), $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 420 => static function ($self, $stackPos) { + $self->semValue = new Expr\Assign($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 421 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignRef($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 422 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignRef($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + if (!$self->phpVersion->allowsAssignNewByReference()) { + $self->emitError(new Error('Cannot assign new by reference', $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos]))); + } + }, 423 => null, 424 => null, 425 => static function ($self, $stackPos) { + $self->semValue = new Expr\FuncCall(new Node\Name($self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos - (2 - 1)])), $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 426 => static function ($self, $stackPos) { + $self->semValue = new Expr\Clone_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 427 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Plus($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 428 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Minus($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 429 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Mul($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 430 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Div($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 431 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Concat($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 432 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Mod($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 433 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\BitwiseAnd($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 434 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\BitwiseOr($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 435 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\BitwiseXor($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 436 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\ShiftLeft($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 437 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\ShiftRight($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 438 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Pow($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 439 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Coalesce($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 440 => static function ($self, $stackPos) { + $self->semValue = new Expr\PostInc($self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 441 => static function ($self, $stackPos) { + $self->semValue = new Expr\PreInc($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 442 => static function ($self, $stackPos) { + $self->semValue = new Expr\PostDec($self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 443 => static function ($self, $stackPos) { + $self->semValue = new Expr\PreDec($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 444 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BooleanOr($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 445 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BooleanAnd($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 446 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\LogicalOr($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 447 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\LogicalAnd($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 448 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\LogicalXor($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 449 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BitwiseOr($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 450 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BitwiseAnd($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 451 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BitwiseAnd($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 452 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BitwiseXor($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 453 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Concat($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 454 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Plus($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 455 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Minus($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 456 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Mul($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 457 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Div($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 458 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Mod($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 459 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\ShiftLeft($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 460 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\ShiftRight($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 461 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Pow($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 462 => static function ($self, $stackPos) { + $self->semValue = new Expr\UnaryPlus($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 463 => static function ($self, $stackPos) { + $self->semValue = new Expr\UnaryMinus($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 464 => static function ($self, $stackPos) { + $self->semValue = new Expr\BooleanNot($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 465 => static function ($self, $stackPos) { + $self->semValue = new Expr\BitwiseNot($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 466 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Identical($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 467 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\NotIdentical($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 468 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Equal($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 469 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\NotEqual($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 470 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Spaceship($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 471 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Smaller($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 472 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\SmallerOrEqual($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 473 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Greater($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 474 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\GreaterOrEqual($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 475 => static function ($self, $stackPos) { + $self->semValue = new Expr\Instanceof_($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 476 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + if ($self->semValue instanceof Expr\ArrowFunction) { + $self->parenthesizedArrowFunctions->offsetSet($self->semValue); + } + }, 477 => static function ($self, $stackPos) { + $self->semValue = new Expr\Ternary($self->semStack[$stackPos - (5 - 1)], $self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 478 => static function ($self, $stackPos) { + $self->semValue = new Expr\Ternary($self->semStack[$stackPos - (4 - 1)], null, $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 479 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Coalesce($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 480 => static function ($self, $stackPos) { + $self->semValue = new Expr\Isset_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 481 => static function ($self, $stackPos) { + $self->semValue = new Expr\Empty_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 482 => static function ($self, $stackPos) { + $self->semValue = new Expr\Include_($self->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 483 => static function ($self, $stackPos) { + $self->semValue = new Expr\Include_($self->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE_ONCE, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 484 => static function ($self, $stackPos) { + $self->semValue = new Expr\Eval_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 485 => static function ($self, $stackPos) { + $self->semValue = new Expr\Include_($self->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 486 => static function ($self, $stackPos) { + $self->semValue = new Expr\Include_($self->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE_ONCE, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 487 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->getIntCastKind($self->semStack[$stackPos - (2 - 1)]); + $self->semValue = new Expr\Cast\Int_($self->semStack[$stackPos - (2 - 2)], $attrs); + }, 488 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->getFloatCastKind($self->semStack[$stackPos - (2 - 1)]); + $self->semValue = new Expr\Cast\Double($self->semStack[$stackPos - (2 - 2)], $attrs); + }, 489 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->getStringCastKind($self->semStack[$stackPos - (2 - 1)]); + $self->semValue = new Expr\Cast\String_($self->semStack[$stackPos - (2 - 2)], $attrs); + }, 490 => static function ($self, $stackPos) { + $self->semValue = new Expr\Cast\Array_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 491 => static function ($self, $stackPos) { + $self->semValue = new Expr\Cast\Object_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 492 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->getBoolCastKind($self->semStack[$stackPos - (2 - 1)]); + $self->semValue = new Expr\Cast\Bool_($self->semStack[$stackPos - (2 - 2)], $attrs); + }, 493 => static function ($self, $stackPos) { + $self->semValue = new Expr\Cast\Unset_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 494 => static function ($self, $stackPos) { + $self->semValue = new Expr\Cast\Void_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 495 => static function ($self, $stackPos) { + $self->semValue = $self->createExitExpr($self->semStack[$stackPos - (2 - 1)], $stackPos - (2 - 1), $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 496 => static function ($self, $stackPos) { + $self->semValue = new Expr\ErrorSuppress($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 497 => null, 498 => static function ($self, $stackPos) { + $self->semValue = new Expr\ShellExec($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 499 => static function ($self, $stackPos) { + $self->semValue = new Expr\Print_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 500 => static function ($self, $stackPos) { + $self->semValue = new Expr\Yield_(null, null, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 501 => static function ($self, $stackPos) { + $self->semValue = new Expr\Yield_($self->semStack[$stackPos - (2 - 2)], null, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 502 => static function ($self, $stackPos) { + $self->semValue = new Expr\Yield_($self->semStack[$stackPos - (4 - 4)], $self->semStack[$stackPos - (4 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 503 => static function ($self, $stackPos) { + $self->semValue = new Expr\YieldFrom($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 504 => static function ($self, $stackPos) { + $self->semValue = new Expr\Throw_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 505 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrowFunction(['static' => \false, 'byRef' => $self->semStack[$stackPos - (8 - 2)], 'params' => $self->semStack[$stackPos - (8 - 4)], 'returnType' => $self->semStack[$stackPos - (8 - 6)], 'expr' => $self->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + }, 506 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrowFunction(['static' => \true, 'byRef' => $self->semStack[$stackPos - (9 - 3)], 'params' => $self->semStack[$stackPos - (9 - 5)], 'returnType' => $self->semStack[$stackPos - (9 - 7)], 'expr' => $self->semStack[$stackPos - (9 - 9)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 507 => static function ($self, $stackPos) { + $self->semValue = new Expr\Closure(['static' => \false, 'byRef' => $self->semStack[$stackPos - (8 - 2)], 'params' => $self->semStack[$stackPos - (8 - 4)], 'uses' => $self->semStack[$stackPos - (8 - 6)], 'returnType' => $self->semStack[$stackPos - (8 - 7)], 'stmts' => $self->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + }, 508 => static function ($self, $stackPos) { + $self->semValue = new Expr\Closure(['static' => \true, 'byRef' => $self->semStack[$stackPos - (9 - 3)], 'params' => $self->semStack[$stackPos - (9 - 5)], 'uses' => $self->semStack[$stackPos - (9 - 7)], 'returnType' => $self->semStack[$stackPos - (9 - 8)], 'stmts' => $self->semStack[$stackPos - (9 - 9)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 509 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrowFunction(['static' => \false, 'byRef' => $self->semStack[$stackPos - (9 - 3)], 'params' => $self->semStack[$stackPos - (9 - 5)], 'returnType' => $self->semStack[$stackPos - (9 - 7)], 'expr' => $self->semStack[$stackPos - (9 - 9)], 'attrGroups' => $self->semStack[$stackPos - (9 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 510 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrowFunction(['static' => \true, 'byRef' => $self->semStack[$stackPos - (10 - 4)], 'params' => $self->semStack[$stackPos - (10 - 6)], 'returnType' => $self->semStack[$stackPos - (10 - 8)], 'expr' => $self->semStack[$stackPos - (10 - 10)], 'attrGroups' => $self->semStack[$stackPos - (10 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (10 - 1)], $self->tokenEndStack[$stackPos])); + }, 511 => static function ($self, $stackPos) { + $self->semValue = new Expr\Closure(['static' => \false, 'byRef' => $self->semStack[$stackPos - (9 - 3)], 'params' => $self->semStack[$stackPos - (9 - 5)], 'uses' => $self->semStack[$stackPos - (9 - 7)], 'returnType' => $self->semStack[$stackPos - (9 - 8)], 'stmts' => $self->semStack[$stackPos - (9 - 9)], 'attrGroups' => $self->semStack[$stackPos - (9 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 512 => static function ($self, $stackPos) { + $self->semValue = new Expr\Closure(['static' => \true, 'byRef' => $self->semStack[$stackPos - (10 - 4)], 'params' => $self->semStack[$stackPos - (10 - 6)], 'uses' => $self->semStack[$stackPos - (10 - 8)], 'returnType' => $self->semStack[$stackPos - (10 - 9)], 'stmts' => $self->semStack[$stackPos - (10 - 10)], 'attrGroups' => $self->semStack[$stackPos - (10 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (10 - 1)], $self->tokenEndStack[$stackPos])); + }, 513 => static function ($self, $stackPos) { + $self->semValue = array(new Stmt\Class_(null, ['type' => $self->semStack[$stackPos - (8 - 2)], 'extends' => $self->semStack[$stackPos - (8 - 4)], 'implements' => $self->semStack[$stackPos - (8 - 5)], 'stmts' => $self->semStack[$stackPos - (8 - 7)], 'attrGroups' => $self->semStack[$stackPos - (8 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])), $self->semStack[$stackPos - (8 - 3)]); + $self->checkClass($self->semValue[0], -1); + }, 514 => static function ($self, $stackPos) { + $self->semValue = new Expr\New_($self->semStack[$stackPos - (3 - 2)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 515 => static function ($self, $stackPos) { + list($class, $ctorArgs) = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = new Expr\New_($class, $ctorArgs, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 516 => static function ($self, $stackPos) { + $self->semValue = new Expr\New_($self->semStack[$stackPos - (2 - 2)], [], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 517 => null, 518 => null, 519 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 520 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 3)]; + }, 521 => null, 522 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 523 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 524 => static function ($self, $stackPos) { + $self->semValue = new Node\ClosureUse($self->semStack[$stackPos - (2 - 2)], $self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 525 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 526 => static function ($self, $stackPos) { + $self->semValue = new Expr\FuncCall($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 527 => static function ($self, $stackPos) { + $self->semValue = new Expr\FuncCall($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 528 => static function ($self, $stackPos) { + $self->semValue = new Expr\FuncCall($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 529 => static function ($self, $stackPos) { + $self->semValue = new Expr\StaticCall($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 530 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 531 => null, 532 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 533 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 534 => static function ($self, $stackPos) { + $self->semValue = new Name\FullyQualified(substr($self->semStack[$stackPos - (1 - 1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 535 => static function ($self, $stackPos) { + $self->semValue = new Name\Relative(substr($self->semStack[$stackPos - (1 - 1)], 10), $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 536 => null, 537 => null, 538 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 539 => static function ($self, $stackPos) { + $self->semValue = new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + $self->errorState = 2; + }, 540 => null, 541 => null, 542 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 543 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + foreach ($self->semValue as $s) { + if ($s instanceof Node\InterpolatedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', $self->phpVersion->supportsUnicodeEscapes()); + } + } + }, 544 => static function ($self, $stackPos) { + foreach ($self->semStack[$stackPos - (1 - 1)] as $s) { + if ($s instanceof Node\InterpolatedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', $self->phpVersion->supportsUnicodeEscapes()); + } + } + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 545 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 546 => null, 547 => static function ($self, $stackPos) { + $self->semValue = new Expr\ConstFetch($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 548 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Line($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 549 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\File($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 550 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Dir($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 551 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Class_($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 552 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Trait_($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 553 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Method($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 554 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Function_($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 555 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Namespace_($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 556 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Property($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 557 => static function ($self, $stackPos) { + $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 558 => static function ($self, $stackPos) { + $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos - (5 - 1)], $self->semStack[$stackPos - (5 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 559 => static function ($self, $stackPos) { + $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos - (3 - 1)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (3 - 3)], $self->tokenEndStack[$stackPos - (3 - 3)])), $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + $self->errorState = 2; + }, 560 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = Expr\Array_::KIND_SHORT; + $self->semValue = new Expr\Array_($self->semStack[$stackPos - (3 - 2)], $attrs); + }, 561 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = Expr\Array_::KIND_LONG; + $self->semValue = new Expr\Array_($self->semStack[$stackPos - (4 - 3)], $attrs); + $self->createdArrays->offsetSet($self->semValue); + }, 562 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + $self->createdArrays->offsetSet($self->semValue); + }, 563 => static function ($self, $stackPos) { + $self->semValue = Scalar\String_::fromString($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->supportsUnicodeEscapes()); + }, 564 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; + foreach ($self->semStack[$stackPos - (3 - 2)] as $s) { + if ($s instanceof Node\InterpolatedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '"', $self->phpVersion->supportsUnicodeEscapes()); + } + } + $self->semValue = new Scalar\InterpolatedString($self->semStack[$stackPos - (3 - 2)], $attrs); + }, 565 => static function ($self, $stackPos) { + $self->semValue = $self->parseLNumber($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->allowsInvalidOctals()); + }, 566 => static function ($self, $stackPos) { + $self->semValue = Scalar\Float_::fromString($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 567 => null, 568 => null, 569 => null, 570 => static function ($self, $stackPos) { + $self->semValue = $self->parseDocString($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 2)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 3)], $self->tokenEndStack[$stackPos - (3 - 3)]), \true); + }, 571 => static function ($self, $stackPos) { + $self->semValue = $self->parseDocString($self->semStack[$stackPos - (2 - 1)], '', $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 2)], $self->tokenEndStack[$stackPos - (2 - 2)]), \true); + }, 572 => static function ($self, $stackPos) { + $self->semValue = $self->parseDocString($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 2)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 3)], $self->tokenEndStack[$stackPos - (3 - 3)]), \true); + }, 573 => static function ($self, $stackPos) { + $self->semValue = null; + }, 574 => null, 575 => null, 576 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 577 => null, 578 => null, 579 => null, 580 => null, 581 => null, 582 => null, 583 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 584 => null, 585 => null, 586 => null, 587 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 588 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 589 => null, 590 => static function ($self, $stackPos) { + $self->semValue = new Expr\MethodCall($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 591 => static function ($self, $stackPos) { + $self->semValue = new Expr\NullsafeMethodCall($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 592 => static function ($self, $stackPos) { + $self->semValue = null; + }, 593 => null, 594 => null, 595 => null, 596 => static function ($self, $stackPos) { + $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 597 => static function ($self, $stackPos) { + $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 598 => null, 599 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 600 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 601 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable(new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])), $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + $self->errorState = 2; + }, 602 => static function ($self, $stackPos) { + $var = $self->semStack[$stackPos - (1 - 1)]->name; + $self->semValue = \is_string($var) ? new Node\VarLikeIdentifier($var, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])) : $var; + }, 603 => static function ($self, $stackPos) { + $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 604 => null, 605 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 606 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 607 => static function ($self, $stackPos) { + $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 608 => static function ($self, $stackPos) { + $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 609 => static function ($self, $stackPos) { + $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 610 => static function ($self, $stackPos) { + $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 611 => null, 612 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 613 => null, 614 => null, 615 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 616 => null, 617 => static function ($self, $stackPos) { + $self->semValue = new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + $self->errorState = 2; + }, 618 => static function ($self, $stackPos) { + $self->semValue = new Expr\List_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + $self->semValue->setAttribute('kind', Expr\List_::KIND_LIST); + $self->postprocessList($self->semValue); + }, 619 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + $end = count($self->semValue) - 1; + if ($self->semValue[$end]->value instanceof Expr\Error) { + array_pop($self->semValue); + } + }, 620 => null, 621 => static function ($self, $stackPos) { + /* do nothing -- prevent default action of $$=$self->semStack[$1]. See $551. */ + }, 622 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 623 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 624 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (1 - 1)], null, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 625 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (2 - 2)], null, \true, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 626 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (1 - 1)], null, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 627 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (3 - 3)], $self->semStack[$stackPos - (3 - 1)], \false, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 628 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (4 - 4)], $self->semStack[$stackPos - (4 - 1)], \true, $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 629 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (3 - 3)], $self->semStack[$stackPos - (3 - 1)], \false, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 630 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (2 - 2)], null, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]), \true); + }, 631 => static function ($self, $stackPos) { + /* Create an Error node now to remember the position. We'll later either report an error, + or convert this into a null element, depending on whether this is a creation or destructuring context. */ + $attrs = $self->createEmptyElemAttributes($self->tokenPos); + $self->semValue = new Node\ArrayItem(new Expr\Error($attrs), null, \false, $attrs); + }, 632 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 633 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 634 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 635 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)]); + }, 636 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['rawValue'] = $self->semStack[$stackPos - (1 - 1)]; + $self->semValue = new Node\InterpolatedStringPart($self->semStack[$stackPos - (1 - 1)], $attrs); + }, 637 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 638 => null, 639 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 640 => static function ($self, $stackPos) { + $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 641 => static function ($self, $stackPos) { + $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 642 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 643 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 644 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos - (6 - 2)], $self->semStack[$stackPos - (6 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])); + }, 645 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 646 => static function ($self, $stackPos) { + $self->semValue = new Scalar\String_($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 647 => static function ($self, $stackPos) { + $self->semValue = $self->parseNumString($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 648 => static function ($self, $stackPos) { + $self->semValue = $self->parseNumString('-' . $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 649 => null]; + } +} +'", "T_IS_GREATER_OR_EQUAL", "T_PIPE", "'.'", "T_SL", "T_SR", "'+'", "'-'", "'*'", "'/'", "'%'", "'!'", "T_INSTANCEOF", "'~'", "T_INC", "T_DEC", "T_INT_CAST", "T_DOUBLE_CAST", "T_STRING_CAST", "T_ARRAY_CAST", "T_OBJECT_CAST", "T_BOOL_CAST", "T_UNSET_CAST", "'@'", "T_POW", "'['", "T_NEW", "T_CLONE", "T_EXIT", "T_IF", "T_ELSEIF", "T_ELSE", "T_ENDIF", "T_LNUMBER", "T_DNUMBER", "T_STRING", "T_STRING_VARNAME", "T_VARIABLE", "T_NUM_STRING", "T_INLINE_HTML", "T_ENCAPSED_AND_WHITESPACE", "T_CONSTANT_ENCAPSED_STRING", "T_ECHO", "T_DO", "T_WHILE", "T_ENDWHILE", "T_FOR", "T_ENDFOR", "T_FOREACH", "T_ENDFOREACH", "T_DECLARE", "T_ENDDECLARE", "T_AS", "T_SWITCH", "T_MATCH", "T_ENDSWITCH", "T_CASE", "T_DEFAULT", "T_BREAK", "T_CONTINUE", "T_GOTO", "T_FUNCTION", "T_FN", "T_CONST", "T_RETURN", "T_TRY", "T_CATCH", "T_FINALLY", "T_USE", "T_INSTEADOF", "T_GLOBAL", "T_STATIC", "T_ABSTRACT", "T_FINAL", "T_PRIVATE", "T_PROTECTED", "T_PUBLIC", "T_READONLY", "T_PUBLIC_SET", "T_PROTECTED_SET", "T_PRIVATE_SET", "T_VAR", "T_UNSET", "T_ISSET", "T_EMPTY", "T_HALT_COMPILER", "T_CLASS", "T_TRAIT", "T_INTERFACE", "T_ENUM", "T_EXTENDS", "T_IMPLEMENTS", "T_OBJECT_OPERATOR", "T_NULLSAFE_OBJECT_OPERATOR", "T_LIST", "T_ARRAY", "T_CALLABLE", "T_CLASS_C", "T_TRAIT_C", "T_METHOD_C", "T_FUNC_C", "T_PROPERTY_C", "T_LINE", "T_FILE", "T_START_HEREDOC", "T_END_HEREDOC", "T_DOLLAR_OPEN_CURLY_BRACES", "T_CURLY_OPEN", "T_PAAMAYIM_NEKUDOTAYIM", "T_NAMESPACE", "T_NS_C", "T_DIR", "T_NS_SEPARATOR", "T_ELLIPSIS", "T_NAME_FULLY_QUALIFIED", "T_NAME_QUALIFIED", "T_NAME_RELATIVE", "T_ATTRIBUTE", "';'", "']'", "'('", "')'", "'{'", "'}'", "'`'", "'\"'", "'\$'"); + protected array $tokenToSymbol = array(0, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 58, 172, 174, 173, 57, 174, 174, 167, 168, 55, 53, 9, 54, 50, 56, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 32, 165, 45, 17, 47, 31, 70, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 72, 174, 166, 37, 174, 171, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 169, 36, 170, 60, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35, 38, 39, 40, 41, 42, 43, 44, 46, 48, 49, 51, 52, 59, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164); + protected array $action = array(132, 133, 134, 582, 135, 136, 162, 779, 780, 781, 137, 41, 863, -32766, 970, 1404, -584, 974, 973, 1302, 0, 395, 396, 455, 246, 854, -32766, -32766, -32766, -32766, -32766, 440, -32766, 27, -32766, 773, 772, -32766, -32766, -32766, -32766, 508, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 131, -32766, -32766, -32766, -32766, 437, 782, 859, 1148, -32766, 949, -32766, -32766, -32766, -32766, -32766, -32766, 972, 1385, 300, 271, 53, 398, 786, 787, 788, 789, 305, 865, 441, -341, 39, 254, -584, -584, -195, 843, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 819, 583, 820, 821, 822, 823, 811, 812, 353, 354, 814, 815, 800, 801, 802, 804, 805, 806, 368, 846, 847, 848, 849, 850, 584, 1062, -194, 856, 807, 808, 585, 586, 3, 831, 829, 830, 842, 826, 827, 4, 860, 587, 588, 825, 589, 590, 591, 592, 939, 593, 594, 5, 854, -32766, -32766, -32766, 828, 595, 596, -32766, 138, 764, 132, 133, 134, 582, 135, 136, 1098, 779, 780, 781, 137, 41, -32766, -32766, -32766, -32766, -32766, -32766, -275, 1302, 613, 153, 1071, 749, 990, 991, -32766, -32766, -32766, 992, -32766, 891, -32766, 892, -32766, 773, 772, -32766, 986, 1309, 397, 396, -32766, -32766, -32766, 858, 299, 630, -32766, -32766, 440, 502, 736, -32766, -32766, 437, 782, -32767, -32767, -32767, -32767, 106, 107, 108, 109, 951, -32766, 1021, 29, 734, 271, 53, 398, 786, 787, 788, 789, 144, 1071, 441, -341, 332, 38, 864, 862, -195, 843, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 819, 583, 820, 821, 822, 823, 811, 812, 353, 354, 814, 815, 800, 801, 802, 804, 805, 806, 368, 846, 847, 848, 849, 850, 584, 863, -194, 139, 807, 808, 585, 586, 323, 831, 829, 830, 842, 826, 827, 1370, 148, 587, 588, 825, 589, 590, 591, 592, 245, 593, 594, 395, 396, -32766, -32766, -32766, 828, 595, 596, -85, 138, 440, 132, 133, 134, 582, 135, 136, 1095, 779, 780, 781, 137, 41, -32766, -32766, -32766, -32766, -32766, 51, 578, 1302, 257, -32766, 636, 107, 108, 109, -32766, -32766, -32766, 503, -32766, 316, -32766, -32766, -32766, 773, 772, -32766, -383, 166, -383, 1022, -32766, -32766, -32766, 305, 79, 1133, -32766, -32766, 1414, 762, 332, 1415, -32766, 437, 782, -32766, 1071, 110, 111, 112, 113, 114, -85, 283, -32766, 477, 478, 479, 271, 53, 398, 786, 787, 788, 789, 115, 407, 441, 10, -32766, 299, 1341, 306, 307, 843, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 819, 583, 820, 821, 822, 823, 811, 812, 353, 354, 814, 815, 800, 801, 802, 804, 805, 806, 368, 846, 847, 848, 849, 850, 584, 320, 1068, -582, 807, 808, 585, 586, 1389, 831, 829, 830, 842, 826, 827, 329, 1388, 587, 588, 825, 589, 590, 591, 592, 86, 593, 594, 1071, 332, -32766, -32766, -32766, 828, 595, 596, 349, 151, -581, 132, 133, 134, 582, 135, 136, 1100, 779, 780, 781, 137, 41, -32766, 290, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, -32767, -32766, -32766, -32766, 891, 1175, 892, -582, -582, 754, 773, 772, 1159, 1160, 1161, 1155, 1154, 1153, 1162, 1156, 1157, 1158, -32766, -582, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 782, -32766, -32766, -32766, -588, -78, -32766, -32766, -32766, 350, -581, -581, -32766, -32766, 271, 53, 398, 786, 787, 788, 789, 383, -32766, 441, -32766, -32766, -581, -32766, 773, 772, 843, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 819, 583, 820, 821, 822, 823, 811, 812, 353, 354, 814, 815, 800, 801, 802, 804, 805, 806, 368, 846, 847, 848, 849, 850, 584, -620, 1068, -620, 807, 808, 585, 586, 389, 831, 829, 830, 842, 826, 827, 441, 405, 587, 588, 825, 589, 590, 591, 592, 333, 593, 594, 1071, 87, 88, 89, 459, 828, 595, 596, 460, 151, 803, 774, 775, 776, 777, 778, 854, 779, 780, 781, 816, 817, 40, 461, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 462, 283, 1329, 1159, 1160, 1161, 1155, 1154, 1153, 1162, 1156, 1157, 1158, 115, 869, 488, 489, 782, 1304, 1303, 1305, 108, 109, 1132, 154, -32766, -32766, 1134, 679, 23, 156, 783, 784, 785, 786, 787, 788, 789, 698, 699, 852, 152, 423, -580, 393, 394, 157, 843, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 819, 841, 820, 821, 822, 823, 811, 812, 813, 840, 814, 815, 800, 801, 802, 804, 805, 806, 845, 846, 847, 848, 849, 850, 851, 1094, -578, 863, 807, 808, 809, 810, -58, 831, 829, 830, 842, 826, 827, 399, 400, 818, 824, 825, 832, 833, 835, 834, 294, 836, 837, 158, -580, -580, 160, 294, 828, 839, 838, 54, 55, 56, 57, 534, 58, 59, 36, -110, -580, -57, 60, 61, -110, 62, -110, 670, 671, 129, 130, 312, -587, 140, -110, -110, -110, -110, -110, -110, -110, -110, -110, -110, -110, -578, -578, 141, 147, 949, 161, 712, -87, 163, 164, 165, -84, 949, -78, -73, -72, -578, 63, 64, 143, -309, -71, 65, 332, 66, 251, 252, 67, 68, 69, 70, 71, 72, 73, 74, 739, 31, 276, 47, 457, 535, -357, 713, 740, 1335, 1336, 536, -70, 863, 1068, -69, -68, 1333, 45, 22, 537, 949, 538, -67, 539, -66, 540, 52, -65, 541, 542, 714, 715, -46, 48, 49, 463, 392, 391, 1071, 50, 543, -18, 145, 281, 1302, 381, 348, 291, 750, 1304, 1303, 1305, 1295, 939, 753, 290, 948, 545, 546, 547, 150, 939, 290, -305, 295, 288, 289, 292, 293, 549, 550, 338, 1321, 1322, 1323, 1324, 1326, 1318, 1319, 304, 1300, 296, 301, 302, 283, 1325, 1320, 773, 772, 1304, 1303, 1305, 305, 308, 309, 75, -154, -154, -154, 327, 328, 332, 966, 854, 1070, 939, 149, 115, 1416, 388, 680, -154, 708, -154, 725, -154, 13, -154, 668, 723, 313, 31, 277, 1304, 1303, 1305, 863, 390, -32766, 600, 1166, 987, 951, 863, 310, 701, 734, 1333, 990, 991, 951, -32766, 686, 544, 734, 949, 685, 606, 1340, 485, 513, 925, 986, -110, -110, -110, 35, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 702, 949, 634, 1295, 773, 772, 741, -579, 305, -614, 1334, 0, 0, 0, 951, 311, 949, 0, 734, -154, 549, 550, 319, 1321, 1322, 1323, 1324, 1326, 1318, 1319, 1209, 1211, 744, 0, 1342, 0, 1325, 1320, -544, -534, 0, -578, -32766, -4, 949, 11, 77, 751, 1302, 30, 387, 328, 332, 862, 43, -32766, -32766, -32766, -613, -32766, 939, -32766, 968, -32766, 44, 759, -32766, 1330, 773, 772, 760, -32766, -32766, -32766, -579, -579, 882, -32766, -32766, 930, 1031, 1008, 1015, -32766, 437, 1005, 939, 1016, 928, 1003, -579, 1137, 1140, 1141, 1138, -32766, 1177, 1139, 1145, 37, 874, 939, -586, 1357, 1374, 1407, -32766, 673, -578, -578, -612, -588, 1302, -587, -586, -585, 31, 276, -528, -32766, -32766, -32766, 1, -32766, -578, -32766, 78, -32766, 863, 939, -32766, 32, 1333, -278, 33, -32766, -32766, -32766, 42, 1007, 46, -32766, -32766, 734, 76, 80, 81, -32766, 437, 82, 83, 390, 84, 453, 31, 277, 85, 146, 303, -32766, 155, 159, 990, 991, 249, 951, 863, 544, 1295, 734, 1333, 334, 369, 370, 371, 548, 986, -110, -110, -110, 951, 372, 326, 373, 734, 374, 550, 375, 1321, 1322, 1323, 1324, 1326, 1318, 1319, 376, 377, 422, 378, 21, -50, 1325, 1320, 379, 382, 454, 1295, 577, 951, 380, 384, 77, 734, -4, -276, -275, 328, 332, 15, 16, 17, 18, 20, 363, 550, 421, 1321, 1322, 1323, 1324, 1326, 1318, 1319, 142, 504, 505, 512, 515, 516, 1325, 1320, 949, 517, 518, -32766, 522, 523, 524, 531, 77, 1302, 611, 718, 1101, 328, 332, 1097, -32766, -32766, -32766, 1250, -32766, 1331, -32766, 949, -32766, 1099, 1096, -32766, 1077, 1290, 1309, 1073, -32766, -32766, -32766, -280, -32766, -102, -32766, -32766, 14, 19, 1302, 24, -32766, 437, 323, 420, 625, -32766, -32766, -32766, 631, -32766, 659, -32766, -32766, -32766, 724, 1254, -32766, -16, 1308, 1251, 1386, -32766, -32766, -32766, 735, -32766, 738, -32766, -32766, 742, 743, 1302, 745, -32766, 437, 746, 747, 748, -32766, -32766, -32766, 939, -32766, 300, -32766, -32766, -32766, 752, 1309, -32766, 764, 737, 332, 765, -32766, -32766, -32766, -253, -253, -253, -32766, -32766, 426, 390, 939, 756, -32766, 437, 926, 863, 1411, 1413, 885, 884, 990, 991, 980, 1023, -32766, 544, -252, -252, -252, 1412, 979, 977, 390, 925, 986, -110, -110, -110, 978, 981, 1283, 959, 969, 990, 991, 957, 1176, 1172, 544, 1126, -110, -110, 1013, 1014, 657, -110, 925, 986, -110, -110, -110, 1410, 2, 1368, -110, 1268, 951, 1383, 0, 0, 734, -253, 0, -32766, 0, 0, -32766, 863, 1059, 1054, 1053, 1052, 1058, 1055, 1056, 1057, 0, 0, 0, 951, 0, 0, 0, 734, -252, 305, 0, 0, 79, 0, 0, 1071, 0, 0, 332, 0, 0, 0, 0, 0, 0, 0, -110, -110, 0, 0, 0, -110, 0, 0, 0, 0, 0, 0, 0, 299, -110, 0, 0, 0, 0, 0, 0, 0, 0, -32766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 305, 0, 0, 79, 0, 0, 0, 0, 0, 332); + protected array $actionCheck = array(3, 4, 5, 6, 7, 8, 17, 10, 11, 12, 13, 14, 84, 76, 1, 87, 72, 74, 75, 82, 0, 108, 109, 110, 15, 82, 89, 90, 91, 10, 93, 118, 95, 103, 97, 38, 39, 100, 10, 11, 12, 104, 105, 106, 107, 10, 11, 12, 111, 112, 15, 10, 11, 12, 117, 118, 59, 82, 128, 31, 1, 33, 34, 35, 36, 37, 129, 124, 1, 31, 73, 74, 75, 76, 77, 78, 79, 164, 1, 82, 9, 153, 154, 139, 140, 9, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 1, 9, 82, 128, 129, 130, 131, 9, 133, 134, 135, 136, 137, 138, 9, 162, 141, 142, 143, 144, 145, 146, 147, 86, 149, 150, 9, 82, 10, 11, 12, 156, 157, 158, 118, 160, 169, 3, 4, 5, 6, 7, 8, 168, 10, 11, 12, 13, 14, 31, 76, 33, 34, 35, 36, 168, 82, 83, 15, 143, 169, 119, 120, 89, 90, 91, 124, 93, 108, 95, 110, 97, 38, 39, 100, 133, 1, 108, 109, 105, 106, 107, 162, 167, 1, 111, 112, 118, 32, 169, 118, 117, 118, 59, 45, 46, 47, 48, 49, 50, 51, 52, 165, 129, 32, 9, 169, 73, 74, 75, 76, 77, 78, 79, 169, 143, 82, 168, 173, 9, 165, 161, 168, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 84, 168, 9, 128, 129, 130, 131, 168, 133, 134, 135, 136, 137, 138, 1, 9, 141, 142, 143, 144, 145, 146, 147, 99, 149, 150, 108, 109, 10, 11, 12, 156, 157, 158, 32, 160, 118, 3, 4, 5, 6, 7, 8, 168, 10, 11, 12, 13, 14, 31, 76, 33, 34, 35, 72, 87, 82, 9, 142, 54, 50, 51, 52, 89, 90, 91, 169, 93, 9, 95, 118, 97, 38, 39, 100, 108, 15, 110, 165, 105, 106, 107, 164, 167, 165, 111, 112, 82, 169, 173, 85, 117, 118, 59, 118, 143, 53, 54, 55, 56, 57, 99, 59, 129, 134, 135, 136, 73, 74, 75, 76, 77, 78, 79, 71, 108, 82, 110, 142, 167, 152, 139, 140, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 9, 118, 72, 128, 129, 130, 131, 1, 133, 134, 135, 136, 137, 138, 9, 9, 141, 142, 143, 144, 145, 146, 147, 169, 149, 150, 143, 173, 10, 11, 12, 156, 157, 158, 9, 160, 72, 3, 4, 5, 6, 7, 8, 168, 10, 11, 12, 13, 14, 31, 167, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 10, 11, 12, 108, 165, 110, 139, 140, 169, 38, 39, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 31, 155, 33, 34, 35, 36, 37, 38, 39, 59, 10, 11, 12, 167, 17, 10, 11, 12, 9, 139, 140, 10, 11, 73, 74, 75, 76, 77, 78, 79, 9, 31, 82, 33, 34, 155, 31, 38, 39, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 166, 118, 168, 128, 129, 130, 131, 9, 133, 134, 135, 136, 137, 138, 82, 9, 141, 142, 143, 144, 145, 146, 147, 72, 149, 150, 143, 10, 11, 12, 9, 156, 157, 158, 9, 160, 3, 4, 5, 6, 7, 8, 82, 10, 11, 12, 13, 14, 31, 9, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9, 59, 1, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 71, 9, 139, 140, 59, 161, 162, 163, 51, 52, 1, 15, 53, 54, 170, 77, 78, 15, 73, 74, 75, 76, 77, 78, 79, 77, 78, 82, 103, 104, 72, 108, 109, 15, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 1, 72, 84, 128, 129, 130, 131, 17, 133, 134, 135, 136, 137, 138, 108, 109, 141, 142, 143, 144, 145, 146, 147, 31, 149, 150, 15, 139, 140, 15, 31, 156, 157, 158, 2, 3, 4, 5, 6, 7, 8, 15, 103, 155, 17, 13, 14, 108, 16, 110, 113, 114, 17, 17, 115, 167, 17, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 139, 140, 17, 17, 1, 17, 82, 32, 17, 17, 17, 32, 1, 32, 32, 32, 155, 53, 54, 169, 36, 32, 58, 173, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 32, 72, 73, 74, 75, 76, 170, 118, 32, 80, 81, 82, 32, 84, 118, 32, 32, 88, 89, 90, 91, 1, 93, 32, 95, 32, 97, 72, 32, 100, 101, 142, 143, 32, 105, 106, 107, 108, 109, 143, 111, 112, 32, 32, 32, 82, 117, 118, 32, 32, 161, 162, 163, 124, 86, 32, 167, 32, 129, 130, 131, 32, 86, 167, 36, 38, 36, 36, 36, 36, 141, 142, 36, 144, 145, 146, 147, 148, 149, 150, 151, 118, 38, 38, 38, 59, 157, 158, 38, 39, 161, 162, 163, 164, 139, 140, 167, 77, 78, 79, 171, 172, 173, 39, 82, 142, 86, 72, 71, 85, 155, 92, 92, 79, 94, 94, 96, 99, 98, 115, 82, 116, 72, 73, 161, 162, 163, 84, 108, 87, 91, 84, 133, 165, 84, 137, 96, 169, 88, 119, 120, 165, 142, 102, 124, 169, 1, 98, 159, 152, 99, 99, 132, 133, 134, 135, 136, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 102, 1, 159, 124, 38, 39, 32, 72, 164, 167, 172, -1, -1, -1, 165, 138, 1, -1, 169, 170, 141, 142, 137, 144, 145, 146, 147, 148, 149, 150, 61, 62, 32, -1, 152, -1, 157, 158, 155, 155, -1, 72, 76, 0, 1, 155, 167, 32, 82, 155, 155, 172, 173, 161, 165, 89, 90, 91, 167, 93, 86, 95, 160, 97, 165, 165, 100, 166, 38, 39, 165, 105, 106, 107, 139, 140, 165, 111, 112, 165, 165, 165, 165, 117, 118, 165, 86, 165, 165, 165, 155, 165, 165, 165, 165, 129, 165, 165, 165, 169, 166, 86, 167, 166, 166, 166, 76, 166, 139, 140, 167, 167, 82, 167, 167, 167, 72, 73, 167, 89, 90, 91, 167, 93, 155, 95, 160, 97, 84, 86, 100, 167, 88, 168, 167, 105, 106, 107, 167, 165, 167, 111, 112, 169, 167, 167, 167, 117, 118, 167, 167, 108, 167, 110, 72, 73, 167, 167, 115, 129, 167, 167, 119, 120, 167, 165, 84, 124, 124, 169, 88, 167, 167, 167, 167, 132, 133, 134, 135, 136, 165, 167, 169, 167, 169, 167, 142, 167, 144, 145, 146, 147, 148, 149, 150, 167, 167, 170, 167, 156, 32, 157, 158, 167, 167, 167, 124, 167, 165, 167, 169, 167, 169, 170, 168, 168, 172, 173, 168, 168, 168, 168, 168, 168, 142, 168, 144, 145, 146, 147, 148, 149, 150, 32, 168, 168, 168, 168, 168, 157, 158, 1, 168, 168, 76, 168, 168, 168, 168, 167, 82, 168, 168, 168, 172, 173, 168, 89, 90, 91, 168, 93, 168, 95, 1, 97, 168, 168, 100, 168, 168, 1, 168, 105, 106, 107, 168, 76, 168, 111, 112, 168, 168, 82, 168, 117, 118, 168, 168, 168, 89, 90, 91, 168, 93, 168, 95, 129, 97, 168, 168, 100, 32, 168, 168, 168, 105, 106, 107, 169, 76, 169, 111, 112, 169, 169, 82, 169, 117, 118, 169, 169, 169, 89, 90, 91, 86, 93, 31, 95, 129, 97, 169, 1, 100, 169, 169, 173, 169, 105, 106, 107, 102, 103, 104, 111, 112, 170, 108, 86, 170, 117, 118, 170, 84, 170, 170, 170, 170, 119, 120, 170, 170, 129, 124, 102, 103, 104, 170, 170, 170, 108, 132, 133, 134, 135, 136, 170, 170, 170, 170, 170, 119, 120, 170, 170, 170, 124, 170, 119, 120, 170, 170, 170, 124, 132, 133, 134, 135, 136, 170, 167, 170, 133, 171, 165, 170, -1, -1, 169, 170, -1, 142, -1, -1, 118, 84, 120, 121, 122, 123, 124, 125, 126, 127, -1, -1, -1, 165, -1, -1, -1, 169, 170, 164, -1, -1, 167, -1, -1, 143, -1, -1, 173, -1, -1, -1, -1, -1, -1, -1, 119, 120, -1, -1, -1, 124, -1, -1, -1, -1, -1, -1, -1, 167, 133, -1, -1, -1, -1, -1, -1, -1, -1, 142, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 164, -1, -1, 167, -1, -1, -1, -1, -1, 173); + protected array $actionBase = array(0, 156, -3, 315, 474, 474, 880, 1074, 1271, 1294, 749, 675, 531, 559, 836, 1031, 1031, 1046, 1031, 828, 1005, 42, 59, 59, 59, 963, 898, 632, 632, 898, 632, 997, 997, 997, 997, 1061, 1061, -63, -63, 96, 1232, 1199, 255, 255, 255, 255, 255, 1265, 255, 255, 255, 255, 255, 1265, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 77, 194, 120, 205, 1197, 783, 1150, 1163, 1152, 1166, 1145, 1144, 1151, 1156, 1167, 1261, 1263, 889, 1254, 1267, 1158, 972, 1147, 1162, 962, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 19, 35, 535, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 529, 529, 529, 910, 910, 524, 299, 1113, 1075, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 140, 28, 1000, 493, 493, 458, 458, 458, 458, 458, 696, 1328, 1301, 171, 171, 171, 171, 1363, 1363, -70, 523, 248, 756, 291, 197, -87, 644, 38, 199, 323, 323, 482, 482, 233, 233, 482, 482, 482, 324, 324, 94, 94, 94, 94, 82, 249, 860, 67, 67, 67, 67, 860, 860, 860, 860, 913, 869, 860, 1036, 1049, 860, 860, 370, 645, 966, 646, 646, 398, -72, -72, 398, 64, -72, 294, 286, 257, 859, 91, 433, 257, 1073, 404, 686, 686, 815, 686, 686, 686, 923, 610, 923, 1141, 902, 902, 861, 807, 964, 1198, 1168, 901, 1252, 929, 1253, 1200, 342, 251, -56, 263, 550, 806, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1139, 1195, 523, 1141, -25, 1247, 1249, 1195, 1195, 1195, 523, 523, 523, 523, 523, 523, 523, 523, 870, 523, 523, 694, -25, 625, 635, -25, 896, 523, 915, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 178, 77, 77, 194, 13, 13, 77, 200, 121, 13, 13, 13, -11, 13, 77, 77, 77, 610, 886, 849, 663, 283, 874, 114, 886, 886, 886, 71, 9, 76, 809, 888, 288, 882, 882, 882, 907, 986, 986, 882, 903, 882, 907, 882, 882, 986, 986, 875, 986, 274, 620, 465, 597, 624, 986, 340, 882, 882, 882, 882, 916, 986, 127, 139, 639, 882, 329, 287, 882, 882, 916, 858, 876, 908, 986, 986, 986, 916, 545, 908, 908, 908, 931, 936, 864, 872, 445, 431, 679, 232, 924, 872, 872, 882, 605, 864, 872, 864, 872, 933, 872, 872, 872, 864, 872, 903, 533, 872, 813, 665, 218, 872, 882, 20, 1008, 1009, 800, 1010, 1002, 1013, 1069, 1014, 1016, 1171, 982, 1028, 1004, 1020, 1071, 998, 995, 885, 792, 793, 921, 914, 979, 897, 897, 897, 975, 977, 897, 897, 897, 897, 897, 897, 897, 897, 792, 932, 926, 899, 1037, 796, 810, 1114, 857, 1214, 1264, 1036, 1008, 1016, 804, 1004, 1020, 998, 995, 856, 853, 844, 851, 843, 840, 808, 814, 871, 1116, 1119, 1021, 920, 811, 1085, 1038, 1211, 1044, 1045, 1047, 1088, 1123, 942, 1125, 1216, 895, 1217, 1218, 965, 1051, 1173, 897, 974, 873, 968, 1049, 978, 792, 969, 1129, 1130, 1081, 961, 1097, 1098, 1072, 911, 884, 970, 1219, 1059, 1060, 1062, 1176, 1177, 930, 1082, 996, 1099, 912, 1058, 1100, 1101, 1105, 1106, 1179, 1222, 1182, 922, 1183, 945, 879, 1077, 909, 1223, 165, 892, 893, 906, 1068, 683, 1035, 1184, 1208, 1229, 1108, 1109, 1110, 1230, 1231, 1024, 946, 1083, 900, 1084, 1078, 947, 948, 689, 905, 1132, 890, 891, 904, 705, 768, 1238, 1239, 1240, 1025, 877, 894, 951, 953, 1133, 887, 1135, 1241, 771, 954, 1242, 1115, 816, 817, 521, 784, 747, 818, 881, 1194, 925, 865, 878, 1067, 817, 883, 955, 1245, 957, 958, 959, 1111, 960, 1086, 1246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 789, 789, 789, 789, 789, 789, 789, 789, 789, 632, 632, 632, 632, 789, 789, 789, 789, 789, 789, 789, 632, 789, 789, 789, 632, 632, 0, 0, 632, 0, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 789, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 823, 823, 616, 616, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 616, 616, 0, 616, 616, 616, 616, 616, 616, 616, 875, 823, 823, 324, 324, 324, 324, 823, 823, 396, 396, 396, 823, 324, 823, 64, 324, 823, 64, 823, 823, 823, 823, 823, 823, 823, 823, 823, 0, 0, 823, 823, 823, 823, -25, -72, 823, 903, 903, 903, 903, 823, 823, 823, 823, -72, -72, 823, -57, -57, 823, 823, 0, 0, 0, 324, 324, -25, 0, 0, -25, 0, 0, 903, 903, 823, 64, 875, 446, 823, 342, 0, 0, 0, 0, 0, 0, 0, -25, 903, -25, 523, -72, -72, 523, 523, 13, 77, 446, 612, 612, 612, 612, 77, 0, 0, 0, 0, 0, 610, 875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 903, 0, 875, 0, 875, 875, 903, 903, 903, 0, 0, 0, 0, 0, 0, 0, 0, 986, 0, 0, 0, 0, 0, 0, 0, 903, 0, 986, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 903, 0, 0, 0, 0, 0, 0, 0, 0, 0, 897, 911, 0, 0, 911, 0, 897, 897, 897, 0, 0, 0, 905, 887); + protected array $actionDefault = array(3, 32767, 32767, 32767, 102, 102, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 100, 32767, 632, 632, 632, 632, 32767, 32767, 257, 102, 32767, 32767, 503, 417, 417, 417, 32767, 32767, 32767, 576, 576, 576, 576, 576, 17, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 503, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 36, 7, 8, 10, 11, 49, 338, 100, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 102, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 404, 625, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 497, 507, 485, 486, 488, 489, 416, 577, 631, 344, 628, 342, 415, 146, 354, 343, 245, 261, 508, 262, 509, 512, 513, 218, 401, 150, 151, 448, 504, 450, 502, 506, 449, 422, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 420, 421, 505, 482, 481, 480, 32767, 32767, 446, 447, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 102, 32767, 451, 454, 419, 452, 453, 470, 471, 468, 469, 472, 32767, 323, 32767, 473, 474, 475, 476, 32767, 32767, 382, 196, 380, 32767, 477, 32767, 111, 455, 323, 111, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 461, 462, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 102, 32767, 32767, 32767, 100, 520, 570, 479, 456, 457, 32767, 545, 32767, 102, 32767, 547, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 572, 443, 445, 540, 626, 423, 629, 32767, 533, 100, 196, 32767, 546, 196, 196, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 571, 32767, 639, 533, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 32767, 196, 110, 32767, 110, 110, 32767, 32767, 100, 196, 196, 196, 196, 196, 196, 196, 196, 548, 196, 196, 191, 32767, 271, 273, 102, 594, 196, 550, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 404, 32767, 32767, 32767, 32767, 533, 466, 139, 32767, 535, 139, 578, 458, 459, 460, 578, 578, 578, 319, 296, 32767, 32767, 32767, 32767, 32767, 548, 548, 100, 100, 100, 100, 32767, 32767, 32767, 32767, 111, 519, 99, 99, 99, 99, 99, 103, 101, 32767, 32767, 32767, 32767, 226, 32767, 101, 101, 99, 32767, 101, 101, 32767, 32767, 226, 228, 215, 230, 32767, 598, 599, 226, 101, 230, 230, 230, 250, 250, 522, 325, 101, 99, 101, 101, 198, 325, 325, 32767, 101, 522, 325, 522, 325, 200, 325, 325, 325, 522, 325, 32767, 101, 325, 217, 99, 99, 325, 32767, 32767, 32767, 32767, 535, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 225, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 565, 32767, 583, 596, 464, 465, 467, 582, 580, 490, 491, 492, 493, 494, 495, 496, 499, 627, 32767, 539, 32767, 32767, 32767, 353, 32767, 637, 32767, 32767, 32767, 9, 74, 528, 42, 43, 51, 57, 554, 555, 556, 557, 551, 552, 558, 553, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 638, 32767, 578, 32767, 32767, 32767, 32767, 463, 560, 604, 32767, 32767, 579, 630, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 139, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 565, 32767, 137, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 561, 32767, 32767, 32767, 578, 32767, 32767, 32767, 32767, 321, 318, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 578, 32767, 32767, 32767, 32767, 32767, 298, 32767, 315, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 400, 535, 301, 303, 304, 32767, 32767, 32767, 32767, 376, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 153, 153, 3, 3, 356, 153, 153, 153, 356, 356, 153, 356, 356, 356, 153, 153, 153, 153, 153, 153, 153, 283, 186, 265, 268, 250, 250, 153, 368, 153, 402, 402, 411); + protected array $goto = array(201, 169, 201, 201, 201, 1069, 598, 719, 448, 684, 644, 681, 443, 345, 341, 342, 344, 615, 447, 346, 449, 661, 481, 728, 570, 570, 570, 570, 1245, 626, 172, 172, 172, 172, 225, 202, 198, 198, 182, 184, 220, 198, 198, 198, 198, 198, 1195, 199, 199, 199, 199, 199, 1195, 192, 193, 194, 195, 196, 197, 222, 220, 223, 557, 558, 438, 559, 562, 563, 564, 565, 566, 567, 568, 569, 173, 174, 175, 200, 176, 177, 178, 170, 179, 180, 181, 183, 219, 221, 224, 242, 247, 248, 259, 260, 262, 263, 264, 265, 266, 267, 268, 272, 273, 274, 275, 282, 285, 297, 298, 324, 325, 444, 445, 446, 620, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 193, 194, 195, 196, 197, 222, 203, 204, 205, 206, 243, 185, 186, 207, 187, 208, 204, 188, 244, 203, 168, 209, 210, 189, 211, 212, 213, 190, 214, 215, 171, 216, 217, 218, 191, 287, 284, 287, 287, 883, 255, 255, 255, 255, 255, 1125, 605, 487, 487, 622, 758, 660, 662, 1103, 359, 682, 487, 1075, 1074, 706, 709, 1041, 717, 726, 1037, 733, 922, 879, 922, 922, 253, 253, 253, 253, 250, 256, 646, 646, 1078, 1079, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 880, 351, 938, 933, 934, 947, 889, 935, 886, 936, 937, 887, 890, 476, 941, 894, 476, 1044, 1044, 893, 364, 364, 364, 364, 352, 351, 532, 1131, 1127, 1128, 1351, 1351, 331, 315, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1351, 1069, 1301, 1072, 1072, 704, 983, 1301, 1301, 1064, 1080, 1081, 1069, 942, 1301, 943, 458, 1069, 881, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 897, 855, 1069, 1069, 1069, 1069, 677, 678, 1301, 695, 696, 697, 1006, 1301, 1301, 1301, 1301, 450, 909, 1301, 436, 896, 1301, 1301, 1382, 1382, 1382, 1382, 915, 581, 574, 499, 612, 450, 367, 971, 971, 955, 501, 1076, 1076, 956, 1400, 1400, 367, 367, 688, 1087, 1083, 1084, 572, 411, 414, 623, 627, 572, 572, 367, 367, 1400, 357, 367, 572, 1417, 1377, 1378, 317, 574, 581, 607, 608, 318, 618, 624, 1390, 640, 641, 1027, 576, 1403, 1403, 367, 367, 28, 474, 520, 442, 521, 635, 1000, 1000, 1000, 1000, 527, 409, 474, 1348, 1348, 994, 1001, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 633, 647, 650, 651, 652, 653, 674, 675, 676, 730, 732, 561, 561, 258, 258, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 610, 1362, 467, 683, 467, 876, 616, 638, 876, 467, 467, 1191, 861, 1373, 360, 361, 1093, 456, 1373, 1373, 560, 560, 705, 432, 560, 1373, 560, 560, 560, 560, 560, 560, 560, 560, 1277, 975, 575, 602, 575, 1278, 1281, 976, 575, 1282, 602, 689, 412, 480, 1384, 1384, 1384, 1384, 347, 873, 716, 576, 861, 876, 861, 490, 619, 491, 492, 639, 8, 857, 9, 902, 907, 989, 716, 1408, 1409, 716, 1369, 418, 1296, 278, 899, 330, 1174, 424, 425, 1292, 330, 330, 693, 1049, 694, 1114, 429, 430, 431, 761, 707, 1060, 905, 433, 1102, 1104, 1107, 355, 467, 467, 467, 467, 467, 467, 467, 467, 467, 467, 467, 467, 419, 339, 467, 911, 467, 467, 1294, 628, 629, 1116, 497, 960, 1181, 621, 1144, 1371, 1371, 1116, 1118, 1297, 1298, 1011, 1284, 1046, 1151, 1179, 1152, 731, 871, 528, 722, 901, 1142, 687, 1025, 1284, 496, 1375, 1376, 895, 910, 898, 1113, 1117, 998, 427, 727, 1165, 1299, 1359, 1360, 1291, 1030, 386, 1009, 1002, 0, 757, 0, 0, 573, 1039, 1034, 654, 656, 658, 0, 0, 0, 0, 0, 0, 0, 0, 876, 0, 0, 999, 0, 766, 766, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1163, 914); + protected array $gotoCheck = array(42, 42, 42, 42, 42, 73, 127, 73, 66, 66, 56, 56, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 159, 9, 107, 107, 107, 107, 159, 107, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 23, 23, 23, 23, 15, 5, 5, 5, 5, 5, 15, 48, 157, 157, 134, 48, 48, 48, 131, 97, 48, 157, 119, 119, 48, 48, 48, 48, 48, 48, 48, 25, 25, 25, 25, 5, 5, 5, 5, 5, 5, 108, 108, 120, 120, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 26, 177, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 83, 15, 15, 83, 107, 107, 15, 24, 24, 24, 24, 177, 177, 76, 15, 15, 15, 179, 179, 178, 178, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 73, 73, 89, 89, 89, 89, 73, 73, 89, 89, 89, 73, 65, 73, 65, 83, 73, 27, 73, 73, 73, 73, 73, 73, 73, 73, 73, 35, 6, 73, 73, 73, 73, 86, 86, 73, 86, 86, 86, 49, 73, 73, 73, 73, 118, 35, 73, 43, 35, 73, 73, 9, 9, 9, 9, 45, 76, 76, 84, 181, 118, 14, 9, 9, 73, 84, 118, 118, 73, 191, 191, 14, 14, 118, 118, 118, 118, 19, 59, 59, 59, 59, 19, 19, 14, 14, 191, 188, 14, 19, 14, 187, 187, 76, 76, 76, 76, 76, 76, 76, 76, 190, 76, 76, 103, 14, 191, 191, 14, 14, 76, 19, 163, 13, 163, 13, 19, 19, 19, 19, 163, 62, 19, 180, 180, 19, 19, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 182, 182, 5, 5, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 104, 14, 23, 64, 23, 22, 2, 2, 22, 23, 23, 158, 12, 134, 97, 97, 115, 113, 134, 134, 165, 165, 117, 14, 165, 134, 165, 165, 165, 165, 165, 165, 165, 165, 79, 79, 9, 9, 9, 79, 79, 79, 9, 79, 9, 121, 9, 9, 134, 134, 134, 134, 29, 18, 7, 14, 12, 22, 12, 9, 9, 9, 9, 80, 46, 7, 46, 39, 9, 92, 7, 9, 9, 7, 134, 28, 20, 24, 37, 24, 156, 82, 82, 169, 24, 24, 82, 110, 82, 133, 82, 82, 82, 99, 82, 114, 9, 82, 130, 130, 130, 82, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 31, 9, 23, 41, 23, 23, 14, 17, 17, 134, 160, 17, 17, 8, 8, 134, 134, 134, 136, 20, 20, 96, 20, 17, 149, 149, 149, 8, 20, 8, 8, 17, 8, 17, 17, 20, 185, 185, 185, 17, 16, 16, 16, 16, 93, 93, 93, 152, 20, 20, 20, 17, 50, 141, 16, 50, -1, 50, -1, -1, 50, 50, 50, 85, 85, 85, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, 16, -1, 24, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16, 16); + protected array $gotoBase = array(0, 0, -303, 0, 0, 170, 280, 471, 543, 10, 0, 0, 136, 31, 22, -186, 111, 66, 164, 71, 95, 0, 148, 160, 235, 191, 214, 275, 155, 176, 0, 86, 0, 0, 0, -92, 0, 156, 0, 165, 0, 85, -1, 286, 0, 291, -270, 0, -558, 284, 579, 0, 0, 0, 0, 0, -33, 0, 0, 294, 0, 0, 341, 0, 184, 261, -237, 0, 0, 0, 0, 0, 0, -5, 0, 0, -32, 0, 0, 37, 172, 32, -3, -50, -167, 105, -444, 0, 0, -21, 0, 0, 161, 274, 0, 0, 101, -318, 0, 97, 0, 0, 0, 331, 381, 0, 0, -7, -38, 0, 131, 0, 0, 158, 90, 162, 0, 159, 39, -100, -83, 173, 0, 0, 0, 0, 0, 4, 0, 0, 522, 182, 0, 127, 169, 0, 99, 0, 0, 0, 0, -171, 0, 0, 0, 0, 0, 0, 0, 287, 0, 0, 126, 0, 0, 0, 144, 141, 188, -255, 93, 0, 0, -138, 0, 202, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, -82, -74, 6, 143, 292, 168, 0, 0, 270, 0, -31, 319, 0, 332, 20, 0, 0); + protected array $gotoDefault = array(-32768, 533, 768, 7, 769, 964, 844, 853, 597, 551, 729, 356, 648, 439, 1367, 940, 1180, 617, 872, 1310, 1316, 475, 875, 336, 755, 952, 923, 924, 415, 402, 888, 413, 672, 649, 514, 908, 471, 900, 506, 903, 470, 912, 167, 435, 530, 916, 6, 919, 579, 950, 1004, 403, 927, 404, 700, 929, 601, 931, 932, 410, 416, 417, 1185, 609, 645, 944, 261, 603, 945, 401, 946, 954, 406, 408, 710, 486, 525, 519, 428, 1146, 604, 632, 669, 464, 493, 643, 655, 642, 500, 451, 434, 335, 988, 996, 507, 484, 1010, 358, 1018, 763, 1193, 663, 509, 1026, 664, 1033, 1036, 552, 553, 498, 1048, 270, 1051, 510, 1061, 26, 690, 1066, 1067, 691, 665, 1089, 666, 692, 667, 1091, 483, 599, 1194, 482, 1106, 1112, 472, 1115, 1356, 473, 1119, 269, 1122, 286, 362, 385, 452, 1129, 1130, 12, 1136, 720, 721, 25, 280, 529, 1164, 711, 1170, 279, 1173, 469, 1192, 468, 1265, 1267, 580, 511, 1285, 321, 1288, 703, 526, 1293, 465, 1358, 466, 554, 494, 343, 555, 1401, 314, 365, 340, 571, 322, 366, 556, 495, 1364, 1372, 337, 34, 1391, 1402, 614, 637); + protected array $ruleToNonTerminal = array(0, 1, 3, 3, 2, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 10, 11, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18, 21, 21, 22, 23, 23, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 29, 29, 30, 30, 32, 34, 34, 28, 36, 36, 33, 38, 38, 35, 35, 37, 37, 39, 39, 31, 40, 40, 41, 43, 44, 44, 45, 45, 46, 46, 48, 47, 47, 47, 47, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 25, 25, 50, 69, 69, 72, 72, 71, 70, 70, 63, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 80, 80, 26, 26, 27, 27, 27, 27, 27, 88, 88, 90, 90, 83, 83, 91, 91, 92, 92, 92, 84, 84, 87, 87, 85, 85, 93, 94, 94, 57, 57, 65, 65, 68, 68, 68, 67, 95, 95, 96, 58, 58, 58, 58, 97, 97, 98, 98, 99, 99, 100, 101, 101, 102, 102, 103, 103, 55, 55, 51, 51, 105, 53, 53, 106, 52, 52, 54, 54, 64, 64, 64, 64, 81, 81, 109, 109, 111, 111, 112, 112, 112, 112, 112, 112, 112, 112, 110, 110, 110, 115, 115, 115, 115, 89, 89, 118, 118, 118, 119, 119, 116, 116, 120, 120, 122, 122, 123, 123, 117, 124, 124, 121, 125, 125, 125, 125, 113, 113, 82, 82, 82, 20, 20, 20, 128, 128, 128, 128, 129, 129, 129, 127, 126, 126, 131, 131, 131, 130, 130, 60, 132, 132, 133, 61, 135, 135, 136, 136, 137, 137, 86, 138, 138, 138, 138, 138, 138, 138, 138, 144, 144, 145, 145, 146, 146, 146, 146, 146, 147, 148, 148, 143, 143, 139, 139, 142, 142, 150, 150, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 140, 151, 151, 153, 152, 152, 141, 141, 114, 114, 154, 154, 156, 156, 156, 155, 155, 62, 104, 157, 157, 56, 56, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 164, 165, 165, 166, 158, 158, 163, 163, 167, 168, 168, 169, 170, 171, 171, 171, 171, 19, 19, 73, 73, 73, 73, 159, 159, 159, 159, 173, 173, 162, 162, 162, 160, 160, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 180, 180, 180, 108, 182, 182, 182, 182, 161, 161, 161, 161, 161, 161, 161, 161, 59, 59, 176, 176, 176, 176, 176, 183, 183, 172, 172, 172, 172, 184, 184, 184, 184, 184, 74, 74, 66, 66, 66, 66, 134, 134, 134, 134, 187, 186, 175, 175, 175, 175, 175, 175, 174, 174, 174, 185, 185, 185, 185, 107, 181, 189, 189, 188, 188, 190, 190, 190, 190, 190, 190, 190, 190, 178, 178, 178, 178, 177, 192, 191, 191, 191, 191, 191, 191, 191, 191, 193, 193, 193, 193); + protected array $ruleToLength = array(1, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 2, 1, 3, 4, 1, 2, 0, 1, 1, 1, 1, 4, 3, 5, 4, 3, 4, 1, 3, 4, 1, 1, 8, 7, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 3, 1, 3, 1, 2, 2, 3, 1, 3, 2, 3, 1, 3, 3, 2, 0, 1, 1, 1, 1, 1, 3, 7, 10, 5, 7, 9, 5, 3, 3, 3, 3, 3, 3, 1, 2, 5, 7, 9, 6, 5, 6, 3, 2, 1, 1, 1, 1, 0, 2, 1, 3, 8, 0, 4, 2, 1, 3, 0, 1, 0, 1, 0, 1, 3, 1, 1, 1, 1, 1, 8, 9, 7, 8, 7, 6, 8, 0, 2, 0, 2, 1, 2, 1, 2, 1, 1, 1, 0, 2, 0, 2, 0, 2, 2, 1, 3, 1, 4, 1, 4, 1, 1, 4, 2, 1, 3, 3, 3, 4, 4, 5, 0, 2, 4, 3, 1, 1, 7, 0, 2, 1, 3, 3, 4, 1, 4, 0, 2, 5, 0, 2, 6, 0, 2, 0, 3, 1, 2, 1, 1, 2, 0, 1, 3, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 7, 9, 6, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 3, 3, 3, 3, 3, 1, 3, 3, 1, 1, 2, 1, 1, 0, 1, 0, 2, 2, 2, 4, 3, 2, 4, 4, 3, 3, 1, 3, 1, 1, 3, 2, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 3, 2, 0, 1, 5, 7, 5, 6, 10, 3, 5, 1, 1, 3, 0, 2, 4, 5, 4, 4, 4, 3, 1, 1, 1, 1, 1, 1, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 3, 1, 1, 3, 0, 2, 0, 3, 5, 8, 1, 3, 3, 0, 2, 2, 2, 3, 1, 0, 1, 1, 3, 3, 3, 4, 4, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 4, 4, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 2, 1, 2, 4, 2, 2, 8, 9, 8, 9, 9, 10, 9, 10, 8, 3, 2, 2, 1, 1, 0, 4, 2, 1, 3, 2, 1, 2, 2, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 3, 3, 4, 1, 1, 3, 1, 1, 1, 1, 1, 3, 2, 3, 0, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 4, 1, 4, 4, 0, 1, 1, 1, 3, 3, 1, 4, 2, 2, 1, 3, 1, 4, 3, 3, 3, 3, 1, 3, 1, 1, 3, 1, 1, 4, 1, 1, 1, 3, 1, 1, 2, 1, 3, 4, 3, 2, 0, 2, 2, 1, 2, 1, 1, 1, 4, 3, 3, 3, 3, 6, 3, 1, 1, 2, 1); + protected function initReduceCallbacks(): void + { + $this->reduceCallbacks = [0 => null, 1 => static function ($self, $stackPos) { + $self->semValue = $self->handleNamespaces($self->semStack[$stackPos - (1 - 1)]); + }, 2 => static function ($self, $stackPos) { + if ($self->semStack[$stackPos - (2 - 2)] !== null) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + } + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 3 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 4 => static function ($self, $stackPos) { + $nop = $self->maybeCreateZeroLengthNop($self->tokenPos); + if ($nop !== null) { + $self->semStack[$stackPos - (1 - 1)][] = $nop; + } + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 5 => null, 6 => null, 7 => null, 8 => null, 9 => null, 10 => null, 11 => null, 12 => null, 13 => null, 14 => null, 15 => null, 16 => null, 17 => null, 18 => null, 19 => null, 20 => null, 21 => null, 22 => null, 23 => null, 24 => null, 25 => null, 26 => null, 27 => null, 28 => null, 29 => null, 30 => null, 31 => null, 32 => null, 33 => null, 34 => null, 35 => null, 36 => null, 37 => null, 38 => null, 39 => null, 40 => null, 41 => null, 42 => null, 43 => null, 44 => null, 45 => null, 46 => null, 47 => null, 48 => null, 49 => null, 50 => null, 51 => null, 52 => null, 53 => null, 54 => null, 55 => null, 56 => null, 57 => null, 58 => null, 59 => null, 60 => null, 61 => null, 62 => null, 63 => null, 64 => null, 65 => null, 66 => null, 67 => null, 68 => null, 69 => null, 70 => null, 71 => null, 72 => null, 73 => null, 74 => null, 75 => null, 76 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + if ($self->semValue === "emitError(new Error('Cannot use "getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]))); + } + }, 77 => null, 78 => null, 79 => null, 80 => null, 81 => null, 82 => null, 83 => null, 84 => null, 85 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 86 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 87 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 88 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 89 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 90 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 91 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 92 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 93 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 94 => null, 95 => static function ($self, $stackPos) { + $self->semValue = new Name(substr($self->semStack[$stackPos - (1 - 1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 96 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable(substr($self->semStack[$stackPos - (1 - 1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 97 => static function ($self, $stackPos) { + /* nothing */ + }, 98 => static function ($self, $stackPos) { + /* nothing */ + }, 99 => static function ($self, $stackPos) { + /* nothing */ + }, 100 => static function ($self, $stackPos) { + $self->emitError(new Error('A trailing comma is not allowed here', $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]))); + }, 101 => null, 102 => null, 103 => static function ($self, $stackPos) { + $self->semValue = new Node\Attribute($self->semStack[$stackPos - (1 - 1)], [], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 104 => static function ($self, $stackPos) { + $self->semValue = new Node\Attribute($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 105 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 106 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 107 => static function ($self, $stackPos) { + $self->semValue = new Node\AttributeGroup($self->semStack[$stackPos - (4 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 108 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 109 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 110 => static function ($self, $stackPos) { + $self->semValue = []; + }, 111 => null, 112 => null, 113 => null, 114 => null, 115 => static function ($self, $stackPos) { + $self->semValue = new Stmt\HaltCompiler($self->handleHaltCompiler(), $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 116 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Namespace_($self->semStack[$stackPos - (3 - 2)], null, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON); + $self->checkNamespace($self->semValue); + }, 117 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Namespace_($self->semStack[$stackPos - (5 - 2)], $self->semStack[$stackPos - (5 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $self->checkNamespace($self->semValue); + }, 118 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Namespace_(null, $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $self->checkNamespace($self->semValue); + }, 119 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Use_($self->semStack[$stackPos - (3 - 2)], Stmt\Use_::TYPE_NORMAL, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 120 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Use_($self->semStack[$stackPos - (4 - 3)], $self->semStack[$stackPos - (4 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 121 => null, 122 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Const_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]), []); + }, 123 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Const_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (4 - 1)]); + $self->checkConstantAttributes($self->semValue); + }, 124 => static function ($self, $stackPos) { + $self->semValue = Stmt\Use_::TYPE_FUNCTION; + }, 125 => static function ($self, $stackPos) { + $self->semValue = Stmt\Use_::TYPE_CONSTANT; + }, 126 => static function ($self, $stackPos) { + $self->semValue = new Stmt\GroupUse($self->semStack[$stackPos - (8 - 3)], $self->semStack[$stackPos - (8 - 6)], $self->semStack[$stackPos - (8 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + }, 127 => static function ($self, $stackPos) { + $self->semValue = new Stmt\GroupUse($self->semStack[$stackPos - (7 - 2)], $self->semStack[$stackPos - (7 - 5)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + }, 128 => null, 129 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 130 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 131 => null, 132 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 133 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 134 => null, 135 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 136 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 137 => static function ($self, $stackPos) { + $self->semValue = new Node\UseItem($self->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkUseUse($self->semValue, $stackPos - (1 - 1)); + }, 138 => static function ($self, $stackPos) { + $self->semValue = new Node\UseItem($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkUseUse($self->semValue, $stackPos - (3 - 3)); + }, 139 => static function ($self, $stackPos) { + $self->semValue = new Node\UseItem($self->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkUseUse($self->semValue, $stackPos - (1 - 1)); + }, 140 => static function ($self, $stackPos) { + $self->semValue = new Node\UseItem($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkUseUse($self->semValue, $stackPos - (3 - 3)); + }, 141 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + $self->semValue->type = Stmt\Use_::TYPE_NORMAL; + }, 142 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue->type = $self->semStack[$stackPos - (2 - 1)]; + }, 143 => null, 144 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 145 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 146 => static function ($self, $stackPos) { + $self->semValue = new Node\Const_($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 147 => null, 148 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 149 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 150 => static function ($self, $stackPos) { + $self->semValue = new Node\Const_(new Node\Identifier($self->semStack[$stackPos - (3 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos - (3 - 1)])), $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 151 => static function ($self, $stackPos) { + $self->semValue = new Node\Const_(new Node\Identifier($self->semStack[$stackPos - (3 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos - (3 - 1)])), $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 152 => static function ($self, $stackPos) { + if ($self->semStack[$stackPos - (2 - 2)] !== null) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + } + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 153 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 154 => static function ($self, $stackPos) { + $nop = $self->maybeCreateZeroLengthNop($self->tokenPos); + if ($nop !== null) { + $self->semStack[$stackPos - (1 - 1)][] = $nop; + } + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 155 => null, 156 => null, 157 => null, 158 => static function ($self, $stackPos) { + throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 159 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Block($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 160 => static function ($self, $stackPos) { + $self->semValue = new Stmt\If_($self->semStack[$stackPos - (7 - 3)], ['stmts' => $self->semStack[$stackPos - (7 - 5)], 'elseifs' => $self->semStack[$stackPos - (7 - 6)], 'else' => $self->semStack[$stackPos - (7 - 7)]], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + }, 161 => static function ($self, $stackPos) { + $self->semValue = new Stmt\If_($self->semStack[$stackPos - (10 - 3)], ['stmts' => $self->semStack[$stackPos - (10 - 6)], 'elseifs' => $self->semStack[$stackPos - (10 - 7)], 'else' => $self->semStack[$stackPos - (10 - 8)]], $self->getAttributes($self->tokenStartStack[$stackPos - (10 - 1)], $self->tokenEndStack[$stackPos])); + }, 162 => static function ($self, $stackPos) { + $self->semValue = new Stmt\While_($self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 163 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Do_($self->semStack[$stackPos - (7 - 5)], $self->semStack[$stackPos - (7 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + }, 164 => static function ($self, $stackPos) { + $self->semValue = new Stmt\For_(['init' => $self->semStack[$stackPos - (9 - 3)], 'cond' => $self->semStack[$stackPos - (9 - 5)], 'loop' => $self->semStack[$stackPos - (9 - 7)], 'stmts' => $self->semStack[$stackPos - (9 - 9)]], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 165 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Switch_($self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 166 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Break_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 167 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Continue_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 168 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Return_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 169 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Global_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 170 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Static_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 171 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Echo_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 172 => static function ($self, $stackPos) { + $self->semValue = new Stmt\InlineHTML($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + $self->semValue->setAttribute('hasLeadingNewline', $self->inlineHtmlHasLeadingNewline($stackPos - (1 - 1))); + }, 173 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Expression($self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 174 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Unset_($self->semStack[$stackPos - (5 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 175 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos - (7 - 3)], $self->semStack[$stackPos - (7 - 5)][0], ['keyVar' => null, 'byRef' => $self->semStack[$stackPos - (7 - 5)][1], 'stmts' => $self->semStack[$stackPos - (7 - 7)]], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + }, 176 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos - (9 - 3)], $self->semStack[$stackPos - (9 - 7)][0], ['keyVar' => $self->semStack[$stackPos - (9 - 5)], 'byRef' => $self->semStack[$stackPos - (9 - 7)][1], 'stmts' => $self->semStack[$stackPos - (9 - 9)]], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 177 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos - (6 - 3)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (6 - 4)], $self->tokenEndStack[$stackPos - (6 - 4)])), ['stmts' => $self->semStack[$stackPos - (6 - 6)]], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])); + }, 178 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Declare_($self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 179 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TryCatch($self->semStack[$stackPos - (6 - 3)], $self->semStack[$stackPos - (6 - 5)], $self->semStack[$stackPos - (6 - 6)], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkTryCatch($self->semValue); + }, 180 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Goto_($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 181 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Label($self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 182 => static function ($self, $stackPos) { + $self->semValue = null; + /* means: no statement */ + }, 183 => null, 184 => static function ($self, $stackPos) { + $self->semValue = $self->maybeCreateNop($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]); + }, 185 => static function ($self, $stackPos) { + if ($self->semStack[$stackPos - (1 - 1)] instanceof Stmt\Block) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]->stmts; + } else if ($self->semStack[$stackPos - (1 - 1)] === null) { + $self->semValue = []; + } else { + $self->semValue = [$self->semStack[$stackPos - (1 - 1)]]; + } + }, 186 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 187 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 188 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 189 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 190 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Catch_($self->semStack[$stackPos - (8 - 3)], $self->semStack[$stackPos - (8 - 4)], $self->semStack[$stackPos - (8 - 7)], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + }, 191 => static function ($self, $stackPos) { + $self->semValue = null; + }, 192 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Finally_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 193 => null, 194 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 195 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 196 => static function ($self, $stackPos) { + $self->semValue = \false; + }, 197 => static function ($self, $stackPos) { + $self->semValue = \true; + }, 198 => static function ($self, $stackPos) { + $self->semValue = \false; + }, 199 => static function ($self, $stackPos) { + $self->semValue = \true; + }, 200 => static function ($self, $stackPos) { + $self->semValue = \false; + }, 201 => static function ($self, $stackPos) { + $self->semValue = \true; + }, 202 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 203 => static function ($self, $stackPos) { + $self->semValue = []; + }, 204 => null, 205 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 206 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 207 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 208 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Function_($self->semStack[$stackPos - (8 - 3)], ['byRef' => $self->semStack[$stackPos - (8 - 2)], 'params' => $self->semStack[$stackPos - (8 - 5)], 'returnType' => $self->semStack[$stackPos - (8 - 7)], 'stmts' => $self->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + }, 209 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Function_($self->semStack[$stackPos - (9 - 4)], ['byRef' => $self->semStack[$stackPos - (9 - 3)], 'params' => $self->semStack[$stackPos - (9 - 6)], 'returnType' => $self->semStack[$stackPos - (9 - 8)], 'stmts' => $self->semStack[$stackPos - (9 - 9)], 'attrGroups' => $self->semStack[$stackPos - (9 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 210 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Class_($self->semStack[$stackPos - (7 - 2)], ['type' => $self->semStack[$stackPos - (7 - 1)], 'extends' => $self->semStack[$stackPos - (7 - 3)], 'implements' => $self->semStack[$stackPos - (7 - 4)], 'stmts' => $self->semStack[$stackPos - (7 - 6)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkClass($self->semValue, $stackPos - (7 - 2)); + }, 211 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Class_($self->semStack[$stackPos - (8 - 3)], ['type' => $self->semStack[$stackPos - (8 - 2)], 'extends' => $self->semStack[$stackPos - (8 - 4)], 'implements' => $self->semStack[$stackPos - (8 - 5)], 'stmts' => $self->semStack[$stackPos - (8 - 7)], 'attrGroups' => $self->semStack[$stackPos - (8 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkClass($self->semValue, $stackPos - (8 - 3)); + }, 212 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Interface_($self->semStack[$stackPos - (7 - 3)], ['extends' => $self->semStack[$stackPos - (7 - 4)], 'stmts' => $self->semStack[$stackPos - (7 - 6)], 'attrGroups' => $self->semStack[$stackPos - (7 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkInterface($self->semValue, $stackPos - (7 - 3)); + }, 213 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Trait_($self->semStack[$stackPos - (6 - 3)], ['stmts' => $self->semStack[$stackPos - (6 - 5)], 'attrGroups' => $self->semStack[$stackPos - (6 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])); + }, 214 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Enum_($self->semStack[$stackPos - (8 - 3)], ['scalarType' => $self->semStack[$stackPos - (8 - 4)], 'implements' => $self->semStack[$stackPos - (8 - 5)], 'stmts' => $self->semStack[$stackPos - (8 - 7)], 'attrGroups' => $self->semStack[$stackPos - (8 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkEnum($self->semValue, $stackPos - (8 - 3)); + }, 215 => static function ($self, $stackPos) { + $self->semValue = null; + }, 216 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 217 => static function ($self, $stackPos) { + $self->semValue = null; + }, 218 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 219 => static function ($self, $stackPos) { + $self->semValue = 0; + }, 220 => null, 221 => null, 222 => static function ($self, $stackPos) { + $self->checkClassModifier($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $self->semValue = $self->semStack[$stackPos - (2 - 1)] | $self->semStack[$stackPos - (2 - 2)]; + }, 223 => static function ($self, $stackPos) { + $self->semValue = Modifiers::ABSTRACT; + }, 224 => static function ($self, $stackPos) { + $self->semValue = Modifiers::FINAL; + }, 225 => static function ($self, $stackPos) { + $self->semValue = Modifiers::READONLY; + }, 226 => static function ($self, $stackPos) { + $self->semValue = null; + }, 227 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 228 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 229 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 230 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 231 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 232 => null, 233 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 234 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 235 => null, 236 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 237 => null, 238 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 239 => static function ($self, $stackPos) { + if ($self->semStack[$stackPos - (1 - 1)] instanceof Stmt\Block) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]->stmts; + } else if ($self->semStack[$stackPos - (1 - 1)] === null) { + $self->semValue = []; + } else { + $self->semValue = [$self->semStack[$stackPos - (1 - 1)]]; + } + }, 240 => static function ($self, $stackPos) { + $self->semValue = null; + }, 241 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 242 => null, 243 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 244 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 245 => static function ($self, $stackPos) { + $self->semValue = new Node\DeclareItem($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 246 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 247 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 3)]; + }, 248 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 249 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (5 - 3)]; + }, 250 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 251 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 252 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Case_($self->semStack[$stackPos - (4 - 2)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 253 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Case_(null, $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 254 => null, 255 => null, 256 => static function ($self, $stackPos) { + $self->semValue = new Expr\Match_($self->semStack[$stackPos - (7 - 3)], $self->semStack[$stackPos - (7 - 6)], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos])); + }, 257 => static function ($self, $stackPos) { + $self->semValue = []; + }, 258 => null, 259 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 260 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 261 => static function ($self, $stackPos) { + $self->semValue = new Node\MatchArm($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 262 => static function ($self, $stackPos) { + $self->semValue = new Node\MatchArm(null, $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 263 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 264 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 265 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 266 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 267 => static function ($self, $stackPos) { + $self->semValue = new Stmt\ElseIf_($self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 268 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 269 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 270 => static function ($self, $stackPos) { + $self->semValue = new Stmt\ElseIf_($self->semStack[$stackPos - (6 - 3)], $self->semStack[$stackPos - (6 - 6)], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])); + $self->fixupAlternativeElse($self->semValue); + }, 271 => static function ($self, $stackPos) { + $self->semValue = null; + }, 272 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Else_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 273 => static function ($self, $stackPos) { + $self->semValue = null; + }, 274 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Else_($self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + $self->fixupAlternativeElse($self->semValue); + }, 275 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)], \false); + }, 276 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (2 - 2)], \true); + }, 277 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)], \false); + }, 278 => static function ($self, $stackPos) { + $self->semValue = array($self->fixupArrayDestructuring($self->semStack[$stackPos - (1 - 1)]), \false); + }, 279 => null, 280 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 281 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 282 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 283 => static function ($self, $stackPos) { + $self->semValue = 0; + }, 284 => static function ($self, $stackPos) { + $self->checkModifier($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $self->semValue = $self->semStack[$stackPos - (2 - 1)] | $self->semStack[$stackPos - (2 - 2)]; + }, 285 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PUBLIC; + }, 286 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PROTECTED; + }, 287 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PRIVATE; + }, 288 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PUBLIC_SET; + }, 289 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PROTECTED_SET; + }, 290 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PRIVATE_SET; + }, 291 => static function ($self, $stackPos) { + $self->semValue = Modifiers::READONLY; + }, 292 => static function ($self, $stackPos) { + $self->semValue = Modifiers::FINAL; + }, 293 => static function ($self, $stackPos) { + $self->semValue = new Node\Param($self->semStack[$stackPos - (7 - 6)], null, $self->semStack[$stackPos - (7 - 3)], $self->semStack[$stackPos - (7 - 4)], $self->semStack[$stackPos - (7 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (7 - 2)], $self->semStack[$stackPos - (7 - 1)], $self->semStack[$stackPos - (7 - 7)]); + $self->checkParam($self->semValue); + $self->addPropertyNameToHooks($self->semValue); + }, 294 => static function ($self, $stackPos) { + $self->semValue = new Node\Param($self->semStack[$stackPos - (9 - 6)], $self->semStack[$stackPos - (9 - 8)], $self->semStack[$stackPos - (9 - 3)], $self->semStack[$stackPos - (9 - 4)], $self->semStack[$stackPos - (9 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (9 - 2)], $self->semStack[$stackPos - (9 - 1)], $self->semStack[$stackPos - (9 - 9)]); + $self->checkParam($self->semValue); + $self->addPropertyNameToHooks($self->semValue); + }, 295 => static function ($self, $stackPos) { + $self->semValue = new Node\Param(new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])), null, $self->semStack[$stackPos - (6 - 3)], $self->semStack[$stackPos - (6 - 4)], $self->semStack[$stackPos - (6 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (6 - 2)], $self->semStack[$stackPos - (6 - 1)]); + }, 296 => null, 297 => static function ($self, $stackPos) { + $self->semValue = new Node\NullableType($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 298 => static function ($self, $stackPos) { + $self->semValue = new Node\UnionType($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 299 => null, 300 => null, 301 => static function ($self, $stackPos) { + $self->semValue = new Node\Name('static', $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 302 => static function ($self, $stackPos) { + $self->semValue = $self->handleBuiltinTypes($self->semStack[$stackPos - (1 - 1)]); + }, 303 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier('array', $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 304 => static function ($self, $stackPos) { + $self->semValue = new Node\Identifier('callable', $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 305 => null, 306 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 307 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)]); + }, 308 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 309 => null, 310 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 311 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)]); + }, 312 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 313 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)]); + }, 314 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 315 => static function ($self, $stackPos) { + $self->semValue = new Node\IntersectionType($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 316 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)]); + }, 317 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 318 => static function ($self, $stackPos) { + $self->semValue = new Node\IntersectionType($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 319 => null, 320 => static function ($self, $stackPos) { + $self->semValue = new Node\NullableType($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 321 => static function ($self, $stackPos) { + $self->semValue = new Node\UnionType($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 322 => null, 323 => static function ($self, $stackPos) { + $self->semValue = null; + }, 324 => null, 325 => static function ($self, $stackPos) { + $self->semValue = null; + }, 326 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (2 - 2)]; + }, 327 => static function ($self, $stackPos) { + $self->semValue = null; + }, 328 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 329 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 330 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 2)]); + }, 331 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 332 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 2)]; + }, 333 => static function ($self, $stackPos) { + $self->semValue = array(new Node\Arg($self->semStack[$stackPos - (4 - 2)], \false, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos]))); + }, 334 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 2)]); + }, 335 => static function ($self, $stackPos) { + $self->semValue = array(new Node\Arg($self->semStack[$stackPos - (3 - 1)], \false, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos - (3 - 1)])), $self->semStack[$stackPos - (3 - 3)]); + }, 336 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 337 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 338 => static function ($self, $stackPos) { + $self->semValue = new Node\VariadicPlaceholder($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 339 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 340 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 341 => static function ($self, $stackPos) { + $self->semValue = new Node\Arg($self->semStack[$stackPos - (2 - 2)], \true, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 342 => static function ($self, $stackPos) { + $self->semValue = new Node\Arg($self->semStack[$stackPos - (2 - 2)], \false, \true, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 343 => static function ($self, $stackPos) { + $self->semValue = new Node\Arg($self->semStack[$stackPos - (3 - 3)], \false, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (3 - 1)]); + }, 344 => static function ($self, $stackPos) { + $self->semValue = new Node\Arg($self->semStack[$stackPos - (1 - 1)], \false, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 345 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 346 => null, 347 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 348 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 349 => null, 350 => null, 351 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 352 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 353 => static function ($self, $stackPos) { + $self->semValue = new Node\StaticVar($self->semStack[$stackPos - (1 - 1)], null, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 354 => static function ($self, $stackPos) { + $self->semValue = new Node\StaticVar($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 355 => static function ($self, $stackPos) { + if ($self->semStack[$stackPos - (2 - 2)] !== null) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + } else { + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + } + }, 356 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 357 => static function ($self, $stackPos) { + $nop = $self->maybeCreateZeroLengthNop($self->tokenPos); + if ($nop !== null) { + $self->semStack[$stackPos - (1 - 1)][] = $nop; + } + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 358 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Property($self->semStack[$stackPos - (5 - 2)], $self->semStack[$stackPos - (5 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 1)]); + }, 359 => static function ($self, $stackPos) { + $self->semValue = new Stmt\Property($self->semStack[$stackPos - (7 - 2)], $self->semStack[$stackPos - (7 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (7 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (7 - 3)], $self->semStack[$stackPos - (7 - 1)], $self->semStack[$stackPos - (7 - 6)]); + $self->checkPropertyHooksForMultiProperty($self->semValue, $stackPos - (7 - 5)); + $self->checkEmptyPropertyHookList($self->semStack[$stackPos - (7 - 6)], $stackPos - (7 - 5)); + $self->addPropertyNameToHooks($self->semValue); + }, 360 => static function ($self, $stackPos) { + $self->semValue = new Stmt\ClassConst($self->semStack[$stackPos - (5 - 4)], $self->semStack[$stackPos - (5 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (5 - 1)]); + $self->checkClassConst($self->semValue, $stackPos - (5 - 2)); + }, 361 => static function ($self, $stackPos) { + $self->semValue = new Stmt\ClassConst($self->semStack[$stackPos - (6 - 5)], $self->semStack[$stackPos - (6 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos - (6 - 1)], $self->semStack[$stackPos - (6 - 4)]); + $self->checkClassConst($self->semValue, $stackPos - (6 - 2)); + }, 362 => static function ($self, $stackPos) { + $self->semValue = new Stmt\ClassMethod($self->semStack[$stackPos - (10 - 5)], ['type' => $self->semStack[$stackPos - (10 - 2)], 'byRef' => $self->semStack[$stackPos - (10 - 4)], 'params' => $self->semStack[$stackPos - (10 - 7)], 'returnType' => $self->semStack[$stackPos - (10 - 9)], 'stmts' => $self->semStack[$stackPos - (10 - 10)], 'attrGroups' => $self->semStack[$stackPos - (10 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (10 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkClassMethod($self->semValue, $stackPos - (10 - 2)); + }, 363 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUse($self->semStack[$stackPos - (3 - 2)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 364 => static function ($self, $stackPos) { + $self->semValue = new Stmt\EnumCase($self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 4)], $self->semStack[$stackPos - (5 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 365 => static function ($self, $stackPos) { + $self->semValue = null; + /* will be skipped */ + }, 366 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 367 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 368 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 369 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 370 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUseAdaptation\Precedence($self->semStack[$stackPos - (4 - 1)][0], $self->semStack[$stackPos - (4 - 1)][1], $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 371 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos - (5 - 1)][0], $self->semStack[$stackPos - (5 - 1)][1], $self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 372 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos - (4 - 1)][0], $self->semStack[$stackPos - (4 - 1)][1], $self->semStack[$stackPos - (4 - 3)], null, $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 373 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos - (4 - 1)][0], $self->semStack[$stackPos - (4 - 1)][1], null, $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 374 => static function ($self, $stackPos) { + $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos - (4 - 1)][0], $self->semStack[$stackPos - (4 - 1)][1], null, $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 375 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)]); + }, 376 => null, 377 => static function ($self, $stackPos) { + $self->semValue = array(null, $self->semStack[$stackPos - (1 - 1)]); + }, 378 => static function ($self, $stackPos) { + $self->semValue = null; + }, 379 => null, 380 => null, 381 => static function ($self, $stackPos) { + $self->semValue = 0; + }, 382 => static function ($self, $stackPos) { + $self->semValue = 0; + }, 383 => null, 384 => null, 385 => static function ($self, $stackPos) { + $self->checkModifier($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $self->semValue = $self->semStack[$stackPos - (2 - 1)] | $self->semStack[$stackPos - (2 - 2)]; + }, 386 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PUBLIC; + }, 387 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PROTECTED; + }, 388 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PRIVATE; + }, 389 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PUBLIC_SET; + }, 390 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PROTECTED_SET; + }, 391 => static function ($self, $stackPos) { + $self->semValue = Modifiers::PRIVATE_SET; + }, 392 => static function ($self, $stackPos) { + $self->semValue = Modifiers::STATIC; + }, 393 => static function ($self, $stackPos) { + $self->semValue = Modifiers::ABSTRACT; + }, 394 => static function ($self, $stackPos) { + $self->semValue = Modifiers::FINAL; + }, 395 => static function ($self, $stackPos) { + $self->semValue = Modifiers::READONLY; + }, 396 => null, 397 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 398 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 399 => static function ($self, $stackPos) { + $self->semValue = new Node\VarLikeIdentifier(substr($self->semStack[$stackPos - (1 - 1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 400 => static function ($self, $stackPos) { + $self->semValue = new Node\PropertyItem($self->semStack[$stackPos - (1 - 1)], null, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 401 => static function ($self, $stackPos) { + $self->semValue = new Node\PropertyItem($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 402 => static function ($self, $stackPos) { + $self->semValue = []; + }, 403 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 404 => static function ($self, $stackPos) { + $self->semValue = []; + }, 405 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + $self->checkEmptyPropertyHookList($self->semStack[$stackPos - (3 - 2)], $stackPos - (3 - 1)); + }, 406 => static function ($self, $stackPos) { + $self->semValue = new Node\PropertyHook($self->semStack[$stackPos - (5 - 4)], $self->semStack[$stackPos - (5 - 5)], ['flags' => $self->semStack[$stackPos - (5 - 2)], 'byRef' => $self->semStack[$stackPos - (5 - 3)], 'params' => [], 'attrGroups' => $self->semStack[$stackPos - (5 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkPropertyHook($self->semValue, null); + }, 407 => static function ($self, $stackPos) { + $self->semValue = new Node\PropertyHook($self->semStack[$stackPos - (8 - 4)], $self->semStack[$stackPos - (8 - 8)], ['flags' => $self->semStack[$stackPos - (8 - 2)], 'byRef' => $self->semStack[$stackPos - (8 - 3)], 'params' => $self->semStack[$stackPos - (8 - 6)], 'attrGroups' => $self->semStack[$stackPos - (8 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkPropertyHook($self->semValue, $stackPos - (8 - 5)); + }, 408 => static function ($self, $stackPos) { + $self->semValue = null; + }, 409 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 410 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 411 => static function ($self, $stackPos) { + $self->semValue = 0; + }, 412 => static function ($self, $stackPos) { + $self->checkPropertyHookModifiers($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $self->semValue = $self->semStack[$stackPos - (2 - 1)] | $self->semStack[$stackPos - (2 - 2)]; + }, 413 => null, 414 => null, 415 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 416 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 417 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 418 => null, 419 => null, 420 => static function ($self, $stackPos) { + $self->semValue = new Expr\Assign($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 421 => static function ($self, $stackPos) { + $self->semValue = new Expr\Assign($self->fixupArrayDestructuring($self->semStack[$stackPos - (3 - 1)]), $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 422 => static function ($self, $stackPos) { + $self->semValue = new Expr\Assign($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 423 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignRef($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 424 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignRef($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + if (!$self->phpVersion->allowsAssignNewByReference()) { + $self->emitError(new Error('Cannot assign new by reference', $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos]))); + } + }, 425 => null, 426 => null, 427 => static function ($self, $stackPos) { + $self->semValue = new Expr\FuncCall(new Node\Name($self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos - (2 - 1)])), $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 428 => static function ($self, $stackPos) { + $self->semValue = new Expr\Clone_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 429 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Plus($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 430 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Minus($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 431 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Mul($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 432 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Div($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 433 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Concat($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 434 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Mod($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 435 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\BitwiseAnd($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 436 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\BitwiseOr($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 437 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\BitwiseXor($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 438 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\ShiftLeft($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 439 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\ShiftRight($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 440 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Pow($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 441 => static function ($self, $stackPos) { + $self->semValue = new Expr\AssignOp\Coalesce($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 442 => static function ($self, $stackPos) { + $self->semValue = new Expr\PostInc($self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 443 => static function ($self, $stackPos) { + $self->semValue = new Expr\PreInc($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 444 => static function ($self, $stackPos) { + $self->semValue = new Expr\PostDec($self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 445 => static function ($self, $stackPos) { + $self->semValue = new Expr\PreDec($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 446 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BooleanOr($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 447 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BooleanAnd($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 448 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\LogicalOr($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 449 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\LogicalAnd($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 450 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\LogicalXor($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 451 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BitwiseOr($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 452 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BitwiseAnd($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 453 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BitwiseAnd($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 454 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\BitwiseXor($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 455 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Concat($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 456 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Plus($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 457 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Minus($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 458 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Mul($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 459 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Div($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 460 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Mod($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 461 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\ShiftLeft($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 462 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\ShiftRight($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 463 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Pow($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 464 => static function ($self, $stackPos) { + $self->semValue = new Expr\UnaryPlus($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 465 => static function ($self, $stackPos) { + $self->semValue = new Expr\UnaryMinus($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 466 => static function ($self, $stackPos) { + $self->semValue = new Expr\BooleanNot($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 467 => static function ($self, $stackPos) { + $self->semValue = new Expr\BitwiseNot($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 468 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Identical($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 469 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\NotIdentical($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 470 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Equal($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 471 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\NotEqual($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 472 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Spaceship($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 473 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Smaller($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 474 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\SmallerOrEqual($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 475 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Greater($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 476 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\GreaterOrEqual($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 477 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Pipe($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + $self->checkPipeOperatorParentheses($self->semStack[$stackPos - (3 - 3)]); + }, 478 => static function ($self, $stackPos) { + $self->semValue = new Expr\Instanceof_($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 479 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + if ($self->semValue instanceof Expr\ArrowFunction) { + $self->parenthesizedArrowFunctions->offsetSet($self->semValue); + } + }, 480 => static function ($self, $stackPos) { + $self->semValue = new Expr\Ternary($self->semStack[$stackPos - (5 - 1)], $self->semStack[$stackPos - (5 - 3)], $self->semStack[$stackPos - (5 - 5)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 481 => static function ($self, $stackPos) { + $self->semValue = new Expr\Ternary($self->semStack[$stackPos - (4 - 1)], null, $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 482 => static function ($self, $stackPos) { + $self->semValue = new Expr\BinaryOp\Coalesce($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 483 => static function ($self, $stackPos) { + $self->semValue = new Expr\Isset_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 484 => static function ($self, $stackPos) { + $self->semValue = new Expr\Empty_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 485 => static function ($self, $stackPos) { + $self->semValue = new Expr\Include_($self->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 486 => static function ($self, $stackPos) { + $self->semValue = new Expr\Include_($self->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE_ONCE, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 487 => static function ($self, $stackPos) { + $self->semValue = new Expr\Eval_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 488 => static function ($self, $stackPos) { + $self->semValue = new Expr\Include_($self->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 489 => static function ($self, $stackPos) { + $self->semValue = new Expr\Include_($self->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE_ONCE, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 490 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->getIntCastKind($self->semStack[$stackPos - (2 - 1)]); + $self->semValue = new Expr\Cast\Int_($self->semStack[$stackPos - (2 - 2)], $attrs); + }, 491 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->getFloatCastKind($self->semStack[$stackPos - (2 - 1)]); + $self->semValue = new Expr\Cast\Double($self->semStack[$stackPos - (2 - 2)], $attrs); + }, 492 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->getStringCastKind($self->semStack[$stackPos - (2 - 1)]); + $self->semValue = new Expr\Cast\String_($self->semStack[$stackPos - (2 - 2)], $attrs); + }, 493 => static function ($self, $stackPos) { + $self->semValue = new Expr\Cast\Array_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 494 => static function ($self, $stackPos) { + $self->semValue = new Expr\Cast\Object_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 495 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = $self->getBoolCastKind($self->semStack[$stackPos - (2 - 1)]); + $self->semValue = new Expr\Cast\Bool_($self->semStack[$stackPos - (2 - 2)], $attrs); + }, 496 => static function ($self, $stackPos) { + $self->semValue = new Expr\Cast\Unset_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 497 => static function ($self, $stackPos) { + $self->semValue = new Expr\Cast\Void_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 498 => static function ($self, $stackPos) { + $self->semValue = $self->createExitExpr($self->semStack[$stackPos - (2 - 1)], $stackPos - (2 - 1), $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 499 => static function ($self, $stackPos) { + $self->semValue = new Expr\ErrorSuppress($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 500 => null, 501 => static function ($self, $stackPos) { + $self->semValue = new Expr\ShellExec($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 502 => static function ($self, $stackPos) { + $self->semValue = new Expr\Print_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 503 => static function ($self, $stackPos) { + $self->semValue = new Expr\Yield_(null, null, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 504 => static function ($self, $stackPos) { + $self->semValue = new Expr\Yield_($self->semStack[$stackPos - (2 - 2)], null, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 505 => static function ($self, $stackPos) { + $self->semValue = new Expr\Yield_($self->semStack[$stackPos - (4 - 4)], $self->semStack[$stackPos - (4 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 506 => static function ($self, $stackPos) { + $self->semValue = new Expr\YieldFrom($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 507 => static function ($self, $stackPos) { + $self->semValue = new Expr\Throw_($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 508 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrowFunction(['static' => \false, 'byRef' => $self->semStack[$stackPos - (8 - 2)], 'params' => $self->semStack[$stackPos - (8 - 4)], 'returnType' => $self->semStack[$stackPos - (8 - 6)], 'expr' => $self->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + }, 509 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrowFunction(['static' => \true, 'byRef' => $self->semStack[$stackPos - (9 - 3)], 'params' => $self->semStack[$stackPos - (9 - 5)], 'returnType' => $self->semStack[$stackPos - (9 - 7)], 'expr' => $self->semStack[$stackPos - (9 - 9)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 510 => static function ($self, $stackPos) { + $self->semValue = new Expr\Closure(['static' => \false, 'byRef' => $self->semStack[$stackPos - (8 - 2)], 'params' => $self->semStack[$stackPos - (8 - 4)], 'uses' => $self->semStack[$stackPos - (8 - 6)], 'returnType' => $self->semStack[$stackPos - (8 - 7)], 'stmts' => $self->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])); + }, 511 => static function ($self, $stackPos) { + $self->semValue = new Expr\Closure(['static' => \true, 'byRef' => $self->semStack[$stackPos - (9 - 3)], 'params' => $self->semStack[$stackPos - (9 - 5)], 'uses' => $self->semStack[$stackPos - (9 - 7)], 'returnType' => $self->semStack[$stackPos - (9 - 8)], 'stmts' => $self->semStack[$stackPos - (9 - 9)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 512 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrowFunction(['static' => \false, 'byRef' => $self->semStack[$stackPos - (9 - 3)], 'params' => $self->semStack[$stackPos - (9 - 5)], 'returnType' => $self->semStack[$stackPos - (9 - 7)], 'expr' => $self->semStack[$stackPos - (9 - 9)], 'attrGroups' => $self->semStack[$stackPos - (9 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 513 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrowFunction(['static' => \true, 'byRef' => $self->semStack[$stackPos - (10 - 4)], 'params' => $self->semStack[$stackPos - (10 - 6)], 'returnType' => $self->semStack[$stackPos - (10 - 8)], 'expr' => $self->semStack[$stackPos - (10 - 10)], 'attrGroups' => $self->semStack[$stackPos - (10 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (10 - 1)], $self->tokenEndStack[$stackPos])); + }, 514 => static function ($self, $stackPos) { + $self->semValue = new Expr\Closure(['static' => \false, 'byRef' => $self->semStack[$stackPos - (9 - 3)], 'params' => $self->semStack[$stackPos - (9 - 5)], 'uses' => $self->semStack[$stackPos - (9 - 7)], 'returnType' => $self->semStack[$stackPos - (9 - 8)], 'stmts' => $self->semStack[$stackPos - (9 - 9)], 'attrGroups' => $self->semStack[$stackPos - (9 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (9 - 1)], $self->tokenEndStack[$stackPos])); + }, 515 => static function ($self, $stackPos) { + $self->semValue = new Expr\Closure(['static' => \true, 'byRef' => $self->semStack[$stackPos - (10 - 4)], 'params' => $self->semStack[$stackPos - (10 - 6)], 'uses' => $self->semStack[$stackPos - (10 - 8)], 'returnType' => $self->semStack[$stackPos - (10 - 9)], 'stmts' => $self->semStack[$stackPos - (10 - 10)], 'attrGroups' => $self->semStack[$stackPos - (10 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (10 - 1)], $self->tokenEndStack[$stackPos])); + }, 516 => static function ($self, $stackPos) { + $self->semValue = array(new Stmt\Class_(null, ['type' => $self->semStack[$stackPos - (8 - 2)], 'extends' => $self->semStack[$stackPos - (8 - 4)], 'implements' => $self->semStack[$stackPos - (8 - 5)], 'stmts' => $self->semStack[$stackPos - (8 - 7)], 'attrGroups' => $self->semStack[$stackPos - (8 - 1)]], $self->getAttributes($self->tokenStartStack[$stackPos - (8 - 1)], $self->tokenEndStack[$stackPos])), $self->semStack[$stackPos - (8 - 3)]); + $self->checkClass($self->semValue[0], -1); + }, 517 => static function ($self, $stackPos) { + $self->semValue = new Expr\New_($self->semStack[$stackPos - (3 - 2)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 518 => static function ($self, $stackPos) { + list($class, $ctorArgs) = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = new Expr\New_($class, $ctorArgs, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 519 => static function ($self, $stackPos) { + $self->semValue = new Expr\New_($self->semStack[$stackPos - (2 - 2)], [], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 520 => null, 521 => null, 522 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 523 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (4 - 3)]; + }, 524 => null, 525 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 526 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 527 => static function ($self, $stackPos) { + $self->semValue = new Node\ClosureUse($self->semStack[$stackPos - (2 - 2)], $self->semStack[$stackPos - (2 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 528 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 529 => static function ($self, $stackPos) { + $self->semValue = new Expr\FuncCall($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 530 => static function ($self, $stackPos) { + $self->semValue = new Expr\FuncCall($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 531 => static function ($self, $stackPos) { + $self->semValue = new Expr\FuncCall($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 532 => static function ($self, $stackPos) { + $self->semValue = new Expr\StaticCall($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 533 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 534 => null, 535 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 536 => static function ($self, $stackPos) { + $self->semValue = new Name($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 537 => static function ($self, $stackPos) { + $self->semValue = new Name\FullyQualified(substr($self->semStack[$stackPos - (1 - 1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 538 => static function ($self, $stackPos) { + $self->semValue = new Name\Relative(substr($self->semStack[$stackPos - (1 - 1)], 10), $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 539 => null, 540 => null, 541 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 542 => static function ($self, $stackPos) { + $self->semValue = new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + $self->errorState = 2; + }, 543 => null, 544 => null, 545 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 546 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + foreach ($self->semValue as $s) { + if ($s instanceof Node\InterpolatedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', $self->phpVersion->supportsUnicodeEscapes()); + } + } + }, 547 => static function ($self, $stackPos) { + foreach ($self->semStack[$stackPos - (1 - 1)] as $s) { + if ($s instanceof Node\InterpolatedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', $self->phpVersion->supportsUnicodeEscapes()); + } + } + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + }, 548 => static function ($self, $stackPos) { + $self->semValue = array(); + }, 549 => null, 550 => static function ($self, $stackPos) { + $self->semValue = new Expr\ConstFetch($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 551 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Line($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 552 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\File($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 553 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Dir($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 554 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Class_($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 555 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Trait_($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 556 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Method($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 557 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Function_($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 558 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Namespace_($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 559 => static function ($self, $stackPos) { + $self->semValue = new Scalar\MagicConst\Property($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 560 => static function ($self, $stackPos) { + $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 561 => static function ($self, $stackPos) { + $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos - (5 - 1)], $self->semStack[$stackPos - (5 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (5 - 1)], $self->tokenEndStack[$stackPos])); + }, 562 => static function ($self, $stackPos) { + $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos - (3 - 1)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (3 - 3)], $self->tokenEndStack[$stackPos - (3 - 3)])), $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + $self->errorState = 2; + }, 563 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = Expr\Array_::KIND_SHORT; + $self->semValue = new Expr\Array_($self->semStack[$stackPos - (3 - 2)], $attrs); + }, 564 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = Expr\Array_::KIND_LONG; + $self->semValue = new Expr\Array_($self->semStack[$stackPos - (4 - 3)], $attrs); + $self->createdArrays->offsetSet($self->semValue); + }, 565 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + $self->createdArrays->offsetSet($self->semValue); + }, 566 => static function ($self, $stackPos) { + $self->semValue = Scalar\String_::fromString($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->supportsUnicodeEscapes()); + }, 567 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; + foreach ($self->semStack[$stackPos - (3 - 2)] as $s) { + if ($s instanceof Node\InterpolatedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '"', $self->phpVersion->supportsUnicodeEscapes()); + } + } + $self->semValue = new Scalar\InterpolatedString($self->semStack[$stackPos - (3 - 2)], $attrs); + }, 568 => static function ($self, $stackPos) { + $self->semValue = $self->parseLNumber($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->allowsInvalidOctals()); + }, 569 => static function ($self, $stackPos) { + $self->semValue = Scalar\Float_::fromString($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 570 => null, 571 => null, 572 => null, 573 => static function ($self, $stackPos) { + $self->semValue = $self->parseDocString($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 2)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 3)], $self->tokenEndStack[$stackPos - (3 - 3)]), \true); + }, 574 => static function ($self, $stackPos) { + $self->semValue = $self->parseDocString($self->semStack[$stackPos - (2 - 1)], '', $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 2)], $self->tokenEndStack[$stackPos - (2 - 2)]), \true); + }, 575 => static function ($self, $stackPos) { + $self->semValue = $self->parseDocString($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 2)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 3)], $self->tokenEndStack[$stackPos - (3 - 3)]), \true); + }, 576 => static function ($self, $stackPos) { + $self->semValue = null; + }, 577 => null, 578 => null, 579 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 580 => null, 581 => null, 582 => null, 583 => null, 584 => null, 585 => null, 586 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 587 => null, 588 => null, 589 => null, 590 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 591 => null, 592 => static function ($self, $stackPos) { + $self->semValue = new Expr\MethodCall($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 593 => static function ($self, $stackPos) { + $self->semValue = new Expr\NullsafeMethodCall($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->semStack[$stackPos - (4 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 594 => static function ($self, $stackPos) { + $self->semValue = null; + }, 595 => null, 596 => null, 597 => null, 598 => static function ($self, $stackPos) { + $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 599 => static function ($self, $stackPos) { + $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 600 => null, 601 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 602 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable($self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 603 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable(new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])), $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + $self->errorState = 2; + }, 604 => static function ($self, $stackPos) { + $var = $self->semStack[$stackPos - (1 - 1)]->name; + $self->semValue = \is_string($var) ? new Node\VarLikeIdentifier($var, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])) : $var; + }, 605 => static function ($self, $stackPos) { + $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 606 => null, 607 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 608 => static function ($self, $stackPos) { + $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 609 => static function ($self, $stackPos) { + $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 610 => static function ($self, $stackPos) { + $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 611 => static function ($self, $stackPos) { + $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 612 => null, 613 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 614 => null, 615 => null, 616 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 617 => null, 618 => static function ($self, $stackPos) { + $self->semValue = new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + $self->errorState = 2; + }, 619 => static function ($self, $stackPos) { + $self->semValue = new Expr\List_($self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + $self->semValue->setAttribute('kind', Expr\List_::KIND_LIST); + $self->postprocessList($self->semValue); + }, 620 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (1 - 1)]; + $end = count($self->semValue) - 1; + if ($self->semValue[$end]->value instanceof Expr\Error) { + array_pop($self->semValue); + } + }, 621 => null, 622 => static function ($self, $stackPos) { + /* do nothing -- prevent default action of $$=$self->semStack[$1]. See $551. */ + }, 623 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (3 - 1)][] = $self->semStack[$stackPos - (3 - 3)]; + $self->semValue = $self->semStack[$stackPos - (3 - 1)]; + }, 624 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 625 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (1 - 1)], null, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 626 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (2 - 2)], null, \true, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 627 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (1 - 1)], null, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 628 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (3 - 3)], $self->semStack[$stackPos - (3 - 1)], \false, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 629 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (4 - 4)], $self->semStack[$stackPos - (4 - 1)], \true, $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 630 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (3 - 3)], $self->semStack[$stackPos - (3 - 1)], \false, $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 631 => static function ($self, $stackPos) { + $self->semValue = new Node\ArrayItem($self->semStack[$stackPos - (2 - 2)], null, \false, $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos]), \true); + }, 632 => static function ($self, $stackPos) { + /* Create an Error node now to remember the position. We'll later either report an error, + or convert this into a null element, depending on whether this is a creation or destructuring context. */ + $attrs = $self->createEmptyElemAttributes($self->tokenPos); + $self->semValue = new Node\ArrayItem(new Expr\Error($attrs), null, \false, $attrs); + }, 633 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 634 => static function ($self, $stackPos) { + $self->semStack[$stackPos - (2 - 1)][] = $self->semStack[$stackPos - (2 - 2)]; + $self->semValue = $self->semStack[$stackPos - (2 - 1)]; + }, 635 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (1 - 1)]); + }, 636 => static function ($self, $stackPos) { + $self->semValue = array($self->semStack[$stackPos - (2 - 1)], $self->semStack[$stackPos - (2 - 2)]); + }, 637 => static function ($self, $stackPos) { + $attrs = $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos]); + $attrs['rawValue'] = $self->semStack[$stackPos - (1 - 1)]; + $self->semValue = new Node\InterpolatedStringPart($self->semStack[$stackPos - (1 - 1)], $attrs); + }, 638 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 639 => null, 640 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos - (4 - 1)], $self->semStack[$stackPos - (4 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (4 - 1)], $self->tokenEndStack[$stackPos])); + }, 641 => static function ($self, $stackPos) { + $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 642 => static function ($self, $stackPos) { + $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos - (3 - 1)], $self->semStack[$stackPos - (3 - 3)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 643 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 644 => static function ($self, $stackPos) { + $self->semValue = new Expr\Variable($self->semStack[$stackPos - (3 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (3 - 1)], $self->tokenEndStack[$stackPos])); + }, 645 => static function ($self, $stackPos) { + $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos - (6 - 2)], $self->semStack[$stackPos - (6 - 4)], $self->getAttributes($self->tokenStartStack[$stackPos - (6 - 1)], $self->tokenEndStack[$stackPos])); + }, 646 => static function ($self, $stackPos) { + $self->semValue = $self->semStack[$stackPos - (3 - 2)]; + }, 647 => static function ($self, $stackPos) { + $self->semValue = new Scalar\String_($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 648 => static function ($self, $stackPos) { + $self->semValue = $self->parseNumString($self->semStack[$stackPos - (1 - 1)], $self->getAttributes($self->tokenStartStack[$stackPos - (1 - 1)], $self->tokenEndStack[$stackPos])); + }, 649 => static function ($self, $stackPos) { + $self->semValue = $self->parseNumString('-' . $self->semStack[$stackPos - (2 - 2)], $self->getAttributes($self->tokenStartStack[$stackPos - (2 - 1)], $self->tokenEndStack[$stackPos])); + }, 650 => null]; + } +} + Map of PHP token IDs to drop */ + protected array $dropTokens; + /** @var int[] Map of external symbols (static::T_*) to internal symbols */ + protected array $tokenToSymbol; + /** @var string[] Map of symbols to their names */ + protected array $symbolToName; + /** @var array Names of the production rules (only necessary for debugging) */ + protected array $productions; + /** @var int[] Map of states to a displacement into the $action table. The corresponding action for this + * state/symbol pair is $action[$actionBase[$state] + $symbol]. If $actionBase[$state] is 0, the + * action is defaulted, i.e. $actionDefault[$state] should be used instead. */ + protected array $actionBase; + /** @var int[] Table of actions. Indexed according to $actionBase comment. */ + protected array $action; + /** @var int[] Table indexed analogously to $action. If $actionCheck[$actionBase[$state] + $symbol] != $symbol + * then the action is defaulted, i.e. $actionDefault[$state] should be used instead. */ + protected array $actionCheck; + /** @var int[] Map of states to their default action */ + protected array $actionDefault; + /** @var callable[] Semantic action callbacks */ + protected array $reduceCallbacks; + /** @var int[] Map of non-terminals to a displacement into the $goto table. The corresponding goto state for this + * non-terminal/state pair is $goto[$gotoBase[$nonTerminal] + $state] (unless defaulted) */ + protected array $gotoBase; + /** @var int[] Table of states to goto after reduction. Indexed according to $gotoBase comment. */ + protected array $goto; + /** @var int[] Table indexed analogously to $goto. If $gotoCheck[$gotoBase[$nonTerminal] + $state] != $nonTerminal + * then the goto state is defaulted, i.e. $gotoDefault[$nonTerminal] should be used. */ + protected array $gotoCheck; + /** @var int[] Map of non-terminals to the default state to goto after their reduction */ + protected array $gotoDefault; + /** @var int[] Map of rules to the non-terminal on their left-hand side, i.e. the non-terminal to use for + * determining the state to goto after reduction. */ + protected array $ruleToNonTerminal; + /** @var int[] Map of rules to the length of their right-hand side, which is the number of elements that have to + * be popped from the stack(s) on reduction. */ + protected array $ruleToLength; + /* + * The following members are part of the parser state: + */ + /** @var mixed Temporary value containing the result of last semantic action (reduction) */ + protected $semValue; + /** @var mixed[] Semantic value stack (contains values of tokens and semantic action results) */ + protected array $semStack; + /** @var int[] Token start position stack */ + protected array $tokenStartStack; + /** @var int[] Token end position stack */ + protected array $tokenEndStack; + /** @var ErrorHandler Error handler */ + protected ErrorHandler $errorHandler; + /** @var int Error state, used to avoid error floods */ + protected int $errorState; + /** @var \SplObjectStorage|null Array nodes created during parsing, for postprocessing of empty elements. */ + protected ?\SplObjectStorage $createdArrays; + /** @var \SplObjectStorage|null + * Arrow functions that are wrapped in parentheses, to enforce the pipe operator parentheses requirements. + */ + protected ?\SplObjectStorage $parenthesizedArrowFunctions; + /** @var Token[] Tokens for the current parse */ + protected array $tokens; + /** @var int Current position in token array */ + protected int $tokenPos; + /** + * Initialize $reduceCallbacks map. + */ + abstract protected function initReduceCallbacks(): void; + /** + * Creates a parser instance. + * + * Options: + * * phpVersion: ?PhpVersion, + * + * @param Lexer $lexer A lexer + * @param PhpVersion $phpVersion PHP version to target, defaults to latest supported. This + * option is best-effort: Even if specified, parsing will generally assume the latest + * supported version and only adjust behavior in minor ways, for example by omitting + * errors in older versions and interpreting type hints as a name or identifier depending + * on version. + */ + public function __construct(Lexer $lexer, ?PhpVersion $phpVersion = null) + { + $this->lexer = $lexer; + $this->phpVersion = $phpVersion ?? PhpVersion::getNewestSupported(); + $this->initReduceCallbacks(); + $this->phpTokenToSymbol = $this->createTokenMap(); + $this->dropTokens = array_fill_keys([\T_WHITESPACE, \T_OPEN_TAG, \T_COMMENT, \T_DOC_COMMENT, \T_BAD_CHARACTER], \true); + } + /** + * Parses PHP code into a node tree. + * + * If a non-throwing error handler is used, the parser will continue parsing after an error + * occurred and attempt to build a partial AST. + * + * @param string $code The source code to parse + * @param ErrorHandler|null $errorHandler Error handler to use for lexer/parser errors, defaults + * to ErrorHandler\Throwing. + * + * @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and + * the parser was unable to recover from an error). + */ + public function parse(string $code, ?ErrorHandler $errorHandler = null): ?array + { + $this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing(); + $this->createdArrays = new \SplObjectStorage(); + $this->parenthesizedArrowFunctions = new \SplObjectStorage(); + $this->tokens = $this->lexer->tokenize($code, $this->errorHandler); + $result = $this->doParse(); + // Report errors for any empty elements used inside arrays. This is delayed until after the main parse, + // because we don't know a priori whether a given array expression will be used in a destructuring context + // or not. + foreach ($this->createdArrays as $node) { + foreach ($node->items as $item) { + if ($item->value instanceof Expr\Error) { + $this->errorHandler->handleError(new Error('Cannot use empty array elements in arrays', $item->getAttributes())); + } + } + } + // Clear out some of the interior state, so we don't hold onto unnecessary + // memory between uses of the parser + $this->tokenStartStack = []; + $this->tokenEndStack = []; + $this->semStack = []; + $this->semValue = null; + $this->createdArrays = null; + $this->parenthesizedArrowFunctions = null; + if ($result !== null) { + $traverser = new NodeTraverser(new CommentAnnotatingVisitor($this->tokens)); + $traverser->traverse($result); + } + return $result; + } + public function getTokens(): array + { + return $this->tokens; + } + /** @return Stmt[]|null */ + protected function doParse(): ?array + { + // We start off with no lookahead-token + $symbol = self::SYMBOL_NONE; + $tokenValue = null; + $this->tokenPos = -1; + // Keep stack of start and end attributes + $this->tokenStartStack = []; + $this->tokenEndStack = [0]; + // Start off in the initial state and keep a stack of previous states + $state = 0; + $stateStack = [$state]; + // Semantic value stack (contains values of tokens and semantic action results) + $this->semStack = []; + // Current position in the stack(s) + $stackPos = 0; + $this->errorState = 0; + for (;;) { + //$this->traceNewState($state, $symbol); + if ($this->actionBase[$state] === 0) { + $rule = $this->actionDefault[$state]; + } else { + if ($symbol === self::SYMBOL_NONE) { + do { + $token = $this->tokens[++$this->tokenPos]; + $tokenId = $token->id; + } while (isset($this->dropTokens[$tokenId])); + // Map the lexer token id to the internally used symbols. + $tokenValue = $token->text; + if (!isset($this->phpTokenToSymbol[$tokenId])) { + throw new \RangeException(sprintf('The lexer returned an invalid token (id=%d, value=%s)', $tokenId, $tokenValue)); + } + $symbol = $this->phpTokenToSymbol[$tokenId]; + //$this->traceRead($symbol); + } + $idx = $this->actionBase[$state] + $symbol; + if (($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol) && ($action = $this->action[$idx]) !== $this->defaultAction) { + /* + * >= numNonLeafStates: shift and reduce + * > 0: shift + * = 0: accept + * < 0: reduce + * = -YYUNEXPECTED: error + */ + if ($action > 0) { + /* shift */ + //$this->traceShift($symbol); + ++$stackPos; + $stateStack[$stackPos] = $state = $action; + $this->semStack[$stackPos] = $tokenValue; + $this->tokenStartStack[$stackPos] = $this->tokenPos; + $this->tokenEndStack[$stackPos] = $this->tokenPos; + $symbol = self::SYMBOL_NONE; + if ($this->errorState) { + --$this->errorState; + } + if ($action < $this->numNonLeafStates) { + continue; + } + /* $yyn >= numNonLeafStates means shift-and-reduce */ + $rule = $action - $this->numNonLeafStates; + } else { + $rule = -$action; + } + } else { + $rule = $this->actionDefault[$state]; + } + } + for (;;) { + if ($rule === 0) { + /* accept */ + //$this->traceAccept(); + return $this->semValue; + } + if ($rule !== $this->unexpectedTokenRule) { + /* reduce */ + //$this->traceReduce($rule); + $ruleLength = $this->ruleToLength[$rule]; + try { + $callback = $this->reduceCallbacks[$rule]; + if ($callback !== null) { + $callback($this, $stackPos); + } elseif ($ruleLength > 0) { + $this->semValue = $this->semStack[$stackPos - $ruleLength + 1]; + } + } catch (Error $e) { + if (-1 === $e->getStartLine()) { + $e->setStartLine($this->tokens[$this->tokenPos]->line); + } + $this->emitError($e); + // Can't recover from this type of error + return null; + } + /* Goto - shift nonterminal */ + $lastTokenEnd = $this->tokenEndStack[$stackPos]; + $stackPos -= $ruleLength; + $nonTerminal = $this->ruleToNonTerminal[$rule]; + $idx = $this->gotoBase[$nonTerminal] + $stateStack[$stackPos]; + if ($idx >= 0 && $idx < $this->gotoTableSize && $this->gotoCheck[$idx] === $nonTerminal) { + $state = $this->goto[$idx]; + } else { + $state = $this->gotoDefault[$nonTerminal]; + } + ++$stackPos; + $stateStack[$stackPos] = $state; + $this->semStack[$stackPos] = $this->semValue; + $this->tokenEndStack[$stackPos] = $lastTokenEnd; + if ($ruleLength === 0) { + // Empty productions use the start attributes of the lookahead token. + $this->tokenStartStack[$stackPos] = $this->tokenPos; + } + } else { + /* error */ + switch ($this->errorState) { + case 0: + $msg = $this->getErrorMessage($symbol, $state); + $this->emitError(new Error($msg, $this->getAttributesForToken($this->tokenPos))); + // Break missing intentionally + // no break + case 1: + case 2: + $this->errorState = 3; + // Pop until error-expecting state uncovered + while (!(($idx = $this->actionBase[$state] + $this->errorSymbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $this->errorSymbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol) || ($action = $this->action[$idx]) === $this->defaultAction) { + // Not totally sure about this + if ($stackPos <= 0) { + // Could not recover from error + return null; + } + $state = $stateStack[--$stackPos]; + //$this->tracePop($state); + } + //$this->traceShift($this->errorSymbol); + ++$stackPos; + $stateStack[$stackPos] = $state = $action; + // We treat the error symbol as being empty, so we reset the end attributes + // to the end attributes of the last non-error symbol + $this->tokenStartStack[$stackPos] = $this->tokenPos; + $this->tokenEndStack[$stackPos] = $this->tokenEndStack[$stackPos - 1]; + break; + case 3: + if ($symbol === 0) { + // Reached EOF without recovering from error + return null; + } + //$this->traceDiscard($symbol); + $symbol = self::SYMBOL_NONE; + break 2; + } + } + if ($state < $this->numNonLeafStates) { + break; + } + /* >= numNonLeafStates means shift-and-reduce */ + $rule = $state - $this->numNonLeafStates; + } + } + } + protected function emitError(Error $error): void + { + $this->errorHandler->handleError($error); + } + /** + * Format error message including expected tokens. + * + * @param int $symbol Unexpected symbol + * @param int $state State at time of error + * + * @return string Formatted error message + */ + protected function getErrorMessage(int $symbol, int $state): string + { + $expectedString = ''; + if ($expected = $this->getExpectedTokens($state)) { + $expectedString = ', expecting ' . implode(' or ', $expected); + } + return 'Syntax error, unexpected ' . $this->symbolToName[$symbol] . $expectedString; + } + /** + * Get limited number of expected tokens in given state. + * + * @param int $state State + * + * @return string[] Expected tokens. If too many, an empty array is returned. + */ + protected function getExpectedTokens(int $state): array + { + $expected = []; + $base = $this->actionBase[$state]; + foreach ($this->symbolToName as $symbol => $name) { + $idx = $base + $symbol; + if ($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol) { + if ($this->action[$idx] !== $this->unexpectedTokenRule && $this->action[$idx] !== $this->defaultAction && $symbol !== $this->errorSymbol) { + if (count($expected) === 4) { + /* Too many expected tokens */ + return []; + } + $expected[] = $name; + } + } + } + return $expected; + } + /** + * Get attributes for a node with the given start and end token positions. + * + * @param int $tokenStartPos Token position the node starts at + * @param int $tokenEndPos Token position the node ends at + * @return array Attributes + */ + protected function getAttributes(int $tokenStartPos, int $tokenEndPos): array + { + $startToken = $this->tokens[$tokenStartPos]; + $afterEndToken = $this->tokens[$tokenEndPos + 1]; + return ['startLine' => $startToken->line, 'startTokenPos' => $tokenStartPos, 'startFilePos' => $startToken->pos, 'endLine' => $afterEndToken->line, 'endTokenPos' => $tokenEndPos, 'endFilePos' => $afterEndToken->pos - 1]; + } + /** + * Get attributes for a single token at the given token position. + * + * @return array Attributes + */ + protected function getAttributesForToken(int $tokenPos): array + { + if ($tokenPos < \count($this->tokens) - 1) { + return $this->getAttributes($tokenPos, $tokenPos); + } + // Get attributes for the sentinel token. + $token = $this->tokens[$tokenPos]; + return ['startLine' => $token->line, 'startTokenPos' => $tokenPos, 'startFilePos' => $token->pos, 'endLine' => $token->line, 'endTokenPos' => $tokenPos, 'endFilePos' => $token->pos]; + } + /* + * Tracing functions used for debugging the parser. + */ + /* + protected function traceNewState($state, $symbol): void { + echo '% State ' . $state + . ', Lookahead ' . ($symbol == self::SYMBOL_NONE ? '--none--' : $this->symbolToName[$symbol]) . "\n"; + } + + protected function traceRead($symbol): void { + echo '% Reading ' . $this->symbolToName[$symbol] . "\n"; + } + + protected function traceShift($symbol): void { + echo '% Shift ' . $this->symbolToName[$symbol] . "\n"; + } + + protected function traceAccept(): void { + echo "% Accepted.\n"; + } + + protected function traceReduce($n): void { + echo '% Reduce by (' . $n . ') ' . $this->productions[$n] . "\n"; + } + + protected function tracePop($state): void { + echo '% Recovering, uncovered state ' . $state . "\n"; + } + + protected function traceDiscard($symbol): void { + echo '% Discard ' . $this->symbolToName[$symbol] . "\n"; + } + */ + /* + * Helper functions invoked by semantic actions + */ + /** + * Moves statements of semicolon-style namespaces into $ns->stmts and checks various error conditions. + * + * @param Node\Stmt[] $stmts + * @return Node\Stmt[] + */ + protected function handleNamespaces(array $stmts): array + { + $hasErrored = \false; + $style = $this->getNamespacingStyle($stmts); + if (null === $style) { + // not namespaced, nothing to do + return $stmts; + } + if ('brace' === $style) { + // For braced namespaces we only have to check that there are no invalid statements between the namespaces + $afterFirstNamespace = \false; + foreach ($stmts as $stmt) { + if ($stmt instanceof Node\Stmt\Namespace_) { + $afterFirstNamespace = \true; + } elseif (!$stmt instanceof Node\Stmt\HaltCompiler && !$stmt instanceof Node\Stmt\Nop && $afterFirstNamespace && !$hasErrored) { + $this->emitError(new Error('No code may exist outside of namespace {}', $stmt->getAttributes())); + $hasErrored = \true; + // Avoid one error for every statement + } + } + return $stmts; + } else { + // For semicolon namespaces we have to move the statements after a namespace declaration into ->stmts + $resultStmts = []; + $targetStmts =& $resultStmts; + $lastNs = null; + foreach ($stmts as $stmt) { + if ($stmt instanceof Node\Stmt\Namespace_) { + if ($lastNs !== null) { + $this->fixupNamespaceAttributes($lastNs); + } + if ($stmt->stmts === null) { + $stmt->stmts = []; + $targetStmts =& $stmt->stmts; + $resultStmts[] = $stmt; + } else { + // This handles the invalid case of mixed style namespaces + $resultStmts[] = $stmt; + $targetStmts =& $resultStmts; + } + $lastNs = $stmt; + } elseif ($stmt instanceof Node\Stmt\HaltCompiler) { + // __halt_compiler() is not moved into the namespace + $resultStmts[] = $stmt; + } else { + $targetStmts[] = $stmt; + } + } + if ($lastNs !== null) { + $this->fixupNamespaceAttributes($lastNs); + } + return $resultStmts; + } + } + private function fixupNamespaceAttributes(Node\Stmt\Namespace_ $stmt): void + { + // We moved the statements into the namespace node, as such the end of the namespace node + // needs to be extended to the end of the statements. + if (empty($stmt->stmts)) { + return; + } + // We only move the builtin end attributes here. This is the best we can do with the + // knowledge we have. + $endAttributes = ['endLine', 'endFilePos', 'endTokenPos']; + $lastStmt = $stmt->stmts[count($stmt->stmts) - 1]; + foreach ($endAttributes as $endAttribute) { + if ($lastStmt->hasAttribute($endAttribute)) { + $stmt->setAttribute($endAttribute, $lastStmt->getAttribute($endAttribute)); + } + } + } + /** @return array */ + private function getNamespaceErrorAttributes(Namespace_ $node): array + { + $attrs = $node->getAttributes(); + // Adjust end attributes to only cover the "namespace" keyword, not the whole namespace. + if (isset($attrs['startLine'])) { + $attrs['endLine'] = $attrs['startLine']; + } + if (isset($attrs['startTokenPos'])) { + $attrs['endTokenPos'] = $attrs['startTokenPos']; + } + if (isset($attrs['startFilePos'])) { + $attrs['endFilePos'] = $attrs['startFilePos'] + \strlen('namespace') - 1; + } + return $attrs; + } + /** + * Determine namespacing style (semicolon or brace) + * + * @param Node[] $stmts Top-level statements. + * + * @return null|string One of "semicolon", "brace" or null (no namespaces) + */ + private function getNamespacingStyle(array $stmts): ?string + { + $style = null; + $hasNotAllowedStmts = \false; + foreach ($stmts as $i => $stmt) { + if ($stmt instanceof Node\Stmt\Namespace_) { + $currentStyle = null === $stmt->stmts ? 'semicolon' : 'brace'; + if (null === $style) { + $style = $currentStyle; + if ($hasNotAllowedStmts) { + $this->emitError(new Error('Namespace declaration statement has to be the very first statement in the script', $this->getNamespaceErrorAttributes($stmt))); + } + } elseif ($style !== $currentStyle) { + $this->emitError(new Error('Cannot mix bracketed namespace declarations with unbracketed namespace declarations', $this->getNamespaceErrorAttributes($stmt))); + // Treat like semicolon style for namespace normalization + return 'semicolon'; + } + continue; + } + /* declare(), __halt_compiler() and nops can be used before a namespace declaration */ + if ($stmt instanceof Node\Stmt\Declare_ || $stmt instanceof Node\Stmt\HaltCompiler || $stmt instanceof Node\Stmt\Nop) { + continue; + } + /* There may be a hashbang line at the very start of the file */ + if ($i === 0 && $stmt instanceof Node\Stmt\InlineHTML && preg_match('/\A#!.*\r?\n\z/', $stmt->value)) { + continue; + } + /* Everything else if forbidden before namespace declarations */ + $hasNotAllowedStmts = \true; + } + return $style; + } + /** @return Name|Identifier */ + protected function handleBuiltinTypes(Name $name) + { + if (!$name->isUnqualified()) { + return $name; + } + $lowerName = $name->toLowerString(); + if (!$this->phpVersion->supportsBuiltinType($lowerName)) { + return $name; + } + return new Node\Identifier($lowerName, $name->getAttributes()); + } + /** + * Get combined start and end attributes at a stack location + * + * @param int $stackPos Stack location + * + * @return array Combined start and end attributes + */ + protected function getAttributesAt(int $stackPos): array + { + return $this->getAttributes($this->tokenStartStack[$stackPos], $this->tokenEndStack[$stackPos]); + } + protected function getFloatCastKind(string $cast): int + { + $cast = strtolower($cast); + if (strpos($cast, 'float') !== \false) { + return Double::KIND_FLOAT; + } + if (strpos($cast, 'real') !== \false) { + return Double::KIND_REAL; + } + return Double::KIND_DOUBLE; + } + protected function getIntCastKind(string $cast): int + { + $cast = strtolower($cast); + if (strpos($cast, 'integer') !== \false) { + return Expr\Cast\Int_::KIND_INTEGER; + } + return Expr\Cast\Int_::KIND_INT; + } + protected function getBoolCastKind(string $cast): int + { + $cast = strtolower($cast); + if (strpos($cast, 'boolean') !== \false) { + return Expr\Cast\Bool_::KIND_BOOLEAN; + } + return Expr\Cast\Bool_::KIND_BOOL; + } + protected function getStringCastKind(string $cast): int + { + $cast = strtolower($cast); + if (strpos($cast, 'binary') !== \false) { + return Expr\Cast\String_::KIND_BINARY; + } + return Expr\Cast\String_::KIND_STRING; + } + /** @param array $attributes */ + protected function parseLNumber(string $str, array $attributes, bool $allowInvalidOctal = \false): Int_ + { + try { + return Int_::fromString($str, $attributes, $allowInvalidOctal); + } catch (Error $error) { + $this->emitError($error); + // Use dummy value + return new Int_(0, $attributes); + } + } + /** + * Parse a T_NUM_STRING token into either an integer or string node. + * + * @param string $str Number string + * @param array $attributes Attributes + * + * @return Int_|String_ Integer or string node. + */ + protected function parseNumString(string $str, array $attributes) + { + if (!preg_match('/^(?:0|-?[1-9][0-9]*)$/', $str)) { + return new String_($str, $attributes); + } + $num = +$str; + if (!is_int($num)) { + return new String_($str, $attributes); + } + return new Int_($num, $attributes); + } + /** @param array $attributes */ + protected function stripIndentation(string $string, int $indentLen, string $indentChar, bool $newlineAtStart, bool $newlineAtEnd, array $attributes): string + { + if ($indentLen === 0) { + return $string; + } + $start = $newlineAtStart ? '(?:(?<=\n)|\A)' : '(?<=\n)'; + $end = $newlineAtEnd ? '(?:(?=[\r\n])|\z)' : '(?=[\r\n])'; + $regex = '/' . $start . '([ \t]*)(' . $end . ')?/'; + return preg_replace_callback($regex, function ($matches) use ($indentLen, $indentChar, $attributes) { + $prefix = substr($matches[1], 0, $indentLen); + if (\false !== strpos($prefix, $indentChar === " " ? "\t" : " ")) { + $this->emitError(new Error('Invalid indentation - tabs and spaces cannot be mixed', $attributes)); + } elseif (strlen($prefix) < $indentLen && !isset($matches[2])) { + $this->emitError(new Error('Invalid body indentation level ' . '(expecting an indentation level of at least ' . $indentLen . ')', $attributes)); + } + return substr($matches[0], strlen($prefix)); + }, $string); + } + /** + * @param string|(Expr|InterpolatedStringPart)[] $contents + * @param array $attributes + * @param array $endTokenAttributes + */ + protected function parseDocString(string $startToken, $contents, string $endToken, array $attributes, array $endTokenAttributes, bool $parseUnicodeEscape): Expr + { + $kind = strpos($startToken, "'") === \false ? String_::KIND_HEREDOC : String_::KIND_NOWDOC; + $regex = '/\A[bB]?<<<[ \t]*[\'"]?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)[\'"]?(?:\r\n|\n|\r)\z/'; + $result = preg_match($regex, $startToken, $matches); + assert($result === 1); + $label = $matches[1]; + $result = preg_match('/\A[ \t]*/', $endToken, $matches); + assert($result === 1); + $indentation = $matches[0]; + $attributes['kind'] = $kind; + $attributes['docLabel'] = $label; + $attributes['docIndentation'] = $indentation; + $indentHasSpaces = \false !== strpos($indentation, " "); + $indentHasTabs = \false !== strpos($indentation, "\t"); + if ($indentHasSpaces && $indentHasTabs) { + $this->emitError(new Error('Invalid indentation - tabs and spaces cannot be mixed', $endTokenAttributes)); + // Proceed processing as if this doc string is not indented + $indentation = ''; + } + $indentLen = \strlen($indentation); + $indentChar = $indentHasSpaces ? " " : "\t"; + if (\is_string($contents)) { + if ($contents === '') { + $attributes['rawValue'] = $contents; + return new String_('', $attributes); + } + $contents = $this->stripIndentation($contents, $indentLen, $indentChar, \true, \true, $attributes); + $contents = preg_replace('~(\r\n|\n|\r)\z~', '', $contents); + $attributes['rawValue'] = $contents; + if ($kind === String_::KIND_HEREDOC) { + $contents = String_::parseEscapeSequences($contents, null, $parseUnicodeEscape); + } + return new String_($contents, $attributes); + } else { + assert(count($contents) > 0); + if (!$contents[0] instanceof Node\InterpolatedStringPart) { + // If there is no leading encapsed string part, pretend there is an empty one + $this->stripIndentation('', $indentLen, $indentChar, \true, \false, $contents[0]->getAttributes()); + } + $newContents = []; + foreach ($contents as $i => $part) { + if ($part instanceof Node\InterpolatedStringPart) { + $isLast = $i === \count($contents) - 1; + $part->value = $this->stripIndentation($part->value, $indentLen, $indentChar, $i === 0, $isLast, $part->getAttributes()); + if ($isLast) { + $part->value = preg_replace('~(\r\n|\n|\r)\z~', '', $part->value); + } + $part->setAttribute('rawValue', $part->value); + $part->value = String_::parseEscapeSequences($part->value, null, $parseUnicodeEscape); + if ('' === $part->value) { + continue; + } + } + $newContents[] = $part; + } + return new InterpolatedString($newContents, $attributes); + } + } + protected function createCommentFromToken(Token $token, int $tokenPos): Comment + { + assert($token->id === \T_COMMENT || $token->id == \T_DOC_COMMENT); + return \T_DOC_COMMENT === $token->id ? new Comment\Doc($token->text, $token->line, $token->pos, $tokenPos, $token->getEndLine(), $token->getEndPos() - 1, $tokenPos) : new Comment($token->text, $token->line, $token->pos, $tokenPos, $token->getEndLine(), $token->getEndPos() - 1, $tokenPos); + } + /** + * Get last comment before the given token position, if any + */ + protected function getCommentBeforeToken(int $tokenPos): ?Comment + { + while (--$tokenPos >= 0) { + $token = $this->tokens[$tokenPos]; + if (!isset($this->dropTokens[$token->id])) { + break; + } + if ($token->id === \T_COMMENT || $token->id === \T_DOC_COMMENT) { + return $this->createCommentFromToken($token, $tokenPos); + } + } + return null; + } + /** + * Create a zero-length nop to capture preceding comments, if any. + */ + protected function maybeCreateZeroLengthNop(int $tokenPos): ?Nop + { + $comment = $this->getCommentBeforeToken($tokenPos); + if ($comment === null) { + return null; + } + $commentEndLine = $comment->getEndLine(); + $commentEndFilePos = $comment->getEndFilePos(); + $commentEndTokenPos = $comment->getEndTokenPos(); + $attributes = ['startLine' => $commentEndLine, 'endLine' => $commentEndLine, 'startFilePos' => $commentEndFilePos + 1, 'endFilePos' => $commentEndFilePos, 'startTokenPos' => $commentEndTokenPos + 1, 'endTokenPos' => $commentEndTokenPos]; + return new Nop($attributes); + } + protected function maybeCreateNop(int $tokenStartPos, int $tokenEndPos): ?Nop + { + if ($this->getCommentBeforeToken($tokenStartPos) === null) { + return null; + } + return new Nop($this->getAttributes($tokenStartPos, $tokenEndPos)); + } + protected function handleHaltCompiler(): string + { + // Prevent the lexer from returning any further tokens. + $nextToken = $this->tokens[$this->tokenPos + 1]; + $this->tokenPos = \count($this->tokens) - 2; + // Return text after __halt_compiler. + return $nextToken->id === \T_INLINE_HTML ? $nextToken->text : ''; + } + protected function inlineHtmlHasLeadingNewline(int $stackPos): bool + { + $tokenPos = $this->tokenStartStack[$stackPos]; + $token = $this->tokens[$tokenPos]; + assert($token->id == \T_INLINE_HTML); + if ($tokenPos > 0) { + $prevToken = $this->tokens[$tokenPos - 1]; + assert($prevToken->id == \T_CLOSE_TAG); + return \false !== strpos($prevToken->text, "\n") || \false !== strpos($prevToken->text, "\r"); + } + return \true; + } + /** + * @return array + */ + protected function createEmptyElemAttributes(int $tokenPos): array + { + return $this->getAttributesForToken($tokenPos); + } + protected function fixupArrayDestructuring(Array_ $node): Expr\List_ + { + $this->createdArrays->offsetUnset($node); + return new Expr\List_(array_map(function (Node\ArrayItem $item) { + if ($item->value instanceof Expr\Error) { + // We used Error as a placeholder for empty elements, which are legal for destructuring. + return null; + } + if ($item->value instanceof Array_) { + return new Node\ArrayItem($this->fixupArrayDestructuring($item->value), $item->key, $item->byRef, $item->getAttributes()); + } + return $item; + }, $node->items), ['kind' => Expr\List_::KIND_ARRAY] + $node->getAttributes()); + } + protected function postprocessList(Expr\List_ $node): void + { + foreach ($node->items as $i => $item) { + if ($item->value instanceof Expr\Error) { + // We used Error as a placeholder for empty elements, which are legal for destructuring. + $node->items[$i] = null; + } + } + } + /** @param ElseIf_|Else_ $node */ + protected function fixupAlternativeElse($node): void + { + // Make sure a trailing nop statement carrying comments is part of the node. + $numStmts = \count($node->stmts); + if ($numStmts !== 0 && $node->stmts[$numStmts - 1] instanceof Nop) { + $nopAttrs = $node->stmts[$numStmts - 1]->getAttributes(); + if (isset($nopAttrs['endLine'])) { + $node->setAttribute('endLine', $nopAttrs['endLine']); + } + if (isset($nopAttrs['endFilePos'])) { + $node->setAttribute('endFilePos', $nopAttrs['endFilePos']); + } + if (isset($nopAttrs['endTokenPos'])) { + $node->setAttribute('endTokenPos', $nopAttrs['endTokenPos']); + } + } + } + protected function checkClassModifier(int $a, int $b, int $modifierPos): void + { + try { + Modifiers::verifyClassModifier($a, $b); + } catch (Error $error) { + $error->setAttributes($this->getAttributesAt($modifierPos)); + $this->emitError($error); + } + } + protected function checkModifier(int $a, int $b, int $modifierPos): void + { + // Jumping through some hoops here because verifyModifier() is also used elsewhere + try { + Modifiers::verifyModifier($a, $b); + } catch (Error $error) { + $error->setAttributes($this->getAttributesAt($modifierPos)); + $this->emitError($error); + } + } + protected function checkParam(Param $node): void + { + if ($node->variadic && null !== $node->default) { + $this->emitError(new Error('Variadic parameter cannot have a default value', $node->default->getAttributes())); + } + } + protected function checkTryCatch(TryCatch $node): void + { + if (empty($node->catches) && null === $node->finally) { + $this->emitError(new Error('Cannot use try without catch or finally', $node->getAttributes())); + } + } + protected function checkNamespace(Namespace_ $node): void + { + if (null !== $node->stmts) { + foreach ($node->stmts as $stmt) { + if ($stmt instanceof Namespace_) { + $this->emitError(new Error('Namespace declarations cannot be nested', $stmt->getAttributes())); + } + } + } + } + private function checkClassName(?Identifier $name, int $namePos): void + { + if (null !== $name && $name->isSpecialClassName()) { + $this->emitError(new Error(sprintf('Cannot use \'%s\' as class name as it is reserved', $name), $this->getAttributesAt($namePos))); + } + } + /** @param Name[] $interfaces */ + private function checkImplementedInterfaces(array $interfaces): void + { + foreach ($interfaces as $interface) { + if ($interface->isSpecialClassName()) { + $this->emitError(new Error(sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface), $interface->getAttributes())); + } + } + } + protected function checkClass(Class_ $node, int $namePos): void + { + $this->checkClassName($node->name, $namePos); + if ($node->extends && $node->extends->isSpecialClassName()) { + $this->emitError(new Error(sprintf('Cannot use \'%s\' as class name as it is reserved', $node->extends), $node->extends->getAttributes())); + } + $this->checkImplementedInterfaces($node->implements); + } + protected function checkInterface(Interface_ $node, int $namePos): void + { + $this->checkClassName($node->name, $namePos); + $this->checkImplementedInterfaces($node->extends); + } + protected function checkEnum(Enum_ $node, int $namePos): void + { + $this->checkClassName($node->name, $namePos); + $this->checkImplementedInterfaces($node->implements); + } + protected function checkClassMethod(ClassMethod $node, int $modifierPos): void + { + if ($node->flags & Modifiers::STATIC) { + switch ($node->name->toLowerString()) { + case '__construct': + $this->emitError(new Error(sprintf('Constructor %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); + break; + case '__destruct': + $this->emitError(new Error(sprintf('Destructor %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); + break; + case '__clone': + $this->emitError(new Error(sprintf('Clone method %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); + break; + } + } + if ($node->flags & Modifiers::READONLY) { + $this->emitError(new Error(sprintf('Method %s() cannot be readonly', $node->name), $this->getAttributesAt($modifierPos))); + } + } + protected function checkClassConst(ClassConst $node, int $modifierPos): void + { + foreach ([Modifiers::STATIC, Modifiers::ABSTRACT, Modifiers::READONLY] as $modifier) { + if ($node->flags & $modifier) { + $this->emitError(new Error("Cannot use '" . Modifiers::toString($modifier) . "' as constant modifier", $this->getAttributesAt($modifierPos))); + } + } + } + protected function checkUseUse(UseItem $node, int $namePos): void + { + if ($node->alias && $node->alias->isSpecialClassName()) { + $this->emitError(new Error(sprintf('Cannot use %s as %s because \'%2$s\' is a special class name', $node->name, $node->alias), $this->getAttributesAt($namePos))); + } + } + protected function checkPropertyHooksForMultiProperty(Property $property, int $hookPos): void + { + if (count($property->props) > 1) { + $this->emitError(new Error('Cannot use hooks when declaring multiple properties', $this->getAttributesAt($hookPos))); + } + } + /** @param PropertyHook[] $hooks */ + protected function checkEmptyPropertyHookList(array $hooks, int $hookPos): void + { + if (empty($hooks)) { + $this->emitError(new Error('Property hook list cannot be empty', $this->getAttributesAt($hookPos))); + } + } + protected function checkPropertyHook(PropertyHook $hook, ?int $paramListPos): void + { + $name = $hook->name->toLowerString(); + if ($name !== 'get' && $name !== 'set') { + $this->emitError(new Error('Unknown hook "' . $hook->name . '", expected "get" or "set"', $hook->name->getAttributes())); + } + if ($name === 'get' && $paramListPos !== null) { + $this->emitError(new Error('get hook must not have a parameter list', $this->getAttributesAt($paramListPos))); + } + } + protected function checkPropertyHookModifiers(int $a, int $b, int $modifierPos): void + { + try { + Modifiers::verifyModifier($a, $b); + } catch (Error $error) { + $error->setAttributes($this->getAttributesAt($modifierPos)); + $this->emitError($error); + } + if ($b != Modifiers::FINAL) { + $this->emitError(new Error('Cannot use the ' . Modifiers::toString($b) . ' modifier on a property hook', $this->getAttributesAt($modifierPos))); + } + } + protected function checkConstantAttributes(Const_ $node): void + { + if ($node->attrGroups !== [] && count($node->consts) > 1) { + $this->emitError(new Error('Cannot use attributes on multiple constants at once', $node->getAttributes())); + } + } + protected function checkPipeOperatorParentheses(Expr $node): void + { + if ($node instanceof Expr\ArrowFunction && !$this->parenthesizedArrowFunctions->offsetExists($node)) { + $this->emitError(new Error('Arrow functions on the right hand side of |> must be parenthesized', $node->getAttributes())); + } + } + /** + * @param Property|Param $node + */ + protected function addPropertyNameToHooks(Node $node): void + { + if ($node instanceof Property) { + $name = $node->props[0]->name->toString(); + } else { + $name = $node->var->name; + } + foreach ($node->hooks as $hook) { + $hook->setAttribute('propertyName', $name); + } + } + /** @param array $args */ + private function isSimpleExit(array $args): bool + { + if (\count($args) === 0) { + return \true; + } + if (\count($args) === 1) { + $arg = $args[0]; + return $arg instanceof Arg && $arg->name === null && $arg->byRef === \false && $arg->unpack === \false; + } + return \false; + } + /** + * @param array $args + * @param array $attrs + */ + protected function createExitExpr(string $name, int $namePos, array $args, array $attrs): Expr + { + if ($this->isSimpleExit($args)) { + // Create Exit node for backwards compatibility. + $attrs['kind'] = strtolower($name) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE; + return new Expr\Exit_(\count($args) === 1 ? $args[0]->value : null, $attrs); + } + return new Expr\FuncCall(new Name($name, $this->getAttributesAt($namePos)), $args, $attrs); + } + /** + * Creates the token map. + * + * The token map maps the PHP internal token identifiers + * to the identifiers used by the Parser. Additionally it + * maps T_OPEN_TAG_WITH_ECHO to T_ECHO and T_CLOSE_TAG to ';'. + * + * @return array The token map + */ + protected function createTokenMap(): array + { + $tokenMap = []; + // Single-char tokens use an identity mapping. + for ($i = 0; $i < 256; ++$i) { + $tokenMap[$i] = $i; + } + foreach ($this->symbolToName as $name) { + if ($name[0] === 'T') { + $tokenMap[\constant($name)] = constant(static::class . '::' . $name); + } + } + // T_OPEN_TAG_WITH_ECHO with dropped T_OPEN_TAG results in T_ECHO + $tokenMap[\T_OPEN_TAG_WITH_ECHO] = static::T_ECHO; + // T_CLOSE_TAG is equivalent to ';' + $tokenMap[\T_CLOSE_TAG] = ord(';'); + // We have created a map from PHP token IDs to external symbol IDs. + // Now map them to the internal symbol ID. + $fullTokenMap = []; + foreach ($tokenMap as $phpToken => $extSymbol) { + $intSymbol = $this->tokenToSymbol[$extSymbol]; + if ($intSymbol === $this->invalidSymbol) { + continue; + } + $fullTokenMap[$phpToken] = $intSymbol; + } + return $fullTokenMap; + } +} +isHostVersion()) { + $lexer = new Lexer(); + } else { + $lexer = new Lexer\Emulative($version); + } + if ($version->id >= 80000) { + return new Php8($lexer, $version); + } + return new Php7($lexer, $version); + } + /** + * Create a parser targeting the newest version supported by this library. Code for older + * versions will be accepted if there have been no relevant backwards-compatibility breaks in + * PHP. + */ + public function createForNewestSupportedVersion(): Parser + { + return $this->createForVersion(PhpVersion::getNewestSupported()); + } + /** + * Create a parser targeting the host PHP version, that is the PHP version we're currently + * running on. This parser will not use any token emulation. + */ + public function createForHostVersion(): Parser + { + return $this->createForVersion(PhpVersion::getHostVersion()); + } +} + 50100, 'callable' => 50400, 'bool' => 70000, 'int' => 70000, 'float' => 70000, 'string' => 70000, 'iterable' => 70100, 'void' => 70100, 'object' => 70200, 'null' => 80000, 'false' => 80000, 'mixed' => 80000, 'never' => 80100, 'true' => 80200]; + private function __construct(int $id) + { + $this->id = $id; + } + /** + * Create a PhpVersion object from major and minor version components. + */ + public static function fromComponents(int $major, int $minor): self + { + return new self($major * 10000 + $minor * 100); + } + /** + * Get the newest PHP version supported by this library. Support for this version may be partial, + * if it is still under development. + */ + public static function getNewestSupported(): self + { + return self::fromComponents(8, 5); + } + /** + * Get the host PHP version, that is the PHP version we're currently running on. + */ + public static function getHostVersion(): self + { + return self::fromComponents(\PHP_MAJOR_VERSION, \PHP_MINOR_VERSION); + } + /** + * Parse the version from a string like "8.1". + */ + public static function fromString(string $version): self + { + if (!preg_match('/^(\d+)\.(\d+)/', $version, $matches)) { + throw new \LogicException("Invalid PHP version \"{$version}\""); + } + return self::fromComponents((int) $matches[1], (int) $matches[2]); + } + /** + * Check whether two versions are the same. + */ + public function equals(PhpVersion $other): bool + { + return $this->id === $other->id; + } + /** + * Check whether this version is greater than or equal to the argument. + */ + public function newerOrEqual(PhpVersion $other): bool + { + return $this->id >= $other->id; + } + /** + * Check whether this version is older than the argument. + */ + public function older(PhpVersion $other): bool + { + return $this->id < $other->id; + } + /** + * Check whether this is the host PHP version. + */ + public function isHostVersion(): bool + { + return $this->equals(self::getHostVersion()); + } + /** + * Check whether this PHP version supports the given builtin type. Type name must be lowercase. + */ + public function supportsBuiltinType(string $type): bool + { + $minVersion = self::BUILTIN_TYPE_VERSIONS[$type] ?? null; + return $minVersion !== null && $this->id >= $minVersion; + } + /** + * Whether this version supports [] array literals. + */ + public function supportsShortArraySyntax(): bool + { + return $this->id >= 50400; + } + /** + * Whether this version supports [] for destructuring. + */ + public function supportsShortArrayDestructuring(): bool + { + return $this->id >= 70100; + } + /** + * Whether this version supports flexible heredoc/nowdoc. + */ + public function supportsFlexibleHeredoc(): bool + { + return $this->id >= 70300; + } + /** + * Whether this version supports trailing commas in parameter lists. + */ + public function supportsTrailingCommaInParamList(): bool + { + return $this->id >= 80000; + } + /** + * Whether this version allows "$var =& new Obj". + */ + public function allowsAssignNewByReference(): bool + { + return $this->id < 70000; + } + /** + * Whether this version allows invalid octals like "08". + */ + public function allowsInvalidOctals(): bool + { + return $this->id < 70000; + } + /** + * Whether this version allows DEL (\x7f) to occur in identifiers. + */ + public function allowsDelInIdentifiers(): bool + { + return $this->id < 70100; + } + /** + * Whether this version supports yield in expression context without parentheses. + */ + public function supportsYieldWithoutParentheses(): bool + { + return $this->id >= 70000; + } + /** + * Whether this version supports unicode escape sequences in strings. + */ + public function supportsUnicodeEscapes(): bool + { + return $this->id >= 70000; + } + /* + * Whether this version supports attributes. + */ + public function supportsAttributes(): bool + { + return $this->id >= 80000; + } + public function supportsNewDereferenceWithoutParentheses(): bool + { + return $this->id >= 80400; + } +} +pAttrGroups($node->attrGroups, $this->phpVersion->supportsAttributes()) . $this->pModifiers($node->flags) . ($node->type ? $this->p($node->type) . ' ' : '') . ($node->byRef ? '&' : '') . ($node->variadic ? '...' : '') . $this->p($node->var) . ($node->default ? ' = ' . $this->p($node->default) : '') . ($node->hooks ? ' {' . $this->pStmts($node->hooks) . $this->nl . '}' : ''); + } + protected function pArg(Node\Arg $node): string + { + return ($node->name ? $node->name->toString() . ': ' : '') . ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '') . $this->p($node->value); + } + protected function pVariadicPlaceholder(Node\VariadicPlaceholder $node): string + { + return '...'; + } + protected function pConst(Node\Const_ $node): string + { + return $node->name . ' = ' . $this->p($node->value); + } + protected function pNullableType(Node\NullableType $node): string + { + return '?' . $this->p($node->type); + } + protected function pUnionType(Node\UnionType $node): string + { + $types = []; + foreach ($node->types as $typeNode) { + if ($typeNode instanceof Node\IntersectionType) { + $types[] = '(' . $this->p($typeNode) . ')'; + continue; + } + $types[] = $this->p($typeNode); + } + return implode('|', $types); + } + protected function pIntersectionType(Node\IntersectionType $node): string + { + return $this->pImplode($node->types, '&'); + } + protected function pIdentifier(Node\Identifier $node): string + { + return $node->name; + } + protected function pVarLikeIdentifier(Node\VarLikeIdentifier $node): string + { + return '$' . $node->name; + } + protected function pAttribute(Node\Attribute $node): string + { + return $this->p($node->name) . ($node->args ? '(' . $this->pCommaSeparated($node->args) . ')' : ''); + } + protected function pAttributeGroup(Node\AttributeGroup $node): string + { + return '#[' . $this->pCommaSeparated($node->attrs) . ']'; + } + // Names + protected function pName(Name $node): string + { + return $node->name; + } + protected function pName_FullyQualified(Name\FullyQualified $node): string + { + return '\\' . $node->name; + } + protected function pName_Relative(Name\Relative $node): string + { + return 'namespace\\' . $node->name; + } + // Magic Constants + protected function pScalar_MagicConst_Class(MagicConst\Class_ $node): string + { + return '__CLASS__'; + } + protected function pScalar_MagicConst_Dir(MagicConst\Dir $node): string + { + return '__DIR__'; + } + protected function pScalar_MagicConst_File(MagicConst\File $node): string + { + return '__FILE__'; + } + protected function pScalar_MagicConst_Function(MagicConst\Function_ $node): string + { + return '__FUNCTION__'; + } + protected function pScalar_MagicConst_Line(MagicConst\Line $node): string + { + return '__LINE__'; + } + protected function pScalar_MagicConst_Method(MagicConst\Method $node): string + { + return '__METHOD__'; + } + protected function pScalar_MagicConst_Namespace(MagicConst\Namespace_ $node): string + { + return '__NAMESPACE__'; + } + protected function pScalar_MagicConst_Trait(MagicConst\Trait_ $node): string + { + return '__TRAIT__'; + } + protected function pScalar_MagicConst_Property(MagicConst\Property $node): string + { + return '__PROPERTY__'; + } + // Scalars + private function indentString(string $str): string + { + return str_replace("\n", $this->nl, $str); + } + protected function pScalar_String(Scalar\String_ $node): string + { + $kind = $node->getAttribute('kind', Scalar\String_::KIND_SINGLE_QUOTED); + switch ($kind) { + case Scalar\String_::KIND_NOWDOC: + $label = $node->getAttribute('docLabel'); + if ($label && !$this->containsEndLabel($node->value, $label)) { + $shouldIdent = $this->phpVersion->supportsFlexibleHeredoc(); + $nl = $shouldIdent ? $this->nl : $this->newline; + if ($node->value === '') { + return "<<<'{$label}'{$nl}{$label}{$this->docStringEndToken}"; + } + // Make sure trailing \r is not combined with following \n into CRLF. + if ($node->value[strlen($node->value) - 1] !== "\r") { + $value = $shouldIdent ? $this->indentString($node->value) : $node->value; + return "<<<'{$label}'{$nl}{$value}{$nl}{$label}{$this->docStringEndToken}"; + } + } + /* break missing intentionally */ + // no break + case Scalar\String_::KIND_SINGLE_QUOTED: + return $this->pSingleQuotedString($node->value); + case Scalar\String_::KIND_HEREDOC: + $label = $node->getAttribute('docLabel'); + $escaped = $this->escapeString($node->value, null); + if ($label && !$this->containsEndLabel($escaped, $label)) { + $nl = $this->phpVersion->supportsFlexibleHeredoc() ? $this->nl : $this->newline; + if ($escaped === '') { + return "<<<{$label}{$nl}{$label}{$this->docStringEndToken}"; + } + return "<<<{$label}{$nl}{$escaped}{$nl}{$label}{$this->docStringEndToken}"; + } + /* break missing intentionally */ + // no break + case Scalar\String_::KIND_DOUBLE_QUOTED: + return '"' . $this->escapeString($node->value, '"') . '"'; + } + throw new \Exception('Invalid string kind'); + } + protected function pScalar_InterpolatedString(Scalar\InterpolatedString $node): string + { + if ($node->getAttribute('kind') === Scalar\String_::KIND_HEREDOC) { + $label = $node->getAttribute('docLabel'); + if ($label && !$this->encapsedContainsEndLabel($node->parts, $label)) { + $nl = $this->phpVersion->supportsFlexibleHeredoc() ? $this->nl : $this->newline; + if (count($node->parts) === 1 && $node->parts[0] instanceof Node\InterpolatedStringPart && $node->parts[0]->value === '') { + return "<<<{$label}{$nl}{$label}{$this->docStringEndToken}"; + } + return "<<<{$label}{$nl}" . $this->pEncapsList($node->parts, null) . "{$nl}{$label}{$this->docStringEndToken}"; + } + } + return '"' . $this->pEncapsList($node->parts, '"') . '"'; + } + protected function pScalar_Int(Scalar\Int_ $node): string + { + if ($node->getAttribute('shouldPrintRawValue') === \true) { + return $node->getAttribute('rawValue'); + } + if ($node->value === -\PHP_INT_MAX - 1) { + // PHP_INT_MIN cannot be represented as a literal, + // because the sign is not part of the literal + return '(-' . \PHP_INT_MAX . '-1)'; + } + $kind = $node->getAttribute('kind', Scalar\Int_::KIND_DEC); + if (Scalar\Int_::KIND_DEC === $kind) { + return (string) $node->value; + } + if ($node->value < 0) { + $sign = '-'; + $str = (string) -$node->value; + } else { + $sign = ''; + $str = (string) $node->value; + } + switch ($kind) { + case Scalar\Int_::KIND_BIN: + return $sign . '0b' . base_convert($str, 10, 2); + case Scalar\Int_::KIND_OCT: + return $sign . '0' . base_convert($str, 10, 8); + case Scalar\Int_::KIND_HEX: + return $sign . '0x' . base_convert($str, 10, 16); + } + throw new \Exception('Invalid number kind'); + } + protected function pScalar_Float(Scalar\Float_ $node): string + { + if (!is_finite($node->value)) { + if ($node->value === \INF) { + return '1.0E+1000'; + } + if ($node->value === -\INF) { + return '-1.0E+1000'; + } else { + return '\NAN'; + } + } + // Try to find a short full-precision representation + $stringValue = sprintf('%.16G', $node->value); + if ($node->value !== (float) $stringValue) { + $stringValue = sprintf('%.17G', $node->value); + } + // %G is locale dependent and there exists no locale-independent alternative. We don't want + // mess with switching locales here, so let's assume that a comma is the only non-standard + // decimal separator we may encounter... + $stringValue = str_replace(',', '.', $stringValue); + // ensure that number is really printed as float + return preg_match('/^-?[0-9]+$/', $stringValue) ? $stringValue . '.0' : $stringValue; + } + // Assignments + protected function pExpr_Assign(Expr\Assign $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\Assign::class, $this->p($node->var) . ' = ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignRef(Expr\AssignRef $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\AssignRef::class, $this->p($node->var) . ' =& ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_Plus(AssignOp\Plus $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\Plus::class, $this->p($node->var) . ' += ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_Minus(AssignOp\Minus $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\Minus::class, $this->p($node->var) . ' -= ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_Mul(AssignOp\Mul $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\Mul::class, $this->p($node->var) . ' *= ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_Div(AssignOp\Div $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\Div::class, $this->p($node->var) . ' /= ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_Concat(AssignOp\Concat $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\Concat::class, $this->p($node->var) . ' .= ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_Mod(AssignOp\Mod $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\Mod::class, $this->p($node->var) . ' %= ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_BitwiseAnd(AssignOp\BitwiseAnd $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\BitwiseAnd::class, $this->p($node->var) . ' &= ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_BitwiseOr(AssignOp\BitwiseOr $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\BitwiseOr::class, $this->p($node->var) . ' |= ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_BitwiseXor(AssignOp\BitwiseXor $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\BitwiseXor::class, $this->p($node->var) . ' ^= ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_ShiftLeft(AssignOp\ShiftLeft $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\ShiftLeft::class, $this->p($node->var) . ' <<= ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_ShiftRight(AssignOp\ShiftRight $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\ShiftRight::class, $this->p($node->var) . ' >>= ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_Pow(AssignOp\Pow $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\Pow::class, $this->p($node->var) . ' **= ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_AssignOp_Coalesce(AssignOp\Coalesce $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(AssignOp\Coalesce::class, $this->p($node->var) . ' ??= ', $node->expr, $precedence, $lhsPrecedence); + } + // Binary expressions + protected function pExpr_BinaryOp_Plus(BinaryOp\Plus $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Plus::class, $node->left, ' + ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Minus(BinaryOp\Minus $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Minus::class, $node->left, ' - ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Mul(BinaryOp\Mul $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Mul::class, $node->left, ' * ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Div(BinaryOp\Div $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Div::class, $node->left, ' / ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Concat(BinaryOp\Concat $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Concat::class, $node->left, ' . ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Mod(BinaryOp\Mod $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Mod::class, $node->left, ' % ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_BooleanAnd(BinaryOp\BooleanAnd $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\BooleanAnd::class, $node->left, ' && ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_BooleanOr(BinaryOp\BooleanOr $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\BooleanOr::class, $node->left, ' || ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_BitwiseAnd(BinaryOp\BitwiseAnd $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\BitwiseAnd::class, $node->left, ' & ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_BitwiseOr(BinaryOp\BitwiseOr $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\BitwiseOr::class, $node->left, ' | ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_BitwiseXor(BinaryOp\BitwiseXor $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\BitwiseXor::class, $node->left, ' ^ ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_ShiftLeft(BinaryOp\ShiftLeft $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\ShiftLeft::class, $node->left, ' << ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_ShiftRight(BinaryOp\ShiftRight $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\ShiftRight::class, $node->left, ' >> ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Pow(BinaryOp\Pow $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Pow::class, $node->left, ' ** ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_LogicalAnd(BinaryOp\LogicalAnd $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\LogicalAnd::class, $node->left, ' and ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_LogicalOr(BinaryOp\LogicalOr $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\LogicalOr::class, $node->left, ' or ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_LogicalXor(BinaryOp\LogicalXor $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\LogicalXor::class, $node->left, ' xor ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Equal(BinaryOp\Equal $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Equal::class, $node->left, ' == ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_NotEqual(BinaryOp\NotEqual $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\NotEqual::class, $node->left, ' != ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Identical(BinaryOp\Identical $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Identical::class, $node->left, ' === ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_NotIdentical(BinaryOp\NotIdentical $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\NotIdentical::class, $node->left, ' !== ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Spaceship(BinaryOp\Spaceship $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Spaceship::class, $node->left, ' <=> ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Greater(BinaryOp\Greater $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Greater::class, $node->left, ' > ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_GreaterOrEqual(BinaryOp\GreaterOrEqual $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\GreaterOrEqual::class, $node->left, ' >= ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Smaller(BinaryOp\Smaller $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Smaller::class, $node->left, ' < ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_SmallerOrEqual(BinaryOp\SmallerOrEqual $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\SmallerOrEqual::class, $node->left, ' <= ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Coalesce(BinaryOp\Coalesce $node, int $precedence, int $lhsPrecedence): string + { + return $this->pInfixOp(BinaryOp\Coalesce::class, $node->left, ' ?? ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_BinaryOp_Pipe(BinaryOp\Pipe $node, int $precedence, int $lhsPrecedence): string + { + if ($node->right instanceof Expr\ArrowFunction) { + // Force parentheses around arrow functions. + $lhsPrecedence = $this->precedenceMap[Expr\ArrowFunction::class][0]; + } + return $this->pInfixOp(BinaryOp\Pipe::class, $node->left, ' |> ', $node->right, $precedence, $lhsPrecedence); + } + protected function pExpr_Instanceof(Expr\Instanceof_ $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPostfixOp(Expr\Instanceof_::class, $node->expr, ' instanceof ' . $this->pNewOperand($node->class), $precedence, $lhsPrecedence); + } + // Unary expressions + protected function pExpr_BooleanNot(Expr\BooleanNot $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\BooleanNot::class, '!', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_BitwiseNot(Expr\BitwiseNot $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\BitwiseNot::class, '~', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_UnaryMinus(Expr\UnaryMinus $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\UnaryMinus::class, '-', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_UnaryPlus(Expr\UnaryPlus $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\UnaryPlus::class, '+', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_PreInc(Expr\PreInc $node): string + { + return '++' . $this->p($node->var); + } + protected function pExpr_PreDec(Expr\PreDec $node): string + { + return '--' . $this->p($node->var); + } + protected function pExpr_PostInc(Expr\PostInc $node): string + { + return $this->p($node->var) . '++'; + } + protected function pExpr_PostDec(Expr\PostDec $node): string + { + return $this->p($node->var) . '--'; + } + protected function pExpr_ErrorSuppress(Expr\ErrorSuppress $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\ErrorSuppress::class, '@', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_YieldFrom(Expr\YieldFrom $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\YieldFrom::class, 'yield from ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_Print(Expr\Print_ $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\Print_::class, 'print ', $node->expr, $precedence, $lhsPrecedence); + } + // Casts + protected function pExpr_Cast_Int(Cast\Int_ $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Cast\Int_::class, '(int) ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_Cast_Double(Cast\Double $node, int $precedence, int $lhsPrecedence): string + { + $kind = $node->getAttribute('kind', Cast\Double::KIND_DOUBLE); + if ($kind === Cast\Double::KIND_DOUBLE) { + $cast = '(double)'; + } elseif ($kind === Cast\Double::KIND_FLOAT) { + $cast = '(float)'; + } else { + assert($kind === Cast\Double::KIND_REAL); + $cast = '(real)'; + } + return $this->pPrefixOp(Cast\Double::class, $cast . ' ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_Cast_String(Cast\String_ $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Cast\String_::class, '(string) ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_Cast_Array(Cast\Array_ $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Cast\Array_::class, '(array) ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_Cast_Object(Cast\Object_ $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Cast\Object_::class, '(object) ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_Cast_Bool(Cast\Bool_ $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Cast\Bool_::class, '(bool) ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_Cast_Unset(Cast\Unset_ $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Cast\Unset_::class, '(unset) ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_Cast_Void(Cast\Void_ $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Cast\Void_::class, '(void) ', $node->expr, $precedence, $lhsPrecedence); + } + // Function calls and similar constructs + protected function pExpr_FuncCall(Expr\FuncCall $node): string + { + return $this->pCallLhs($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_MethodCall(Expr\MethodCall $node): string + { + return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_NullsafeMethodCall(Expr\NullsafeMethodCall $node): string + { + return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_StaticCall(Expr\StaticCall $node): string + { + return $this->pStaticDereferenceLhs($node->class) . '::' . ($node->name instanceof Expr ? $node->name instanceof Expr\Variable ? $this->p($node->name) : '{' . $this->p($node->name) . '}' : $node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_Empty(Expr\Empty_ $node): string + { + return 'empty(' . $this->p($node->expr) . ')'; + } + protected function pExpr_Isset(Expr\Isset_ $node): string + { + return 'isset(' . $this->pCommaSeparated($node->vars) . ')'; + } + protected function pExpr_Eval(Expr\Eval_ $node): string + { + return 'eval(' . $this->p($node->expr) . ')'; + } + protected function pExpr_Include(Expr\Include_ $node, int $precedence, int $lhsPrecedence): string + { + static $map = [Expr\Include_::TYPE_INCLUDE => 'include', Expr\Include_::TYPE_INCLUDE_ONCE => 'include_once', Expr\Include_::TYPE_REQUIRE => 'require', Expr\Include_::TYPE_REQUIRE_ONCE => 'require_once']; + return $this->pPrefixOp(Expr\Include_::class, $map[$node->type] . ' ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_List(Expr\List_ $node): string + { + $syntax = $node->getAttribute('kind', $this->phpVersion->supportsShortArrayDestructuring() ? Expr\List_::KIND_ARRAY : Expr\List_::KIND_LIST); + if ($syntax === Expr\List_::KIND_ARRAY) { + return '[' . $this->pMaybeMultiline($node->items, \true) . ']'; + } else { + return 'list(' . $this->pMaybeMultiline($node->items, \true) . ')'; + } + } + // Other + protected function pExpr_Error(Expr\Error $node): string + { + throw new \LogicException('Cannot pretty-print AST with Error nodes'); + } + protected function pExpr_Variable(Expr\Variable $node): string + { + if ($node->name instanceof Expr) { + return '${' . $this->p($node->name) . '}'; + } else { + return '$' . $node->name; + } + } + protected function pExpr_Array(Expr\Array_ $node): string + { + $syntax = $node->getAttribute('kind', $this->shortArraySyntax ? Expr\Array_::KIND_SHORT : Expr\Array_::KIND_LONG); + if ($syntax === Expr\Array_::KIND_SHORT) { + return '[' . $this->pMaybeMultiline($node->items, \true) . ']'; + } else { + return 'array(' . $this->pMaybeMultiline($node->items, \true) . ')'; + } + } + protected function pKey(?Node $node): string + { + if ($node === null) { + return ''; + } + // => is not really an operator and does not typically participate in precedence resolution. + // However, there is an exception if yield expressions with keys are involved: + // [yield $a => $b] is interpreted as [(yield $a => $b)], so we need to ensure that + // [(yield $a) => $b] is printed with parentheses. We approximate this by lowering the LHS + // precedence to that of yield (which will also print unnecessary parentheses for rare low + // precedence unary operators like include). + $yieldPrecedence = $this->precedenceMap[Expr\Yield_::class][0]; + return $this->p($node, self::MAX_PRECEDENCE, $yieldPrecedence) . ' => '; + } + protected function pArrayItem(Node\ArrayItem $node): string + { + return $this->pKey($node->key) . ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '') . $this->p($node->value); + } + protected function pExpr_ArrayDimFetch(Expr\ArrayDimFetch $node): string + { + return $this->pDereferenceLhs($node->var) . '[' . (null !== $node->dim ? $this->p($node->dim) : '') . ']'; + } + protected function pExpr_ConstFetch(Expr\ConstFetch $node): string + { + return $this->p($node->name); + } + protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node): string + { + return $this->pStaticDereferenceLhs($node->class) . '::' . $this->pObjectProperty($node->name); + } + protected function pExpr_PropertyFetch(Expr\PropertyFetch $node): string + { + return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name); + } + protected function pExpr_NullsafePropertyFetch(Expr\NullsafePropertyFetch $node): string + { + return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name); + } + protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node): string + { + return $this->pStaticDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name); + } + protected function pExpr_ShellExec(Expr\ShellExec $node): string + { + return '`' . $this->pEncapsList($node->parts, '`') . '`'; + } + protected function pExpr_Closure(Expr\Closure $node): string + { + return $this->pAttrGroups($node->attrGroups, \true) . $this->pStatic($node->static) . 'function ' . ($node->byRef ? '&' : '') . '(' . $this->pParams($node->params) . ')' . (!empty($node->uses) ? ' use (' . $this->pCommaSeparated($node->uses) . ')' : '') . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '') . ' {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pExpr_Match(Expr\Match_ $node): string + { + return 'match (' . $this->p($node->cond) . ') {' . $this->pCommaSeparatedMultiline($node->arms, \true) . $this->nl . '}'; + } + protected function pMatchArm(Node\MatchArm $node): string + { + $result = ''; + if ($node->conds) { + for ($i = 0, $c = \count($node->conds); $i + 1 < $c; $i++) { + $result .= $this->p($node->conds[$i]) . ', '; + } + $result .= $this->pKey($node->conds[$i]); + } else { + $result = 'default => '; + } + return $result . $this->p($node->body); + } + protected function pExpr_ArrowFunction(Expr\ArrowFunction $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\ArrowFunction::class, $this->pAttrGroups($node->attrGroups, \true) . $this->pStatic($node->static) . 'fn' . ($node->byRef ? '&' : '') . '(' . $this->pParams($node->params) . ')' . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '') . ' => ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pClosureUse(Node\ClosureUse $node): string + { + return ($node->byRef ? '&' : '') . $this->p($node->var); + } + protected function pExpr_New(Expr\New_ $node): string + { + if ($node->class instanceof Stmt\Class_) { + $args = $node->args ? '(' . $this->pMaybeMultiline($node->args) . ')' : ''; + return 'new ' . $this->pClassCommon($node->class, $args); + } + return 'new ' . $this->pNewOperand($node->class) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_Clone(Expr\Clone_ $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\Clone_::class, 'clone ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_Ternary(Expr\Ternary $node, int $precedence, int $lhsPrecedence): string + { + // a bit of cheating: we treat the ternary as a binary op where the ?...: part is the operator. + // this is okay because the part between ? and : never needs parentheses. + return $this->pInfixOp(Expr\Ternary::class, $node->cond, ' ?' . (null !== $node->if ? ' ' . $this->p($node->if) . ' ' : '') . ': ', $node->else, $precedence, $lhsPrecedence); + } + protected function pExpr_Exit(Expr\Exit_ $node): string + { + $kind = $node->getAttribute('kind', Expr\Exit_::KIND_DIE); + return ($kind === Expr\Exit_::KIND_EXIT ? 'exit' : 'die') . (null !== $node->expr ? '(' . $this->p($node->expr) . ')' : ''); + } + protected function pExpr_Throw(Expr\Throw_ $node, int $precedence, int $lhsPrecedence): string + { + return $this->pPrefixOp(Expr\Throw_::class, 'throw ', $node->expr, $precedence, $lhsPrecedence); + } + protected function pExpr_Yield(Expr\Yield_ $node, int $precedence, int $lhsPrecedence): string + { + if ($node->value === null) { + $opPrecedence = $this->precedenceMap[Expr\Yield_::class][0]; + return $opPrecedence >= $lhsPrecedence ? '(yield)' : 'yield'; + } else { + if (!$this->phpVersion->supportsYieldWithoutParentheses()) { + return '(yield ' . $this->pKey($node->key) . $this->p($node->value) . ')'; + } + return $this->pPrefixOp(Expr\Yield_::class, 'yield ' . $this->pKey($node->key), $node->value, $precedence, $lhsPrecedence); + } + } + // Declarations + protected function pStmt_Namespace(Stmt\Namespace_ $node): string + { + if ($this->canUseSemicolonNamespaces) { + return 'namespace ' . $this->p($node->name) . ';' . $this->nl . $this->pStmts($node->stmts, \false); + } else { + return 'namespace' . (null !== $node->name ? ' ' . $this->p($node->name) : '') . ' {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + } + protected function pStmt_Use(Stmt\Use_ $node): string + { + return 'use ' . $this->pUseType($node->type) . $this->pCommaSeparated($node->uses) . ';'; + } + protected function pStmt_GroupUse(Stmt\GroupUse $node): string + { + return 'use ' . $this->pUseType($node->type) . $this->pName($node->prefix) . '\{' . $this->pCommaSeparated($node->uses) . '};'; + } + protected function pUseItem(Node\UseItem $node): string + { + return $this->pUseType($node->type) . $this->p($node->name) . (null !== $node->alias ? ' as ' . $node->alias : ''); + } + protected function pUseType(int $type): string + { + return $type === Stmt\Use_::TYPE_FUNCTION ? 'function ' : ($type === Stmt\Use_::TYPE_CONSTANT ? 'const ' : ''); + } + protected function pStmt_Interface(Stmt\Interface_ $node): string + { + return $this->pAttrGroups($node->attrGroups) . 'interface ' . $node->name . (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Enum(Stmt\Enum_ $node): string + { + return $this->pAttrGroups($node->attrGroups) . 'enum ' . $node->name . ($node->scalarType ? ' : ' . $this->p($node->scalarType) : '') . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Class(Stmt\Class_ $node): string + { + return $this->pClassCommon($node, ' ' . $node->name); + } + protected function pStmt_Trait(Stmt\Trait_ $node): string + { + return $this->pAttrGroups($node->attrGroups) . 'trait ' . $node->name . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_EnumCase(Stmt\EnumCase $node): string + { + return $this->pAttrGroups($node->attrGroups) . 'case ' . $node->name . ($node->expr ? ' = ' . $this->p($node->expr) : '') . ';'; + } + protected function pStmt_TraitUse(Stmt\TraitUse $node): string + { + return 'use ' . $this->pCommaSeparated($node->traits) . (empty($node->adaptations) ? ';' : ' {' . $this->pStmts($node->adaptations) . $this->nl . '}'); + } + protected function pStmt_TraitUseAdaptation_Precedence(Stmt\TraitUseAdaptation\Precedence $node): string + { + return $this->p($node->trait) . '::' . $node->method . ' insteadof ' . $this->pCommaSeparated($node->insteadof) . ';'; + } + protected function pStmt_TraitUseAdaptation_Alias(Stmt\TraitUseAdaptation\Alias $node): string + { + return (null !== $node->trait ? $this->p($node->trait) . '::' : '') . $node->method . ' as' . (null !== $node->newModifier ? ' ' . rtrim($this->pModifiers($node->newModifier), ' ') : '') . (null !== $node->newName ? ' ' . $node->newName : '') . ';'; + } + protected function pStmt_Property(Stmt\Property $node): string + { + return $this->pAttrGroups($node->attrGroups) . (0 === $node->flags ? 'var ' : $this->pModifiers($node->flags)) . ($node->type ? $this->p($node->type) . ' ' : '') . $this->pCommaSeparated($node->props) . ($node->hooks ? ' {' . $this->pStmts($node->hooks) . $this->nl . '}' : ';'); + } + protected function pPropertyItem(Node\PropertyItem $node): string + { + return '$' . $node->name . (null !== $node->default ? ' = ' . $this->p($node->default) : ''); + } + protected function pPropertyHook(Node\PropertyHook $node): string + { + return $this->pAttrGroups($node->attrGroups) . $this->pModifiers($node->flags) . ($node->byRef ? '&' : '') . $node->name . ($node->params ? '(' . $this->pParams($node->params) . ')' : '') . (\is_array($node->body) ? ' {' . $this->pStmts($node->body) . $this->nl . '}' : ($node->body !== null ? ' => ' . $this->p($node->body) : '') . ';'); + } + protected function pStmt_ClassMethod(Stmt\ClassMethod $node): string + { + return $this->pAttrGroups($node->attrGroups) . $this->pModifiers($node->flags) . 'function ' . ($node->byRef ? '&' : '') . $node->name . '(' . $this->pParams($node->params) . ')' . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '') . (null !== $node->stmts ? $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}' : ';'); + } + protected function pStmt_ClassConst(Stmt\ClassConst $node): string + { + return $this->pAttrGroups($node->attrGroups) . $this->pModifiers($node->flags) . 'const ' . (null !== $node->type ? $this->p($node->type) . ' ' : '') . $this->pCommaSeparated($node->consts) . ';'; + } + protected function pStmt_Function(Stmt\Function_ $node): string + { + return $this->pAttrGroups($node->attrGroups) . 'function ' . ($node->byRef ? '&' : '') . $node->name . '(' . $this->pParams($node->params) . ')' . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Const(Stmt\Const_ $node): string + { + return $this->pAttrGroups($node->attrGroups) . 'const ' . $this->pCommaSeparated($node->consts) . ';'; + } + protected function pStmt_Declare(Stmt\Declare_ $node): string + { + return 'declare (' . $this->pCommaSeparated($node->declares) . ')' . (null !== $node->stmts ? ' {' . $this->pStmts($node->stmts) . $this->nl . '}' : ';'); + } + protected function pDeclareItem(Node\DeclareItem $node): string + { + return $node->key . '=' . $this->p($node->value); + } + // Control flow + protected function pStmt_If(Stmt\If_ $node): string + { + return 'if (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}' . ($node->elseifs ? ' ' . $this->pImplode($node->elseifs, ' ') : '') . (null !== $node->else ? ' ' . $this->p($node->else) : ''); + } + protected function pStmt_ElseIf(Stmt\ElseIf_ $node): string + { + return 'elseif (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Else(Stmt\Else_ $node): string + { + if (\count($node->stmts) === 1 && $node->stmts[0] instanceof Stmt\If_) { + // Print as "else if" rather than "else { if }" + return 'else ' . $this->p($node->stmts[0]); + } + return 'else {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_For(Stmt\For_ $node): string + { + return 'for (' . $this->pCommaSeparated($node->init) . ';' . (!empty($node->cond) ? ' ' : '') . $this->pCommaSeparated($node->cond) . ';' . (!empty($node->loop) ? ' ' : '') . $this->pCommaSeparated($node->loop) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Foreach(Stmt\Foreach_ $node): string + { + return 'foreach (' . $this->p($node->expr) . ' as ' . (null !== $node->keyVar ? $this->p($node->keyVar) . ' => ' : '') . ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_While(Stmt\While_ $node): string + { + return 'while (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Do(Stmt\Do_ $node): string + { + return 'do {' . $this->pStmts($node->stmts) . $this->nl . '} while (' . $this->p($node->cond) . ');'; + } + protected function pStmt_Switch(Stmt\Switch_ $node): string + { + return 'switch (' . $this->p($node->cond) . ') {' . $this->pStmts($node->cases) . $this->nl . '}'; + } + protected function pStmt_Case(Stmt\Case_ $node): string + { + return (null !== $node->cond ? 'case ' . $this->p($node->cond) : 'default') . ':' . $this->pStmts($node->stmts); + } + protected function pStmt_TryCatch(Stmt\TryCatch $node): string + { + return 'try {' . $this->pStmts($node->stmts) . $this->nl . '}' . ($node->catches ? ' ' . $this->pImplode($node->catches, ' ') : '') . ($node->finally !== null ? ' ' . $this->p($node->finally) : ''); + } + protected function pStmt_Catch(Stmt\Catch_ $node): string + { + return 'catch (' . $this->pImplode($node->types, '|') . ($node->var !== null ? ' ' . $this->p($node->var) : '') . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Finally(Stmt\Finally_ $node): string + { + return 'finally {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Break(Stmt\Break_ $node): string + { + return 'break' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';'; + } + protected function pStmt_Continue(Stmt\Continue_ $node): string + { + return 'continue' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';'; + } + protected function pStmt_Return(Stmt\Return_ $node): string + { + return 'return' . (null !== $node->expr ? ' ' . $this->p($node->expr) : '') . ';'; + } + protected function pStmt_Label(Stmt\Label $node): string + { + return $node->name . ':'; + } + protected function pStmt_Goto(Stmt\Goto_ $node): string + { + return 'goto ' . $node->name . ';'; + } + // Other + protected function pStmt_Expression(Stmt\Expression $node): string + { + return $this->p($node->expr) . ';'; + } + protected function pStmt_Echo(Stmt\Echo_ $node): string + { + return 'echo ' . $this->pCommaSeparated($node->exprs) . ';'; + } + protected function pStmt_Static(Stmt\Static_ $node): string + { + return 'static ' . $this->pCommaSeparated($node->vars) . ';'; + } + protected function pStmt_Global(Stmt\Global_ $node): string + { + return 'global ' . $this->pCommaSeparated($node->vars) . ';'; + } + protected function pStaticVar(Node\StaticVar $node): string + { + return $this->p($node->var) . (null !== $node->default ? ' = ' . $this->p($node->default) : ''); + } + protected function pStmt_Unset(Stmt\Unset_ $node): string + { + return 'unset(' . $this->pCommaSeparated($node->vars) . ');'; + } + protected function pStmt_InlineHTML(Stmt\InlineHTML $node): string + { + $newline = $node->getAttribute('hasLeadingNewline', \true) ? $this->newline : ''; + return '?>' . $newline . $node->value . 'remaining; + } + protected function pStmt_Nop(Stmt\Nop $node): string + { + return ''; + } + protected function pStmt_Block(Stmt\Block $node): string + { + return '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + // Helpers + protected function pClassCommon(Stmt\Class_ $node, string $afterClassToken): string + { + return $this->pAttrGroups($node->attrGroups, $node->name === null) . $this->pModifiers($node->flags) . 'class' . $afterClassToken . (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '') . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pObjectProperty(Node $node): string + { + if ($node instanceof Expr) { + return '{' . $this->p($node) . '}'; + } else { + assert($node instanceof Node\Identifier); + return $node->name; + } + } + /** @param (Expr|Node\InterpolatedStringPart)[] $encapsList */ + protected function pEncapsList(array $encapsList, ?string $quote): string + { + $return = ''; + foreach ($encapsList as $element) { + if ($element instanceof Node\InterpolatedStringPart) { + $return .= $this->escapeString($element->value, $quote); + } else { + $return .= '{' . $this->p($element) . '}'; + } + } + return $return; + } + protected function pSingleQuotedString(string $string): string + { + // It is idiomatic to only escape backslashes when necessary, i.e. when followed by ', \ or + // the end of the string ('Foo\Bar' instead of 'Foo\\Bar'). However, we also don't want to + // produce an odd number of backslashes, so '\\\\a' should not get rendered as '\\\a', even + // though that would be legal. + $regex = '/\'|\\\\(?=[\'\\\\]|$)|(?<=\\\\)\\\\/'; + return '\'' . preg_replace($regex, '\\\\$0', $string) . '\''; + } + protected function escapeString(string $string, ?string $quote): string + { + if (null === $quote) { + // For doc strings, don't escape newlines + $escaped = addcslashes($string, "\t\f\v\$\\"); + // But do escape isolated \r. Combined with the terminating newline, it might get + // interpreted as \r\n and dropped from the string contents. + $escaped = preg_replace('/\r(?!\n)/', '\r', $escaped); + if ($this->phpVersion->supportsFlexibleHeredoc()) { + $escaped = $this->indentString($escaped); + } + } else { + $escaped = addcslashes($string, "\n\r\t\f\v\$" . $quote . "\\"); + } + // Escape control characters and non-UTF-8 characters. + // Regex based on https://stackoverflow.com/a/11709412/385378. + $regex = '/( + [\x00-\x08\x0E-\x1F] # Control characters + | [\xC0-\xC1] # Invalid UTF-8 Bytes + | [\xF5-\xFF] # Invalid UTF-8 Bytes + | \xE0(?=[\x80-\x9F]) # Overlong encoding of prior code point + | \xF0(?=[\x80-\x8F]) # Overlong encoding of prior code point + | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start + | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start + | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start + | (?<=[\x00-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle + | (? $part) { + if ($part instanceof Node\InterpolatedStringPart && $this->containsEndLabel($this->escapeString($part->value, null), $label, $i === 0)) { + return \true; + } + } + return \false; + } + protected function pDereferenceLhs(Node $node): string + { + if (!$this->dereferenceLhsRequiresParens($node)) { + return $this->p($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + protected function pStaticDereferenceLhs(Node $node): string + { + if (!$this->staticDereferenceLhsRequiresParens($node)) { + return $this->p($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + protected function pCallLhs(Node $node): string + { + if (!$this->callLhsRequiresParens($node)) { + return $this->p($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + protected function pNewOperand(Node $node): string + { + if (!$this->newOperandRequiresParens($node)) { + return $this->p($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + /** + * @param Node[] $nodes + */ + protected function hasNodeWithComments(array $nodes): bool + { + foreach ($nodes as $node) { + if ($node && $node->getComments()) { + return \true; + } + } + return \false; + } + /** @param Node[] $nodes */ + protected function pMaybeMultiline(array $nodes, bool $trailingComma = \false): string + { + if (!$this->hasNodeWithComments($nodes)) { + return $this->pCommaSeparated($nodes); + } else { + return $this->pCommaSeparatedMultiline($nodes, $trailingComma) . $this->nl; + } + } + /** @param Node\Param[] $params + */ + private function hasParamWithAttributes(array $params): bool + { + foreach ($params as $param) { + if ($param->attrGroups) { + return \true; + } + } + return \false; + } + /** @param Node\Param[] $params */ + protected function pParams(array $params): string + { + if ($this->hasNodeWithComments($params) || $this->hasParamWithAttributes($params) && !$this->phpVersion->supportsAttributes()) { + return $this->pCommaSeparatedMultiline($params, $this->phpVersion->supportsTrailingCommaInParamList()) . $this->nl; + } + return $this->pCommaSeparated($params); + } + /** @param Node\AttributeGroup[] $nodes */ + protected function pAttrGroups(array $nodes, bool $inline = \false): string + { + $result = ''; + $sep = $inline ? ' ' : $this->nl; + foreach ($nodes as $node) { + $result .= $this->p($node) . $sep; + } + return $result; + } +} + */ + protected array $precedenceMap = [ + // [precedence, precedenceLHS, precedenceRHS] + // Where the latter two are the precedences to use for the LHS and RHS of a binary operator, + // where 1 is added to one of the sides depending on associativity. This information is not + // used for unary operators and set to -1. + Expr\Clone_::class => [-10, 0, 1], + BinaryOp\Pow::class => [0, 0, 1], + Expr\BitwiseNot::class => [10, -1, -1], + Expr\UnaryPlus::class => [10, -1, -1], + Expr\UnaryMinus::class => [10, -1, -1], + Cast\Int_::class => [10, -1, -1], + Cast\Double::class => [10, -1, -1], + Cast\String_::class => [10, -1, -1], + Cast\Array_::class => [10, -1, -1], + Cast\Object_::class => [10, -1, -1], + Cast\Bool_::class => [10, -1, -1], + Cast\Unset_::class => [10, -1, -1], + Expr\ErrorSuppress::class => [10, -1, -1], + Expr\Instanceof_::class => [20, -1, -1], + Expr\BooleanNot::class => [30, -1, -1], + BinaryOp\Mul::class => [40, 41, 40], + BinaryOp\Div::class => [40, 41, 40], + BinaryOp\Mod::class => [40, 41, 40], + BinaryOp\Plus::class => [50, 51, 50], + BinaryOp\Minus::class => [50, 51, 50], + // FIXME: This precedence is incorrect for PHP 8. + BinaryOp\Concat::class => [50, 51, 50], + BinaryOp\ShiftLeft::class => [60, 61, 60], + BinaryOp\ShiftRight::class => [60, 61, 60], + BinaryOp\Pipe::class => [65, 66, 65], + BinaryOp\Smaller::class => [70, 70, 70], + BinaryOp\SmallerOrEqual::class => [70, 70, 70], + BinaryOp\Greater::class => [70, 70, 70], + BinaryOp\GreaterOrEqual::class => [70, 70, 70], + BinaryOp\Equal::class => [80, 80, 80], + BinaryOp\NotEqual::class => [80, 80, 80], + BinaryOp\Identical::class => [80, 80, 80], + BinaryOp\NotIdentical::class => [80, 80, 80], + BinaryOp\Spaceship::class => [80, 80, 80], + BinaryOp\BitwiseAnd::class => [90, 91, 90], + BinaryOp\BitwiseXor::class => [100, 101, 100], + BinaryOp\BitwiseOr::class => [110, 111, 110], + BinaryOp\BooleanAnd::class => [120, 121, 120], + BinaryOp\BooleanOr::class => [130, 131, 130], + BinaryOp\Coalesce::class => [140, 140, 141], + Expr\Ternary::class => [150, 150, 150], + Expr\Assign::class => [160, -1, -1], + Expr\AssignRef::class => [160, -1, -1], + AssignOp\Plus::class => [160, -1, -1], + AssignOp\Minus::class => [160, -1, -1], + AssignOp\Mul::class => [160, -1, -1], + AssignOp\Div::class => [160, -1, -1], + AssignOp\Concat::class => [160, -1, -1], + AssignOp\Mod::class => [160, -1, -1], + AssignOp\BitwiseAnd::class => [160, -1, -1], + AssignOp\BitwiseOr::class => [160, -1, -1], + AssignOp\BitwiseXor::class => [160, -1, -1], + AssignOp\ShiftLeft::class => [160, -1, -1], + AssignOp\ShiftRight::class => [160, -1, -1], + AssignOp\Pow::class => [160, -1, -1], + AssignOp\Coalesce::class => [160, -1, -1], + Expr\YieldFrom::class => [170, -1, -1], + Expr\Yield_::class => [175, -1, -1], + Expr\Print_::class => [180, -1, -1], + BinaryOp\LogicalAnd::class => [190, 191, 190], + BinaryOp\LogicalXor::class => [200, 201, 200], + BinaryOp\LogicalOr::class => [210, 211, 210], + Expr\Include_::class => [220, -1, -1], + Expr\ArrowFunction::class => [230, -1, -1], + Expr\Throw_::class => [240, -1, -1], + Expr\Cast\Void_::class => [250, -1, -1], + ]; + /** @var int Current indentation level. */ + protected int $indentLevel; + /** @var string String for single level of indentation */ + private string $indent; + /** @var int Width in spaces to indent by. */ + private int $indentWidth; + /** @var bool Whether to use tab indentation. */ + private bool $useTabs; + /** @var int Width in spaces of one tab. */ + private int $tabWidth = 4; + /** @var string Newline style. Does not include current indentation. */ + protected string $newline; + /** @var string Newline including current indentation. */ + protected string $nl; + /** @var string|null Token placed at end of doc string to ensure it is followed by a newline. + * Null if flexible doc strings are used. */ + protected ?string $docStringEndToken; + /** @var bool Whether semicolon namespaces can be used (i.e. no global namespace is used) */ + protected bool $canUseSemicolonNamespaces; + /** @var bool Whether to use short array syntax if the node specifies no preference */ + protected bool $shortArraySyntax; + /** @var PhpVersion PHP version to target */ + protected PhpVersion $phpVersion; + /** @var TokenStream|null Original tokens for use in format-preserving pretty print */ + protected ?TokenStream $origTokens; + /** @var Internal\Differ Differ for node lists */ + protected Differ $nodeListDiffer; + /** @var array Map determining whether a certain character is a label character */ + protected array $labelCharMap; + /** + * @var array> Map from token classes and subnode names to FIXUP_* constants. + * This is used during format-preserving prints to place additional parens/braces if necessary. + */ + protected array $fixupMap; + /** + * @var array Map from "{$node->getType()}->{$subNode}" + * to ['left' => $l, 'right' => $r], where $l and $r specify the token type that needs to be stripped + * when removing this node. + */ + protected array $removalMap; + /** + * @var array Map from + * "{$node->getType()}->{$subNode}" to [$find, $beforeToken, $extraLeft, $extraRight]. + * $find is an optional token after which the insertion occurs. $extraLeft/Right + * are optionally added before/after the main insertions. + */ + protected array $insertionMap; + /** + * @var array Map From "{$class}->{$subNode}" to string that should be inserted + * between elements of this list subnode. + */ + protected array $listInsertionMap; + /** + * @var array + */ + protected array $emptyListInsertionMap; + /** @var array + * Map from "{$class}->{$subNode}" to [$printFn, $skipToken, $findToken] where $printFn is the function to + * print the modifiers, $skipToken is the token to skip at the start and $findToken is the token before which + * the modifiers should be reprinted. */ + protected array $modifierChangeMap; + /** + * Creates a pretty printer instance using the given options. + * + * Supported options: + * * PhpVersion $phpVersion: The PHP version to target (default to PHP 7.4). This option + * controls compatibility of the generated code with older PHP + * versions in cases where a simple stylistic choice exists (e.g. + * array() vs []). It is safe to pretty-print an AST for a newer + * PHP version while specifying an older target (but the result will + * of course not be compatible with the older version in that case). + * * string $newline: The newline style to use. Should be "\n" (default) or "\r\n". + * * string $indent: The indentation to use. Should either be all spaces or a single + * tab. Defaults to four spaces (" "). + * * bool $shortArraySyntax: Whether to use [] instead of array() as the default array + * syntax, if the node does not specify a format. Defaults to whether + * the phpVersion support short array syntax. + * + * @param array{ + * phpVersion?: PhpVersion, newline?: string, indent?: string, shortArraySyntax?: bool + * } $options Dictionary of formatting options + */ + public function __construct(array $options = []) + { + $this->phpVersion = $options['phpVersion'] ?? PhpVersion::fromComponents(7, 4); + $this->newline = $options['newline'] ?? "\n"; + if ($this->newline !== "\n" && $this->newline != "\r\n") { + throw new \LogicException('Option "newline" must be one of "\n" or "\r\n"'); + } + $this->shortArraySyntax = $options['shortArraySyntax'] ?? $this->phpVersion->supportsShortArraySyntax(); + $this->docStringEndToken = $this->phpVersion->supportsFlexibleHeredoc() ? null : '_DOC_STRING_END_' . mt_rand(); + $this->indent = $indent = $options['indent'] ?? ' '; + if ($indent === "\t") { + $this->useTabs = \true; + $this->indentWidth = $this->tabWidth; + } elseif ($indent === \str_repeat(' ', \strlen($indent))) { + $this->useTabs = \false; + $this->indentWidth = \strlen($indent); + } else { + throw new \LogicException('Option "indent" must either be all spaces or a single tab'); + } + } + /** + * Reset pretty printing state. + */ + protected function resetState(): void + { + $this->indentLevel = 0; + $this->nl = $this->newline; + $this->origTokens = null; + } + /** + * Set indentation level + * + * @param int $level Level in number of spaces + */ + protected function setIndentLevel(int $level): void + { + $this->indentLevel = $level; + if ($this->useTabs) { + $tabs = \intdiv($level, $this->tabWidth); + $spaces = $level % $this->tabWidth; + $this->nl = $this->newline . \str_repeat("\t", $tabs) . \str_repeat(' ', $spaces); + } else { + $this->nl = $this->newline . \str_repeat(' ', $level); + } + } + /** + * Increase indentation level. + */ + protected function indent(): void + { + $this->indentLevel += $this->indentWidth; + $this->nl .= $this->indent; + } + /** + * Decrease indentation level. + */ + protected function outdent(): void + { + assert($this->indentLevel >= $this->indentWidth); + $this->setIndentLevel($this->indentLevel - $this->indentWidth); + } + /** + * Pretty prints an array of statements. + * + * @param Node[] $stmts Array of statements + * + * @return string Pretty printed statements + */ + public function prettyPrint(array $stmts): string + { + $this->resetState(); + $this->preprocessNodes($stmts); + return ltrim($this->handleMagicTokens($this->pStmts($stmts, \false))); + } + /** + * Pretty prints an expression. + * + * @param Expr $node Expression node + * + * @return string Pretty printed node + */ + public function prettyPrintExpr(Expr $node): string + { + $this->resetState(); + return $this->handleMagicTokens($this->p($node)); + } + /** + * Pretty prints a file of statements (includes the opening newline . $this->newline; + } + $p = "newline . $this->newline . $this->prettyPrint($stmts); + if ($stmts[0] instanceof Stmt\InlineHTML) { + $p = preg_replace('/^<\?php\s+\?>\r?\n?/', '', $p); + } + if ($stmts[count($stmts) - 1] instanceof Stmt\InlineHTML) { + $p = preg_replace('/<\?php$/', '', rtrim($p)); + } + return $p; + } + /** + * Preprocesses the top-level nodes to initialize pretty printer state. + * + * @param Node[] $nodes Array of nodes + */ + protected function preprocessNodes(array $nodes): void + { + /* We can use semicolon-namespaces unless there is a global namespace declaration */ + $this->canUseSemicolonNamespaces = \true; + foreach ($nodes as $node) { + if ($node instanceof Stmt\Namespace_ && null === $node->name) { + $this->canUseSemicolonNamespaces = \false; + break; + } + } + } + /** + * Handles (and removes) doc-string-end tokens. + */ + protected function handleMagicTokens(string $str): string + { + if ($this->docStringEndToken !== null) { + // Replace doc-string-end tokens with nothing or a newline + $str = str_replace($this->docStringEndToken . ';' . $this->newline, ';' . $this->newline, $str); + $str = str_replace($this->docStringEndToken, $this->newline, $str); + } + return $str; + } + /** + * Pretty prints an array of nodes (statements) and indents them optionally. + * + * @param Node[] $nodes Array of nodes + * @param bool $indent Whether to indent the printed nodes + * + * @return string Pretty printed statements + */ + protected function pStmts(array $nodes, bool $indent = \true): string + { + if ($indent) { + $this->indent(); + } + $result = ''; + foreach ($nodes as $node) { + $comments = $node->getComments(); + if ($comments) { + $result .= $this->nl . $this->pComments($comments); + if ($node instanceof Stmt\Nop) { + continue; + } + } + $result .= $this->nl . $this->p($node); + } + if ($indent) { + $this->outdent(); + } + return $result; + } + /** + * Pretty-print an infix operation while taking precedence into account. + * + * @param string $class Node class of operator + * @param Node $leftNode Left-hand side node + * @param string $operatorString String representation of the operator + * @param Node $rightNode Right-hand side node + * @param int $precedence Precedence of parent operator + * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator + * + * @return string Pretty printed infix operation + */ + protected function pInfixOp(string $class, Node $leftNode, string $operatorString, Node $rightNode, int $precedence, int $lhsPrecedence): string + { + list($opPrecedence, $newPrecedenceLHS, $newPrecedenceRHS) = $this->precedenceMap[$class]; + $prefix = ''; + $suffix = ''; + if ($opPrecedence >= $precedence) { + $prefix = '('; + $suffix = ')'; + $lhsPrecedence = self::MAX_PRECEDENCE; + } + return $prefix . $this->p($leftNode, $newPrecedenceLHS, $newPrecedenceLHS) . $operatorString . $this->p($rightNode, $newPrecedenceRHS, $lhsPrecedence) . $suffix; + } + /** + * Pretty-print a prefix operation while taking precedence into account. + * + * @param string $class Node class of operator + * @param string $operatorString String representation of the operator + * @param Node $node Node + * @param int $precedence Precedence of parent operator + * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator + * + * @return string Pretty printed prefix operation + */ + protected function pPrefixOp(string $class, string $operatorString, Node $node, int $precedence, int $lhsPrecedence): string + { + $opPrecedence = $this->precedenceMap[$class][0]; + $prefix = ''; + $suffix = ''; + if ($opPrecedence >= $lhsPrecedence) { + $prefix = '('; + $suffix = ')'; + $lhsPrecedence = self::MAX_PRECEDENCE; + } + $printedArg = $this->p($node, $opPrecedence, $lhsPrecedence); + if ($operatorString === '+' && $printedArg[0] === '+' || $operatorString === '-' && $printedArg[0] === '-') { + // Avoid printing +(+$a) as ++$a and similar. + $printedArg = '(' . $printedArg . ')'; + } + return $prefix . $operatorString . $printedArg . $suffix; + } + /** + * Pretty-print a postfix operation while taking precedence into account. + * + * @param string $class Node class of operator + * @param string $operatorString String representation of the operator + * @param Node $node Node + * @param int $precedence Precedence of parent operator + * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator + * + * @return string Pretty printed postfix operation + */ + protected function pPostfixOp(string $class, Node $node, string $operatorString, int $precedence, int $lhsPrecedence): string + { + $opPrecedence = $this->precedenceMap[$class][0]; + $prefix = ''; + $suffix = ''; + if ($opPrecedence >= $precedence) { + $prefix = '('; + $suffix = ')'; + $lhsPrecedence = self::MAX_PRECEDENCE; + } + if ($opPrecedence < $lhsPrecedence) { + $lhsPrecedence = $opPrecedence; + } + return $prefix . $this->p($node, $opPrecedence, $lhsPrecedence) . $operatorString . $suffix; + } + /** + * Pretty prints an array of nodes and implodes the printed values. + * + * @param Node[] $nodes Array of Nodes to be printed + * @param string $glue Character to implode with + * + * @return string Imploded pretty printed nodes> $pre + */ + protected function pImplode(array $nodes, string $glue = ''): string + { + $pNodes = []; + foreach ($nodes as $node) { + if (null === $node) { + $pNodes[] = ''; + } else { + $pNodes[] = $this->p($node); + } + } + return implode($glue, $pNodes); + } + /** + * Pretty prints an array of nodes and implodes the printed values with commas. + * + * @param Node[] $nodes Array of Nodes to be printed + * + * @return string Comma separated pretty printed nodes + */ + protected function pCommaSeparated(array $nodes): string + { + return $this->pImplode($nodes, ', '); + } + /** + * Pretty prints a comma-separated list of nodes in multiline style, including comments. + * + * The result includes a leading newline and one level of indentation (same as pStmts). + * + * @param Node[] $nodes Array of Nodes to be printed + * @param bool $trailingComma Whether to use a trailing comma + * + * @return string Comma separated pretty printed nodes in multiline style + */ + protected function pCommaSeparatedMultiline(array $nodes, bool $trailingComma): string + { + $this->indent(); + $result = ''; + $lastIdx = count($nodes) - 1; + foreach ($nodes as $idx => $node) { + if ($node !== null) { + $comments = $node->getComments(); + if ($comments) { + $result .= $this->nl . $this->pComments($comments); + } + $result .= $this->nl . $this->p($node); + } else { + $result .= $this->nl; + } + if ($trailingComma || $idx !== $lastIdx) { + $result .= ','; + } + } + $this->outdent(); + return $result; + } + /** + * Prints reformatted text of the passed comments. + * + * @param Comment[] $comments List of comments + * + * @return string Reformatted text of comments + */ + protected function pComments(array $comments): string + { + $formattedComments = []; + foreach ($comments as $comment) { + $formattedComments[] = str_replace("\n", $this->nl, $comment->getReformattedText()); + } + return implode($this->nl, $formattedComments); + } + /** + * Perform a format-preserving pretty print of an AST. + * + * The format preservation is best effort. For some changes to the AST the formatting will not + * be preserved (at least not locally). + * + * In order to use this method a number of prerequisites must be satisfied: + * * The startTokenPos and endTokenPos attributes in the lexer must be enabled. + * * The CloningVisitor must be run on the AST prior to modification. + * * The original tokens must be provided, using the getTokens() method on the lexer. + * + * @param Node[] $stmts Modified AST with links to original AST + * @param Node[] $origStmts Original AST with token offset information + * @param Token[] $origTokens Tokens of the original code + */ + public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens): string + { + $this->initializeNodeListDiffer(); + $this->initializeLabelCharMap(); + $this->initializeFixupMap(); + $this->initializeRemovalMap(); + $this->initializeInsertionMap(); + $this->initializeListInsertionMap(); + $this->initializeEmptyListInsertionMap(); + $this->initializeModifierChangeMap(); + $this->resetState(); + $this->origTokens = new TokenStream($origTokens, $this->tabWidth); + $this->preprocessNodes($stmts); + $pos = 0; + $result = $this->pArray($stmts, $origStmts, $pos, 0, 'File', 'stmts', null); + if (null !== $result) { + $result .= $this->origTokens->getTokenCode($pos, count($origTokens) - 1, 0); + } else { + // Fallback + // TODO Add newline . $this->pStmts($stmts, \false); + } + return $this->handleMagicTokens($result); + } + protected function pFallback(Node $node, int $precedence, int $lhsPrecedence): string + { + return $this->{'p' . $node->getType()}($node, $precedence, $lhsPrecedence); + } + /** + * Pretty prints a node. + * + * This method also handles formatting preservation for nodes. + * + * @param Node $node Node to be pretty printed + * @param int $precedence Precedence of parent operator + * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator + * @param bool $parentFormatPreserved Whether parent node has preserved formatting + * + * @return string Pretty printed node + */ + protected function p(Node $node, int $precedence = self::MAX_PRECEDENCE, int $lhsPrecedence = self::MAX_PRECEDENCE, bool $parentFormatPreserved = \false): string + { + // No orig tokens means this is a normal pretty print without preservation of formatting + if (!$this->origTokens) { + return $this->{'p' . $node->getType()}($node, $precedence, $lhsPrecedence); + } + /** @var Node|null $origNode */ + $origNode = $node->getAttribute('origNode'); + if (null === $origNode) { + return $this->pFallback($node, $precedence, $lhsPrecedence); + } + $class = \get_class($node); + \assert($class === \get_class($origNode)); + $startPos = $origNode->getStartTokenPos(); + $endPos = $origNode->getEndTokenPos(); + \assert($startPos >= 0 && $endPos >= 0); + $fallbackNode = $node; + if ($node instanceof Expr\New_ && $node->class instanceof Stmt\Class_) { + // Normalize node structure of anonymous classes + assert($origNode instanceof Expr\New_); + $node = PrintableNewAnonClassNode::fromNewNode($node); + $origNode = PrintableNewAnonClassNode::fromNewNode($origNode); + $class = PrintableNewAnonClassNode::class; + } + // InlineHTML node does not contain closing and opening PHP tags. If the parent formatting + // is not preserved, then we need to use the fallback code to make sure the tags are + // printed. + if ($node instanceof Stmt\InlineHTML && !$parentFormatPreserved) { + return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence); + } + $indentAdjustment = $this->indentLevel - $this->origTokens->getIndentationBefore($startPos); + $type = $node->getType(); + $fixupInfo = $this->fixupMap[$class] ?? null; + $result = ''; + $pos = $startPos; + foreach ($node->getSubNodeNames() as $subNodeName) { + $subNode = $node->{$subNodeName}; + $origSubNode = $origNode->{$subNodeName}; + if (!$subNode instanceof Node && $subNode !== null || !$origSubNode instanceof Node && $origSubNode !== null) { + if ($subNode === $origSubNode) { + // Unchanged, can reuse old code + continue; + } + if (is_array($subNode) && is_array($origSubNode)) { + // Array subnode changed, we might be able to reconstruct it + $listResult = $this->pArray($subNode, $origSubNode, $pos, $indentAdjustment, $class, $subNodeName, $fixupInfo[$subNodeName] ?? null); + if (null === $listResult) { + return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence); + } + $result .= $listResult; + continue; + } + // Check if this is a modifier change + $key = $class . '->' . $subNodeName; + if (!isset($this->modifierChangeMap[$key])) { + return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence); + } + [$printFn, $skipToken, $findToken] = $this->modifierChangeMap[$key]; + $skipWSPos = $this->origTokens->skipRight($pos, $skipToken); + $result .= $this->origTokens->getTokenCode($pos, $skipWSPos, $indentAdjustment); + $result .= $this->{$printFn}($subNode); + $pos = $this->origTokens->findRight($skipWSPos, $findToken); + continue; + } + $extraLeft = ''; + $extraRight = ''; + if ($origSubNode !== null) { + $subStartPos = $origSubNode->getStartTokenPos(); + $subEndPos = $origSubNode->getEndTokenPos(); + \assert($subStartPos >= 0 && $subEndPos >= 0); + } else { + if ($subNode === null) { + // Both null, nothing to do + continue; + } + // A node has been inserted, check if we have insertion information for it + $key = $type . '->' . $subNodeName; + if (!isset($this->insertionMap[$key])) { + return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence); + } + list($findToken, $beforeToken, $extraLeft, $extraRight) = $this->insertionMap[$key]; + if (null !== $findToken) { + $subStartPos = $this->origTokens->findRight($pos, $findToken) + (int) !$beforeToken; + } else { + $subStartPos = $pos; + } + if (null === $extraLeft && null !== $extraRight) { + // If inserting on the right only, skipping whitespace looks better + $subStartPos = $this->origTokens->skipRightWhitespace($subStartPos); + } + $subEndPos = $subStartPos - 1; + } + if (null === $subNode) { + // A node has been removed, check if we have removal information for it + $key = $type . '->' . $subNodeName; + if (!isset($this->removalMap[$key])) { + return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence); + } + // Adjust positions to account for additional tokens that must be skipped + $removalInfo = $this->removalMap[$key]; + if (isset($removalInfo['left'])) { + $subStartPos = $this->origTokens->skipLeft($subStartPos - 1, $removalInfo['left']) + 1; + } + if (isset($removalInfo['right'])) { + $subEndPos = $this->origTokens->skipRight($subEndPos + 1, $removalInfo['right']) - 1; + } + } + $result .= $this->origTokens->getTokenCode($pos, $subStartPos, $indentAdjustment); + if (null !== $subNode) { + $result .= $extraLeft; + $origIndentLevel = $this->indentLevel; + $this->setIndentLevel(max($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment, 0)); + // If it's the same node that was previously in this position, it certainly doesn't + // need fixup. It's important to check this here, because our fixup checks are more + // conservative than strictly necessary. + if (isset($fixupInfo[$subNodeName]) && $subNode->getAttribute('origNode') !== $origSubNode) { + $fixup = $fixupInfo[$subNodeName]; + $res = $this->pFixup($fixup, $subNode, $class, $subStartPos, $subEndPos); + } else { + $res = $this->p($subNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, \true); + } + $this->safeAppend($result, $res); + $this->setIndentLevel($origIndentLevel); + $result .= $extraRight; + } + $pos = $subEndPos + 1; + } + $result .= $this->origTokens->getTokenCode($pos, $endPos + 1, $indentAdjustment); + return $result; + } + /** + * Perform a format-preserving pretty print of an array. + * + * @param Node[] $nodes New nodes + * @param Node[] $origNodes Original nodes + * @param int $pos Current token position (updated by reference) + * @param int $indentAdjustment Adjustment for indentation + * @param string $parentNodeClass Class of the containing node. + * @param string $subNodeName Name of array subnode. + * @param null|int $fixup Fixup information for array item nodes + * + * @return null|string Result of pretty print or null if cannot preserve formatting + */ + protected function pArray(array $nodes, array $origNodes, int &$pos, int $indentAdjustment, string $parentNodeClass, string $subNodeName, ?int $fixup): ?string + { + $diff = $this->nodeListDiffer->diffWithReplacements($origNodes, $nodes); + $mapKey = $parentNodeClass . '->' . $subNodeName; + $insertStr = $this->listInsertionMap[$mapKey] ?? null; + $isStmtList = $subNodeName === 'stmts'; + $beforeFirstKeepOrReplace = \true; + $skipRemovedNode = \false; + $delayedAdd = []; + $lastElemIndentLevel = $this->indentLevel; + $insertNewline = \false; + if ($insertStr === "\n") { + $insertStr = ''; + $insertNewline = \true; + } + if ($isStmtList && \count($origNodes) === 1 && \count($nodes) !== 1) { + $startPos = $origNodes[0]->getStartTokenPos(); + $endPos = $origNodes[0]->getEndTokenPos(); + \assert($startPos >= 0 && $endPos >= 0); + if (!$this->origTokens->haveBraces($startPos, $endPos)) { + // This was a single statement without braces, but either additional statements + // have been added, or the single statement has been removed. This requires the + // addition of braces. For now fall back. + // TODO: Try to preserve formatting + return null; + } + } + $result = ''; + foreach ($diff as $i => $diffElem) { + $diffType = $diffElem->type; + /** @var Node|string|null $arrItem */ + $arrItem = $diffElem->new; + /** @var Node|string|null $origArrItem */ + $origArrItem = $diffElem->old; + if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) { + $beforeFirstKeepOrReplace = \false; + if ($origArrItem === null || $arrItem === null) { + // We can only handle the case where both are null + if ($origArrItem === $arrItem) { + continue; + } + return null; + } + if (!$arrItem instanceof Node || !$origArrItem instanceof Node) { + // We can only deal with nodes. This can occur for Names, which use string arrays. + return null; + } + $itemStartPos = $origArrItem->getStartTokenPos(); + $itemEndPos = $origArrItem->getEndTokenPos(); + \assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos); + $origIndentLevel = $this->indentLevel; + $lastElemIndentLevel = max($this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment, 0); + $this->setIndentLevel($lastElemIndentLevel); + $comments = $arrItem->getComments(); + $origComments = $origArrItem->getComments(); + $commentStartPos = $origComments ? $origComments[0]->getStartTokenPos() : $itemStartPos; + \assert($commentStartPos >= 0); + if ($commentStartPos < $pos) { + // Comments may be assigned to multiple nodes if they start at the same position. + // Make sure we don't try to print them multiple times. + $commentStartPos = $itemStartPos; + } + if ($skipRemovedNode) { + if ($isStmtList && $this->origTokens->haveTagInRange($pos, $itemStartPos)) { + // We'd remove an opening/closing PHP tag. + // TODO: Preserve formatting. + $this->setIndentLevel($origIndentLevel); + return null; + } + } else { + $result .= $this->origTokens->getTokenCode($pos, $commentStartPos, $indentAdjustment); + } + if (!empty($delayedAdd)) { + /** @var Node $delayedAddNode */ + foreach ($delayedAdd as $delayedAddNode) { + if ($insertNewline) { + $delayedAddComments = $delayedAddNode->getComments(); + if ($delayedAddComments) { + $result .= $this->pComments($delayedAddComments) . $this->nl; + } + } + $this->safeAppend($result, $this->p($delayedAddNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, \true)); + if ($insertNewline) { + $result .= $insertStr . $this->nl; + } else { + $result .= $insertStr; + } + } + $delayedAdd = []; + } + if ($comments !== $origComments) { + if ($comments) { + $result .= $this->pComments($comments) . $this->nl; + } + } else { + $result .= $this->origTokens->getTokenCode($commentStartPos, $itemStartPos, $indentAdjustment); + } + // If we had to remove anything, we have done so now. + $skipRemovedNode = \false; + } elseif ($diffType === DiffElem::TYPE_ADD) { + if (null === $insertStr) { + // We don't have insertion information for this list type + return null; + } + if (!$arrItem instanceof Node) { + // We only support list insertion of nodes. + return null; + } + // We go multiline if the original code was multiline, + // or if it's an array item with a comment above it. + // Match always uses multiline formatting. + if ($insertStr === ', ' && ($this->isMultiline($origNodes) || $arrItem->getComments() || $parentNodeClass === Expr\Match_::class)) { + $insertStr = ','; + $insertNewline = \true; + } + if ($beforeFirstKeepOrReplace) { + // Will be inserted at the next "replace" or "keep" element + $delayedAdd[] = $arrItem; + continue; + } + $itemStartPos = $pos; + $itemEndPos = $pos - 1; + $origIndentLevel = $this->indentLevel; + $this->setIndentLevel($lastElemIndentLevel); + if ($insertNewline) { + $result .= $insertStr . $this->nl; + $comments = $arrItem->getComments(); + if ($comments) { + $result .= $this->pComments($comments) . $this->nl; + } + } else { + $result .= $insertStr; + } + } elseif ($diffType === DiffElem::TYPE_REMOVE) { + if (!$origArrItem instanceof Node) { + // We only support removal for nodes + return null; + } + $itemStartPos = $origArrItem->getStartTokenPos(); + $itemEndPos = $origArrItem->getEndTokenPos(); + \assert($itemStartPos >= 0 && $itemEndPos >= 0); + // Consider comments part of the node. + $origComments = $origArrItem->getComments(); + if ($origComments) { + $itemStartPos = $origComments[0]->getStartTokenPos(); + } + if ($i === 0) { + // If we're removing from the start, keep the tokens before the node and drop those after it, + // instead of the other way around. + $result .= $this->origTokens->getTokenCode($pos, $itemStartPos, $indentAdjustment); + $skipRemovedNode = \true; + } else if ($isStmtList && $this->origTokens->haveTagInRange($pos, $itemStartPos)) { + // We'd remove an opening/closing PHP tag. + // TODO: Preserve formatting. + return null; + } + $pos = $itemEndPos + 1; + continue; + } else { + throw new \Exception("Shouldn't happen"); + } + if (null !== $fixup && $arrItem->getAttribute('origNode') !== $origArrItem) { + $res = $this->pFixup($fixup, $arrItem, null, $itemStartPos, $itemEndPos); + } else { + $res = $this->p($arrItem, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, \true); + } + $this->safeAppend($result, $res); + $this->setIndentLevel($origIndentLevel); + $pos = $itemEndPos + 1; + } + if ($skipRemovedNode) { + // TODO: Support removing single node. + return null; + } + if (!empty($delayedAdd)) { + if (!isset($this->emptyListInsertionMap[$mapKey])) { + return null; + } + list($findToken, $extraLeft, $extraRight) = $this->emptyListInsertionMap[$mapKey]; + if (null !== $findToken) { + $insertPos = $this->origTokens->findRight($pos, $findToken) + 1; + $result .= $this->origTokens->getTokenCode($pos, $insertPos, $indentAdjustment); + $pos = $insertPos; + } + $first = \true; + $result .= $extraLeft; + foreach ($delayedAdd as $delayedAddNode) { + if (!$first) { + $result .= $insertStr; + if ($insertNewline) { + $result .= $this->nl; + } + } + $result .= $this->p($delayedAddNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, \true); + $first = \false; + } + $result .= $extraRight === "\n" ? $this->nl : $extraRight; + } + return $result; + } + /** + * Print node with fixups. + * + * Fixups here refer to the addition of extra parentheses, braces or other characters, that + * are required to preserve program semantics in a certain context (e.g. to maintain precedence + * or because only certain expressions are allowed in certain places). + * + * @param int $fixup Fixup type + * @param Node $subNode Subnode to print + * @param string|null $parentClass Class of parent node + * @param int $subStartPos Original start pos of subnode + * @param int $subEndPos Original end pos of subnode + * + * @return string Result of fixed-up print of subnode + */ + protected function pFixup(int $fixup, Node $subNode, ?string $parentClass, int $subStartPos, int $subEndPos): string + { + switch ($fixup) { + case self::FIXUP_PREC_LEFT: + // We use a conservative approximation where lhsPrecedence == precedence. + if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) { + $precedence = $this->precedenceMap[$parentClass][1]; + return $this->p($subNode, $precedence, $precedence); + } + break; + case self::FIXUP_PREC_RIGHT: + if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) { + $precedence = $this->precedenceMap[$parentClass][2]; + return $this->p($subNode, $precedence, $precedence); + } + break; + case self::FIXUP_PREC_UNARY: + if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) { + $precedence = $this->precedenceMap[$parentClass][0]; + return $this->p($subNode, $precedence, $precedence); + } + break; + case self::FIXUP_CALL_LHS: + if ($this->callLhsRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { + return '(' . $this->p($subNode) . ')'; + } + break; + case self::FIXUP_DEREF_LHS: + if ($this->dereferenceLhsRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { + return '(' . $this->p($subNode) . ')'; + } + break; + case self::FIXUP_STATIC_DEREF_LHS: + if ($this->staticDereferenceLhsRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { + return '(' . $this->p($subNode) . ')'; + } + break; + case self::FIXUP_NEW: + if ($this->newOperandRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { + return '(' . $this->p($subNode) . ')'; + } + break; + case self::FIXUP_BRACED_NAME: + case self::FIXUP_VAR_BRACED_NAME: + if ($subNode instanceof Expr && !$this->origTokens->haveBraces($subStartPos, $subEndPos)) { + return ($fixup === self::FIXUP_VAR_BRACED_NAME ? '$' : '') . '{' . $this->p($subNode) . '}'; + } + break; + case self::FIXUP_ENCAPSED: + if (!$subNode instanceof Node\InterpolatedStringPart && !$this->origTokens->haveBraces($subStartPos, $subEndPos)) { + return '{' . $this->p($subNode) . '}'; + } + break; + default: + throw new \Exception('Cannot happen'); + } + // Nothing special to do + return $this->p($subNode); + } + /** + * Appends to a string, ensuring whitespace between label characters. + * + * Example: "echo" and "$x" result in "echo$x", but "echo" and "x" result in "echo x". + * Without safeAppend the result would be "echox", which does not preserve semantics. + */ + protected function safeAppend(string &$str, string $append): void + { + if ($str === "") { + $str = $append; + return; + } + if ($append === "") { + return; + } + if (!$this->labelCharMap[$append[0]] || !$this->labelCharMap[$str[\strlen($str) - 1]]) { + $str .= $append; + } else { + $str .= " " . $append; + } + } + /** + * Determines whether the LHS of a call must be wrapped in parenthesis. + * + * @param Node $node LHS of a call + * + * @return bool Whether parentheses are required + */ + protected function callLhsRequiresParens(Node $node): bool + { + if ($node instanceof Expr\New_) { + return !$this->phpVersion->supportsNewDereferenceWithoutParentheses(); + } + return !($node instanceof Node\Name || $node instanceof Expr\Variable || $node instanceof Expr\ArrayDimFetch || $node instanceof Expr\FuncCall || $node instanceof Expr\MethodCall || $node instanceof Expr\NullsafeMethodCall || $node instanceof Expr\StaticCall || $node instanceof Expr\Array_); + } + /** + * Determines whether the LHS of an array/object operation must be wrapped in parentheses. + * + * @param Node $node LHS of dereferencing operation + * + * @return bool Whether parentheses are required + */ + protected function dereferenceLhsRequiresParens(Node $node): bool + { + // A constant can occur on the LHS of an array/object deref, but not a static deref. + return $this->staticDereferenceLhsRequiresParens($node) && !$node instanceof Expr\ConstFetch; + } + /** + * Determines whether the LHS of a static operation must be wrapped in parentheses. + * + * @param Node $node LHS of dereferencing operation + * + * @return bool Whether parentheses are required + */ + protected function staticDereferenceLhsRequiresParens(Node $node): bool + { + if ($node instanceof Expr\New_) { + return !$this->phpVersion->supportsNewDereferenceWithoutParentheses(); + } + return !($node instanceof Expr\Variable || $node instanceof Node\Name || $node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch || $node instanceof Expr\NullsafePropertyFetch || $node instanceof Expr\StaticPropertyFetch || $node instanceof Expr\FuncCall || $node instanceof Expr\MethodCall || $node instanceof Expr\NullsafeMethodCall || $node instanceof Expr\StaticCall || $node instanceof Expr\Array_ || $node instanceof Scalar\String_ || $node instanceof Expr\ClassConstFetch); + } + /** + * Determines whether an expression used in "new" or "instanceof" requires parentheses. + * + * @param Node $node New or instanceof operand + * + * @return bool Whether parentheses are required + */ + protected function newOperandRequiresParens(Node $node): bool + { + if ($node instanceof Node\Name || $node instanceof Expr\Variable) { + return \false; + } + if ($node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch || $node instanceof Expr\NullsafePropertyFetch) { + return $this->newOperandRequiresParens($node->var); + } + if ($node instanceof Expr\StaticPropertyFetch) { + return $this->newOperandRequiresParens($node->class); + } + return \true; + } + /** + * Print modifiers, including trailing whitespace. + * + * @param int $modifiers Modifier mask to print + * + * @return string Printed modifiers + */ + protected function pModifiers(int $modifiers): string + { + return ($modifiers & Modifiers::FINAL ? 'final ' : '') . ($modifiers & Modifiers::ABSTRACT ? 'abstract ' : '') . ($modifiers & Modifiers::PUBLIC ? 'public ' : '') . ($modifiers & Modifiers::PROTECTED ? 'protected ' : '') . ($modifiers & Modifiers::PRIVATE ? 'private ' : '') . ($modifiers & Modifiers::PUBLIC_SET ? 'public(set) ' : '') . ($modifiers & Modifiers::PROTECTED_SET ? 'protected(set) ' : '') . ($modifiers & Modifiers::PRIVATE_SET ? 'private(set) ' : '') . ($modifiers & Modifiers::STATIC ? 'static ' : '') . ($modifiers & Modifiers::READONLY ? 'readonly ' : ''); + } + protected function pStatic(bool $static): string + { + return $static ? 'static ' : ''; + } + /** + * Determine whether a list of nodes uses multiline formatting. + * + * @param (Node|null)[] $nodes Node list + * + * @return bool Whether multiline formatting is used + */ + protected function isMultiline(array $nodes): bool + { + if (\count($nodes) < 2) { + return \false; + } + $pos = -1; + foreach ($nodes as $node) { + if (null === $node) { + continue; + } + $endPos = $node->getEndTokenPos() + 1; + if ($pos >= 0) { + $text = $this->origTokens->getTokenCode($pos, $endPos, 0); + if (\false === strpos($text, "\n")) { + // We require that a newline is present between *every* item. If the formatting + // is inconsistent, with only some items having newlines, we don't consider it + // as multiline + return \false; + } + } + $pos = $endPos; + } + return \true; + } + /** + * Lazily initializes label char map. + * + * The label char map determines whether a certain character may occur in a label. + */ + protected function initializeLabelCharMap(): void + { + if (isset($this->labelCharMap)) { + return; + } + $this->labelCharMap = []; + for ($i = 0; $i < 256; $i++) { + $chr = chr($i); + $this->labelCharMap[$chr] = $i >= 0x80 || ctype_alnum($chr); + } + if ($this->phpVersion->allowsDelInIdentifiers()) { + $this->labelCharMap[""] = \true; + } + } + /** + * Lazily initializes node list differ. + * + * The node list differ is used to determine differences between two array subnodes. + */ + protected function initializeNodeListDiffer(): void + { + if (isset($this->nodeListDiffer)) { + return; + } + $this->nodeListDiffer = new Internal\Differ(function ($a, $b) { + if ($a instanceof Node && $b instanceof Node) { + return $a === $b->getAttribute('origNode'); + } + // Can happen for array destructuring + return $a === null && $b === null; + }); + } + /** + * Lazily initializes fixup map. + * + * The fixup map is used to determine whether a certain subnode of a certain node may require + * some kind of "fixup" operation, e.g. the addition of parenthesis or braces. + */ + protected function initializeFixupMap(): void + { + if (isset($this->fixupMap)) { + return; + } + $this->fixupMap = [Expr\Instanceof_::class => ['expr' => self::FIXUP_PREC_UNARY, 'class' => self::FIXUP_NEW], Expr\Ternary::class => ['cond' => self::FIXUP_PREC_LEFT, 'else' => self::FIXUP_PREC_RIGHT], Expr\Yield_::class => ['value' => self::FIXUP_PREC_UNARY], Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS], Expr\StaticCall::class => ['class' => self::FIXUP_STATIC_DEREF_LHS], Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS], Expr\ClassConstFetch::class => ['class' => self::FIXUP_STATIC_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\New_::class => ['class' => self::FIXUP_NEW], Expr\MethodCall::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\NullsafeMethodCall::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\StaticPropertyFetch::class => ['class' => self::FIXUP_STATIC_DEREF_LHS, 'name' => self::FIXUP_VAR_BRACED_NAME], Expr\PropertyFetch::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\NullsafePropertyFetch::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Scalar\InterpolatedString::class => ['parts' => self::FIXUP_ENCAPSED]]; + $binaryOps = [BinaryOp\Pow::class, BinaryOp\Mul::class, BinaryOp\Div::class, BinaryOp\Mod::class, BinaryOp\Plus::class, BinaryOp\Minus::class, BinaryOp\Concat::class, BinaryOp\ShiftLeft::class, BinaryOp\ShiftRight::class, BinaryOp\Smaller::class, BinaryOp\SmallerOrEqual::class, BinaryOp\Greater::class, BinaryOp\GreaterOrEqual::class, BinaryOp\Equal::class, BinaryOp\NotEqual::class, BinaryOp\Identical::class, BinaryOp\NotIdentical::class, BinaryOp\Spaceship::class, BinaryOp\BitwiseAnd::class, BinaryOp\BitwiseXor::class, BinaryOp\BitwiseOr::class, BinaryOp\BooleanAnd::class, BinaryOp\BooleanOr::class, BinaryOp\Coalesce::class, BinaryOp\LogicalAnd::class, BinaryOp\LogicalXor::class, BinaryOp\LogicalOr::class, BinaryOp\Pipe::class]; + foreach ($binaryOps as $binaryOp) { + $this->fixupMap[$binaryOp] = ['left' => self::FIXUP_PREC_LEFT, 'right' => self::FIXUP_PREC_RIGHT]; + } + $prefixOps = [Expr\Clone_::class, Expr\BitwiseNot::class, Expr\BooleanNot::class, Expr\UnaryPlus::class, Expr\UnaryMinus::class, Cast\Int_::class, Cast\Double::class, Cast\String_::class, Cast\Array_::class, Cast\Object_::class, Cast\Bool_::class, Cast\Unset_::class, Expr\ErrorSuppress::class, Expr\YieldFrom::class, Expr\Print_::class, Expr\Include_::class, Expr\Assign::class, Expr\AssignRef::class, AssignOp\Plus::class, AssignOp\Minus::class, AssignOp\Mul::class, AssignOp\Div::class, AssignOp\Concat::class, AssignOp\Mod::class, AssignOp\BitwiseAnd::class, AssignOp\BitwiseOr::class, AssignOp\BitwiseXor::class, AssignOp\ShiftLeft::class, AssignOp\ShiftRight::class, AssignOp\Pow::class, AssignOp\Coalesce::class, Expr\ArrowFunction::class, Expr\Throw_::class]; + foreach ($prefixOps as $prefixOp) { + $this->fixupMap[$prefixOp] = ['expr' => self::FIXUP_PREC_UNARY]; + } + } + /** + * Lazily initializes the removal map. + * + * The removal map is used to determine which additional tokens should be removed when a + * certain node is replaced by null. + */ + protected function initializeRemovalMap(): void + { + if (isset($this->removalMap)) { + return; + } + $stripBoth = ['left' => \T_WHITESPACE, 'right' => \T_WHITESPACE]; + $stripLeft = ['left' => \T_WHITESPACE]; + $stripRight = ['right' => \T_WHITESPACE]; + $stripDoubleArrow = ['right' => \T_DOUBLE_ARROW]; + $stripColon = ['left' => ':']; + $stripEquals = ['left' => '=']; + $this->removalMap = ['Expr_ArrayDimFetch->dim' => $stripBoth, 'ArrayItem->key' => $stripDoubleArrow, 'Expr_ArrowFunction->returnType' => $stripColon, 'Expr_Closure->returnType' => $stripColon, 'Expr_Exit->expr' => $stripBoth, 'Expr_Ternary->if' => $stripBoth, 'Expr_Yield->key' => $stripDoubleArrow, 'Expr_Yield->value' => $stripBoth, 'Param->type' => $stripRight, 'Param->default' => $stripEquals, 'Stmt_Break->num' => $stripBoth, 'Stmt_Catch->var' => $stripLeft, 'Stmt_ClassConst->type' => $stripRight, 'Stmt_ClassMethod->returnType' => $stripColon, 'Stmt_Class->extends' => ['left' => \T_EXTENDS], 'Stmt_Enum->scalarType' => $stripColon, 'Stmt_EnumCase->expr' => $stripEquals, 'Expr_PrintableNewAnonClass->extends' => ['left' => \T_EXTENDS], 'Stmt_Continue->num' => $stripBoth, 'Stmt_Foreach->keyVar' => $stripDoubleArrow, 'Stmt_Function->returnType' => $stripColon, 'Stmt_If->else' => $stripLeft, 'Stmt_Namespace->name' => $stripLeft, 'Stmt_Property->type' => $stripRight, 'PropertyItem->default' => $stripEquals, 'Stmt_Return->expr' => $stripBoth, 'Stmt_StaticVar->default' => $stripEquals, 'Stmt_TraitUseAdaptation_Alias->newName' => $stripLeft, 'Stmt_TryCatch->finally' => $stripLeft]; + } + protected function initializeInsertionMap(): void + { + if (isset($this->insertionMap)) { + return; + } + // TODO: "yield" where both key and value are inserted doesn't work + // [$find, $beforeToken, $extraLeft, $extraRight] + $this->insertionMap = [ + 'Expr_ArrayDimFetch->dim' => ['[', \false, null, null], + 'ArrayItem->key' => [null, \false, null, ' => '], + 'Expr_ArrowFunction->returnType' => [')', \false, ': ', null], + 'Expr_Closure->returnType' => [')', \false, ': ', null], + 'Expr_Ternary->if' => ['?', \false, ' ', ' '], + 'Expr_Yield->key' => [\T_YIELD, \false, null, ' => '], + 'Expr_Yield->value' => [\T_YIELD, \false, ' ', null], + 'Param->type' => [null, \false, null, ' '], + 'Param->default' => [null, \false, ' = ', null], + 'Stmt_Break->num' => [\T_BREAK, \false, ' ', null], + 'Stmt_Catch->var' => [null, \false, ' ', null], + 'Stmt_ClassMethod->returnType' => [')', \false, ': ', null], + 'Stmt_ClassConst->type' => [\T_CONST, \false, ' ', null], + 'Stmt_Class->extends' => [null, \false, ' extends ', null], + 'Stmt_Enum->scalarType' => [null, \false, ' : ', null], + 'Stmt_EnumCase->expr' => [null, \false, ' = ', null], + 'Expr_PrintableNewAnonClass->extends' => [null, \false, ' extends ', null], + 'Stmt_Continue->num' => [\T_CONTINUE, \false, ' ', null], + 'Stmt_Foreach->keyVar' => [\T_AS, \false, null, ' => '], + 'Stmt_Function->returnType' => [')', \false, ': ', null], + 'Stmt_If->else' => [null, \false, ' ', null], + 'Stmt_Namespace->name' => [\T_NAMESPACE, \false, ' ', null], + 'Stmt_Property->type' => [\T_VARIABLE, \true, null, ' '], + 'PropertyItem->default' => [null, \false, ' = ', null], + 'Stmt_Return->expr' => [\T_RETURN, \false, ' ', null], + 'Stmt_StaticVar->default' => [null, \false, ' = ', null], + //'Stmt_TraitUseAdaptation_Alias->newName' => [T_AS, false, ' ', null], // TODO + 'Stmt_TryCatch->finally' => [null, \false, ' ', null], + ]; + } + protected function initializeListInsertionMap(): void + { + if (isset($this->listInsertionMap)) { + return; + } + $this->listInsertionMap = [ + // special + //'Expr_ShellExec->parts' => '', // TODO These need to be treated more carefully + //'Scalar_InterpolatedString->parts' => '', + Stmt\Catch_::class . '->types' => '|', + UnionType::class . '->types' => '|', + IntersectionType::class . '->types' => '&', + Stmt\If_::class . '->elseifs' => ' ', + Stmt\TryCatch::class . '->catches' => ' ', + // comma-separated lists + Expr\Array_::class . '->items' => ', ', + Expr\ArrowFunction::class . '->params' => ', ', + Expr\Closure::class . '->params' => ', ', + Expr\Closure::class . '->uses' => ', ', + Expr\FuncCall::class . '->args' => ', ', + Expr\Isset_::class . '->vars' => ', ', + Expr\List_::class . '->items' => ', ', + Expr\MethodCall::class . '->args' => ', ', + Expr\NullsafeMethodCall::class . '->args' => ', ', + Expr\New_::class . '->args' => ', ', + PrintableNewAnonClassNode::class . '->args' => ', ', + Expr\StaticCall::class . '->args' => ', ', + Stmt\ClassConst::class . '->consts' => ', ', + Stmt\ClassMethod::class . '->params' => ', ', + Stmt\Class_::class . '->implements' => ', ', + Stmt\Enum_::class . '->implements' => ', ', + PrintableNewAnonClassNode::class . '->implements' => ', ', + Stmt\Const_::class . '->consts' => ', ', + Stmt\Declare_::class . '->declares' => ', ', + Stmt\Echo_::class . '->exprs' => ', ', + Stmt\For_::class . '->init' => ', ', + Stmt\For_::class . '->cond' => ', ', + Stmt\For_::class . '->loop' => ', ', + Stmt\Function_::class . '->params' => ', ', + Stmt\Global_::class . '->vars' => ', ', + Stmt\GroupUse::class . '->uses' => ', ', + Stmt\Interface_::class . '->extends' => ', ', + Expr\Match_::class . '->arms' => ', ', + Stmt\Property::class . '->props' => ', ', + Stmt\StaticVar::class . '->vars' => ', ', + Stmt\TraitUse::class . '->traits' => ', ', + Stmt\TraitUseAdaptation\Precedence::class . '->insteadof' => ', ', + Stmt\Unset_::class . '->vars' => ', ', + Stmt\UseUse::class . '->uses' => ', ', + MatchArm::class . '->conds' => ', ', + AttributeGroup::class . '->attrs' => ', ', + PropertyHook::class . '->params' => ', ', + // statement lists + Expr\Closure::class . '->stmts' => "\n", + Stmt\Case_::class . '->stmts' => "\n", + Stmt\Catch_::class . '->stmts' => "\n", + Stmt\Class_::class . '->stmts' => "\n", + Stmt\Enum_::class . '->stmts' => "\n", + PrintableNewAnonClassNode::class . '->stmts' => "\n", + Stmt\Interface_::class . '->stmts' => "\n", + Stmt\Trait_::class . '->stmts' => "\n", + Stmt\ClassMethod::class . '->stmts' => "\n", + Stmt\Declare_::class . '->stmts' => "\n", + Stmt\Do_::class . '->stmts' => "\n", + Stmt\ElseIf_::class . '->stmts' => "\n", + Stmt\Else_::class . '->stmts' => "\n", + Stmt\Finally_::class . '->stmts' => "\n", + Stmt\Foreach_::class . '->stmts' => "\n", + Stmt\For_::class . '->stmts' => "\n", + Stmt\Function_::class . '->stmts' => "\n", + Stmt\If_::class . '->stmts' => "\n", + Stmt\Namespace_::class . '->stmts' => "\n", + Stmt\Block::class . '->stmts' => "\n", + // Attribute groups + Stmt\Class_::class . '->attrGroups' => "\n", + Stmt\Enum_::class . '->attrGroups' => "\n", + Stmt\EnumCase::class . '->attrGroups' => "\n", + Stmt\Interface_::class . '->attrGroups' => "\n", + Stmt\Trait_::class . '->attrGroups' => "\n", + Stmt\Function_::class . '->attrGroups' => "\n", + Stmt\ClassMethod::class . '->attrGroups' => "\n", + Stmt\ClassConst::class . '->attrGroups' => "\n", + Stmt\Property::class . '->attrGroups' => "\n", + PrintableNewAnonClassNode::class . '->attrGroups' => ' ', + Expr\Closure::class . '->attrGroups' => ' ', + Expr\ArrowFunction::class . '->attrGroups' => ' ', + Param::class . '->attrGroups' => ' ', + PropertyHook::class . '->attrGroups' => ' ', + Stmt\Switch_::class . '->cases' => "\n", + Stmt\TraitUse::class . '->adaptations' => "\n", + Stmt\TryCatch::class . '->stmts' => "\n", + Stmt\While_::class . '->stmts' => "\n", + PropertyHook::class . '->body' => "\n", + Stmt\Property::class . '->hooks' => "\n", + Param::class . '->hooks' => "\n", + // dummy for top-level context + 'File->stmts' => "\n", + ]; + } + protected function initializeEmptyListInsertionMap(): void + { + if (isset($this->emptyListInsertionMap)) { + return; + } + // TODO Insertion into empty statement lists. + // [$find, $extraLeft, $extraRight] + $this->emptyListInsertionMap = [Expr\ArrowFunction::class . '->params' => ['(', '', ''], Expr\Closure::class . '->uses' => [')', ' use (', ')'], Expr\Closure::class . '->params' => ['(', '', ''], Expr\FuncCall::class . '->args' => ['(', '', ''], Expr\MethodCall::class . '->args' => ['(', '', ''], Expr\NullsafeMethodCall::class . '->args' => ['(', '', ''], Expr\New_::class . '->args' => ['(', '', ''], PrintableNewAnonClassNode::class . '->args' => ['(', '', ''], PrintableNewAnonClassNode::class . '->implements' => [null, ' implements ', ''], Expr\StaticCall::class . '->args' => ['(', '', ''], Stmt\Class_::class . '->implements' => [null, ' implements ', ''], Stmt\Enum_::class . '->implements' => [null, ' implements ', ''], Stmt\ClassMethod::class . '->params' => ['(', '', ''], Stmt\Interface_::class . '->extends' => [null, ' extends ', ''], Stmt\Function_::class . '->params' => ['(', '', ''], Stmt\Interface_::class . '->attrGroups' => [null, '', "\n"], Stmt\Class_::class . '->attrGroups' => [null, '', "\n"], Stmt\ClassConst::class . '->attrGroups' => [null, '', "\n"], Stmt\ClassMethod::class . '->attrGroups' => [null, '', "\n"], Stmt\Function_::class . '->attrGroups' => [null, '', "\n"], Stmt\Property::class . '->attrGroups' => [null, '', "\n"], Stmt\Trait_::class . '->attrGroups' => [null, '', "\n"], Expr\ArrowFunction::class . '->attrGroups' => [null, '', ' '], Expr\Closure::class . '->attrGroups' => [null, '', ' '], Stmt\Const_::class . '->attrGroups' => [null, '', "\n"], PrintableNewAnonClassNode::class . '->attrGroups' => [\T_NEW, ' ', '']]; + } + protected function initializeModifierChangeMap(): void + { + if (isset($this->modifierChangeMap)) { + return; + } + $this->modifierChangeMap = [Stmt\ClassConst::class . '->flags' => ['pModifiers', \T_WHITESPACE, \T_CONST], Stmt\ClassMethod::class . '->flags' => ['pModifiers', \T_WHITESPACE, \T_FUNCTION], Stmt\Class_::class . '->flags' => ['pModifiers', \T_WHITESPACE, \T_CLASS], Stmt\Property::class . '->flags' => ['pModifiers', \T_WHITESPACE, \T_VARIABLE], PrintableNewAnonClassNode::class . '->flags' => ['pModifiers', \T_NEW, \T_CLASS], Param::class . '->flags' => ['pModifiers', \T_WHITESPACE, \T_VARIABLE], PropertyHook::class . '->flags' => ['pModifiers', \T_WHITESPACE, \T_STRING], Expr\Closure::class . '->static' => ['pStatic', \T_WHITESPACE, \T_FUNCTION], Expr\ArrowFunction::class . '->static' => ['pStatic', \T_WHITESPACE, \T_FN]]; + // List of integer subnodes that are not modifiers: + // Expr_Include->type + // Stmt_GroupUse->type + // Stmt_Use->type + // UseItem->type + } +} +pos + \strlen($this->text); + } + /** Get 1-based end line number of the token. */ + public function getEndLine(): int + { + return $this->line + \substr_count($this->text, "\n"); + } +} +, Sebastian Heuer , Sebastian Bergmann , and contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of Arne Blankerts nor the names of contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use PHPUnitPHAR\PharIo\Version\Exception as VersionException; +use PHPUnitPHAR\PharIo\Version\Version; +use PHPUnitPHAR\PharIo\Version\VersionConstraintParser; +use Throwable; +use function sprintf; +class ManifestDocumentMapper +{ + public function map(ManifestDocument $document): Manifest + { + try { + $contains = $document->getContainsElement(); + $type = $this->mapType($contains); + $copyright = $this->mapCopyright($document->getCopyrightElement()); + $requirements = $this->mapRequirements($document->getRequiresElement()); + $bundledComponents = $this->mapBundledComponents($document); + return new Manifest(new ApplicationName($contains->getName()), new Version($contains->getVersion()), $type, $copyright, $requirements, $bundledComponents); + } catch (Throwable $e) { + throw new ManifestDocumentMapperException($e->getMessage(), (int) $e->getCode(), $e); + } + } + private function mapType(ContainsElement $contains): Type + { + switch ($contains->getType()) { + case 'application': + return Type::application(); + case 'library': + return Type::library(); + case 'extension': + return $this->mapExtension($contains->getExtensionElement()); + } + throw new ManifestDocumentMapperException(sprintf('Unsupported type %s', $contains->getType())); + } + private function mapCopyright(CopyrightElement $copyright): CopyrightInformation + { + $authors = new AuthorCollection(); + foreach ($copyright->getAuthorElements() as $authorElement) { + $authors->add(new Author($authorElement->getName(), $authorElement->hasEMail() ? new Email($authorElement->getEmail()) : null)); + } + $licenseElement = $copyright->getLicenseElement(); + $license = new License($licenseElement->getType(), new Url($licenseElement->getUrl())); + return new CopyrightInformation($authors, $license); + } + private function mapRequirements(RequiresElement $requires): RequirementCollection + { + $collection = new RequirementCollection(); + $phpElement = $requires->getPHPElement(); + $parser = new VersionConstraintParser(); + try { + $versionConstraint = $parser->parse($phpElement->getVersion()); + } catch (VersionException $e) { + throw new ManifestDocumentMapperException(sprintf('Unsupported version constraint - %s', $e->getMessage()), (int) $e->getCode(), $e); + } + $collection->add(new PhpVersionRequirement($versionConstraint)); + if (!$phpElement->hasExtElements()) { + return $collection; + } + foreach ($phpElement->getExtElements() as $extElement) { + $collection->add(new PhpExtensionRequirement($extElement->getName())); + } + return $collection; + } + private function mapBundledComponents(ManifestDocument $document): BundledComponentCollection + { + $collection = new BundledComponentCollection(); + if (!$document->hasBundlesElement()) { + return $collection; + } + foreach ($document->getBundlesElement()->getComponentElements() as $componentElement) { + $collection->add(new BundledComponent($componentElement->getName(), new Version($componentElement->getVersion()))); + } + return $collection; + } + private function mapExtension(ExtensionElement $extension): Extension + { + try { + $versionConstraint = (new VersionConstraintParser())->parse($extension->getCompatible()); + return Type::extension(new ApplicationName($extension->getFor()), $versionConstraint); + } catch (VersionException $e) { + throw new ManifestDocumentMapperException(sprintf('Unsupported version constraint - %s', $e->getMessage()), (int) $e->getCode(), $e); + } + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use function sprintf; +class ManifestLoader +{ + public static function fromFile(string $filename): Manifest + { + try { + return (new ManifestDocumentMapper())->map(ManifestDocument::fromFile($filename)); + } catch (Exception $e) { + throw new ManifestLoaderException(sprintf('Loading %s failed.', $filename), (int) $e->getCode(), $e); + } + } + public static function fromPhar(string $filename): Manifest + { + return self::fromFile('phar://' . $filename . '/manifest.xml'); + } + public static function fromString(string $manifest): Manifest + { + try { + return (new ManifestDocumentMapper())->map(ManifestDocument::fromString($manifest)); + } catch (Exception $e) { + throw new ManifestLoaderException('Processing string failed', (int) $e->getCode(), $e); + } + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use PHPUnitPHAR\PharIo\Version\AnyVersionConstraint; +use PHPUnitPHAR\PharIo\Version\Version; +use PHPUnitPHAR\PharIo\Version\VersionConstraint; +use XMLWriter; +use function count; +use function file_put_contents; +use function str_repeat; +/** @psalm-suppress MissingConstructor */ +class ManifestSerializer +{ + /** @var XMLWriter */ + private $xmlWriter; + public function serializeToFile(Manifest $manifest, string $filename): void + { + file_put_contents($filename, $this->serializeToString($manifest)); + } + public function serializeToString(Manifest $manifest): string + { + $this->startDocument(); + $this->addContains($manifest->getName(), $manifest->getVersion(), $manifest->getType()); + $this->addCopyright($manifest->getCopyrightInformation()); + $this->addRequirements($manifest->getRequirements()); + $this->addBundles($manifest->getBundledComponents()); + return $this->finishDocument(); + } + private function startDocument(): void + { + $xmlWriter = new XMLWriter(); + $xmlWriter->openMemory(); + $xmlWriter->setIndent(\true); + $xmlWriter->setIndentString(str_repeat(' ', 4)); + $xmlWriter->startDocument('1.0', 'UTF-8'); + $xmlWriter->startElement('phar'); + $xmlWriter->writeAttribute('xmlns', 'https://phar.io/xml/manifest/1.0'); + $this->xmlWriter = $xmlWriter; + } + private function finishDocument(): string + { + $this->xmlWriter->endElement(); + $this->xmlWriter->endDocument(); + return $this->xmlWriter->outputMemory(); + } + private function addContains(ApplicationName $name, Version $version, Type $type): void + { + $this->xmlWriter->startElement('contains'); + $this->xmlWriter->writeAttribute('name', $name->asString()); + $this->xmlWriter->writeAttribute('version', $version->getVersionString()); + switch (\true) { + case $type->isApplication(): + { + $this->xmlWriter->writeAttribute('type', 'application'); + break; + } + case $type->isLibrary(): + { + $this->xmlWriter->writeAttribute('type', 'library'); + break; + } + case $type->isExtension(): + { + $this->xmlWriter->writeAttribute('type', 'extension'); + /* @var $type Extension */ + $this->addExtension($type->getApplicationName(), $type->getVersionConstraint()); + break; + } + default: + { + $this->xmlWriter->writeAttribute('type', 'custom'); + } + } + $this->xmlWriter->endElement(); + } + private function addCopyright(CopyrightInformation $copyrightInformation): void + { + $this->xmlWriter->startElement('copyright'); + foreach ($copyrightInformation->getAuthors() as $author) { + $this->xmlWriter->startElement('author'); + $this->xmlWriter->writeAttribute('name', $author->getName()); + $this->xmlWriter->writeAttribute('email', $author->getEmail()->asString()); + $this->xmlWriter->endElement(); + } + $license = $copyrightInformation->getLicense(); + $this->xmlWriter->startElement('license'); + $this->xmlWriter->writeAttribute('type', $license->getName()); + $this->xmlWriter->writeAttribute('url', $license->getUrl()->asString()); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + } + private function addRequirements(RequirementCollection $requirementCollection): void + { + $phpRequirement = new AnyVersionConstraint(); + $extensions = []; + foreach ($requirementCollection as $requirement) { + if ($requirement instanceof PhpVersionRequirement) { + $phpRequirement = $requirement->getVersionConstraint(); + continue; + } + if ($requirement instanceof PhpExtensionRequirement) { + $extensions[] = $requirement->asString(); + } + } + $this->xmlWriter->startElement('requires'); + $this->xmlWriter->startElement('php'); + $this->xmlWriter->writeAttribute('version', $phpRequirement->asString()); + foreach ($extensions as $extension) { + $this->xmlWriter->startElement('ext'); + $this->xmlWriter->writeAttribute('name', $extension); + $this->xmlWriter->endElement(); + } + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + } + private function addBundles(BundledComponentCollection $bundledComponentCollection): void + { + if (count($bundledComponentCollection) === 0) { + return; + } + $this->xmlWriter->startElement('bundles'); + foreach ($bundledComponentCollection as $bundledComponent) { + $this->xmlWriter->startElement('component'); + $this->xmlWriter->writeAttribute('name', $bundledComponent->getName()); + $this->xmlWriter->writeAttribute('version', $bundledComponent->getVersion()->getVersionString()); + $this->xmlWriter->endElement(); + } + $this->xmlWriter->endElement(); + } + private function addExtension(ApplicationName $applicationName, VersionConstraint $versionConstraint): void + { + $this->xmlWriter->startElement('extension'); + $this->xmlWriter->writeAttribute('for', $applicationName->asString()); + $this->xmlWriter->writeAttribute('compatible', $versionConstraint->asString()); + $this->xmlWriter->endElement(); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use InvalidArgumentException; +class ElementCollectionException extends InvalidArgumentException implements Exception +{ +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use Throwable; +interface Exception extends Throwable +{ +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use InvalidArgumentException; +class InvalidApplicationNameException extends InvalidArgumentException implements Exception +{ + public const InvalidFormat = 2; +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use InvalidArgumentException; +class InvalidEmailException extends InvalidArgumentException implements Exception +{ +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use InvalidArgumentException; +class InvalidUrlException extends InvalidArgumentException implements Exception +{ +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use RuntimeException; +class ManifestDocumentException extends RuntimeException implements Exception +{ +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use LibXMLError; +use function sprintf; +class ManifestDocumentLoadingException extends \Exception implements Exception +{ + /** @var LibXMLError[] */ + private $libxmlErrors; + /** + * ManifestDocumentLoadingException constructor. + * + * @param LibXMLError[] $libxmlErrors + */ + public function __construct(array $libxmlErrors) + { + $this->libxmlErrors = $libxmlErrors; + $first = $this->libxmlErrors[0]; + parent::__construct(sprintf('%s (Line: %d / Column: %d / File: %s)', $first->message, $first->line, $first->column, $first->file), $first->code); + } + /** + * @return LibXMLError[] + */ + public function getLibxmlErrors(): array + { + return $this->libxmlErrors; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use RuntimeException; +class ManifestDocumentMapperException extends RuntimeException implements Exception +{ +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use RuntimeException; +class ManifestElementException extends RuntimeException implements Exception +{ +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class ManifestLoaderException extends \Exception implements Exception +{ +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use InvalidArgumentException; +class NoEmailAddressException extends InvalidArgumentException implements Exception +{ +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class Application extends Type +{ + public function isApplication(): bool + { + return \true; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use function preg_match; +use function sprintf; +class ApplicationName +{ + /** @var string */ + private $name; + public function __construct(string $name) + { + $this->ensureValidFormat($name); + $this->name = $name; + } + public function asString(): string + { + return $this->name; + } + public function isEqual(ApplicationName $name): bool + { + return $this->name === $name->name; + } + private function ensureValidFormat(string $name): void + { + if (!preg_match('#\w/\w#', $name)) { + throw new InvalidApplicationNameException(sprintf('Format of name "%s" is not valid - expected: vendor/packagename', $name), InvalidApplicationNameException::InvalidFormat); + } + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use function sprintf; +class Author +{ + /** @var string */ + private $name; + /** @var null|Email */ + private $email; + public function __construct(string $name, ?Email $email = null) + { + $this->name = $name; + $this->email = $email; + } + public function asString(): string + { + if (!$this->hasEmail()) { + return $this->name; + } + return sprintf('%s <%s>', $this->name, $this->email->asString()); + } + public function getName(): string + { + return $this->name; + } + /** + * @psalm-assert-if-true Email $this->email + */ + public function hasEmail(): bool + { + return $this->email !== null; + } + public function getEmail(): Email + { + if (!$this->hasEmail()) { + throw new NoEmailAddressException(); + } + return $this->email; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use Countable; +use IteratorAggregate; +use function count; +/** @template-implements IteratorAggregate */ +class AuthorCollection implements Countable, IteratorAggregate +{ + /** @var Author[] */ + private $authors = []; + public function add(Author $author): void + { + $this->authors[] = $author; + } + /** + * @return Author[] + */ + public function getAuthors(): array + { + return $this->authors; + } + public function count(): int + { + return count($this->authors); + } + public function getIterator(): AuthorCollectionIterator + { + return new AuthorCollectionIterator($this); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use Iterator; +use function count; +/** @template-implements Iterator */ +class AuthorCollectionIterator implements Iterator +{ + /** @var Author[] */ + private $authors; + /** @var int */ + private $position = 0; + public function __construct(AuthorCollection $authors) + { + $this->authors = $authors->getAuthors(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return $this->position < count($this->authors); + } + public function key(): int + { + return $this->position; + } + public function current(): Author + { + return $this->authors[$this->position]; + } + public function next(): void + { + $this->position++; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use PHPUnitPHAR\PharIo\Version\Version; +class BundledComponent +{ + /** @var string */ + private $name; + /** @var Version */ + private $version; + public function __construct(string $name, Version $version) + { + $this->name = $name; + $this->version = $version; + } + public function getName(): string + { + return $this->name; + } + public function getVersion(): Version + { + return $this->version; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use Countable; +use IteratorAggregate; +use function count; +/** @template-implements IteratorAggregate */ +class BundledComponentCollection implements Countable, IteratorAggregate +{ + /** @var BundledComponent[] */ + private $bundledComponents = []; + public function add(BundledComponent $bundledComponent): void + { + $this->bundledComponents[] = $bundledComponent; + } + /** + * @return BundledComponent[] + */ + public function getBundledComponents(): array + { + return $this->bundledComponents; + } + public function count(): int + { + return count($this->bundledComponents); + } + public function getIterator(): BundledComponentCollectionIterator + { + return new BundledComponentCollectionIterator($this); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use Iterator; +use function count; +/** @template-implements Iterator */ +class BundledComponentCollectionIterator implements Iterator +{ + /** @var BundledComponent[] */ + private $bundledComponents; + /** @var int */ + private $position = 0; + public function __construct(BundledComponentCollection $bundledComponents) + { + $this->bundledComponents = $bundledComponents->getBundledComponents(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return $this->position < count($this->bundledComponents); + } + public function key(): int + { + return $this->position; + } + public function current(): BundledComponent + { + return $this->bundledComponents[$this->position]; + } + public function next(): void + { + $this->position++; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class CopyrightInformation +{ + /** @var AuthorCollection */ + private $authors; + /** @var License */ + private $license; + public function __construct(AuthorCollection $authors, License $license) + { + $this->authors = $authors; + $this->license = $license; + } + public function getAuthors(): AuthorCollection + { + return $this->authors; + } + public function getLicense(): License + { + return $this->license; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use const FILTER_VALIDATE_EMAIL; +use function filter_var; +class Email +{ + /** @var string */ + private $email; + public function __construct(string $email) + { + $this->ensureEmailIsValid($email); + $this->email = $email; + } + public function asString(): string + { + return $this->email; + } + private function ensureEmailIsValid(string $url): void + { + if (filter_var($url, FILTER_VALIDATE_EMAIL) === \false) { + throw new InvalidEmailException(); + } + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use PHPUnitPHAR\PharIo\Version\Version; +use PHPUnitPHAR\PharIo\Version\VersionConstraint; +class Extension extends Type +{ + /** @var ApplicationName */ + private $application; + /** @var VersionConstraint */ + private $versionConstraint; + public function __construct(ApplicationName $application, VersionConstraint $versionConstraint) + { + $this->application = $application; + $this->versionConstraint = $versionConstraint; + } + public function getApplicationName(): ApplicationName + { + return $this->application; + } + public function getVersionConstraint(): VersionConstraint + { + return $this->versionConstraint; + } + public function isExtension(): bool + { + return \true; + } + public function isExtensionFor(ApplicationName $name): bool + { + return $this->application->isEqual($name); + } + public function isCompatibleWith(ApplicationName $name, Version $version): bool + { + return $this->isExtensionFor($name) && $this->versionConstraint->complies($version); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class Library extends Type +{ + public function isLibrary(): bool + { + return \true; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class License +{ + /** @var string */ + private $name; + /** @var Url */ + private $url; + public function __construct(string $name, Url $url) + { + $this->name = $name; + $this->url = $url; + } + public function getName(): string + { + return $this->name; + } + public function getUrl(): Url + { + return $this->url; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use PHPUnitPHAR\PharIo\Version\Version; +class Manifest +{ + /** @var ApplicationName */ + private $name; + /** @var Version */ + private $version; + /** @var Type */ + private $type; + /** @var CopyrightInformation */ + private $copyrightInformation; + /** @var RequirementCollection */ + private $requirements; + /** @var BundledComponentCollection */ + private $bundledComponents; + public function __construct(ApplicationName $name, Version $version, Type $type, CopyrightInformation $copyrightInformation, RequirementCollection $requirements, BundledComponentCollection $bundledComponents) + { + $this->name = $name; + $this->version = $version; + $this->type = $type; + $this->copyrightInformation = $copyrightInformation; + $this->requirements = $requirements; + $this->bundledComponents = $bundledComponents; + } + public function getName(): ApplicationName + { + return $this->name; + } + public function getVersion(): Version + { + return $this->version; + } + public function getType(): Type + { + return $this->type; + } + public function getCopyrightInformation(): CopyrightInformation + { + return $this->copyrightInformation; + } + public function getRequirements(): RequirementCollection + { + return $this->requirements; + } + public function getBundledComponents(): BundledComponentCollection + { + return $this->bundledComponents; + } + public function isApplication(): bool + { + return $this->type->isApplication(); + } + public function isLibrary(): bool + { + return $this->type->isLibrary(); + } + public function isExtension(): bool + { + return $this->type->isExtension(); + } + public function isExtensionFor(ApplicationName $application, ?Version $version = null): bool + { + if (!$this->isExtension()) { + return \false; + } + /** @var Extension $type */ + $type = $this->type; + if ($version !== null) { + return $type->isCompatibleWith($application, $version); + } + return $type->isExtensionFor($application); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class PhpExtensionRequirement implements Requirement +{ + /** @var string */ + private $extension; + public function __construct(string $extension) + { + $this->extension = $extension; + } + public function asString(): string + { + return $this->extension; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use PHPUnitPHAR\PharIo\Version\VersionConstraint; +class PhpVersionRequirement implements Requirement +{ + /** @var VersionConstraint */ + private $versionConstraint; + public function __construct(VersionConstraint $versionConstraint) + { + $this->versionConstraint = $versionConstraint; + } + public function getVersionConstraint(): VersionConstraint + { + return $this->versionConstraint; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +interface Requirement +{ +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use Countable; +use IteratorAggregate; +use function count; +/** @template-implements IteratorAggregate */ +class RequirementCollection implements Countable, IteratorAggregate +{ + /** @var Requirement[] */ + private $requirements = []; + public function add(Requirement $requirement): void + { + $this->requirements[] = $requirement; + } + /** + * @return Requirement[] + */ + public function getRequirements(): array + { + return $this->requirements; + } + public function count(): int + { + return count($this->requirements); + } + public function getIterator(): RequirementCollectionIterator + { + return new RequirementCollectionIterator($this); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use Iterator; +use function count; +/** @template-implements Iterator */ +class RequirementCollectionIterator implements Iterator +{ + /** @var Requirement[] */ + private $requirements; + /** @var int */ + private $position = 0; + public function __construct(RequirementCollection $requirements) + { + $this->requirements = $requirements->getRequirements(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return $this->position < count($this->requirements); + } + public function key(): int + { + return $this->position; + } + public function current(): Requirement + { + return $this->requirements[$this->position]; + } + public function next(): void + { + $this->position++; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use PHPUnitPHAR\PharIo\Version\VersionConstraint; +abstract class Type +{ + public static function application(): Application + { + return new Application(); + } + public static function library(): Library + { + return new Library(); + } + public static function extension(ApplicationName $application, VersionConstraint $versionConstraint): Extension + { + return new Extension($application, $versionConstraint); + } + /** @psalm-assert-if-true Application $this */ + public function isApplication(): bool + { + return \false; + } + /** @psalm-assert-if-true Library $this */ + public function isLibrary(): bool + { + return \false; + } + /** @psalm-assert-if-true Extension $this */ + public function isExtension(): bool + { + return \false; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use const FILTER_VALIDATE_URL; +use function filter_var; +class Url +{ + /** @var string */ + private $url; + public function __construct(string $url) + { + $this->ensureUrlIsValid($url); + $this->url = $url; + } + public function asString(): string + { + return $this->url; + } + /** + * @throws InvalidUrlException + */ + private function ensureUrlIsValid(string $url): void + { + if (filter_var($url, FILTER_VALIDATE_URL) === \false) { + throw new InvalidUrlException(); + } + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class AuthorElement extends ManifestElement +{ + public function getName(): string + { + return $this->getAttributeValue('name'); + } + public function getEmail(): string + { + return $this->getAttributeValue('email'); + } + public function hasEMail(): bool + { + return $this->hasAttribute('email'); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class AuthorElementCollection extends ElementCollection +{ + public function current(): AuthorElement + { + return new AuthorElement($this->getCurrentElement()); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class BundlesElement extends ManifestElement +{ + public function getComponentElements(): ComponentElementCollection + { + return new ComponentElementCollection($this->getChildrenByName('component')); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class ComponentElement extends ManifestElement +{ + public function getName(): string + { + return $this->getAttributeValue('name'); + } + public function getVersion(): string + { + return $this->getAttributeValue('version'); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class ComponentElementCollection extends ElementCollection +{ + public function current(): ComponentElement + { + return new ComponentElement($this->getCurrentElement()); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class ContainsElement extends ManifestElement +{ + public function getName(): string + { + return $this->getAttributeValue('name'); + } + public function getVersion(): string + { + return $this->getAttributeValue('version'); + } + public function getType(): string + { + return $this->getAttributeValue('type'); + } + public function getExtensionElement(): ExtensionElement + { + return new ExtensionElement($this->getChildByName('extension')); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class CopyrightElement extends ManifestElement +{ + public function getAuthorElements(): AuthorElementCollection + { + return new AuthorElementCollection($this->getChildrenByName('author')); + } + public function getLicenseElement(): LicenseElement + { + return new LicenseElement($this->getChildByName('license')); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use DOMElement; +use DOMNodeList; +use Iterator; +use ReturnTypeWillChange; +use function count; +use function get_class; +use function sprintf; +/** @template-implements Iterator */ +abstract class ElementCollection implements Iterator +{ + /** @var DOMElement[] */ + private $nodes = []; + /** @var int */ + private $position; + public function __construct(DOMNodeList $nodeList) + { + $this->position = 0; + $this->importNodes($nodeList); + } + #[ReturnTypeWillChange] + abstract public function current(); + public function next(): void + { + $this->position++; + } + public function key(): int + { + return $this->position; + } + public function valid(): bool + { + return $this->position < count($this->nodes); + } + public function rewind(): void + { + $this->position = 0; + } + protected function getCurrentElement(): DOMElement + { + return $this->nodes[$this->position]; + } + private function importNodes(DOMNodeList $nodeList): void + { + foreach ($nodeList as $node) { + if (!$node instanceof DOMElement) { + throw new ElementCollectionException(sprintf('\DOMElement expected, got \%s', get_class($node))); + } + $this->nodes[] = $node; + } + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class ExtElement extends ManifestElement +{ + public function getName(): string + { + return $this->getAttributeValue('name'); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class ExtElementCollection extends ElementCollection +{ + public function current(): ExtElement + { + return new ExtElement($this->getCurrentElement()); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class ExtensionElement extends ManifestElement +{ + public function getFor(): string + { + return $this->getAttributeValue('for'); + } + public function getCompatible(): string + { + return $this->getAttributeValue('compatible'); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class LicenseElement extends ManifestElement +{ + public function getType(): string + { + return $this->getAttributeValue('type'); + } + public function getUrl(): string + { + return $this->getAttributeValue('url'); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use DOMDocument; +use DOMElement; +use Throwable; +use function count; +use function file_get_contents; +use function is_file; +use function libxml_clear_errors; +use function libxml_get_errors; +use function libxml_use_internal_errors; +use function sprintf; +class ManifestDocument +{ + public const XMLNS = 'https://phar.io/xml/manifest/1.0'; + /** @var DOMDocument */ + private $dom; + public static function fromFile(string $filename): ManifestDocument + { + if (!is_file($filename)) { + throw new ManifestDocumentException(sprintf('File "%s" not found', $filename)); + } + return self::fromString(file_get_contents($filename)); + } + public static function fromString(string $xmlString): ManifestDocument + { + $prev = libxml_use_internal_errors(\true); + libxml_clear_errors(); + try { + $dom = new DOMDocument(); + $dom->loadXML($xmlString); + $errors = libxml_get_errors(); + libxml_use_internal_errors($prev); + } catch (Throwable $t) { + throw new ManifestDocumentException($t->getMessage(), 0, $t); + } + if (count($errors) !== 0) { + throw new ManifestDocumentLoadingException($errors); + } + return new self($dom); + } + private function __construct(DOMDocument $dom) + { + $this->ensureCorrectDocumentType($dom); + $this->dom = $dom; + } + public function getContainsElement(): ContainsElement + { + return new ContainsElement($this->fetchElementByName('contains')); + } + public function getCopyrightElement(): CopyrightElement + { + return new CopyrightElement($this->fetchElementByName('copyright')); + } + public function getRequiresElement(): RequiresElement + { + return new RequiresElement($this->fetchElementByName('requires')); + } + public function hasBundlesElement(): bool + { + return $this->dom->getElementsByTagNameNS(self::XMLNS, 'bundles')->length === 1; + } + public function getBundlesElement(): BundlesElement + { + return new BundlesElement($this->fetchElementByName('bundles')); + } + private function ensureCorrectDocumentType(DOMDocument $dom): void + { + $root = $dom->documentElement; + if ($root->localName !== 'phar' || $root->namespaceURI !== self::XMLNS) { + throw new ManifestDocumentException('Not a phar.io manifest document'); + } + } + private function fetchElementByName(string $elementName): DOMElement + { + $element = $this->dom->getElementsByTagNameNS(self::XMLNS, $elementName)->item(0); + if (!$element instanceof DOMElement) { + throw new ManifestDocumentException(sprintf('Element %s missing', $elementName)); + } + return $element; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +use DOMElement; +use DOMNodeList; +use function sprintf; +class ManifestElement +{ + public const XMLNS = 'https://phar.io/xml/manifest/1.0'; + /** @var DOMElement */ + private $element; + public function __construct(DOMElement $element) + { + $this->element = $element; + } + protected function getAttributeValue(string $name): string + { + if (!$this->element->hasAttribute($name)) { + throw new ManifestElementException(sprintf('Attribute %s not set on element %s', $name, $this->element->localName)); + } + return $this->element->getAttribute($name); + } + protected function hasAttribute(string $name): bool + { + return $this->element->hasAttribute($name); + } + protected function getChildByName(string $elementName): DOMElement + { + $element = $this->element->getElementsByTagNameNS(self::XMLNS, $elementName)->item(0); + if (!$element instanceof DOMElement) { + throw new ManifestElementException(sprintf('Element %s missing', $elementName)); + } + return $element; + } + protected function getChildrenByName(string $elementName): DOMNodeList + { + $elementList = $this->element->getElementsByTagNameNS(self::XMLNS, $elementName); + if ($elementList->length === 0) { + throw new ManifestElementException(sprintf('Element(s) %s missing', $elementName)); + } + return $elementList; + } + protected function hasChild(string $elementName): bool + { + return $this->element->getElementsByTagNameNS(self::XMLNS, $elementName)->length !== 0; + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class PhpElement extends ManifestElement +{ + public function getVersion(): string + { + return $this->getAttributeValue('version'); + } + public function hasExtElements(): bool + { + return $this->hasChild('ext'); + } + public function getExtElements(): ExtElementCollection + { + return new ExtElementCollection($this->getChildrenByName('ext')); + } +} +, Sebastian Heuer , Sebastian Bergmann and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + */ +namespace PHPUnitPHAR\PharIo\Manifest; + +class RequiresElement extends ManifestElement +{ + public function getPHPElement(): PhpElement + { + return new PhpElement($this->getChildByName('php')); + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +class BuildMetaData +{ + /** @var string */ + private $value; + public function __construct(string $value) + { + $this->value = $value; + } + public function asString(): string + { + return $this->value; + } + public function equals(BuildMetaData $other): bool + { + return $this->asString() === $other->asString(); + } +} +Copyright (c) 2016-2017 Arne Blankerts , Sebastian Heuer and contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + 0, 'a' => 1, 'alpha' => 1, 'b' => 2, 'beta' => 2, 'rc' => 3, 'p' => 4, 'pl' => 4, 'patch' => 4]; + /** @var string */ + private $value; + /** @var int */ + private $valueScore; + /** @var int */ + private $number = 0; + /** @var string */ + private $full; + /** + * @throws InvalidPreReleaseSuffixException + */ + public function __construct(string $value) + { + $this->parseValue($value); + } + public function asString(): string + { + return $this->full; + } + public function getValue(): string + { + return $this->value; + } + public function getNumber(): ?int + { + return $this->number; + } + public function isGreaterThan(PreReleaseSuffix $suffix): bool + { + if ($this->valueScore > $suffix->valueScore) { + return \true; + } + if ($this->valueScore < $suffix->valueScore) { + return \false; + } + return $this->getNumber() > $suffix->getNumber(); + } + private function mapValueToScore(string $value): int + { + $value = \strtolower($value); + return self::valueScoreMap[$value]; + } + private function parseValue(string $value): void + { + $regex = '/-?((dev|beta|b|rc|alpha|a|patch|p|pl)\.?(\d*)).*$/i'; + if (\preg_match($regex, $value, $matches) !== 1) { + throw new InvalidPreReleaseSuffixException(\sprintf('Invalid label %s', $value)); + } + $this->full = $matches[1]; + $this->value = $matches[2]; + if ($matches[3] !== '') { + $this->number = (int) $matches[3]; + } + $this->valueScore = $this->mapValueToScore($matches[2]); + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +class Version +{ + /** @var string */ + private $originalVersionString; + /** @var VersionNumber */ + private $major; + /** @var VersionNumber */ + private $minor; + /** @var VersionNumber */ + private $patch; + /** @var null|PreReleaseSuffix */ + private $preReleaseSuffix; + /** @var null|BuildMetaData */ + private $buildMetadata; + public function __construct(string $versionString) + { + $this->ensureVersionStringIsValid($versionString); + $this->originalVersionString = $versionString; + } + /** + * @throws NoPreReleaseSuffixException + */ + public function getPreReleaseSuffix(): PreReleaseSuffix + { + if ($this->preReleaseSuffix === null) { + throw new NoPreReleaseSuffixException('No pre-release suffix set'); + } + return $this->preReleaseSuffix; + } + public function getOriginalString(): string + { + return $this->originalVersionString; + } + public function getVersionString(): string + { + $str = \sprintf('%d.%d.%d', $this->getMajor()->getValue() ?? 0, $this->getMinor()->getValue() ?? 0, $this->getPatch()->getValue() ?? 0); + if (!$this->hasPreReleaseSuffix()) { + return $str; + } + return $str . '-' . $this->getPreReleaseSuffix()->asString(); + } + public function hasPreReleaseSuffix(): bool + { + return $this->preReleaseSuffix !== null; + } + public function equals(Version $other): bool + { + if ($this->getVersionString() !== $other->getVersionString()) { + return \false; + } + if ($this->hasBuildMetaData() !== $other->hasBuildMetaData()) { + return \false; + } + if ($this->hasBuildMetaData() && $other->hasBuildMetaData() && !$this->getBuildMetaData()->equals($other->getBuildMetaData())) { + return \false; + } + return \true; + } + public function isGreaterThan(Version $version): bool + { + if ($version->getMajor()->getValue() > $this->getMajor()->getValue()) { + return \false; + } + if ($version->getMajor()->getValue() < $this->getMajor()->getValue()) { + return \true; + } + if ($version->getMinor()->getValue() > $this->getMinor()->getValue()) { + return \false; + } + if ($version->getMinor()->getValue() < $this->getMinor()->getValue()) { + return \true; + } + if ($version->getPatch()->getValue() > $this->getPatch()->getValue()) { + return \false; + } + if ($version->getPatch()->getValue() < $this->getPatch()->getValue()) { + return \true; + } + if (!$version->hasPreReleaseSuffix() && !$this->hasPreReleaseSuffix()) { + return \false; + } + if ($version->hasPreReleaseSuffix() && !$this->hasPreReleaseSuffix()) { + return \true; + } + if (!$version->hasPreReleaseSuffix() && $this->hasPreReleaseSuffix()) { + return \false; + } + return $this->getPreReleaseSuffix()->isGreaterThan($version->getPreReleaseSuffix()); + } + public function getMajor(): VersionNumber + { + return $this->major; + } + public function getMinor(): VersionNumber + { + return $this->minor; + } + public function getPatch(): VersionNumber + { + return $this->patch; + } + /** + * @psalm-assert-if-true BuildMetaData $this->buildMetadata + * @psalm-assert-if-true BuildMetaData $this->getBuildMetaData() + */ + public function hasBuildMetaData(): bool + { + return $this->buildMetadata !== null; + } + /** + * @throws NoBuildMetaDataException + */ + public function getBuildMetaData(): BuildMetaData + { + if (!$this->hasBuildMetaData()) { + throw new NoBuildMetaDataException('No build metadata set'); + } + return $this->buildMetadata; + } + /** + * @param string[] $matches + * + * @throws InvalidPreReleaseSuffixException + */ + private function parseVersion(array $matches): void + { + $this->major = new VersionNumber((int) $matches['Major']); + $this->minor = new VersionNumber((int) $matches['Minor']); + $this->patch = isset($matches['Patch']) ? new VersionNumber((int) $matches['Patch']) : new VersionNumber(0); + if (isset($matches['PreReleaseSuffix']) && $matches['PreReleaseSuffix'] !== '') { + $this->preReleaseSuffix = new PreReleaseSuffix($matches['PreReleaseSuffix']); + } + if (isset($matches['BuildMetadata'])) { + $this->buildMetadata = new BuildMetaData($matches['BuildMetadata']); + } + } + /** + * @param string $version + * + * @throws InvalidVersionException + */ + private function ensureVersionStringIsValid($version): void + { + $regex = '/^v? + (?P0|[1-9]\d*) + \. + (?P0|[1-9]\d*) + (\. + (?P0|[1-9]\d*) + )? + (?: + - + (?(?:(dev|beta|b|rc|alpha|a|patch|p|pl)\.?\d*)) + )? + (?: + \+ + (?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-@]+)*) + )? + $/xi'; + if (\preg_match($regex, $version, $matches) !== 1) { + throw new InvalidVersionException(\sprintf("Version string '%s' does not follow SemVer semantics", $version)); + } + $this->parseVersion($matches); + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +class VersionConstraintParser +{ + /** + * @throws UnsupportedVersionConstraintException + */ + public function parse(string $value): VersionConstraint + { + if (\strpos($value, '|') !== \false) { + return $this->handleOrGroup($value); + } + if (!\preg_match('/^[\^~*]?v?[\d.*]+(?:-.*)?$/i', $value)) { + throw new UnsupportedVersionConstraintException(\sprintf('Version constraint %s is not supported.', $value)); + } + switch ($value[0]) { + case '~': + return $this->handleTildeOperator($value); + case '^': + return $this->handleCaretOperator($value); + } + $constraint = new VersionConstraintValue($value); + if ($constraint->getMajor()->isAny()) { + return new AnyVersionConstraint(); + } + if ($constraint->getMinor()->isAny()) { + return new SpecificMajorVersionConstraint($constraint->getVersionString(), $constraint->getMajor()->getValue() ?? 0); + } + if ($constraint->getPatch()->isAny()) { + return new SpecificMajorAndMinorVersionConstraint($constraint->getVersionString(), $constraint->getMajor()->getValue() ?? 0, $constraint->getMinor()->getValue() ?? 0); + } + return new ExactVersionConstraint($constraint->getVersionString()); + } + private function handleOrGroup(string $value): OrVersionConstraintGroup + { + $constraints = []; + foreach (\preg_split('{\s*\|\|?\s*}', \trim($value)) as $groupSegment) { + $constraints[] = $this->parse(\trim($groupSegment)); + } + return new OrVersionConstraintGroup($value, $constraints); + } + private function handleTildeOperator(string $value): AndVersionConstraintGroup + { + $constraintValue = new VersionConstraintValue(\substr($value, 1)); + if ($constraintValue->getPatch()->isAny()) { + return $this->handleCaretOperator($value); + } + $constraints = [new GreaterThanOrEqualToVersionConstraint($value, new Version(\substr($value, 1))), new SpecificMajorAndMinorVersionConstraint($value, $constraintValue->getMajor()->getValue() ?? 0, $constraintValue->getMinor()->getValue() ?? 0)]; + return new AndVersionConstraintGroup($value, $constraints); + } + private function handleCaretOperator(string $value): AndVersionConstraintGroup + { + $constraintValue = new VersionConstraintValue(\substr($value, 1)); + $constraints = [new GreaterThanOrEqualToVersionConstraint($value, new Version(\substr($value, 1)))]; + if ($constraintValue->getMajor()->getValue() === 0) { + $constraints[] = new SpecificMajorAndMinorVersionConstraint($value, $constraintValue->getMajor()->getValue() ?? 0, $constraintValue->getMinor()->getValue() ?? 0); + } else { + $constraints[] = new SpecificMajorVersionConstraint($value, $constraintValue->getMajor()->getValue() ?? 0); + } + return new AndVersionConstraintGroup($value, $constraints); + } +} +versionString = $versionString; + $this->parseVersion($versionString); + } + public function getLabel(): string + { + return $this->label; + } + public function getBuildMetaData(): string + { + return $this->buildMetaData; + } + public function getVersionString(): string + { + return $this->versionString; + } + public function getMajor(): VersionNumber + { + return $this->major; + } + public function getMinor(): VersionNumber + { + return $this->minor; + } + public function getPatch(): VersionNumber + { + return $this->patch; + } + private function parseVersion(string $versionString): void + { + $this->extractBuildMetaData($versionString); + $this->extractLabel($versionString); + $this->stripPotentialVPrefix($versionString); + $versionSegments = \explode('.', $versionString); + $this->major = new VersionNumber(\is_numeric($versionSegments[0]) ? (int) $versionSegments[0] : null); + $minorValue = isset($versionSegments[1]) && \is_numeric($versionSegments[1]) ? (int) $versionSegments[1] : null; + $patchValue = isset($versionSegments[2]) && \is_numeric($versionSegments[2]) ? (int) $versionSegments[2] : null; + $this->minor = new VersionNumber($minorValue); + $this->patch = new VersionNumber($patchValue); + } + private function extractBuildMetaData(string &$versionString): void + { + if (\preg_match('/\+(.*)/', $versionString, $matches) === 1) { + $this->buildMetaData = $matches[1]; + $versionString = \str_replace($matches[0], '', $versionString); + } + } + private function extractLabel(string &$versionString): void + { + if (\preg_match('/-(.*)/', $versionString, $matches) === 1) { + $this->label = $matches[1]; + $versionString = \str_replace($matches[0], '', $versionString); + } + } + private function stripPotentialVPrefix(string &$versionString): void + { + if ($versionString[0] !== 'v') { + return; + } + $versionString = \substr($versionString, 1); + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +class VersionNumber +{ + /** @var ?int */ + private $value; + public function __construct(?int $value) + { + $this->value = $value; + } + public function isAny(): bool + { + return $this->value === null; + } + public function getValue(): ?int + { + return $this->value; + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +abstract class AbstractVersionConstraint implements VersionConstraint +{ + /** @var string */ + private $originalValue; + public function __construct(string $originalValue) + { + $this->originalValue = $originalValue; + } + public function asString(): string + { + return $this->originalValue; + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +class AndVersionConstraintGroup extends AbstractVersionConstraint +{ + /** @var VersionConstraint[] */ + private $constraints = []; + /** + * @param VersionConstraint[] $constraints + */ + public function __construct(string $originalValue, array $constraints) + { + parent::__construct($originalValue); + $this->constraints = $constraints; + } + public function complies(Version $version): bool + { + foreach ($this->constraints as $constraint) { + if (!$constraint->complies($version)) { + return \false; + } + } + return \true; + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +class AnyVersionConstraint implements VersionConstraint +{ + public function complies(Version $version): bool + { + return \true; + } + public function asString(): string + { + return '*'; + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +class ExactVersionConstraint extends AbstractVersionConstraint +{ + public function complies(Version $version): bool + { + $other = $version->getVersionString(); + if ($version->hasBuildMetaData()) { + $other .= '+' . $version->getBuildMetaData()->asString(); + } + return $this->asString() === $other; + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +class GreaterThanOrEqualToVersionConstraint extends AbstractVersionConstraint +{ + /** @var Version */ + private $minimalVersion; + public function __construct(string $originalValue, Version $minimalVersion) + { + parent::__construct($originalValue); + $this->minimalVersion = $minimalVersion; + } + public function complies(Version $version): bool + { + return $version->getVersionString() === $this->minimalVersion->getVersionString() || $version->isGreaterThan($this->minimalVersion); + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +class OrVersionConstraintGroup extends AbstractVersionConstraint +{ + /** @var VersionConstraint[] */ + private $constraints = []; + /** + * @param string $originalValue + * @param VersionConstraint[] $constraints + */ + public function __construct($originalValue, array $constraints) + { + parent::__construct($originalValue); + $this->constraints = $constraints; + } + public function complies(Version $version): bool + { + foreach ($this->constraints as $constraint) { + if ($constraint->complies($version)) { + return \true; + } + } + return \false; + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +class SpecificMajorAndMinorVersionConstraint extends AbstractVersionConstraint +{ + /** @var int */ + private $major; + /** @var int */ + private $minor; + public function __construct(string $originalValue, int $major, int $minor) + { + parent::__construct($originalValue); + $this->major = $major; + $this->minor = $minor; + } + public function complies(Version $version): bool + { + if ($version->getMajor()->getValue() !== $this->major) { + return \false; + } + return $version->getMinor()->getValue() === $this->minor; + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +class SpecificMajorVersionConstraint extends AbstractVersionConstraint +{ + /** @var int */ + private $major; + public function __construct(string $originalValue, int $major) + { + parent::__construct($originalValue); + $this->major = $major; + } + public function complies(Version $version): bool + { + return $version->getMajor()->getValue() === $this->major; + } +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +interface VersionConstraint +{ + public function complies(Version $version): bool; + public function asString(): string; +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +use Throwable; +interface Exception extends Throwable +{ +} +, Sebastian Heuer , Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\PharIo\Version; + +final class UnsupportedVersionConstraintException extends \RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use function array_merge; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedCodeCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\Driver; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Builder; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\CachingSourceAnalyser; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\ParsingSourceAnalyser; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\MapBuilder; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\Mapper; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\TargetCollection; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\TargetCollectionValidator; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\ValidationResult; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestSize; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestStatus; +/** + * Provides collection functionality for PHP code coverage information. + * + * @phpstan-type TestType array{size: string, status: string, time: float} + * @phpstan-type TargetedLines array> + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class CodeCoverage +{ + private const string UNCOVERED_FILES = 'UNCOVERED_FILES'; + private readonly Driver $driver; + private readonly Filter $filter; + private ?FileAnalyser $analyser = null; + private ?Mapper $targetMapper = null; + private ?string $cacheDirectory = null; + private bool $checkForUnintentionallyCoveredCode = \false; + private bool $collectBranchAndPathCoverage = \false; + private bool $includeUncoveredFiles = \true; + private bool $ignoreDeprecatedCode = \false; + private bool $useAnnotationsForIgnoringCode = \true; + /** + * @var list + */ + private array $parentClassesExcludedFromUnintentionallyCoveredCodeCheck = []; + private ?string $currentId = null; + private ?TestSize $currentSize = null; + private ProcessedCodeCoverageData $data; + /** + * @var array + */ + private array $tests = []; + private ?Directory $cachedReport = null; + public function __construct(Driver $driver, Filter $filter) + { + $this->driver = $driver; + $this->filter = $filter; + $this->data = new ProcessedCodeCoverageData(); + } + /** + * @internal This method is not covered by the backward compatibility promise for phpunit/php-code-coverage + */ + public function getReport(): Directory + { + if ($this->cachedReport === null) { + $this->cachedReport = (new Builder($this->analyser()))->build($this->getData(), $this->tests); + } + return $this->cachedReport; + } + /** + * Clears collected code coverage data. + */ + public function clear(): void + { + $this->currentId = null; + $this->currentSize = null; + $this->data = new ProcessedCodeCoverageData(); + $this->tests = []; + $this->cachedReport = null; + } + /** + * @internal + */ + public function clearCache(): void + { + $this->cachedReport = null; + } + /** + * Returns the filter object used. + */ + public function filter(): Filter + { + return $this->filter; + } + /** + * Returns the collected code coverage data. + */ + public function getData(bool $raw = \false): ProcessedCodeCoverageData + { + if (!$raw) { + if ($this->includeUncoveredFiles) { + $this->addUncoveredFilesFromFilter(); + } + } + return $this->data; + } + /** + * Sets the coverage data. + */ + public function setData(ProcessedCodeCoverageData $data): void + { + $this->data = $data; + } + /** + * @return array + */ + public function getTests(): array + { + return $this->tests; + } + /** + * @param array $tests + */ + public function setTests(array $tests): void + { + $this->tests = $tests; + } + public function start(string $id, ?TestSize $size = null, bool $clear = \false): void + { + if ($clear) { + $this->clear(); + } + $this->currentId = $id; + $this->currentSize = $size; + $this->driver->start(); + $this->cachedReport = null; + } + public function stop(bool $append = \true, ?TestStatus $status = null, null|false|TargetCollection $covers = null, ?TargetCollection $uses = null, float $time = 0.0): RawCodeCoverageData + { + $data = $this->driver->stop(); + $this->append($data, null, $append, $status, $covers, $uses, $time); + $this->currentId = null; + $this->currentSize = null; + $this->cachedReport = null; + return $data; + } + /** + * @throws ReflectionException + * @throws TestIdMissingException + * @throws UnintentionallyCoveredCodeException + */ + public function append(RawCodeCoverageData $rawData, ?string $id = null, bool $append = \true, ?TestStatus $status = null, null|false|TargetCollection $covers = null, ?TargetCollection $uses = null, float $time = 0.0): void + { + if ($id === null) { + $id = $this->currentId; + } + if ($id === null) { + throw new TestIdMissingException(); + } + if ($status === null) { + $status = TestStatus::Unknown; + } + if ($covers === null) { + $covers = TargetCollection::fromArray([]); + } + if ($uses === null) { + $uses = TargetCollection::fromArray([]); + } + $size = $this->currentSize; + if ($size === null) { + $size = TestSize::Unknown; + } + $this->cachedReport = null; + $filterProcessor = new FilterProcessor(); + $filterProcessor->applyFilter($rawData, $this->filter); + $filterProcessor->applyExecutableLinesFilter($rawData, $this->filter, $this->analyser()); + if ($this->useAnnotationsForIgnoringCode) { + $filterProcessor->applyIgnoredLinesFilter($rawData, $this->filter, $this->analyser()); + } + $this->data->initializeUnseenData($rawData); + if (!$append) { + return; + } + if ($id === self::UNCOVERED_FILES) { + return; + } + $linesToBeCovered = \false; + $linesToBeUsed = []; + if ($covers !== \false) { + $linesToBeCovered = $this->targetMapper()->mapTargets($covers); + } else { + $covers = TargetCollection::fromArray([]); + } + if ($linesToBeCovered !== \false) { + $linesToBeUsed = $this->targetMapper()->mapTargets($uses); + } + $filterProcessor->applyCoversAndUsesFilter($rawData, $linesToBeCovered, $linesToBeUsed, $size, $this->checkForUnintentionallyCoveredCode, $this->targetMapper, $this->parentClassesExcludedFromUnintentionallyCoveredCodeCheck, $covers, $uses); + if ($rawData->lineCoverage() === []) { + return; + } + $this->tests[$id] = ['size' => $size->asString(), 'status' => $status->asString(), 'time' => $time]; + $this->data->markCodeAsExecutedByTestCase($id, $rawData); + } + public function merge(self $that): void + { + $this->filter->includeFiles($that->filter()->files()); + $this->data->merge($that->data); + $this->tests = array_merge($this->tests, $that->getTests()); + $this->cachedReport = null; + } + public function enableCheckForUnintentionallyCoveredCode(): void + { + $this->checkForUnintentionallyCoveredCode = \true; + } + public function disableCheckForUnintentionallyCoveredCode(): void + { + $this->checkForUnintentionallyCoveredCode = \false; + } + public function includeUncoveredFiles(): void + { + $this->includeUncoveredFiles = \true; + } + public function excludeUncoveredFiles(): void + { + $this->includeUncoveredFiles = \false; + } + public function enableAnnotationsForIgnoringCode(): void + { + $this->useAnnotationsForIgnoringCode = \true; + } + public function disableAnnotationsForIgnoringCode(): void + { + $this->useAnnotationsForIgnoringCode = \false; + } + public function ignoreDeprecatedCode(): void + { + $this->ignoreDeprecatedCode = \true; + } + public function doNotIgnoreDeprecatedCode(): void + { + $this->ignoreDeprecatedCode = \false; + } + /** + * @phpstan-assert-if-true !null $this->cacheDirectory + */ + public function cachesStaticAnalysis(): bool + { + return $this->cacheDirectory !== null; + } + public function cacheStaticAnalysis(string $directory): void + { + $this->cacheDirectory = $directory; + } + public function doNotCacheStaticAnalysis(): void + { + $this->cacheDirectory = null; + } + /** + * @throws StaticAnalysisCacheNotConfiguredException + */ + public function cacheDirectory(): string + { + if (!$this->cachesStaticAnalysis()) { + throw new StaticAnalysisCacheNotConfiguredException('The static analysis cache is not configured'); + } + return $this->cacheDirectory; + } + /** + * @param class-string $className + */ + public function excludeSubclassesOfThisClassFromUnintentionallyCoveredCodeCheck(string $className): void + { + $this->parentClassesExcludedFromUnintentionallyCoveredCodeCheck[] = $className; + } + public function enableBranchAndPathCoverage(): void + { + $this->driver->enableBranchAndPathCoverage(); + $this->collectBranchAndPathCoverage = \true; + } + public function disableBranchAndPathCoverage(): void + { + $this->driver->disableBranchAndPathCoverage(); + $this->collectBranchAndPathCoverage = \false; + } + public function collectsBranchAndPathCoverage(): bool + { + return $this->collectBranchAndPathCoverage; + } + public function validate(TargetCollection $targets): ValidationResult + { + return (new TargetCollectionValidator())->validate($this->targetMapper(), $targets); + } + /** + * @return array{name: non-empty-string, version: non-empty-string} + * + * @internal This method is not covered by the backward compatibility promise for phpunit/php-code-coverage + */ + public function driverInformation(): array + { + return ['name' => $this->driver->name(), 'version' => $this->driver->version()]; + } + /** + * @throws UnintentionallyCoveredCodeException + */ + private function addUncoveredFilesFromFilter(): void + { + $uncoveredFilesData = (new FilterProcessor())->uncoveredFilesFromFilter($this->filter, $this->data, $this->analyser()); + foreach ($uncoveredFilesData as $rawData) { + $this->append($rawData, self::UNCOVERED_FILES); + } + } + private function targetMapper(): Mapper + { + if ($this->targetMapper !== null) { + return $this->targetMapper; + } + $this->targetMapper = new Mapper((new MapBuilder())->build($this->filter, $this->analyser())); + return $this->targetMapper; + } + private function analyser(): FileAnalyser + { + if ($this->analyser !== null) { + return $this->analyser; + } + $sourceAnalyser = new ParsingSourceAnalyser(); + if ($this->cachesStaticAnalysis()) { + $sourceAnalyser = new CachingSourceAnalyser($this->cacheDirectory, $sourceAnalyser); + } + $this->analyser = new FileAnalyser($sourceAnalyser, $this->useAnnotationsForIgnoringCode, $this->ignoreDeprecatedCode); + return $this->analyser; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data; + +use function array_merge; +use function array_unique; +use NoDiscard; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\XdebugDriver; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type TestIdType from ProcessedCodeCoverageData + * @phpstan-import-type XdebugBranchCoverageType from XdebugDriver + */ +final class ProcessedBranchCoverageData +{ + public readonly int $op_start; + public readonly int $op_end; + public readonly int $line_start; + public readonly int $line_end; + /** @var list */ + public array $hit; + /** @var array */ + public readonly array $out; + /** @var array */ + public readonly array $out_hit; + /** + * @param XdebugBranchCoverageType $xdebugCoverageData + */ + public static function fromXdebugCoverage(array $xdebugCoverageData): self + { + return new self($xdebugCoverageData['op_start'], $xdebugCoverageData['op_end'], $xdebugCoverageData['line_start'], $xdebugCoverageData['line_end'], [], $xdebugCoverageData['out'], $xdebugCoverageData['out_hit']); + } + /** + * @param list $hit + * @param array $out + * @param array $out_hit + */ + public function __construct(int $op_start, int $op_end, int $line_start, int $line_end, array $hit, array $out, array $out_hit) + { + $this->out_hit = $out_hit; + $this->out = $out; + $this->hit = $hit; + $this->line_end = $line_end; + $this->line_start = $line_start; + $this->op_end = $op_end; + $this->op_start = $op_start; + } + #[NoDiscard] + public function merge(self $data): self + { + if ($data->hit === []) { + return $this; + } + return new self($this->op_start, $this->op_end, $this->line_start, $this->line_end, array_unique(array_merge($this->hit, $data->hit)), $this->out, $this->out_hit); + } + /** + * @param TestIdType $testCaseId + */ + public function recordHit(string $testCaseId): void + { + $this->hit[] = $testCaseId; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class ProcessedClassType +{ + public readonly string $className; + public readonly string $namespace; + /** + * @var array + */ + public array $methods; + public readonly int $startLine; + public int $executableLines; + public int $executedLines; + public int $executableBranches; + public int $executedBranches; + public int $executablePaths; + public int $executedPaths; + public int $ccn; + public float|int $coverage; + public int|string $crap; + public readonly string $link; + /** + * @param array $methods + */ + public function __construct(string $className, string $namespace, array $methods, int $startLine, int $executableLines, int $executedLines, int $executableBranches, int $executedBranches, int $executablePaths, int $executedPaths, int $ccn, float|int $coverage, int|string $crap, string $link) + { + $this->className = $className; + $this->namespace = $namespace; + $this->methods = $methods; + $this->startLine = $startLine; + $this->executableLines = $executableLines; + $this->executedLines = $executedLines; + $this->executableBranches = $executableBranches; + $this->executedBranches = $executedBranches; + $this->executablePaths = $executablePaths; + $this->executedPaths = $executedPaths; + $this->ccn = $ccn; + $this->coverage = $coverage; + $this->crap = $crap; + $this->link = $link; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data; + +use function array_key_exists; +use function array_keys; +use function array_merge; +use function array_unique; +use function count; +use function is_array; +use function ksort; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\Driver; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\XdebugDriver; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type XdebugFunctionCoverageType from XdebugDriver + * + * @phpstan-type TestIdType string + * @phpstan-type FunctionCoverageType array> + * @phpstan-type LineCoverageType array>> + */ +final class ProcessedCodeCoverageData +{ + /** + * Line coverage data. + * An array of filenames, each having an array of linenumbers, each executable line having an array of testcase ids. + * + * @var LineCoverageType + */ + private array $lineCoverage = []; + /** + * Function coverage data. + * Maintains base format of raw data (@see https://xdebug.org/docs/code_coverage), but each 'hit' entry is an array + * of testcase ids. + * + * @var FunctionCoverageType + */ + private array $functionCoverage = []; + public function initializeUnseenData(RawCodeCoverageData $rawData): void + { + foreach ($rawData->lineCoverage() as $file => $lines) { + if (!isset($this->lineCoverage[$file])) { + $this->lineCoverage[$file] = []; + foreach ($lines as $k => $v) { + $this->lineCoverage[$file][$k] = $v === Driver::LINE_NOT_EXECUTABLE ? null : []; + } + } + } + foreach ($rawData->functionCoverage() as $file => $functions) { + foreach ($functions as $functionName => $functionData) { + if (isset($this->functionCoverage[$file][$functionName])) { + $this->initPreviouslySeenFunction($file, $functionName, $functionData); + } else { + $this->initPreviouslyUnseenFunction($file, $functionName, $functionData); + } + } + } + } + public function markCodeAsExecutedByTestCase(string $testCaseId, RawCodeCoverageData $executedCode): void + { + foreach ($executedCode->lineCoverage() as $file => $lines) { + foreach ($lines as $k => $v) { + if ($v === Driver::LINE_EXECUTED) { + $this->lineCoverage[$file][$k][] = $testCaseId; + } + } + } + foreach ($executedCode->functionCoverage() as $file => $functions) { + foreach ($functions as $functionName => $functionData) { + foreach ($functionData['branches'] as $branchId => $branchData) { + if ($branchData['hit'] === Driver::BRANCH_HIT) { + $this->functionCoverage[$file][$functionName]->recordBranchHit($branchId, $testCaseId); + } + } + foreach ($functionData['paths'] as $pathId => $pathData) { + if ($pathData['hit'] === Driver::BRANCH_HIT) { + $this->functionCoverage[$file][$functionName]->recordPathHit($pathId, $testCaseId); + } + } + } + } + } + /** + * @param LineCoverageType $lineCoverage + */ + public function setLineCoverage(array $lineCoverage): void + { + $this->lineCoverage = $lineCoverage; + } + /** + * @return LineCoverageType + */ + public function lineCoverage(): array + { + ksort($this->lineCoverage); + return $this->lineCoverage; + } + /** + * @param FunctionCoverageType $functionCoverage + */ + public function setFunctionCoverage(array $functionCoverage): void + { + $this->functionCoverage = $functionCoverage; + } + /** + * @return FunctionCoverageType + */ + public function functionCoverage(): array + { + ksort($this->functionCoverage); + return $this->functionCoverage; + } + /** + * @return array + */ + public function coveredFiles(): array + { + ksort($this->lineCoverage); + return array_keys($this->lineCoverage); + } + public function renameFile(string $oldFile, string $newFile): void + { + $this->lineCoverage[$newFile] = $this->lineCoverage[$oldFile]; + if (isset($this->functionCoverage[$oldFile])) { + $this->functionCoverage[$newFile] = $this->functionCoverage[$oldFile]; + } + unset($this->lineCoverage[$oldFile], $this->functionCoverage[$oldFile]); + } + public function merge(self $newData): void + { + foreach ($newData->lineCoverage as $file => $lines) { + if (!isset($this->lineCoverage[$file])) { + $this->lineCoverage[$file] = $lines; + continue; + } + // we should compare the lines if any of two contains data + $compareLineNumbers = array_unique(array_merge(array_keys($this->lineCoverage[$file]), array_keys($newData->lineCoverage[$file]))); + foreach ($compareLineNumbers as $line) { + $thatPriority = $this->priorityForLine($newData->lineCoverage[$file], $line); + $thisPriority = $this->priorityForLine($this->lineCoverage[$file], $line); + if ($thatPriority > $thisPriority) { + $this->lineCoverage[$file][$line] = $newData->lineCoverage[$file][$line]; + } elseif ($thatPriority === $thisPriority && is_array($this->lineCoverage[$file][$line])) { + $this->lineCoverage[$file][$line] = array_unique(array_merge($this->lineCoverage[$file][$line], $newData->lineCoverage[$file][$line])); + } + } + } + foreach ($newData->functionCoverage as $file => $functions) { + if (!isset($this->functionCoverage[$file])) { + $this->functionCoverage[$file] = $functions; + continue; + } + foreach ($functions as $functionName => $functionData) { + if (isset($this->functionCoverage[$file][$functionName])) { + $this->initPreviouslySeenFunction($file, $functionName, $functionData); + } else { + $this->initPreviouslyUnseenFunction($file, $functionName, $functionData); + } + } + } + } + /** + * Determine the priority for a line. + * + * 1 = the line is not set + * 2 = the line has not been tested + * 3 = the line is dead code + * 4 = the line has been tested + * + * During a merge, a higher number is better. + * + * @param array> $data + * + * @return 1|2|3|4 + */ + private function priorityForLine(array $data, int $line): int + { + if (!array_key_exists($line, $data)) { + return 1; + } + if (is_array($data[$line]) && count($data[$line]) === 0) { + return 2; + } + if ($data[$line] === null) { + return 3; + } + return 4; + } + /** + * For a function we have never seen before, copy all data over and simply init the 'hit' array. + * + * @param ProcessedFunctionCoverageData|XdebugFunctionCoverageType $functionData + */ + private function initPreviouslyUnseenFunction(string $file, string $functionName, array|ProcessedFunctionCoverageData $functionData): void + { + if (is_array($functionData)) { + $functionData = ProcessedFunctionCoverageData::fromXdebugCoverage($functionData); + } + $this->functionCoverage[$file][$functionName] = $functionData; + } + /** + * For a function we have seen before, only copy over and init the 'hit' array for any unseen branches and paths. + * Techniques such as mocking and where the contents of a file are different vary during tests (e.g. compiling + * containers) mean that the functions inside a file cannot be relied upon to be static. + * + * @param ProcessedFunctionCoverageData|XdebugFunctionCoverageType $functionData + */ + private function initPreviouslySeenFunction(string $file, string $functionName, array|ProcessedFunctionCoverageData $functionData): void + { + if (is_array($functionData)) { + $functionData = ProcessedFunctionCoverageData::fromXdebugCoverage($functionData); + } + $this->functionCoverage[$file][$functionName] = $this->functionCoverage[$file][$functionName]->merge($functionData); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data; + +use NoDiscard; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\XdebugDriver; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type TestIdType from ProcessedCodeCoverageData + * @phpstan-import-type XdebugFunctionCoverageType from XdebugDriver + */ +final readonly class ProcessedFunctionCoverageData +{ + /** @var array */ + public array $branches; + /** @var array */ + public array $paths; + /** + * @param XdebugFunctionCoverageType $xdebugCoverageData + */ + public static function fromXdebugCoverage(array $xdebugCoverageData): self + { + $branches = []; + foreach ($xdebugCoverageData['branches'] as $branchId => $branch) { + $branches[$branchId] = ProcessedBranchCoverageData::fromXdebugCoverage($branch); + } + $paths = []; + foreach ($xdebugCoverageData['paths'] as $pathId => $path) { + $paths[$pathId] = ProcessedPathCoverageData::fromXdebugCoverage($path); + } + return new self($branches, $paths); + } + /** + * @param array $branches + * @param array $paths + */ + public function __construct(array $branches, array $paths) + { + $this->paths = $paths; + $this->branches = $branches; + } + #[NoDiscard] + public function merge(self $data): self + { + $branches = null; + if ($data->branches !== $this->branches) { + $branches = $this->branches; + foreach ($data->branches as $branchId => $branch) { + if (!isset($branches[$branchId])) { + $branches[$branchId] = $branch; + } else { + $branches[$branchId] = $branches[$branchId]->merge($branch); + } + } + } + $paths = null; + if ($data->paths !== $this->paths) { + $paths = $this->paths; + foreach ($data->paths as $pathId => $path) { + if (!isset($paths[$pathId])) { + $paths[$pathId] = $path; + } else { + $paths[$pathId] = $paths[$pathId]->merge($path); + } + } + } + if ($branches === null && $paths === null) { + return $this; + } + return new self($branches ?? $this->branches, $paths ?? $this->paths); + } + /** + * @param TestIdType $testCaseId + */ + public function recordBranchHit(int $branchId, string $testCaseId): void + { + $this->branches[$branchId]->recordHit($testCaseId); + } + /** + * @param TestIdType $testCaseId + */ + public function recordPathHit(int $pathId, string $testCaseId): void + { + $this->paths[$pathId]->recordHit($testCaseId); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class ProcessedFunctionType +{ + public readonly string $functionName; + public readonly string $namespace; + public readonly string $signature; + public readonly int $startLine; + public readonly int $endLine; + public int $executableLines; + public int $executedLines; + public int $executableBranches; + public int $executedBranches; + public int $executablePaths; + public int $executedPaths; + public int $ccn; + public float|int $coverage; + public int|string $crap; + public readonly string $link; + public function __construct(string $functionName, string $namespace, string $signature, int $startLine, int $endLine, int $executableLines, int $executedLines, int $executableBranches, int $executedBranches, int $executablePaths, int $executedPaths, int $ccn, float|int $coverage, int|string $crap, string $link) + { + $this->link = $link; + $this->crap = $crap; + $this->coverage = $coverage; + $this->ccn = $ccn; + $this->executedPaths = $executedPaths; + $this->executablePaths = $executablePaths; + $this->executedBranches = $executedBranches; + $this->executableBranches = $executableBranches; + $this->executedLines = $executedLines; + $this->executableLines = $executableLines; + $this->endLine = $endLine; + $this->startLine = $startLine; + $this->signature = $signature; + $this->namespace = $namespace; + $this->functionName = $functionName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class ProcessedMethodType +{ + public readonly string $methodName; + public readonly string $visibility; + public readonly string $signature; + public readonly int $startLine; + public readonly int $endLine; + public int $executableLines; + public int $executedLines; + public int $executableBranches; + public int $executedBranches; + public int $executablePaths; + public int $executedPaths; + public int $ccn; + public float|int $coverage; + public int|string $crap; + public readonly string $link; + public function __construct(string $methodName, string $visibility, string $signature, int $startLine, int $endLine, int $executableLines, int $executedLines, int $executableBranches, int $executedBranches, int $executablePaths, int $executedPaths, int $ccn, float|int $coverage, int|string $crap, string $link) + { + $this->link = $link; + $this->crap = $crap; + $this->coverage = $coverage; + $this->ccn = $ccn; + $this->executedPaths = $executedPaths; + $this->executablePaths = $executablePaths; + $this->executedBranches = $executedBranches; + $this->executableBranches = $executableBranches; + $this->executedLines = $executedLines; + $this->executableLines = $executableLines; + $this->endLine = $endLine; + $this->startLine = $startLine; + $this->signature = $signature; + $this->visibility = $visibility; + $this->methodName = $methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data; + +use function array_merge; +use function array_unique; +use NoDiscard; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\XdebugDriver; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type TestIdType from ProcessedCodeCoverageData + * @phpstan-import-type XdebugPathCoverageType from XdebugDriver + */ +final class ProcessedPathCoverageData +{ + /** @var array */ + public readonly array $path; + /** @var list */ + public array $hit; + /** + * @param XdebugPathCoverageType $xdebugCoverageData + */ + public static function fromXdebugCoverage(array $xdebugCoverageData): self + { + return new self($xdebugCoverageData['path'], []); + } + /** + * @param array $path + * @param list $hit + */ + public function __construct(array $path, array $hit) + { + $this->hit = $hit; + $this->path = $path; + } + #[NoDiscard] + public function merge(self $data): self + { + if ($data->hit === []) { + return $this; + } + return new self($this->path, array_unique(array_merge($this->hit, $data->hit))); + } + /** + * @param TestIdType $testCaseId + */ + public function recordHit(string $testCaseId): void + { + $this->hit[] = $testCaseId; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class ProcessedTraitType +{ + public readonly string $traitName; + public readonly string $namespace; + /** + * @var array + */ + public array $methods; + public readonly int $startLine; + public int $executableLines; + public int $executedLines; + public int $executableBranches; + public int $executedBranches; + public int $executablePaths; + public int $executedPaths; + public int $ccn; + public float|int $coverage; + public int|string $crap; + public readonly string $link; + /** + * @param array $methods + */ + public function __construct(string $traitName, string $namespace, array $methods, int $startLine, int $executableLines, int $executedLines, int $executableBranches, int $executedBranches, int $executablePaths, int $executedPaths, int $ccn, float|int $coverage, int|string $crap, string $link) + { + $this->link = $link; + $this->crap = $crap; + $this->coverage = $coverage; + $this->ccn = $ccn; + $this->executedPaths = $executedPaths; + $this->executablePaths = $executablePaths; + $this->executedBranches = $executedBranches; + $this->executableBranches = $executableBranches; + $this->executedLines = $executedLines; + $this->executableLines = $executableLines; + $this->startLine = $startLine; + $this->methods = $methods; + $this->namespace = $namespace; + $this->traitName = $traitName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data; + +use function array_diff; +use function array_diff_key; +use function array_flip; +use function array_intersect; +use function array_intersect_key; +use function array_map; +use function count; +use function explode; +use function file_get_contents; +use function in_array; +use function is_file; +use function preg_replace; +use function range; +use function str_ends_with; +use function str_starts_with; +use function trim; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\Driver; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\XdebugDriver; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type XdebugFunctionsCoverageType from XdebugDriver + * @phpstan-import-type XdebugCodeCoverageWithoutPathCoverageType from XdebugDriver + * @phpstan-import-type XdebugCodeCoverageWithPathCoverageType from XdebugDriver + */ +final class RawCodeCoverageData +{ + /** + * @var array> + */ + private static array $emptyLineCache = []; + /** + * @var XdebugCodeCoverageWithoutPathCoverageType + */ + private array $lineCoverage; + /** + * @var array + */ + private array $functionCoverage; + /** + * @param XdebugCodeCoverageWithoutPathCoverageType $rawCoverage + */ + public static function fromXdebugWithoutPathCoverage(array $rawCoverage): self + { + return new self($rawCoverage, []); + } + /** + * @param XdebugCodeCoverageWithPathCoverageType $rawCoverage + */ + public static function fromXdebugWithPathCoverage(array $rawCoverage): self + { + $lineCoverage = []; + $functionCoverage = []; + foreach ($rawCoverage as $file => $fileCoverageData) { + // Xdebug annotates the function name of traits, strip that off + foreach ($fileCoverageData['functions'] as $existingKey => $data) { + if (str_ends_with($existingKey, '}') && !str_starts_with($existingKey, '{')) { + // don't want to catch {main} + $newKey = preg_replace('/\{.*}$/', '', $existingKey); + $fileCoverageData['functions'][$newKey] = $data; + unset($fileCoverageData['functions'][$existingKey]); + } + } + $lineCoverage[$file] = $fileCoverageData['lines']; + $functionCoverage[$file] = $fileCoverageData['functions']; + } + return new self($lineCoverage, $functionCoverage); + } + public static function fromUncoveredFile(string $filename, FileAnalyser $analyser): self + { + $lineCoverage = array_map(static fn(): int => Driver::LINE_NOT_EXECUTED, $analyser->analyse($filename)->executableLines()); + return new self([$filename => $lineCoverage], []); + } + /** + * @param XdebugCodeCoverageWithoutPathCoverageType $lineCoverage + * @param array $functionCoverage + */ + private function __construct(array $lineCoverage, array $functionCoverage) + { + $this->lineCoverage = $lineCoverage; + $this->functionCoverage = $functionCoverage; + } + public function clear(): void + { + $this->lineCoverage = $this->functionCoverage = []; + } + /** + * @return XdebugCodeCoverageWithoutPathCoverageType + */ + public function lineCoverage(): array + { + return $this->lineCoverage; + } + /** + * @return array + */ + public function functionCoverage(): array + { + return $this->functionCoverage; + } + public function removeCoverageDataForFile(string $filename): void + { + unset($this->lineCoverage[$filename], $this->functionCoverage[$filename]); + } + /** + * @param int[] $lines + */ + public function keepLineCoverageDataOnlyForLines(string $filename, array $lines): void + { + if (!isset($this->lineCoverage[$filename])) { + return; + } + $this->lineCoverage[$filename] = array_intersect_key($this->lineCoverage[$filename], array_flip($lines)); + } + /** + * @param int[] $lines + */ + public function addMissingExecutableLines(string $filename, array $lines): void + { + if (!isset($this->lineCoverage[$filename])) { + return; + } + foreach ($lines as $line) { + if (!isset($this->lineCoverage[$filename][$line])) { + $this->lineCoverage[$filename][$line] = Driver::LINE_NOT_EXECUTED; + } + } + } + /** + * @param int[] $linesToBranchMap + */ + public function markExecutableLineByBranch(string $filename, array $linesToBranchMap): void + { + if (!isset($this->lineCoverage[$filename])) { + return; + } + $linesByBranch = []; + foreach ($linesToBranchMap as $line => $branch) { + $linesByBranch[$branch][] = $line; + } + foreach ($this->lineCoverage[$filename] as $line => $lineStatus) { + if (!isset($linesToBranchMap[$line])) { + continue; + } + $branch = $linesToBranchMap[$line]; + if (!isset($linesByBranch[$branch])) { + continue; + } + foreach ($linesByBranch[$branch] as $lineInBranch) { + $this->lineCoverage[$filename][$lineInBranch] = $lineStatus; + } + if (Driver::LINE_EXECUTED === $lineStatus) { + unset($linesByBranch[$branch]); + } + } + } + /** + * @param int[] $lines + */ + public function keepFunctionCoverageDataOnlyForLines(string $filename, array $lines): void + { + if (!isset($this->functionCoverage[$filename])) { + return; + } + foreach ($this->functionCoverage[$filename] as $functionName => $functionData) { + foreach ($functionData['branches'] as $branchId => $branch) { + if (count(array_diff(range($branch['line_start'], $branch['line_end']), $lines)) > 0) { + unset($this->functionCoverage[$filename][$functionName]['branches'][$branchId]); + foreach ($functionData['paths'] as $pathId => $path) { + if (in_array($branchId, $path['path'], \true)) { + unset($this->functionCoverage[$filename][$functionName]['paths'][$pathId]); + } + } + } + } + } + } + /** + * @param int[] $lines + */ + public function removeCoverageDataForLines(string $filename, array $lines): void + { + if ($lines === []) { + return; + } + if (!isset($this->lineCoverage[$filename])) { + return; + } + $this->lineCoverage[$filename] = array_diff_key($this->lineCoverage[$filename], array_flip($lines)); + if (isset($this->functionCoverage[$filename])) { + foreach ($this->functionCoverage[$filename] as $functionName => $functionData) { + foreach ($functionData['branches'] as $branchId => $branch) { + if (count(array_intersect($lines, range($branch['line_start'], $branch['line_end']))) > 0) { + unset($this->functionCoverage[$filename][$functionName]['branches'][$branchId]); + foreach ($functionData['paths'] as $pathId => $path) { + if (in_array($branchId, $path['path'], \true)) { + unset($this->functionCoverage[$filename][$functionName]['paths'][$pathId]); + } + } + } + } + } + } + } + /** + * At the end of a file, the PHP interpreter always sees an implicit return. Where this occurs in a file that has + * e.g. a class definition, that line cannot be invoked from a test and results in confusing coverage. This engine + * implementation detail therefore needs to be masked which is done here by simply ensuring that all empty lines + * are skipped over for coverage purposes. + * + * @see https://github.com/sebastianbergmann/php-code-coverage/issues/799 + */ + public function skipEmptyLines(): void + { + foreach ($this->lineCoverage as $filename => $coverage) { + foreach ($this->getEmptyLinesForFile($filename) as $emptyLine) { + unset($this->lineCoverage[$filename][$emptyLine]); + } + } + } + /** + * @return array + */ + private function getEmptyLinesForFile(string $filename): array + { + if (!isset(self::$emptyLineCache[$filename])) { + self::$emptyLineCache[$filename] = []; + if (is_file($filename)) { + $sourceLines = explode("\n", file_get_contents($filename)); + foreach ($sourceLines as $line => $source) { + if (trim($source) === '') { + self::$emptyLineCache[$filename][] = $line + 1; + } + } + } + } + return self::$emptyLineCache[$filename]; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver; + +use function sprintf; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\BranchAndPathCoverageNotSupportedException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +abstract class Driver +{ + /** + * @see http://xdebug.org/docs/code_coverage + */ + public const int LINE_NOT_EXECUTABLE = -2; + /** + * @see http://xdebug.org/docs/code_coverage + */ + public const int LINE_NOT_EXECUTED = -1; + /** + * @see http://xdebug.org/docs/code_coverage + */ + public const int LINE_EXECUTED = 1; + /** + * @see http://xdebug.org/docs/code_coverage + */ + public const int BRANCH_NOT_HIT = 0; + /** + * @see http://xdebug.org/docs/code_coverage + */ + public const int BRANCH_HIT = 1; + private bool $collectBranchAndPathCoverage = \false; + public function canCollectBranchAndPathCoverage(): bool + { + return \false; + } + public function collectsBranchAndPathCoverage(): bool + { + return $this->collectBranchAndPathCoverage; + } + /** + * @throws BranchAndPathCoverageNotSupportedException + */ + public function enableBranchAndPathCoverage(): void + { + if (!$this->canCollectBranchAndPathCoverage()) { + throw new BranchAndPathCoverageNotSupportedException(sprintf('%s does not support branch and path coverage', $this->nameAndVersion())); + } + $this->collectBranchAndPathCoverage = \true; + } + public function disableBranchAndPathCoverage(): void + { + $this->collectBranchAndPathCoverage = \false; + } + abstract public function name(): string; + abstract public function version(): string; + public function nameAndVersion(): string + { + return $this->name() . ' ' . $this->version(); + } + abstract public function start(): void; + abstract public function stop(): RawCodeCoverageData; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver; + +use const pcov\inclusive; +use function array_intersect; +use function extension_loaded; +use function pcov\clear; +use function pcov\collect; +use function pcov\start; +use function pcov\stop; +use function pcov\waiting; +use function phpversion; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Filter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class PcovDriver extends Driver +{ + private readonly Filter $filter; + /** + * @throws PcovNotAvailableException + */ + public function __construct(Filter $filter) + { + $this->ensurePcovIsAvailable(); + $this->filter = $filter; + } + /** + * @codeCoverageIgnore + */ + public function start(): void + { + start(); + } + public function stop(): RawCodeCoverageData + { + stop(); + // @codeCoverageIgnoreStart + $filesToCollectCoverageFor = waiting(); + $collected = []; + if ($filesToCollectCoverageFor !== []) { + if (!$this->filter->isEmpty()) { + $filesToCollectCoverageFor = array_intersect($filesToCollectCoverageFor, $this->filter->files()); + } + $collected = collect(inclusive, $filesToCollectCoverageFor); + clear(); + } + return RawCodeCoverageData::fromXdebugWithoutPathCoverage($collected); + // @codeCoverageIgnoreEnd + } + public function name(): string + { + return 'PCOV'; + } + public function version(): string + { + return phpversion('pcov'); + } + /** + * @throws PcovNotAvailableException + */ + private function ensurePcovIsAvailable(): void + { + if (!extension_loaded('pcov')) { + throw new PcovNotAvailableException(); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver; + +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Filter; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\NoCodeCoverageDriverAvailableException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\NoCodeCoverageDriverWithPathCoverageSupportAvailableException; +use PHPUnitPHAR\SebastianBergmann\Environment\Runtime; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Selector +{ + /** + * @throws NoCodeCoverageDriverAvailableException + * @throws PcovNotAvailableException + * @throws XdebugNotAvailableException + * @throws XdebugNotEnabledException + * @throws XdebugVersionNotSupportedException + */ + public function forLineCoverage(Filter $filter): Driver + { + $runtime = new Runtime(); + if ($runtime->hasPCOV()) { + return new PcovDriver($filter); + } + if ($runtime->hasXdebug()) { + return new XdebugDriver($filter); + } + throw new NoCodeCoverageDriverAvailableException(); + } + /** + * @throws NoCodeCoverageDriverWithPathCoverageSupportAvailableException + * @throws XdebugNotAvailableException + * @throws XdebugNotEnabledException + * @throws XdebugVersionNotSupportedException + */ + public function forLineAndPathCoverage(Filter $filter): Driver + { + if ((new Runtime())->hasXdebug()) { + $driver = new XdebugDriver($filter); + $driver->enableBranchAndPathCoverage(); + return $driver; + } + throw new NoCodeCoverageDriverWithPathCoverageSupportAvailableException(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver; + +use const XDEBUG_CC_BRANCH_CHECK; +use const XDEBUG_CC_DEAD_CODE; +use const XDEBUG_CC_UNUSED; +use const XDEBUG_FILTER_CODE_COVERAGE; +use const XDEBUG_PATH_INCLUDE; +use function extension_loaded; +use function in_array; +use function phpversion; +use function version_compare; +use function xdebug_get_code_coverage; +use function xdebug_info; +use function xdebug_set_filter; +use function xdebug_start_code_coverage; +use function xdebug_stop_code_coverage; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Filter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @see https://xdebug.org/docs/code_coverage#xdebug_get_code_coverage + * + * @phpstan-type XdebugLinesCoverageType array + * @phpstan-type XdebugBranchCoverageType array{ + * op_start: int, + * op_end: int, + * line_start: int, + * line_end: int, + * hit: int, + * out: array, + * out_hit: array, + * } + * @phpstan-type XdebugPathCoverageType array{ + * path: array, + * hit: int, + * } + * @phpstan-type XdebugFunctionCoverageType array{ + * branches: array, + * paths: array, + * } + * @phpstan-type XdebugFunctionsCoverageType array + * @phpstan-type XdebugPathAndBranchesCoverageType array{ + * lines: XdebugLinesCoverageType, + * functions: XdebugFunctionsCoverageType, + * } + * @phpstan-type XdebugCodeCoverageWithoutPathCoverageType array + * @phpstan-type XdebugCodeCoverageWithPathCoverageType array + */ +final class XdebugDriver extends Driver +{ + /** + * @throws XdebugNotAvailableException + * @throws XdebugNotEnabledException + * @throws XdebugVersionNotSupportedException + */ + public function __construct(Filter $filter) + { + $this->ensureXdebugIsAvailable(); + if (!$filter->isEmpty()) { + xdebug_set_filter(XDEBUG_FILTER_CODE_COVERAGE, XDEBUG_PATH_INCLUDE, $filter->files()); + } + } + public function canCollectBranchAndPathCoverage(): bool + { + return \true; + } + public function start(): void + { + $flags = XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE; + if ($this->collectsBranchAndPathCoverage()) { + $flags |= XDEBUG_CC_BRANCH_CHECK; + } + xdebug_start_code_coverage($flags); + } + public function stop(): RawCodeCoverageData + { + $data = xdebug_get_code_coverage(); + xdebug_stop_code_coverage(); + if ($this->collectsBranchAndPathCoverage()) { + /* @var XdebugCodeCoverageWithPathCoverageType $data */ + return RawCodeCoverageData::fromXdebugWithPathCoverage($data); + } + /* @var XdebugCodeCoverageWithoutPathCoverageType $data */ + return RawCodeCoverageData::fromXdebugWithoutPathCoverage($data); + } + public function name(): string + { + return 'Xdebug'; + } + public function version(): string + { + return phpversion('xdebug'); + } + /** + * @throws XdebugNotAvailableException + * @throws XdebugNotEnabledException + * @throws XdebugVersionNotSupportedException + */ + private function ensureXdebugIsAvailable(): void + { + if (!extension_loaded('xdebug')) { + throw new XdebugNotAvailableException(); + } + if (!version_compare(phpversion('xdebug'), '3.1', '>=')) { + throw new XdebugVersionNotSupportedException(phpversion('xdebug')); + } + if (!in_array('coverage', xdebug_info('mode'), \true)) { + throw new XdebugNotEnabledException(); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class BranchAndPathCoverageNotSupportedException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class DirectoryCouldNotBeCreatedException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class DriverMismatchException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('Not all files were created using the same code coverage driver'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class EmptyPathListException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('List of paths to merge must not be empty'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class FileCouldNotBeReadException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class FileCouldNotBeWrittenException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use function sprintf; +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class GitInformationMismatchException extends RuntimeException implements Exception +{ + public function __construct(string $field, string $expected, string $actual) + { + parent::__construct(sprintf('Git information mismatch: field "%s" is "%s" in the first file but "%s" in another file', $field, $expected, $actual)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class InvalidArgumentException extends \InvalidArgumentException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +use function sprintf; +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class InvalidCodeCoverageTargetException extends RuntimeException implements Exception +{ + public function __construct(Target $target) + { + parent::__construct(sprintf('%s is not a valid target for code coverage', $target->description())); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class InvalidCoverageDataException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class MethodNotImplementedException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class MixedGitInformationException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('All files must either have Git information or must not have Git information'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class NoCodeCoverageDriverAvailableException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('No code coverage driver available'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class NoCodeCoverageDriverWithPathCoverageSupportAvailableException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('No code coverage driver with path coverage support available'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class ParserException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class PathExistsButIsNotDirectoryException extends RuntimeException implements Exception +{ + public function __construct(string $path) + { + parent::__construct(sprintf('"%s" exists but is not a directory', $path)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class PcovNotAvailableException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('The PCOV extension is not available'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class PharPrefixCouldNotBeStrippedException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('Failed to strip PHAR prefix from serialized data'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class ReflectionException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class ReportAlreadyFinalizedException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('The code coverage report has already been finalized'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class RuntimeMismatchException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('Not all files were created using the same runtime'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class StaticAnalysisCacheNotConfiguredException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class TestIdMissingException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('Test ID is missing'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use function rtrim; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class UnintentionallyCoveredCodeException extends RuntimeException implements Exception +{ + /** + * @var list + */ + private readonly array $unintentionallyCoveredUnits; + /** + * @param list $unintentionallyCoveredUnits + */ + public function __construct(array $unintentionallyCoveredUnits) + { + $this->unintentionallyCoveredUnits = $unintentionallyCoveredUnits; + parent::__construct($this->toString()); + } + /** + * @return list + */ + public function getUnintentionallyCoveredUnits(): array + { + return $this->unintentionallyCoveredUnits; + } + private function toString(): string + { + $message = ''; + foreach ($this->unintentionallyCoveredUnits as $unit) { + $message .= '- ' . $unit . "\n"; + } + return rtrim($message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use function sprintf; +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class VersionMismatchException extends RuntimeException implements Exception +{ + public function __construct(int $storedFormat, int $supportedFormat) + { + parent::__construct(sprintf('Coverage data was written using serialization format %d and cannot be read by code that supports serialization format %d', $storedFormat, $supportedFormat)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class WriteOperationFailedException extends RuntimeException implements Exception +{ + public function __construct(string $path) + { + parent::__construct(sprintf('Cannot write to "%s"', $path)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class XdebugNotAvailableException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('The Xdebug extension is not available'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class XdebugNotEnabledException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('XDEBUG_MODE=coverage (environment variable) or xdebug.mode=coverage (PHP configuration setting) has to be set'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver; + +use function sprintf; +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class XdebugVersionNotSupportedException extends RuntimeException implements Exception +{ + /** + * @param non-empty-string $version + */ + public function __construct(string $version) + { + parent::__construct(sprintf('Version %s of the Xdebug extension is not supported', $version)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class XmlException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use function array_keys; +use function is_file; +use function realpath; +use function str_contains; +use function str_starts_with; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Filter +{ + /** + * @var array + */ + private array $files = []; + /** + * @var array + */ + private array $isFileCache = []; + /** + * @param list $filenames + */ + public function includeFiles(array $filenames): void + { + foreach ($filenames as $filename) { + $this->includeFile($filename); + } + } + public function includeFile(string $filename): void + { + $filename = realpath($filename); + if (!$filename) { + return; + } + $this->files[$filename] = \true; + } + public function isFile(string $filename): bool + { + if (isset($this->isFileCache[$filename])) { + return $this->isFileCache[$filename]; + } + if ($filename === '-' || str_starts_with($filename, 'vfs://') || str_contains($filename, 'xdebug://debug-eval') || str_contains($filename, 'eval()\'d code') || str_contains($filename, 'runtime-created function') || str_contains($filename, 'runkit created function') || str_contains($filename, 'assert code') || str_contains($filename, 'regexp code') || str_contains($filename, 'Standard input code')) { + $isFile = \false; + } else { + $isFile = is_file($filename); + } + $this->isFileCache[$filename] = $isFile; + return $isFile; + } + public function isExcluded(string $filename): bool + { + return !isset($this->files[$filename]) || !$this->isFile($filename); + } + /** + * @return list + */ + public function files(): array + { + return array_keys($this->files); + } + public function isEmpty(): bool + { + return $this->files === []; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use function array_diff; +use function array_diff_key; +use function array_keys; +use function is_file; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedCodeCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\Mapper; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\TargetCollection; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestSize; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type TargetedLines from CodeCoverage + */ +final readonly class FilterProcessor +{ + /** + * @param false|TargetedLines $linesToBeCovered + * @param TargetedLines $linesToBeUsed + * @param list $parentClassesExcludedFromUnintentionallyCoveredCodeCheck + * + * @throws ReflectionException + * @throws UnintentionallyCoveredCodeException + */ + public function applyCoversAndUsesFilter(RawCodeCoverageData $rawData, array|false $linesToBeCovered, array $linesToBeUsed, TestSize $size, bool $checkForUnintentionallyCoveredCode, Mapper $targetMapper, array $parentClassesExcludedFromUnintentionallyCoveredCodeCheck, TargetCollection $covers, TargetCollection $uses): void + { + if ($linesToBeCovered === \false) { + $rawData->clear(); + return; + } + if ($linesToBeCovered === []) { + return; + } + if ($checkForUnintentionallyCoveredCode && !$size->isMedium() && !$size->isLarge()) { + (new UnintentionallyCoveredCodeChecker())->check($rawData, $linesToBeCovered, $linesToBeUsed, $targetMapper, $parentClassesExcludedFromUnintentionallyCoveredCodeCheck, $covers, $uses); + } + $rawLineData = $rawData->lineCoverage(); + $filesWithNoCoverage = array_diff_key($rawLineData, $linesToBeCovered); + foreach (array_keys($filesWithNoCoverage) as $fileWithNoCoverage) { + $rawData->removeCoverageDataForFile($fileWithNoCoverage); + } + foreach ($linesToBeCovered as $fileToBeCovered => $includedLines) { + $rawData->keepLineCoverageDataOnlyForLines($fileToBeCovered, $includedLines); + $rawData->keepFunctionCoverageDataOnlyForLines($fileToBeCovered, $includedLines); + } + } + public function applyFilter(RawCodeCoverageData $data, Filter $filter): void + { + if (!$filter->isEmpty()) { + foreach (array_keys($data->lineCoverage()) as $filename) { + if ($filter->isExcluded($filename)) { + $data->removeCoverageDataForFile($filename); + } + } + } + $data->skipEmptyLines(); + } + public function applyExecutableLinesFilter(RawCodeCoverageData $data, Filter $filter, FileAnalyser $analyser): void + { + foreach (array_keys($data->lineCoverage()) as $filename) { + if (!$filter->isFile($filename)) { + continue; + } + $analysisResult = $analyser->analyse($filename); + $linesToBranchMap = $analysisResult->executableLines(); + $branchOperatorLines = $analysisResult->branchOperatorLines(); + $data->keepLineCoverageDataOnlyForLines($filename, array_keys($linesToBranchMap)); + $data->addMissingExecutableLines($filename, array_keys($branchOperatorLines)); + $data->markExecutableLineByBranch($filename, $linesToBranchMap); + } + } + public function applyIgnoredLinesFilter(RawCodeCoverageData $data, Filter $filter, FileAnalyser $analyser): void + { + foreach (array_keys($data->lineCoverage()) as $filename) { + if (!$filter->isFile($filename)) { + continue; + } + $data->removeCoverageDataForLines($filename, $analyser->analyse($filename)->ignoredLines()); + } + } + /** + * @return list + */ + public function uncoveredFilesFromFilter(Filter $filter, ProcessedCodeCoverageData $data, FileAnalyser $analyser): array + { + $uncoveredFiles = array_diff($filter->files(), $data->coveredFiles()); + $result = []; + foreach ($uncoveredFiles as $uncoveredFile) { + if (is_file($uncoveredFile)) { + $result[] = RawCodeCoverageData::fromUncoveredFile($uncoveredFile, $analyser); + } + } + return $result; + } +} +BSD 3-Clause License + +Copyright (c) 2009-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node; + +use const DIRECTORY_SEPARATOR; +use function array_merge; +use function str_ends_with; +use function str_replace; +use function substr; +use Countable; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedClassType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedFunctionType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedTraitType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\LinesOfCode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Percentage; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +abstract class AbstractNode implements Countable +{ + private readonly string $name; + private string $pathAsString; + /** + * @var non-empty-list + */ + private array $pathAsArray; + private readonly ?AbstractNode $parent; + private string $id; + public function __construct(string $name, ?self $parent = null) + { + if (str_ends_with($name, DIRECTORY_SEPARATOR)) { + $name = substr($name, 0, -1); + } + $this->name = $name; + $this->parent = $parent; + $this->processId(); + $this->processPath(); + } + public function name(): string + { + return $this->name; + } + public function id(): string + { + return $this->id; + } + public function pathAsString(): string + { + return $this->pathAsString; + } + /** + * @return non-empty-list + */ + public function pathAsArray(): array + { + return $this->pathAsArray; + } + public function parent(): ?self + { + return $this->parent; + } + public function percentageOfTestedClasses(): Percentage + { + return Percentage::fromFractionAndTotal($this->numberOfTestedClasses(), $this->numberOfClasses()); + } + public function percentageOfTestedTraits(): Percentage + { + return Percentage::fromFractionAndTotal($this->numberOfTestedTraits(), $this->numberOfTraits()); + } + public function percentageOfTestedClassesAndTraits(): Percentage + { + return Percentage::fromFractionAndTotal($this->numberOfTestedClassesAndTraits(), $this->numberOfClassesAndTraits()); + } + public function percentageOfTestedFunctions(): Percentage + { + return Percentage::fromFractionAndTotal($this->numberOfTestedFunctions(), $this->numberOfFunctions()); + } + public function percentageOfTestedMethods(): Percentage + { + return Percentage::fromFractionAndTotal($this->numberOfTestedMethods(), $this->numberOfMethods()); + } + public function percentageOfTestedFunctionsAndMethods(): Percentage + { + return Percentage::fromFractionAndTotal($this->numberOfTestedFunctionsAndMethods(), $this->numberOfFunctionsAndMethods()); + } + public function percentageOfExecutedLines(): Percentage + { + return Percentage::fromFractionAndTotal($this->numberOfExecutedLines(), $this->numberOfExecutableLines()); + } + public function percentageOfExecutedBranches(): Percentage + { + return Percentage::fromFractionAndTotal($this->numberOfExecutedBranches(), $this->numberOfExecutableBranches()); + } + public function percentageOfExecutedPaths(): Percentage + { + return Percentage::fromFractionAndTotal($this->numberOfExecutedPaths(), $this->numberOfExecutablePaths()); + } + public function numberOfClassesAndTraits(): int + { + return $this->numberOfClasses() + $this->numberOfTraits(); + } + public function numberOfTestedClassesAndTraits(): int + { + return $this->numberOfTestedClasses() + $this->numberOfTestedTraits(); + } + /** + * @return array + */ + public function classesAndTraits(): array + { + return array_merge($this->classes(), $this->traits()); + } + public function numberOfFunctionsAndMethods(): int + { + return $this->numberOfFunctions() + $this->numberOfMethods(); + } + public function numberOfTestedFunctionsAndMethods(): int + { + return $this->numberOfTestedFunctions() + $this->numberOfTestedMethods(); + } + /** + * @return non-negative-int + */ + public function cyclomaticComplexity(): int + { + $ccn = 0; + foreach ($this->classesAndTraits() as $classLike) { + $ccn += $classLike->ccn; + } + foreach ($this->functions() as $function) { + $ccn += $function->ccn; + } + return $ccn; + } + /** + * @return array + */ + abstract public function classes(): array; + /** + * @return array + */ + abstract public function traits(): array; + /** + * @return array + */ + abstract public function functions(): array; + abstract public function linesOfCode(): LinesOfCode; + abstract public function numberOfExecutableLines(): int; + abstract public function numberOfExecutedLines(): int; + abstract public function numberOfExecutableBranches(): int; + abstract public function numberOfExecutedBranches(): int; + abstract public function numberOfExecutablePaths(): int; + abstract public function numberOfExecutedPaths(): int; + abstract public function numberOfFilesWithoutBranchCoverageData(): int; + abstract public function numberOfClasses(): int; + abstract public function numberOfTestedClasses(): int; + abstract public function numberOfTraits(): int; + abstract public function numberOfTestedTraits(): int; + abstract public function numberOfMethods(): int; + abstract public function numberOfTestedMethods(): int; + abstract public function numberOfFunctions(): int; + abstract public function numberOfTestedFunctions(): int; + private function processId(): void + { + if ($this->parent === null) { + $this->id = 'index'; + return; + } + $parentId = $this->parent->id(); + if ($parentId === 'index') { + $this->id = str_replace(':', '_', $this->name); + } else { + $this->id = $parentId . '/' . $this->name; + } + } + private function processPath(): void + { + if ($this->parent === null) { + $this->pathAsArray = [$this]; + $this->pathAsString = $this->name; + return; + } + $this->pathAsArray = $this->parent->pathAsArray(); + $this->pathAsString = $this->parent->pathAsString() . DIRECTORY_SEPARATOR . $this->name; + $this->pathAsArray[] = $this; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node; + +use const DIRECTORY_SEPARATOR; +use function count; +use function explode; +use function is_file; +use function sha1_file; +use function str_ends_with; +use function substr; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedCodeCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\PathReducer; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type TestType from CodeCoverage + */ +final readonly class Builder +{ + private FileAnalyser $analyser; + public function __construct(FileAnalyser $analyser) + { + $this->analyser = $analyser; + } + /** + * @param array $testResults + */ + public function build(ProcessedCodeCoverageData $codeCoverage, array $testResults, string $basePath = ''): Directory + { + // Clone because path munging is destructive to the original data + $codeCoverage = clone $codeCoverage; + $commonPath = (new PathReducer())->reduce($codeCoverage); + if ($commonPath === '') { + $commonPath = '.'; + } + $rootPath = $commonPath; + if ($basePath !== '') { + if ($commonPath === '.') { + $rootPath = $basePath; + } else { + $rootPath = $basePath . DIRECTORY_SEPARATOR . $commonPath; + } + } + $root = new Directory($rootPath, null); + $this->addItems($root, $this->buildDirectoryStructure($codeCoverage), $testResults); + return $root; + } + /** + * @param array $items + * @param array $tests + */ + private function addItems(Directory $root, array $items, array $tests): void + { + foreach ($items as $key => $value) { + $key = (string) $key; + if (str_ends_with($key, '/f')) { + $key = substr($key, 0, -2); + $filename = $root->pathAsString() . DIRECTORY_SEPARATOR . $key; + if (is_file($filename)) { + $analysisResult = $this->analyser->analyse($filename); + $root->addFile(new File($key, $root, sha1_file($filename), $value['lineCoverage'], $value['functionCoverage'], $tests, $analysisResult->classes(), $analysisResult->traits(), $analysisResult->functions(), $analysisResult->linesOfCode(), $value['functionCoverage'] !== [])); + } + } else { + $child = $root->addDirectory($key); + $this->addItems($child, $value, $tests); + } + } + } + /** + * Builds an array representation of the directory structure. + * + * For instance, + * + * + * Array + * ( + * [Money.php] => Array + * ( + * ... + * ) + * + * [MoneyBag.php] => Array + * ( + * ... + * ) + * ) + * + * + * is transformed into + * + * + * Array + * ( + * [.] => Array + * ( + * [Money.php] => Array + * ( + * ... + * ) + * + * [MoneyBag.php] => Array + * ( + * ... + * ) + * ) + * ) + * + * + * @return array, functionCoverage: array>}>> + */ + private function buildDirectoryStructure(ProcessedCodeCoverageData $codeCoverage): array + { + $result = []; + $lineCoverage = $codeCoverage->lineCoverage(); + $functionCoverage = $codeCoverage->functionCoverage(); + foreach ($codeCoverage->coveredFiles() as $originalPath) { + $path = explode(DIRECTORY_SEPARATOR, $originalPath); + $pointer =& $result; + $max = count($path); + for ($i = 0; $i < $max; $i++) { + $type = ''; + if ($i === $max - 1) { + $type = '/f'; + } + $pointer =& $pointer[$path[$i] . $type]; + } + $pointer = ['lineCoverage' => $lineCoverage[$originalPath] ?? [], 'functionCoverage' => $functionCoverage[$originalPath] ?? []]; + } + return $result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node; + +use function sprintf; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class CrapIndex +{ + private int $cyclomaticComplexity; + private float $codeCoverage; + public function __construct(int $cyclomaticComplexity, float $codeCoverage) + { + $this->cyclomaticComplexity = $cyclomaticComplexity; + $this->codeCoverage = $codeCoverage; + } + public function asString(): string + { + if ($this->codeCoverage === 0.0) { + return (string) ($this->cyclomaticComplexity ** 2 + $this->cyclomaticComplexity); + } + if ($this->codeCoverage >= 95) { + return (string) $this->cyclomaticComplexity; + } + return sprintf('%01.2F', $this->cyclomaticComplexity ** 2 * (1 - $this->codeCoverage / 100) ** 3 + $this->cyclomaticComplexity); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node; + +use function array_merge; +use function assert; +use function count; +use IteratorAggregate; +use RecursiveIteratorIterator; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedClassType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedFunctionType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedTraitType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\LinesOfCode; +/** + * @template-implements IteratorAggregate + * + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Directory extends AbstractNode implements IteratorAggregate +{ + /** + * @var list + */ + private array $children = []; + /** + * @var list + */ + private array $directories = []; + /** + * @var list + */ + private array $files = []; + /** + * @var ?array + */ + private ?array $classes = null; + /** + * @var ?array + */ + private ?array $traits = null; + /** + * @var ?array + */ + private ?array $functions = null; + private ?LinesOfCode $linesOfCode = null; + private int $numFiles = -1; + private int $numExecutableLines = -1; + private int $numExecutedLines = -1; + private int $numExecutableBranches = -1; + private int $numExecutedBranches = -1; + private int $numExecutablePaths = -1; + private int $numExecutedPaths = -1; + private int $numFilesWithoutBranchCoverageData = -1; + private int $numClasses = -1; + private int $numTestedClasses = -1; + private int $numTraits = -1; + private int $numTestedTraits = -1; + private int $numMethods = -1; + private int $numTestedMethods = -1; + private int $numFunctions = -1; + private int $numTestedFunctions = -1; + public function count(): int + { + if ($this->numFiles === -1) { + $this->numFiles = 0; + foreach ($this->children as $child) { + $this->numFiles += count($child); + } + } + return $this->numFiles; + } + /** + * @return RecursiveIteratorIterator> + */ + public function getIterator(): RecursiveIteratorIterator + { + return new RecursiveIteratorIterator(new Iterator($this), RecursiveIteratorIterator::SELF_FIRST); + } + public function addDirectory(string $name): self + { + $directory = new self($name, $this); + assert($directory instanceof self); + $this->children[] = $directory; + $this->directories[] =& $this->children[count($this->children) - 1]; + return $directory; + } + public function addFile(File $file): void + { + $this->children[] = $file; + $this->files[] =& $this->children[count($this->children) - 1]; + $this->numExecutableLines = -1; + $this->numExecutedLines = -1; + } + /** + * @return list + */ + public function directories(): array + { + return $this->directories; + } + /** + * @return list + */ + public function files(): array + { + return $this->files; + } + /** + * @return list + */ + public function children(): array + { + return $this->children; + } + /** + * @return array + */ + public function classes(): array + { + if ($this->classes === null) { + $this->classes = []; + foreach ($this->children as $child) { + $this->classes = array_merge($this->classes, $child->classes()); + } + } + return $this->classes; + } + /** + * @return array + */ + public function traits(): array + { + if ($this->traits === null) { + $this->traits = []; + foreach ($this->children as $child) { + $this->traits = array_merge($this->traits, $child->traits()); + } + } + return $this->traits; + } + /** + * @return array + */ + public function functions(): array + { + if ($this->functions === null) { + $this->functions = []; + foreach ($this->children as $child) { + $this->functions = array_merge($this->functions, $child->functions()); + } + } + return $this->functions; + } + public function linesOfCode(): LinesOfCode + { + if ($this->linesOfCode === null) { + $linesOfCode = 0; + $commentLinesOfCode = 0; + $nonCommentLinesOfCode = 0; + foreach ($this->children as $child) { + $childLinesOfCode = $child->linesOfCode(); + $linesOfCode += $childLinesOfCode->linesOfCode(); + $commentLinesOfCode += $childLinesOfCode->commentLinesOfCode(); + $nonCommentLinesOfCode += $childLinesOfCode->nonCommentLinesOfCode(); + } + $this->linesOfCode = new LinesOfCode($linesOfCode, $commentLinesOfCode, $nonCommentLinesOfCode); + } + return $this->linesOfCode; + } + public function numberOfExecutableLines(): int + { + if ($this->numExecutableLines === -1) { + $this->numExecutableLines = 0; + foreach ($this->children as $child) { + $this->numExecutableLines += $child->numberOfExecutableLines(); + } + } + return $this->numExecutableLines; + } + public function numberOfExecutedLines(): int + { + if ($this->numExecutedLines === -1) { + $this->numExecutedLines = 0; + foreach ($this->children as $child) { + $this->numExecutedLines += $child->numberOfExecutedLines(); + } + } + return $this->numExecutedLines; + } + public function numberOfExecutableBranches(): int + { + if ($this->numExecutableBranches === -1) { + $this->numExecutableBranches = 0; + foreach ($this->children as $child) { + $this->numExecutableBranches += $child->numberOfExecutableBranches(); + } + } + return $this->numExecutableBranches; + } + public function numberOfExecutedBranches(): int + { + if ($this->numExecutedBranches === -1) { + $this->numExecutedBranches = 0; + foreach ($this->children as $child) { + $this->numExecutedBranches += $child->numberOfExecutedBranches(); + } + } + return $this->numExecutedBranches; + } + public function numberOfExecutablePaths(): int + { + if ($this->numExecutablePaths === -1) { + $this->numExecutablePaths = 0; + foreach ($this->children as $child) { + $this->numExecutablePaths += $child->numberOfExecutablePaths(); + } + } + return $this->numExecutablePaths; + } + public function numberOfExecutedPaths(): int + { + if ($this->numExecutedPaths === -1) { + $this->numExecutedPaths = 0; + foreach ($this->children as $child) { + $this->numExecutedPaths += $child->numberOfExecutedPaths(); + } + } + return $this->numExecutedPaths; + } + public function numberOfFilesWithoutBranchCoverageData(): int + { + if ($this->numFilesWithoutBranchCoverageData === -1) { + $this->numFilesWithoutBranchCoverageData = 0; + foreach ($this->children as $child) { + $this->numFilesWithoutBranchCoverageData += $child->numberOfFilesWithoutBranchCoverageData(); + } + } + return $this->numFilesWithoutBranchCoverageData; + } + public function numberOfClasses(): int + { + if ($this->numClasses === -1) { + $this->numClasses = 0; + foreach ($this->children as $child) { + $this->numClasses += $child->numberOfClasses(); + } + } + return $this->numClasses; + } + public function numberOfTestedClasses(): int + { + if ($this->numTestedClasses === -1) { + $this->numTestedClasses = 0; + foreach ($this->children as $child) { + $this->numTestedClasses += $child->numberOfTestedClasses(); + } + } + return $this->numTestedClasses; + } + public function numberOfTraits(): int + { + if ($this->numTraits === -1) { + $this->numTraits = 0; + foreach ($this->children as $child) { + $this->numTraits += $child->numberOfTraits(); + } + } + return $this->numTraits; + } + public function numberOfTestedTraits(): int + { + if ($this->numTestedTraits === -1) { + $this->numTestedTraits = 0; + foreach ($this->children as $child) { + $this->numTestedTraits += $child->numberOfTestedTraits(); + } + } + return $this->numTestedTraits; + } + public function numberOfMethods(): int + { + if ($this->numMethods === -1) { + $this->numMethods = 0; + foreach ($this->children as $child) { + $this->numMethods += $child->numberOfMethods(); + } + } + return $this->numMethods; + } + public function numberOfTestedMethods(): int + { + if ($this->numTestedMethods === -1) { + $this->numTestedMethods = 0; + foreach ($this->children as $child) { + $this->numTestedMethods += $child->numberOfTestedMethods(); + } + } + return $this->numTestedMethods; + } + public function numberOfFunctions(): int + { + if ($this->numFunctions === -1) { + $this->numFunctions = 0; + foreach ($this->children as $child) { + $this->numFunctions += $child->numberOfFunctions(); + } + } + return $this->numFunctions; + } + public function numberOfTestedFunctions(): int + { + if ($this->numTestedFunctions === -1) { + $this->numTestedFunctions = 0; + foreach ($this->children as $child) { + $this->numTestedFunctions += $child->numberOfTestedFunctions(); + } + } + return $this->numTestedFunctions; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node; + +use function array_filter; +use function count; +use function range; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedBranchCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedClassType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedFunctionCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedFunctionType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedMethodType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedPathCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedTraitType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\AnalysisResult; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Class_; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Function_; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\LinesOfCode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Method; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type TestType from CodeCoverage + * @phpstan-import-type LinesType from AnalysisResult + */ +final class File extends AbstractNode +{ + /** + * @var non-empty-string + */ + private string $sha1; + /** + * @var array> + */ + private array $lineCoverageData; + /** + * @var array + */ + private array $functionCoverageData; + /** + * @var array + */ + private readonly array $testData; + private int $numExecutableLines = 0; + private int $numExecutedLines = 0; + private int $numExecutableBranches = 0; + private int $numExecutedBranches = 0; + private int $numExecutablePaths = 0; + private int $numExecutedPaths = 0; + /** + * @var array + */ + private array $classes = []; + /** + * @var array + */ + private array $traits = []; + /** + * @var array + */ + private array $functions = []; + private readonly LinesOfCode $linesOfCode; + private readonly bool $hasBranchCoverageData; + private ?int $numClasses = null; + private int $numTestedClasses = 0; + private ?int $numTraits = null; + private int $numTestedTraits = 0; + private ?int $numMethods = null; + private ?int $numTestedMethods = null; + private ?int $numTestedFunctions = null; + /** + * @var array> + */ + private array $codeUnitsByLine = []; + /** + * @param non-empty-string $sha1 + * @param array> $lineCoverageData + * @param array $functionCoverageData + * @param array $testData + * @param array $classes + * @param array $traits + * @param array $functions + */ + public function __construct(string $name, AbstractNode $parent, string $sha1, array $lineCoverageData, array $functionCoverageData, array $testData, array $classes, array $traits, array $functions, LinesOfCode $linesOfCode, bool $hasBranchCoverageData = \false) + { + parent::__construct($name, $parent); + $this->sha1 = $sha1; + $this->lineCoverageData = $lineCoverageData; + $this->functionCoverageData = $functionCoverageData; + $this->testData = $testData; + $this->linesOfCode = $linesOfCode; + $this->hasBranchCoverageData = $hasBranchCoverageData; + $this->calculateStatistics($classes, $traits, $functions); + } + public function count(): int + { + return 1; + } + /** + * @return non-empty-string + */ + public function sha1(): string + { + return $this->sha1; + } + /** + * @return array> + */ + public function lineCoverageData(): array + { + return $this->lineCoverageData; + } + /** + * @return array + */ + public function functionCoverageData(): array + { + return $this->functionCoverageData; + } + /** + * @return array + */ + public function testData(): array + { + return $this->testData; + } + /** + * @return array + */ + public function classes(): array + { + return $this->classes; + } + /** + * @return array + */ + public function traits(): array + { + return $this->traits; + } + /** + * @return array + */ + public function functions(): array + { + return $this->functions; + } + public function linesOfCode(): LinesOfCode + { + return $this->linesOfCode; + } + public function numberOfExecutableLines(): int + { + return $this->numExecutableLines; + } + public function numberOfExecutedLines(): int + { + return $this->numExecutedLines; + } + public function numberOfExecutableBranches(): int + { + return $this->numExecutableBranches; + } + public function numberOfExecutedBranches(): int + { + return $this->numExecutedBranches; + } + public function numberOfExecutablePaths(): int + { + return $this->numExecutablePaths; + } + public function numberOfExecutedPaths(): int + { + return $this->numExecutedPaths; + } + public function hasBranchCoverageData(): bool + { + return $this->hasBranchCoverageData; + } + public function numberOfFilesWithoutBranchCoverageData(): int + { + return $this->hasBranchCoverageData ? 0 : 1; + } + public function numberOfClasses(): int + { + if ($this->numClasses === null) { + $this->numClasses = 0; + foreach ($this->classes as $class) { + foreach ($class->methods as $method) { + if ($method->executableLines > 0) { + $this->numClasses++; + continue 2; + } + } + } + } + return $this->numClasses; + } + public function numberOfTestedClasses(): int + { + return $this->numTestedClasses; + } + public function numberOfTraits(): int + { + if ($this->numTraits === null) { + $this->numTraits = 0; + foreach ($this->traits as $trait) { + foreach ($trait->methods as $method) { + if ($method->executableLines > 0) { + $this->numTraits++; + continue 2; + } + } + } + } + return $this->numTraits; + } + public function numberOfTestedTraits(): int + { + return $this->numTestedTraits; + } + public function numberOfMethods(): int + { + if ($this->numMethods === null) { + $this->numMethods = 0; + foreach ($this->classes as $class) { + foreach ($class->methods as $method) { + if ($method->executableLines > 0) { + $this->numMethods++; + } + } + } + foreach ($this->traits as $trait) { + foreach ($trait->methods as $method) { + if ($method->executableLines > 0) { + $this->numMethods++; + } + } + } + } + return $this->numMethods; + } + public function numberOfTestedMethods(): int + { + if ($this->numTestedMethods === null) { + $this->numTestedMethods = 0; + foreach ($this->classes as $class) { + foreach ($class->methods as $method) { + if ($method->executableLines > 0 && $method->coverage === 100) { + $this->numTestedMethods++; + } + } + } + foreach ($this->traits as $trait) { + foreach ($trait->methods as $method) { + if ($method->executableLines > 0 && $method->coverage === 100) { + $this->numTestedMethods++; + } + } + } + } + return $this->numTestedMethods; + } + public function numberOfFunctions(): int + { + return count($this->functions); + } + public function numberOfTestedFunctions(): int + { + if ($this->numTestedFunctions === null) { + $this->numTestedFunctions = 0; + foreach ($this->functions as $function) { + if ($function->executableLines > 0 && $function->coverage === 100) { + $this->numTestedFunctions++; + } + } + } + return $this->numTestedFunctions; + } + /** + * @param array $classes + * @param array $traits + * @param array $functions + */ + private function calculateStatistics(array $classes, array $traits, array $functions): void + { + foreach (range(1, $this->linesOfCode->linesOfCode()) as $lineNumber) { + $this->codeUnitsByLine[$lineNumber] = []; + } + $this->processClasses($classes); + $this->processTraits($traits); + $this->processFunctions($functions); + foreach (range(1, $this->linesOfCode->linesOfCode()) as $lineNumber) { + if (isset($this->lineCoverageData[$lineNumber])) { + foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) { + $codeUnit->executableLines++; + } + unset($codeUnit); + $this->numExecutableLines++; + if (count($this->lineCoverageData[$lineNumber]) > 0) { + foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) { + $codeUnit->executedLines++; + } + unset($codeUnit); + $this->numExecutedLines++; + } + } + } + foreach ($this->traits as &$trait) { + foreach ($trait->methods as &$method) { + $methodLineCoverage = $method->executableLines > 0 ? $method->executedLines / $method->executableLines * 100 : 100; + $methodBranchCoverage = $method->executableBranches > 0 ? $method->executedBranches / $method->executableBranches * 100 : 0; + $methodPathCoverage = $method->executablePaths > 0 ? $method->executedPaths / $method->executablePaths * 100 : 0; + $method->coverage = $methodBranchCoverage > 0 ? $methodBranchCoverage : $methodLineCoverage; + $method->crap = (new CrapIndex($method->ccn, $methodPathCoverage > 0 ? $methodPathCoverage : $methodLineCoverage))->asString(); + $trait->ccn += $method->ccn; + } + unset($method); + $traitBranchCoverage = $trait->executableBranches > 0 ? $trait->executedBranches / $trait->executableBranches * 100 : 0; + $traitLineCoverage = $trait->executableLines > 0 ? $trait->executedLines / $trait->executableLines * 100 : 100; + $traitPathCoverage = $trait->executablePaths > 0 ? $trait->executedPaths / $trait->executablePaths * 100 : 0; + $trait->coverage = $traitBranchCoverage > 0 ? $traitBranchCoverage : $traitLineCoverage; + $trait->crap = (new CrapIndex($trait->ccn, $traitPathCoverage > 0 ? $traitPathCoverage : $traitLineCoverage))->asString(); + if ($trait->executableLines > 0 && $trait->coverage === 100) { + $this->numTestedTraits++; + } + } + unset($trait); + foreach ($this->classes as &$class) { + foreach ($class->methods as &$method) { + $methodLineCoverage = $method->executableLines > 0 ? $method->executedLines / $method->executableLines * 100 : 100; + $methodBranchCoverage = $method->executableBranches > 0 ? $method->executedBranches / $method->executableBranches * 100 : 0; + $methodPathCoverage = $method->executablePaths > 0 ? $method->executedPaths / $method->executablePaths * 100 : 0; + $method->coverage = $methodBranchCoverage > 0 ? $methodBranchCoverage : $methodLineCoverage; + $method->crap = (new CrapIndex($method->ccn, $methodPathCoverage > 0 ? $methodPathCoverage : $methodLineCoverage))->asString(); + $class->ccn += $method->ccn; + } + unset($method); + $classLineCoverage = $class->executableLines > 0 ? $class->executedLines / $class->executableLines * 100 : 100; + $classBranchCoverage = $class->executableBranches > 0 ? $class->executedBranches / $class->executableBranches * 100 : 0; + $classPathCoverage = $class->executablePaths > 0 ? $class->executedPaths / $class->executablePaths * 100 : 0; + $class->coverage = $classBranchCoverage > 0 ? $classBranchCoverage : $classLineCoverage; + $class->crap = (new CrapIndex($class->ccn, $classPathCoverage > 0 ? $classPathCoverage : $classLineCoverage))->asString(); + if ($class->executableLines > 0 && $class->coverage === 100) { + $this->numTestedClasses++; + } + } + unset($class); + foreach ($this->functions as &$function) { + $functionLineCoverage = $function->executableLines > 0 ? $function->executedLines / $function->executableLines * 100 : 100; + $functionBranchCoverage = $function->executableBranches > 0 ? $function->executedBranches / $function->executableBranches * 100 : 0; + $functionPathCoverage = $function->executablePaths > 0 ? $function->executedPaths / $function->executablePaths * 100 : 0; + $function->coverage = $functionBranchCoverage > 0 ? $functionBranchCoverage : $functionLineCoverage; + $function->crap = (new CrapIndex($function->ccn, $functionPathCoverage > 0 ? $functionPathCoverage : $functionLineCoverage))->asString(); + if ($function->coverage === 100) { + $this->numTestedFunctions++; + } + } + } + /** + * @param array $classes + */ + private function processClasses(array $classes): void + { + $link = $this->id() . '.html#'; + foreach ($classes as $className => $class) { + $this->classes[$className] = new ProcessedClassType($className, $class->namespace(), [], $class->startLine(), 0, 0, 0, 0, 0, 0, 0, 0, 0, $link . $class->startLine()); + foreach ($class->methods() as $methodName => $method) { + $methodData = $this->newMethod($className, $method, $link); + $this->classes[$className]->methods[$methodName] = $methodData; + $this->classes[$className]->executableBranches += $methodData->executableBranches; + $this->classes[$className]->executedBranches += $methodData->executedBranches; + $this->classes[$className]->executablePaths += $methodData->executablePaths; + $this->classes[$className]->executedPaths += $methodData->executedPaths; + $this->numExecutableBranches += $methodData->executableBranches; + $this->numExecutedBranches += $methodData->executedBranches; + $this->numExecutablePaths += $methodData->executablePaths; + $this->numExecutedPaths += $methodData->executedPaths; + foreach (range($method->startLine(), $method->endLine()) as $lineNumber) { + $this->codeUnitsByLine[$lineNumber] = [&$this->classes[$className], &$this->classes[$className]->methods[$methodName]]; + } + } + } + } + /** + * @param array $traits + */ + private function processTraits(array $traits): void + { + $link = $this->id() . '.html#'; + foreach ($traits as $traitName => $trait) { + $this->traits[$traitName] = new ProcessedTraitType($traitName, $trait->namespace(), [], $trait->startLine(), 0, 0, 0, 0, 0, 0, 0, 0, 0, $link . $trait->startLine()); + foreach ($trait->methods() as $methodName => $method) { + $methodData = $this->newMethod($traitName, $method, $link); + $this->traits[$traitName]->methods[$methodName] = $methodData; + $this->traits[$traitName]->executableBranches += $methodData->executableBranches; + $this->traits[$traitName]->executedBranches += $methodData->executedBranches; + $this->traits[$traitName]->executablePaths += $methodData->executablePaths; + $this->traits[$traitName]->executedPaths += $methodData->executedPaths; + $this->numExecutableBranches += $methodData->executableBranches; + $this->numExecutedBranches += $methodData->executedBranches; + $this->numExecutablePaths += $methodData->executablePaths; + $this->numExecutedPaths += $methodData->executedPaths; + foreach (range($method->startLine(), $method->endLine()) as $lineNumber) { + $this->codeUnitsByLine[$lineNumber] = [&$this->traits[$traitName], &$this->traits[$traitName]->methods[$methodName]]; + } + } + } + } + /** + * @param array $functions + */ + private function processFunctions(array $functions): void + { + $link = $this->id() . '.html#'; + foreach ($functions as $functionName => $function) { + $this->functions[$functionName] = new ProcessedFunctionType($functionName, $function->namespace(), $function->signature(), $function->startLine(), $function->endLine(), 0, 0, 0, 0, 0, 0, $function->cyclomaticComplexity(), 0, 0, $link . $function->startLine()); + foreach (range($function->startLine(), $function->endLine()) as $lineNumber) { + $this->codeUnitsByLine[$lineNumber] = [&$this->functions[$functionName]]; + } + if (isset($this->functionCoverageData[$functionName])) { + $this->functions[$functionName]->executableBranches = count($this->functionCoverageData[$functionName]->branches); + $this->functions[$functionName]->executedBranches = count(array_filter($this->functionCoverageData[$functionName]->branches, static function (ProcessedBranchCoverageData $branch) { + return (bool) $branch->hit; + })); + } + if (isset($this->functionCoverageData[$functionName])) { + $this->functions[$functionName]->executablePaths = count($this->functionCoverageData[$functionName]->paths); + $this->functions[$functionName]->executedPaths = count(array_filter($this->functionCoverageData[$functionName]->paths, static function (ProcessedPathCoverageData $path) { + return (bool) $path->hit; + })); + } + $this->numExecutableBranches += $this->functions[$functionName]->executableBranches; + $this->numExecutedBranches += $this->functions[$functionName]->executedBranches; + $this->numExecutablePaths += $this->functions[$functionName]->executablePaths; + $this->numExecutedPaths += $this->functions[$functionName]->executedPaths; + } + } + private function newMethod(string $className, Method $method, string $link): ProcessedMethodType + { + $key = $className . '->' . $method->name(); + $executableBranches = 0; + $executedBranches = 0; + if (isset($this->functionCoverageData[$key])) { + $executableBranches = count($this->functionCoverageData[$key]->branches); + $executedBranches = count(array_filter($this->functionCoverageData[$key]->branches, static function (ProcessedBranchCoverageData $branch) { + return (bool) $branch->hit; + })); + } + $executablePaths = 0; + $executedPaths = 0; + if (isset($this->functionCoverageData[$key])) { + $executablePaths = count($this->functionCoverageData[$key]->paths); + $executedPaths = count(array_filter($this->functionCoverageData[$key]->paths, static function (ProcessedPathCoverageData $path) { + return (bool) $path->hit; + })); + } + return new ProcessedMethodType($method->name(), $method->visibility()->value, $method->signature(), $method->startLine(), $method->endLine(), 0, 0, $executableBranches, $executedBranches, $executablePaths, $executedPaths, $method->cyclomaticComplexity(), 0, 0, $link . $method->startLine()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node; + +use function assert; +use function count; +use RecursiveIterator; +/** + * @template-implements RecursiveIterator + * + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Iterator implements RecursiveIterator +{ + private int $position; + /** + * @var list + */ + private readonly array $nodes; + public function __construct(Directory $node) + { + $this->nodes = $node->children(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return $this->position < count($this->nodes); + } + public function key(): int + { + return $this->position; + } + public function current(): ?AbstractNode + { + return $this->valid() ? $this->nodes[$this->position] : null; + } + public function next(): void + { + $this->position++; + } + public function getChildren(): self + { + assert($this->nodes[$this->position] instanceof Directory); + return new self($this->nodes[$this->position]); + } + public function hasChildren(): bool + { + return $this->nodes[$this->position] instanceof Directory; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report; + +use function count; +use function is_string; +use function ksort; +use function max; +use function range; +use function time; +use DOMDocument; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\EnsuresUtf8; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Xml; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\WriteOperationFailedException; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Clover +{ + use EnsuresUtf8; + /** + * @param null|non-empty-string $target + * @param null|non-empty-string $name + * + * @throws WriteOperationFailedException + */ + public function process(Directory $report, ?string $target = null, ?string $name = null): string + { + $time = (string) time(); + $xmlDocument = new DOMDocument('1.0', 'UTF-8'); + $xmlCoverage = $xmlDocument->createElement('coverage'); + $xmlCoverage->setAttribute('generated', $time); + $xmlDocument->appendChild($xmlCoverage); + $xmlProject = $xmlDocument->createElement('project'); + $xmlProject->setAttribute('timestamp', $time); + if (is_string($name)) { + $xmlProject->setAttribute('name', $this->ensureUtf8($name)); + } + $xmlCoverage->appendChild($xmlProject); + $packages = []; + foreach ($report as $item) { + if (!$item instanceof File) { + continue; + } + /* @var File $item */ + $xmlFile = $xmlDocument->createElement('file'); + $xmlFile->setAttribute('name', $this->ensureUtf8($item->pathAsString())); + $classes = $item->classesAndTraits(); + $coverageData = $item->lineCoverageData(); + $lines = []; + $namespace = 'global'; + foreach ($classes as $className => $class) { + $classStatements = 0; + $coveredClassStatements = 0; + $coveredMethods = 0; + $classMethods = 0; + // Assumption: one namespace per file + if ($class->namespace !== '') { + $namespace = $class->namespace; + } + foreach ($class->methods as $methodName => $method) { + /** @phpstan-ignore equal.notAllowed */ + if ($method->executableLines == 0) { + continue; + } + $classMethods++; + $classStatements += $method->executableLines; + $coveredClassStatements += $method->executedLines; + /** @phpstan-ignore equal.notAllowed */ + if ($method->coverage == 100) { + $coveredMethods++; + } + $methodCount = 0; + foreach (range($method->startLine, $method->endLine) as $line) { + if (isset($coverageData[$line])) { + $methodCount = max($methodCount, count($coverageData[$line])); + } + } + $lines[$method->startLine] = ['ccn' => $method->ccn, 'count' => $methodCount, 'crap' => $method->crap, 'type' => 'method', 'visibility' => $method->visibility, 'name' => $methodName]; + } + $xmlClass = $xmlDocument->createElement('class'); + $xmlClass->setAttribute('name', $this->ensureUtf8($className)); + $xmlClass->setAttribute('namespace', $this->ensureUtf8($namespace)); + $xmlFile->appendChild($xmlClass); + $xmlMetrics = $xmlDocument->createElement('metrics'); + $xmlMetrics->setAttribute('complexity', (string) $class->ccn); + $xmlMetrics->setAttribute('methods', (string) $classMethods); + $xmlMetrics->setAttribute('coveredmethods', (string) $coveredMethods); + $xmlMetrics->setAttribute('conditionals', (string) $class->executableBranches); + $xmlMetrics->setAttribute('coveredconditionals', (string) $class->executedBranches); + $xmlMetrics->setAttribute('statements', (string) $classStatements); + $xmlMetrics->setAttribute('coveredstatements', (string) $coveredClassStatements); + $xmlMetrics->setAttribute('elements', (string) ($classMethods + $classStatements + $class->executableBranches)); + $xmlMetrics->setAttribute('coveredelements', (string) ($coveredMethods + $coveredClassStatements + $class->executedBranches)); + $xmlClass->appendChild($xmlMetrics); + } + foreach ($coverageData as $line => $data) { + if ($data === null || isset($lines[$line])) { + continue; + } + $lines[$line] = ['count' => count($data), 'type' => 'stmt']; + } + ksort($lines); + foreach ($lines as $line => $data) { + $xmlLine = $xmlDocument->createElement('line'); + $xmlLine->setAttribute('num', (string) $line); + $xmlLine->setAttribute('type', $data['type']); + if (isset($data['name'])) { + $xmlLine->setAttribute('name', $this->ensureUtf8($data['name'])); + } + if (isset($data['visibility'])) { + $xmlLine->setAttribute('visibility', $data['visibility']); + } + if (isset($data['ccn'])) { + $xmlLine->setAttribute('complexity', (string) $data['ccn']); + } + if (isset($data['crap'])) { + $xmlLine->setAttribute('crap', (string) $data['crap']); + } + $xmlLine->setAttribute('count', (string) $data['count']); + $xmlFile->appendChild($xmlLine); + } + $linesOfCode = $item->linesOfCode(); + $xmlMetrics = $xmlDocument->createElement('metrics'); + $xmlMetrics->setAttribute('loc', (string) $linesOfCode->linesOfCode()); + $xmlMetrics->setAttribute('ncloc', (string) $linesOfCode->nonCommentLinesOfCode()); + $xmlMetrics->setAttribute('classes', (string) $item->numberOfClassesAndTraits()); + $xmlMetrics->setAttribute('methods', (string) $item->numberOfMethods()); + $xmlMetrics->setAttribute('coveredmethods', (string) $item->numberOfTestedMethods()); + $xmlMetrics->setAttribute('conditionals', (string) $item->numberOfExecutableBranches()); + $xmlMetrics->setAttribute('coveredconditionals', (string) $item->numberOfExecutedBranches()); + $xmlMetrics->setAttribute('statements', (string) $item->numberOfExecutableLines()); + $xmlMetrics->setAttribute('coveredstatements', (string) $item->numberOfExecutedLines()); + $xmlMetrics->setAttribute('elements', (string) ($item->numberOfMethods() + $item->numberOfExecutableLines() + $item->numberOfExecutableBranches())); + $xmlMetrics->setAttribute('coveredelements', (string) ($item->numberOfTestedMethods() + $item->numberOfExecutedLines() + $item->numberOfExecutedBranches())); + $xmlFile->appendChild($xmlMetrics); + if ($namespace === 'global') { + $xmlProject->appendChild($xmlFile); + } else { + if (!isset($packages[$namespace])) { + $packages[$namespace] = $xmlDocument->createElement('package'); + $packages[$namespace]->setAttribute('name', $this->ensureUtf8($namespace)); + $xmlProject->appendChild($packages[$namespace]); + } + $packages[$namespace]->appendChild($xmlFile); + } + } + $linesOfCode = $report->linesOfCode(); + $xmlMetrics = $xmlDocument->createElement('metrics'); + $xmlMetrics->setAttribute('files', (string) count($report)); + $xmlMetrics->setAttribute('loc', (string) $linesOfCode->linesOfCode()); + $xmlMetrics->setAttribute('ncloc', (string) $linesOfCode->nonCommentLinesOfCode()); + $xmlMetrics->setAttribute('classes', (string) $report->numberOfClassesAndTraits()); + $xmlMetrics->setAttribute('methods', (string) $report->numberOfMethods()); + $xmlMetrics->setAttribute('coveredmethods', (string) $report->numberOfTestedMethods()); + $xmlMetrics->setAttribute('conditionals', (string) $report->numberOfExecutableBranches()); + $xmlMetrics->setAttribute('coveredconditionals', (string) $report->numberOfExecutedBranches()); + $xmlMetrics->setAttribute('statements', (string) $report->numberOfExecutableLines()); + $xmlMetrics->setAttribute('coveredstatements', (string) $report->numberOfExecutedLines()); + $xmlMetrics->setAttribute('elements', (string) ($report->numberOfMethods() + $report->numberOfExecutableLines() + $report->numberOfExecutableBranches())); + $xmlMetrics->setAttribute('coveredelements', (string) ($report->numberOfTestedMethods() + $report->numberOfExecutedLines() + $report->numberOfExecutedBranches())); + $xmlProject->appendChild($xmlMetrics); + $buffer = Xml::asString($xmlDocument); + if ($target !== null) { + Filesystem::write($target, $buffer); + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report; + +use const DIRECTORY_SEPARATOR; +use function basename; +use function count; +use function preg_match; +use function range; +use function str_replace; +use function time; +use DOMDocument; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\EnsuresUtf8; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Xml; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\WriteOperationFailedException; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Cobertura +{ + use EnsuresUtf8; + /** + * @param null|non-empty-string $target + * + * @throws WriteOperationFailedException + */ + public function process(Directory $report, ?string $target = null): string + { + $time = (string) time(); + $document = new DOMDocument('1.0', 'UTF-8'); + $coverageElement = $document->createElement('coverage'); + $linesValid = $report->numberOfExecutableLines(); + $linesCovered = $report->numberOfExecutedLines(); + $lineRate = $linesValid === 0 ? 0 : $linesCovered / $linesValid; + $coverageElement->setAttribute('line-rate', (string) $lineRate); + $branchesValid = $report->numberOfExecutableBranches(); + $branchesCovered = $report->numberOfExecutedBranches(); + $branchRate = $branchesValid === 0 ? 0 : $branchesCovered / $branchesValid; + $coverageElement->setAttribute('branch-rate', (string) $branchRate); + $coverageElement->setAttribute('lines-covered', (string) $report->numberOfExecutedLines()); + $coverageElement->setAttribute('lines-valid', (string) $report->numberOfExecutableLines()); + $coverageElement->setAttribute('branches-covered', (string) $report->numberOfExecutedBranches()); + $coverageElement->setAttribute('branches-valid', (string) $report->numberOfExecutableBranches()); + $coverageElement->setAttribute('complexity', ''); + $coverageElement->setAttribute('version', '0.4'); + $coverageElement->setAttribute('timestamp', $time); + $document->appendChild($coverageElement); + $sourcesElement = $document->createElement('sources'); + $coverageElement->appendChild($sourcesElement); + $sourceElement = $document->createElement('source', $this->ensureUtf8($report->pathAsString())); + $sourcesElement->appendChild($sourceElement); + $packagesElement = $document->createElement('packages'); + $coverageElement->appendChild($packagesElement); + $complexity = 0; + foreach ($report as $item) { + if (!$item instanceof File) { + continue; + } + $packageElement = $document->createElement('package'); + $packageComplexity = 0; + $packageElement->setAttribute('name', $this->ensureUtf8(str_replace($report->pathAsString() . DIRECTORY_SEPARATOR, '', $item->pathAsString()))); + $linesValid = $item->numberOfExecutableLines(); + $linesCovered = $item->numberOfExecutedLines(); + $lineRate = $linesValid === 0 ? 0 : $linesCovered / $linesValid; + $packageElement->setAttribute('line-rate', (string) $lineRate); + $branchesValid = $item->numberOfExecutableBranches(); + $branchesCovered = $item->numberOfExecutedBranches(); + $branchRate = $branchesValid === 0 ? 0 : $branchesCovered / $branchesValid; + $packageElement->setAttribute('branch-rate', (string) $branchRate); + $packageElement->setAttribute('complexity', ''); + $packagesElement->appendChild($packageElement); + $classesElement = $document->createElement('classes'); + $packageElement->appendChild($classesElement); + $classes = $item->classesAndTraits(); + $coverageData = $item->lineCoverageData(); + foreach ($classes as $className => $class) { + $complexity += $class->ccn; + $packageComplexity += $class->ccn; + $linesValid = $class->executableLines; + $linesCovered = $class->executedLines; + $lineRate = $linesValid === 0 ? 0 : $linesCovered / $linesValid; + $branchesValid = $class->executableBranches; + $branchesCovered = $class->executedBranches; + $branchRate = $branchesValid === 0 ? 0 : $branchesCovered / $branchesValid; + $classElement = $document->createElement('class'); + $classElement->setAttribute('name', $this->ensureUtf8($className)); + $classElement->setAttribute('filename', $this->ensureUtf8(str_replace($report->pathAsString() . DIRECTORY_SEPARATOR, '', $item->pathAsString()))); + $classElement->setAttribute('line-rate', (string) $lineRate); + $classElement->setAttribute('branch-rate', (string) $branchRate); + $classElement->setAttribute('complexity', (string) $class->ccn); + $classesElement->appendChild($classElement); + $methodsElement = $document->createElement('methods'); + $classElement->appendChild($methodsElement); + $classLinesElement = $document->createElement('lines'); + $classElement->appendChild($classLinesElement); + foreach ($class->methods as $methodName => $method) { + if ($method->executableLines === 0) { + continue; + } + preg_match("/\\((.*?)\\)/", $method->signature, $signature); + $linesValid = $method->executableLines; + $linesCovered = $method->executedLines; + $lineRate = $linesCovered / $linesValid; + $branchesValid = $method->executableBranches; + $branchesCovered = $method->executedBranches; + $branchRate = $branchesValid === 0 ? 0 : $branchesCovered / $branchesValid; + $methodElement = $document->createElement('method'); + $methodElement->setAttribute('name', $this->ensureUtf8($methodName)); + $methodElement->setAttribute('signature', $this->ensureUtf8($signature[1])); + $methodElement->setAttribute('line-rate', (string) $lineRate); + $methodElement->setAttribute('branch-rate', (string) $branchRate); + $methodElement->setAttribute('complexity', (string) $method->ccn); + $methodLinesElement = $document->createElement('lines'); + $methodElement->appendChild($methodLinesElement); + foreach (range($method->startLine, $method->endLine) as $line) { + if (!isset($coverageData[$line])) { + continue; + } + $methodLineElement = $document->createElement('line'); + $methodLineElement->setAttribute('number', (string) $line); + $methodLineElement->setAttribute('hits', (string) count($coverageData[$line])); + $methodLinesElement->appendChild($methodLineElement); + $classLineElement = $methodLineElement->cloneNode(); + $classLinesElement->appendChild($classLineElement); + } + $methodsElement->appendChild($methodElement); + } + } + if ($item->numberOfFunctions() === 0) { + $packageElement->setAttribute('complexity', (string) $packageComplexity); + continue; + } + $functionsComplexity = 0; + $functionsLinesValid = 0; + $functionsLinesCovered = 0; + $functionsBranchesValid = 0; + $functionsBranchesCovered = 0; + $classElement = $document->createElement('class'); + $classElement->setAttribute('name', $this->ensureUtf8(basename($item->pathAsString()))); + $classElement->setAttribute('filename', $this->ensureUtf8(str_replace($report->pathAsString() . DIRECTORY_SEPARATOR, '', $item->pathAsString()))); + $methodsElement = $document->createElement('methods'); + $classElement->appendChild($methodsElement); + $classLinesElement = $document->createElement('lines'); + $classElement->appendChild($classLinesElement); + $functions = $item->functions(); + foreach ($functions as $functionName => $function) { + if ($function->executableLines === 0) { + continue; + } + $complexity += $function->ccn; + $packageComplexity += $function->ccn; + $functionsComplexity += $function->ccn; + $linesValid = $function->executableLines; + $linesCovered = $function->executedLines; + $lineRate = $linesCovered / $linesValid; + $functionsLinesValid += $linesValid; + $functionsLinesCovered += $linesCovered; + $branchesValid = $function->executableBranches; + $branchesCovered = $function->executedBranches; + $branchRate = $branchesValid === 0 ? 0 : $branchesCovered / $branchesValid; + $functionsBranchesValid += $branchesValid; + $functionsBranchesCovered += $branchesValid; + $methodElement = $document->createElement('method'); + $methodElement->setAttribute('name', $this->ensureUtf8($functionName)); + $methodElement->setAttribute('signature', $this->ensureUtf8($function->signature)); + $methodElement->setAttribute('line-rate', (string) $lineRate); + $methodElement->setAttribute('branch-rate', (string) $branchRate); + $methodElement->setAttribute('complexity', (string) $function->ccn); + $methodLinesElement = $document->createElement('lines'); + $methodElement->appendChild($methodLinesElement); + foreach (range($function->startLine, $function->endLine) as $line) { + if (!isset($coverageData[$line])) { + continue; + } + $methodLineElement = $document->createElement('line'); + $methodLineElement->setAttribute('number', (string) $line); + $methodLineElement->setAttribute('hits', (string) count($coverageData[$line])); + $methodLinesElement->appendChild($methodLineElement); + $classLineElement = $methodLineElement->cloneNode(); + $classLinesElement->appendChild($classLineElement); + } + $methodsElement->appendChild($methodElement); + } + $packageElement->setAttribute('complexity', (string) $packageComplexity); + if ($functionsLinesValid === 0) { + continue; + } + $lineRate = $functionsLinesCovered / $functionsLinesValid; + $branchRate = $functionsBranchesValid === 0 ? 0 : $functionsBranchesCovered / $functionsBranchesValid; + $classElement->setAttribute('line-rate', (string) $lineRate); + $classElement->setAttribute('branch-rate', (string) $branchRate); + $classElement->setAttribute('complexity', (string) $functionsComplexity); + $classesElement->appendChild($classElement); + } + $coverageElement->setAttribute('complexity', (string) $complexity); + $buffer = Xml::asString($document); + if ($target !== null) { + Filesystem::write($target, $buffer); + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report; + +use function date; +use function htmlspecialchars; +use function is_string; +use function round; +use DOMDocument; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\EnsuresUtf8; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Xml; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\WriteOperationFailedException; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Crap4j +{ + use EnsuresUtf8; + private int $threshold; + public function __construct(int $threshold = 30) + { + $this->threshold = $threshold; + } + /** + * @param null|non-empty-string $target + * @param null|non-empty-string $name + * + * @throws WriteOperationFailedException + */ + public function process(Directory $report, ?string $target = null, ?string $name = null): string + { + $document = new DOMDocument('1.0', 'UTF-8'); + $root = $document->createElement('crap_result'); + $document->appendChild($root); + $project = $document->createElement('project', is_string($name) ? $this->ensureUtf8($name) : ''); + $root->appendChild($project); + $root->appendChild($document->createElement('timestamp', date('Y-m-d H:i:s'))); + $stats = $document->createElement('stats'); + $methodsNode = $document->createElement('methods'); + $fullMethodCount = 0; + $fullCrapMethodCount = 0; + $fullCrapLoad = 0; + $fullCrap = 0; + foreach ($report as $item) { + $namespace = 'global'; + if (!$item instanceof File) { + continue; + } + $file = $document->createElement('file'); + $file->setAttribute('name', $this->ensureUtf8($item->pathAsString())); + $classes = $item->classesAndTraits(); + foreach ($classes as $className => $class) { + foreach ($class->methods as $methodName => $method) { + $crapLoad = $this->crapLoad((float) $method->crap, $method->ccn, $method->coverage); + $fullCrap += $method->crap; + $fullCrapLoad += $crapLoad; + $fullMethodCount++; + if ($method->crap >= $this->threshold) { + $fullCrapMethodCount++; + } + $methodNode = $document->createElement('method'); + if ($class->namespace !== '') { + $namespace = $class->namespace; + } + $methodNode->appendChild($document->createElement('package', $this->ensureUtf8($namespace))); + $methodNode->appendChild($document->createElement('className', $this->ensureUtf8($className))); + $methodNode->appendChild($document->createElement('methodName', $this->ensureUtf8($methodName))); + $methodNode->appendChild($document->createElement('methodSignature', htmlspecialchars($this->ensureUtf8($method->signature)))); + $methodNode->appendChild($document->createElement('fullMethod', htmlspecialchars($this->ensureUtf8($method->signature)))); + $methodNode->appendChild($document->createElement('crap', (string) $this->roundValue((float) $method->crap))); + $methodNode->appendChild($document->createElement('complexity', (string) $method->ccn)); + $methodNode->appendChild($document->createElement('coverage', (string) $this->roundValue($method->coverage))); + $methodNode->appendChild($document->createElement('crapLoad', (string) round($crapLoad))); + $methodsNode->appendChild($methodNode); + } + } + } + $stats->appendChild($document->createElement('name', 'Method Crap Stats')); + $stats->appendChild($document->createElement('methodCount', (string) $fullMethodCount)); + $stats->appendChild($document->createElement('crapMethodCount', (string) $fullCrapMethodCount)); + $stats->appendChild($document->createElement('crapLoad', (string) round($fullCrapLoad))); + $stats->appendChild($document->createElement('totalCrap', (string) $fullCrap)); + $crapMethodPercent = 0; + if ($fullMethodCount > 0) { + $crapMethodPercent = $this->roundValue(100 * $fullCrapMethodCount / $fullMethodCount); + } + $stats->appendChild($document->createElement('crapMethodPercent', (string) $crapMethodPercent)); + $root->appendChild($stats); + $root->appendChild($methodsNode); + $buffer = Xml::asString($document); + if ($target !== null) { + Filesystem::write($target, $buffer); + } + return $buffer; + } + private function crapLoad(float $crapValue, int $cyclomaticComplexity, float $coveragePercent): float + { + $crapLoad = 0; + if ($crapValue >= $this->threshold) { + $crapLoad += $cyclomaticComplexity * (1.0 - $coveragePercent / 100); + $crapLoad += $cyclomaticComplexity / $this->threshold; + } + return $crapLoad; + } + private function roundValue(float $value): float + { + return round($value, 2); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report; + +use DateTimeImmutable; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Builder; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html\Colors; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html\CustomCssFile; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html\Facade as HtmlFacade; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml\Facade as XmlFacade; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization\Serializer; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\ParsingSourceAnalyser; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\Environment\Runtime; +/** + * @phpstan-import-type SerializedCoverage from Serializer + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Facade +{ + private Directory $report; + /** + * @var array + */ + private array $testResults; + public static function fromObject(CodeCoverage $codeCoverage): self + { + return new self($codeCoverage->getReport(), $codeCoverage->getTests()); + } + /** + * @param SerializedCoverage $serializedCoverage + */ + public static function fromSerializedData(array $serializedCoverage): self + { + return new self(self::buildReport($serializedCoverage), $serializedCoverage['testResults']); + } + /** + * @param array $testResults + */ + private function __construct(Directory $report, array $testResults) + { + $this->report = $report; + $this->testResults = $testResults; + } + /** + * @param non-empty-string $target + */ + public function renderHtml(string $target, string $generator = '', ?Colors $colors = null, ?Thresholds $thresholds = null, ?CustomCssFile $customCssFile = null): void + { + (new HtmlFacade($generator, $colors, $thresholds, $customCssFile))->process($this->report, $target); + } + /** + * @param non-empty-string $target + */ + public function renderXml(string $target, bool $includeSource = \true, ?Runtime $runtime = null, ?DateTimeImmutable $buildDate = null, ?string $phpUnitVersion = null, ?string $coverageVersion = null, ?string $driverExtensionName = null, ?string $driverExtensionVersion = null): void + { + (new XmlFacade($includeSource))->process($target, $this->report, $this->testResults, $runtime, $buildDate, $phpUnitVersion, $coverageVersion, $driverExtensionName, $driverExtensionVersion); + } + /** + * @param non-empty-string $target + * @param null|non-empty-string $name + */ + public function renderClover(string $target, ?string $name = null): void + { + (new Clover())->process($this->report, $target, $name); + } + /** + * @param non-empty-string $target + * @param null|non-empty-string $name + */ + public function renderOpenClover(string $target, ?string $name = null): void + { + (new OpenClover())->process($this->report, $target, $name); + } + /** + * @param non-empty-string $target + */ + public function renderCobertura(string $target): void + { + (new Cobertura())->process($this->report, $target); + } + /** + * @param non-empty-string $target + * @param null|non-empty-string $name + */ + public function renderCrap4j(string $target, int $threshold = 30, ?string $name = null): void + { + (new Crap4j($threshold))->process($this->report, $target, $name); + } + public function summary(): Summary + { + return new Summary($this->report->numberOfExecutableLines(), $this->report->numberOfExecutedLines(), $this->report->numberOfExecutableBranches(), $this->report->numberOfExecutedBranches(), $this->report->numberOfExecutablePaths(), $this->report->numberOfExecutedPaths(), $this->report->numberOfFilesWithoutBranchCoverageData()); + } + /** + * @param ?non-empty-string $target + */ + public function renderText(?string $target, ?Thresholds $thresholds = null, bool $showUncoveredFiles = \false, bool $showOnlySummary = \false, bool $showColors = \false): string + { + if ($thresholds === null) { + $thresholds = Thresholds::default(); + } + $buffer = (new Text($thresholds, $showUncoveredFiles, $showOnlySummary))->process($this->report, $showColors); + if ($target !== null) { + Filesystem::write($target, (new Text($thresholds, $showUncoveredFiles, $showOnlySummary))->process($this->report, $showColors)); + } + return $buffer; + } + /** + * @param SerializedCoverage $serializedCoverage + */ + private static function buildReport(array $serializedCoverage): Directory + { + return (new Builder(new FileAnalyser(new ParsingSourceAnalyser(), \false, \false)))->build($serializedCoverage['codeCoverage'], $serializedCoverage['testResults'], $serializedCoverage['basePath']); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Colors +{ + private string $successLow; + private string $successLowDark; + private string $successMedium; + private string $successMediumDark; + private string $successHigh; + private string $successHighDark; + private string $successBar; + private string $successBarDark; + private string $warning; + private string $warningDark; + private string $warningBar; + private string $warningBarDark; + private string $danger; + private string $dangerDark; + private string $dangerBar; + private string $dangerBarDark; + private string $breadcrumbs; + private string $breadcrumbsDark; + public static function default(): self + { + return new self('#d6e6f2', '#1e3550', '#b3d1e8', '#2d4f6e', '#8cb4d5', '#2a4a6b', '#1a73b4', '#1560a0', '#fdf0d5', '#3d3010', '#e5a100', '#b88a00', '#fad4c0', '#4a2a10', '#d45500', '#b54400', 'var(--bs-gray-200)', 'var(--bs-gray-800)'); + } + public static function from(string $successLow, string $successLowDark, string $successMedium, string $successMediumDark, string $successHigh, string $successHighDark, string $successBar, string $successBarDark, string $warning, string $warningDark, string $warningBar, string $warningBarDark, string $danger, string $dangerDark, string $dangerBar, string $dangerBarDark, string $breadcrumbs, string $breadcrumbsDark): self + { + return new self($successLow, $successLowDark, $successMedium, $successMediumDark, $successHigh, $successHighDark, $successBar, $successBarDark, $warning, $warningDark, $warningBar, $warningBarDark, $danger, $dangerDark, $dangerBar, $dangerBarDark, $breadcrumbs, $breadcrumbsDark); + } + private function __construct(string $successLow, string $successLowDark, string $successMedium, string $successMediumDark, string $successHigh, string $successHighDark, string $successBar, string $successBarDark, string $warning, string $warningDark, string $warningBar, string $warningBarDark, string $danger, string $dangerDark, string $dangerBar, string $dangerBarDark, string $breadcrumbs, string $breadcrumbsDark) + { + $this->successLow = $successLow; + $this->successLowDark = $successLowDark; + $this->successMedium = $successMedium; + $this->successMediumDark = $successMediumDark; + $this->successHigh = $successHigh; + $this->successHighDark = $successHighDark; + $this->successBar = $successBar; + $this->successBarDark = $successBarDark; + $this->warning = $warning; + $this->warningDark = $warningDark; + $this->warningBar = $warningBar; + $this->warningBarDark = $warningBarDark; + $this->danger = $danger; + $this->dangerDark = $dangerDark; + $this->dangerBar = $dangerBar; + $this->dangerBarDark = $dangerBarDark; + $this->breadcrumbs = $breadcrumbs; + $this->breadcrumbsDark = $breadcrumbsDark; + } + public function successLow(): string + { + return $this->successLow; + } + public function successLowDark(): string + { + return $this->successLowDark; + } + public function successMedium(): string + { + return $this->successMedium; + } + public function successMediumDark(): string + { + return $this->successMediumDark; + } + public function successHigh(): string + { + return $this->successHigh; + } + public function successHighDark(): string + { + return $this->successHighDark; + } + public function successBar(): string + { + return $this->successBar; + } + public function successBarDark(): string + { + return $this->successBarDark; + } + public function warning(): string + { + return $this->warning; + } + public function warningDark(): string + { + return $this->warningDark; + } + public function warningBar(): string + { + return $this->warningBar; + } + public function warningBarDark(): string + { + return $this->warningBarDark; + } + public function danger(): string + { + return $this->danger; + } + public function dangerDark(): string + { + return $this->dangerDark; + } + public function dangerBar(): string + { + return $this->dangerBar; + } + public function dangerBarDark(): string + { + return $this->dangerBarDark; + } + public function breadcrumbs(): string + { + return $this->breadcrumbs; + } + public function breadcrumbsDark(): string + { + return $this->breadcrumbsDark; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html; + +use function is_file; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\InvalidArgumentException; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class CustomCssFile +{ + private string $path; + public static function default(): self + { + return new self(__DIR__ . '/Renderer/Template/css/custom.css'); + } + /** + * @throws InvalidArgumentException + */ + public static function from(string $path): self + { + if (!is_file($path)) { + throw new InvalidArgumentException('$path does not exist'); + } + return new self($path); + } + private function __construct(string $path) + { + $this->path = $path; + } + public function path(): string + { + return $this->path; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html; + +use const DIRECTORY_SEPARATOR; +use function copy; +use function date; +use function dirname; +use function str_ends_with; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\FileCouldNotBeWrittenException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Thresholds; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\Template\Exception; +use PHPUnitPHAR\SebastianBergmann\Template\Template; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Facade +{ + private string $templatePath; + private string $generator; + private Colors $colors; + private Thresholds $thresholds; + private CustomCssFile $customCssFile; + public function __construct(string $generator = '', ?Colors $colors = null, ?Thresholds $thresholds = null, ?CustomCssFile $customCssFile = null) + { + $this->generator = $generator; + $this->colors = $colors ?? Colors::default(); + $this->thresholds = $thresholds ?? Thresholds::default(); + $this->customCssFile = $customCssFile ?? CustomCssFile::default(); + $this->templatePath = __DIR__ . '/Renderer/Template/'; + } + public function process(DirectoryNode $report, string $target): void + { + $target = $this->directory($target); + $date = date('D M j G:i:s T Y'); + $hasBranchCoverage = $report->numberOfExecutableBranches() > 0; + $dashboard = new Dashboard($this->templatePath, $this->generator, $date, $this->thresholds, $hasBranchCoverage); + $directory = new Directory($this->templatePath, $this->generator, $date, $this->thresholds, $hasBranchCoverage); + $file = new File($this->templatePath, $this->generator, $date, $this->thresholds, $hasBranchCoverage); + $directory->render($report, $target . 'index.html'); + $dashboard->render($report, $target . 'dashboard.html'); + foreach ($report as $node) { + $id = $node->id(); + if ($node instanceof DirectoryNode) { + Filesystem::createDirectory($target . $id); + $directory->render($node, $target . $id . '/index.html'); + $dashboard->render($node, $target . $id . '/dashboard.html'); + } else { + $dir = dirname($target . $id); + Filesystem::createDirectory($dir); + $file->render($node, $target . $id); + } + } + $this->copyFiles($target); + $this->renderCss($target); + } + private function copyFiles(string $target): void + { + $dir = $this->directory($target . '_css'); + copy($this->templatePath . 'css/bootstrap.min.css', $dir . 'bootstrap.min.css'); + copy($this->customCssFile->path(), $dir . 'custom.css'); + copy($this->templatePath . 'css/octicons.css', $dir . 'octicons.css'); + $dir = $this->directory($target . '_icons'); + copy($this->templatePath . 'icons/file-code.svg', $dir . 'file-code.svg'); + copy($this->templatePath . 'icons/file-directory.svg', $dir . 'file-directory.svg'); + $dir = $this->directory($target . '_js'); + copy($this->templatePath . 'js/bootstrap.bundle.min.js', $dir . 'bootstrap.bundle.min.js'); + copy($this->templatePath . 'js/jquery.min.js', $dir . 'jquery.min.js'); + copy($this->templatePath . 'js/file.js', $dir . 'file.js'); + } + private function renderCss(string $target): void + { + $template = new Template($this->templatePath . 'css/style.css', '{{', '}}'); + $template->setVar(['breadcrumbs' => $this->colors->breadcrumbs(), 'breadcrumbs-dark' => $this->colors->breadcrumbsDark(), 'success-bar' => $this->colors->successBar(), 'success-bar-dark' => $this->colors->successBarDark(), 'success-high' => $this->colors->successHigh(), 'success-high-dark' => $this->colors->successHighDark(), 'success-medium' => $this->colors->successMedium(), 'success-medium-dark' => $this->colors->successMediumDark(), 'success-low' => $this->colors->successLow(), 'success-low-dark' => $this->colors->successLowDark(), 'warning' => $this->colors->warning(), 'warning-dark' => $this->colors->warningDark(), 'warning-bar' => $this->colors->warningBar(), 'warning-bar-dark' => $this->colors->warningBarDark(), 'danger' => $this->colors->danger(), 'danger-dark' => $this->colors->dangerDark(), 'danger-bar' => $this->colors->dangerBar(), 'danger-bar-dark' => $this->colors->dangerBarDark()]); + try { + $template->renderTo($this->directory($target . '_css') . 'style.css'); + // @codeCoverageIgnoreStart + } catch (Exception $e) { + throw new FileCouldNotBeWrittenException($e->getMessage(), $e->getCode(), $e); + // @codeCoverageIgnoreEnd + } + } + private function directory(string $directory): string + { + if (!str_ends_with($directory, DIRECTORY_SEPARATOR)) { + $directory .= DIRECTORY_SEPARATOR; + } + Filesystem::createDirectory($directory); + return $directory; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html; + +use function array_pop; +use function count; +use function sprintf; +use function str_repeat; +use function substr_count; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\AbstractNode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File as FileNode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Thresholds; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Version; +use PHPUnitPHAR\SebastianBergmann\Environment\Runtime; +use PHPUnitPHAR\SebastianBergmann\Template\Template; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +abstract class Renderer +{ + protected string $templatePath; + protected string $generator; + protected string $date; + protected Thresholds $thresholds; + protected bool $hasBranchCoverage; + protected string $version; + public function __construct(string $templatePath, string $generator, string $date, Thresholds $thresholds, bool $hasBranchCoverage) + { + $this->templatePath = $templatePath; + $this->generator = $generator; + $this->date = $date; + $this->thresholds = $thresholds; + $this->version = Version::id(); + $this->hasBranchCoverage = $hasBranchCoverage; + } + /** + * @param array $data + */ + protected function renderItemTemplate(Template $template, array $data): string + { + $numSeparator = ' / '; + if (isset($data['numClasses']) && $data['numClasses'] > 0) { + $classesLevel = $this->colorLevel($data['testedClassesPercent']); + $classesNumber = $data['numTestedClasses'] . $numSeparator . $data['numClasses']; + $classesBar = $this->coverageBar($data['testedClassesPercent']); + } else { + $classesLevel = ''; + $classesNumber = '0' . $numSeparator . '0'; + $classesBar = ''; + $data['testedClassesPercentAsString'] = 'n/a'; + } + if ($data['numMethods'] > 0) { + $methodsLevel = $this->colorLevel($data['testedMethodsPercent']); + $methodsNumber = $data['numTestedMethods'] . $numSeparator . $data['numMethods']; + $methodsBar = $this->coverageBar($data['testedMethodsPercent']); + } else { + $methodsLevel = ''; + $methodsNumber = '0' . $numSeparator . '0'; + $methodsBar = ''; + $data['testedMethodsPercentAsString'] = 'n/a'; + } + if ($data['numExecutableLines'] > 0) { + $linesLevel = $this->colorLevel($data['linesExecutedPercent']); + $linesNumber = $data['numExecutedLines'] . $numSeparator . $data['numExecutableLines']; + $linesBar = $this->coverageBar($data['linesExecutedPercent']); + } else { + $linesLevel = ''; + $linesNumber = '0' . $numSeparator . '0'; + $linesBar = ''; + $data['linesExecutedPercentAsString'] = 'n/a'; + } + $numFilesWithoutBranchCoverageData = $data['numFilesWithoutBranchCoverageData'] ?? 0; + if ($data['numExecutablePaths'] > 0) { + $pathsLevel = $this->colorLevel($data['pathsExecutedPercent']); + $pathsNumber = $data['numExecutedPaths'] . $numSeparator . $data['numExecutablePaths']; + $pathsBar = $this->coverageBar($data['pathsExecutedPercent']); + if ($numFilesWithoutBranchCoverageData > 0) { + $data['pathsExecutedPercentAsString'] .= ' *'; + } + } else { + $pathsLevel = ''; + $pathsNumber = '0' . $numSeparator . '0'; + $pathsBar = ''; + $data['pathsExecutedPercentAsString'] = 'n/a'; + } + if ($data['numExecutableBranches'] > 0) { + $branchesLevel = $this->colorLevel($data['branchesExecutedPercent']); + $branchesNumber = $data['numExecutedBranches'] . $numSeparator . $data['numExecutableBranches']; + $branchesBar = $this->coverageBar($data['branchesExecutedPercent']); + if ($numFilesWithoutBranchCoverageData > 0) { + $data['branchesExecutedPercentAsString'] .= ' *'; + } + } else { + $branchesLevel = ''; + $branchesNumber = '0' . $numSeparator . '0'; + $branchesBar = ''; + $data['branchesExecutedPercentAsString'] = 'n/a'; + } + $template->setVar(['icon' => $data['icon'] ?? '', 'crap' => $data['crap'] ?? '', 'name' => $data['name'], 'lines_bar' => $linesBar, 'lines_executed_percent' => $data['linesExecutedPercentAsString'], 'lines_level' => $linesLevel, 'lines_number' => $linesNumber, 'paths_bar' => $pathsBar, 'paths_executed_percent' => $data['pathsExecutedPercentAsString'], 'paths_level' => $pathsLevel, 'paths_number' => $pathsNumber, 'branches_bar' => $branchesBar, 'branches_executed_percent' => $data['branchesExecutedPercentAsString'], 'branches_level' => $branchesLevel, 'branches_number' => $branchesNumber, 'methods_bar' => $methodsBar, 'methods_tested_percent' => $data['testedMethodsPercentAsString'], 'methods_level' => $methodsLevel, 'methods_number' => $methodsNumber, 'classes_bar' => $classesBar, 'classes_tested_percent' => $data['testedClassesPercentAsString'] ?? '', 'classes_level' => $classesLevel, 'classes_number' => $classesNumber]); + return $template->render(); + } + protected function setCommonTemplateVariables(Template $template, AbstractNode $node): void + { + $template->setVar(['id' => $node->id(), 'full_path' => $node->pathAsString(), 'path_to_root' => $this->pathToRoot($node), 'breadcrumbs' => $this->breadcrumbs($node), 'date' => $this->date, 'version' => $this->version, 'runtime' => $this->runtimeString(), 'generator' => $this->generator, 'low_upper_bound' => (string) $this->thresholds->lowUpperBound(), 'high_lower_bound' => (string) $this->thresholds->highLowerBound()]); + } + protected function breadcrumbs(AbstractNode $node): string + { + $breadcrumbs = ''; + $path = $node->pathAsArray(); + $pathToRoot = []; + $max = count($path); + if ($node instanceof FileNode) { + $max--; + } + for ($i = 0; $i < $max; $i++) { + $pathToRoot[] = str_repeat('../', $i); + } + foreach ($path as $step) { + if ($step !== $node) { + $breadcrumbs .= $this->inactiveBreadcrumb($step, array_pop($pathToRoot)); + } else { + $breadcrumbs .= $this->activeBreadcrumb($step); + } + } + return $breadcrumbs; + } + protected function activeBreadcrumb(AbstractNode $node): string + { + $buffer = sprintf('

' . "\n", $node->name()); + if ($node instanceof DirectoryNode) { + $buffer .= ' ' . "\n"; + } + return $buffer; + } + protected function inactiveBreadcrumb(AbstractNode $node, string $pathToRoot): string + { + return sprintf(' ' . "\n", $pathToRoot, $node->name()); + } + protected function pathToRoot(AbstractNode $node): string + { + $id = $node->id(); + $depth = substr_count($id, '/'); + if ($id !== 'index' && $node instanceof DirectoryNode) { + $depth++; + } + return str_repeat('../', $depth); + } + protected function coverageBar(float $percent): string + { + $level = $this->colorLevel($percent); + $templateName = $this->templatePath . ($this->hasBranchCoverage ? 'coverage_bar_branch.html' : 'coverage_bar.html'); + $template = new Template($templateName, '{{', '}}'); + $template->setVar(['level' => $level, 'percent' => sprintf('%.2F', $percent)]); + return $template->render(); + } + protected function colorLevel(float $percent): string + { + if ($percent <= $this->thresholds->lowUpperBound()) { + return 'danger'; + } + if ($percent > $this->thresholds->lowUpperBound() && $percent < $this->thresholds->highLowerBound()) { + return 'warning'; + } + return 'success'; + } + private function runtimeString(): string + { + $runtime = new Runtime(); + return sprintf('%s %s', $runtime->getVendorUrl(), $runtime->getName(), $runtime->getVersion()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html; + +use const ENT_XML1; +use function array_filter; +use function array_map; +use function ceil; +use function floor; +use function htmlspecialchars; +use function log10; +use function max; +use function sprintf; +use function sqrt; +use function usort; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Thresholds; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class BubbleChart +{ + private Thresholds $thresholds; + public function __construct(Thresholds $thresholds) + { + $this->thresholds = $thresholds; + } + /** + * @param list $items + */ + public function render(array $items): string + { + $items = array_filter($items, static fn(array $item): bool => $item['executableLines'] > 0); + if ($items === []) { + return ''; + } + $maxExecutableLines = max(array_map(static fn(array $f): int => $f['executableLines'], $items)); + $maxComplexity = max(1, max(array_map(static fn(array $f): int => $f['complexity'], $items))); + usort($items, static fn(array $a, array $b): int => $b['executableLines'] <=> $a['executableLines']); + $svgWidth = 800; + $svgHeight = 400; + $paddingLeft = 60; + $paddingRight = 20; + $paddingTop = 20; + $paddingBottom = 50; + $plotWidth = $svgWidth - $paddingLeft - $paddingRight; + $plotHeight = $svgHeight - $paddingTop - $paddingBottom; + $maxRadius = 20; + $minRadius = 4; + // Calculate Y-axis grid step + $yAxisMax = $maxComplexity * 1.1; + $rawStep = $yAxisMax / 5; + $magnitude = 10 ** floor($rawStep > 0 ? log10($rawStep) : 0); + $normalized = $rawStep / $magnitude; + if ($normalized <= 1) { + $gridStep = $magnitude; + } elseif ($normalized <= 2) { + $gridStep = 2 * $magnitude; + } elseif ($normalized <= 5) { + $gridStep = 5 * $magnitude; + } else { + $gridStep = 10 * $magnitude; + } + $gridStep = max(1, (int) $gridStep); + $yAxisMax = $gridStep * (int) ceil($yAxisMax / $gridStep); + if ($yAxisMax === 0) { + $yAxisMax = 10; + } + $svg = sprintf('' . "\n", $svgWidth, $svgHeight); + $svg .= <<<'CSS' + + +CSS; + // Vertical grid lines (x-axis: 0%, 20%, 40%, 60%, 80%, 100%) + for ($pct = 0; $pct <= 100; $pct += 20) { + $x = $paddingLeft + $pct / 100 * $plotWidth; + $svg .= sprintf(' ' . "\n", $x, $paddingTop, $x, $paddingTop + $plotHeight); + $svg .= sprintf(' %d%%' . "\n", $x, $paddingTop + $plotHeight + 18, $pct); + } + // Horizontal grid lines (y-axis) + for ($val = 0; $val <= $yAxisMax; $val += $gridStep) { + $y = $paddingTop + $plotHeight - $val / $yAxisMax * $plotHeight; + $svg .= sprintf(' ' . "\n", $paddingLeft, $y, $paddingLeft + $plotWidth, $y); + $svg .= sprintf(' %d' . "\n", $paddingLeft - 8, $y, $val); + } + // Axes + $svg .= sprintf(' ' . "\n", $paddingLeft, $paddingTop, $paddingLeft, $paddingTop + $plotHeight); + $svg .= sprintf(' ' . "\n", $paddingLeft, $paddingTop + $plotHeight, $paddingLeft + $plotWidth, $paddingTop + $plotHeight); + // Axis titles + $svg .= sprintf(' Line Coverage (%%)' . "\n", $paddingLeft + $plotWidth / 2, $svgHeight - 5); + $svg .= sprintf(' Cyclomatic Complexity' . "\n", $paddingTop + $plotHeight / 2, $paddingTop + $plotHeight / 2); + // Bubbles + foreach ($items as $item) { + $cx = $paddingLeft + $item['coverage'] / 100 * $plotWidth; + $cy = $paddingTop + $plotHeight - $item['complexity'] / $yAxisMax * $plotHeight; + $r = max($minRadius, sqrt($item['executableLines'] / $maxExecutableLines) * $maxRadius); + $colorClass = 'bubble-' . $this->colorLevel($item['coverage']); + $title = htmlspecialchars(sprintf('%s — Coverage: %.1f%% | Lines: %d | Complexity: %d', $item['name'], $item['coverage'], $item['executableLines'], $item['complexity']), ENT_XML1); + $svg .= sprintf(' %s' . "\n", htmlspecialchars($item['link'], ENT_XML1), $cx, $cy, $r, $colorClass, $title); + } + $svg .= ''; + return $svg; + } + private function colorLevel(float $percent): string + { + if ($percent <= $this->thresholds->lowUpperBound()) { + return 'danger'; + } + if ($percent < $this->thresholds->highLowerBound()) { + return 'warning'; + } + return 'success'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html; + +use function htmlspecialchars; +use function sprintf; +use function str_replace; +use function usort; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedClassType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedTraitType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\FileCouldNotBeWrittenException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\AbstractNode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\CrapIndex; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode; +use PHPUnitPHAR\SebastianBergmann\Template\Exception; +use PHPUnitPHAR\SebastianBergmann\Template\Template; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Dashboard extends Renderer +{ + public function render(DirectoryNode $node, string $file): void + { + $classes = $node->classesAndTraits(); + $templateName = $this->templatePath . ($this->hasBranchCoverage ? 'dashboard_branch.html' : 'dashboard.html'); + $template = new Template($templateName, '{{', '}}'); + $this->setCommonTemplateVariables($template, $node); + $baseLink = $node->id() . '/'; + $bubbleChart = new BubbleChart($this->thresholds); + $template->setVar(['class_bubble_chart' => $bubbleChart->render($this->classItems($classes, $baseLink)), 'class_crap_table' => $this->classCrapTable($classes, $baseLink), 'method_bubble_chart' => $bubbleChart->render($this->methodItems($classes, $baseLink)), 'method_crap_table' => $this->methodCrapTable($classes, $baseLink)]); + try { + $template->renderTo($file); + } catch (Exception $e) { + throw new FileCouldNotBeWrittenException($e->getMessage(), $e->getCode(), $e); + } + } + protected function activeBreadcrumb(AbstractNode $node): string + { + return sprintf(' ' . "\n" . ' ' . "\n", $node->name()); + } + /** + * @param array $classes + * + * @return list + */ + private function classItems(array $classes, string $baseLink): array + { + $items = []; + foreach ($classes as $className => $class) { + if ($class->executableLines === 0) { + continue; + } + $items[] = ['name' => $className, 'coverage' => $class->coverage, 'executableLines' => $class->executableLines, 'complexity' => $class->ccn, 'link' => str_replace($baseLink, '', $class->link)]; + } + return $items; + } + /** + * @param array $classes + * + * @return list + */ + private function methodItems(array $classes, string $baseLink): array + { + $items = []; + foreach ($classes as $className => $class) { + foreach ($class->methods as $methodName => $method) { + if ($method->executableLines === 0) { + continue; + } + $name = $methodName; + if ($className !== '*') { + $name = $className . '::' . $methodName; + } + $items[] = ['name' => $name, 'coverage' => $method->coverage, 'executableLines' => $method->executableLines, 'complexity' => $method->ccn, 'link' => str_replace($baseLink, '', $method->link)]; + } + } + return $items; + } + /** + * @param array $classes + */ + private function classCrapTable(array $classes, string $baseLink): string + { + $items = []; + foreach ($classes as $className => $class) { + $items[] = ['name' => $className, 'coverage' => $class->coverage, 'crap' => (new CrapIndex($class->ccn, $class->coverage))->asString(), 'link' => str_replace($baseLink, '', $class->link)]; + } + return $this->crapTable($items, 'Class'); + } + /** + * @param array $classes + */ + private function methodCrapTable(array $classes, string $baseLink): string + { + $items = []; + foreach ($classes as $className => $class) { + foreach ($class->methods as $methodName => $method) { + $name = $methodName; + if ($className !== '*') { + $name = $className . '::' . $methodName; + } + $items[] = ['name' => $name, 'coverage' => $method->coverage, 'crap' => (new CrapIndex($method->ccn, $method->coverage))->asString(), 'link' => str_replace($baseLink, '', $method->link)]; + } + } + return $this->crapTable($items, 'Method'); + } + /** + * @param list $items + */ + private function crapTable(array $items, string $entityLabel): string + { + usort($items, static fn(array $a, array $b): int => (float) $b['crap'] <=> (float) $a['crap']); + $html = '' . "\n"; + $html .= ' ' . "\n"; + $html .= ' ' . "\n"; + $html .= sprintf(' ' . "\n", $entityLabel); + $html .= ' ' . "\n"; + $html .= ' ' . "\n"; + $html .= ' ' . "\n"; + $html .= ' ' . "\n"; + $html .= ' ' . "\n"; + foreach ($items as $item) { + $html .= sprintf(' ' . "\n", htmlspecialchars($item['link']), htmlspecialchars($item['name']), $item['crap'], sprintf('%.1f', $item['coverage'])); + } + $html .= ' ' . "\n"; + $html .= '
%sCRAPCoverage
%s%s%s%%
'; + return $html; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html; + +use function count; +use function sprintf; +use function str_repeat; +use function usort; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\FileCouldNotBeWrittenException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\AbstractNode as Node; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File as FileNode; +use PHPUnitPHAR\SebastianBergmann\Template\Exception; +use PHPUnitPHAR\SebastianBergmann\Template\Template; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Directory extends Renderer +{ + public function render(DirectoryNode $node, string $file): void + { + $templateName = $this->templatePath . ($this->hasBranchCoverage ? 'directory_branch.html' : 'directory.html'); + $template = new Template($templateName, '{{', '}}'); + $this->setCommonTemplateVariables($template, $node); + $items = $this->renderItem($node, \true); + $directories = $node->directories(); + usort($directories, static fn(DirectoryNode $a, DirectoryNode $b) => $a->name() <=> $b->name()); + foreach ($directories as $item) { + $items .= $this->renderItem($item); + } + $files = $node->files(); + usort($files, static fn(FileNode $a, FileNode $b) => $a->name() <=> $b->name()); + foreach ($files as $item) { + $items .= $this->renderItem($item); + } + $template->setVar(['id' => $node->id(), 'items' => $items]); + try { + $template->renderTo($file); + } catch (Exception $e) { + throw new FileCouldNotBeWrittenException($e->getMessage(), $e->getCode(), $e); + } + } + private function renderItem(Node $node, bool $total = \false): string + { + $data = ['numClasses' => $node->numberOfClassesAndTraits(), 'numTestedClasses' => $node->numberOfTestedClassesAndTraits(), 'numMethods' => $node->numberOfFunctionsAndMethods(), 'numTestedMethods' => $node->numberOfTestedFunctionsAndMethods(), 'linesExecutedPercent' => $node->percentageOfExecutedLines()->asFloat(), 'linesExecutedPercentAsString' => $node->percentageOfExecutedLines()->asString(), 'numExecutedLines' => $node->numberOfExecutedLines(), 'numExecutableLines' => $node->numberOfExecutableLines(), 'branchesExecutedPercent' => $node->percentageOfExecutedBranches()->asFloat(), 'branchesExecutedPercentAsString' => $node->percentageOfExecutedBranches()->asString(), 'numExecutedBranches' => $node->numberOfExecutedBranches(), 'numExecutableBranches' => $node->numberOfExecutableBranches(), 'pathsExecutedPercent' => $node->percentageOfExecutedPaths()->asFloat(), 'pathsExecutedPercentAsString' => $node->percentageOfExecutedPaths()->asString(), 'numExecutedPaths' => $node->numberOfExecutedPaths(), 'numExecutablePaths' => $node->numberOfExecutablePaths(), 'testedMethodsPercent' => $node->percentageOfTestedFunctionsAndMethods()->asFloat(), 'testedMethodsPercentAsString' => $node->percentageOfTestedFunctionsAndMethods()->asString(), 'testedClassesPercent' => $node->percentageOfTestedClassesAndTraits()->asFloat(), 'testedClassesPercentAsString' => $node->percentageOfTestedClassesAndTraits()->asString(), 'numFilesWithoutBranchCoverageData' => $node->numberOfFilesWithoutBranchCoverageData()]; + if ($total) { + $data['name'] = 'Total'; + } else { + $up = str_repeat('../', count($node->pathAsArray()) - 2); + $data['icon'] = sprintf('', $up); + if ($node instanceof DirectoryNode) { + $data['name'] = sprintf('%s', $node->name(), $node->name()); + $data['icon'] = sprintf('', $up); + } elseif ($this->hasBranchCoverage) { + $data['name'] = sprintf('%s [line] [branch] [path]', $node->name(), $node->name(), $node->name(), $node->name()); + } else { + $data['name'] = sprintf('%s', $node->name(), $node->name()); + } + } + $templateName = $this->templatePath . ($this->hasBranchCoverage ? 'directory_item_branch.html' : 'directory_item.html'); + return $this->renderItemTemplate(new Template($templateName, '{{', '}}'), $data); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html; + +use const ENT_COMPAT; +use const ENT_HTML401; +use const ENT_SUBSTITUTE; +use function array_key_exists; +use function array_keys; +use function array_merge; +use function array_pop; +use function array_unique; +use function count; +use function explode; +use function htmlspecialchars; +use function ksort; +use function range; +use function sort; +use function sprintf; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedBranchCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedClassType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedFunctionCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedFunctionType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedMethodType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedPathCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedTraitType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\FileCouldNotBeWrittenException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File as FileNode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Thresholds; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Percentage; +use PHPUnitPHAR\SebastianBergmann\Template\Exception; +use PHPUnitPHAR\SebastianBergmann\Template\Template; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type TestType from \SebastianBergmann\CodeCoverage\CodeCoverage + */ +final class File extends Renderer +{ + private const int HTML_SPECIAL_CHARS_FLAGS = ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE; + private readonly SyntaxHighlighter $syntaxHighlighter; + public function __construct(string $templatePath, string $generator, string $date, Thresholds $thresholds, bool $hasBranchCoverage) + { + parent::__construct($templatePath, $generator, $date, $thresholds, $hasBranchCoverage); + $this->syntaxHighlighter = new SyntaxHighlighter(); + } + public function render(FileNode $node, string $file): void + { + $templateName = $this->templatePath . ($this->hasBranchCoverage ? 'file_branch.html' : 'file.html'); + $template = new Template($templateName, '{{', '}}'); + $this->setCommonTemplateVariables($template, $node); + $template->setVar(['items' => $this->renderItems($node), 'lines' => $this->renderSourceWithLineCoverage($node), 'legend' => '

Covered by small (and larger) testsCovered by medium (and large) testsCovered by large tests (and tests of unknown size)Not coveredNot coverable

', 'structure' => '']); + try { + $template->renderTo($file . '.html'); + } catch (Exception $e) { + throw new FileCouldNotBeWrittenException($e->getMessage(), $e->getCode(), $e); + } + if ($this->hasBranchCoverage) { + $template->setVar(['items' => $this->renderItems($node), 'lines' => $this->renderSourceWithBranchCoverage($node), 'legend' => '

Fully coveredPartially coveredNot covered

', 'structure' => $this->renderBranchStructure($node)]); + try { + $template->renderTo($file . '_branch.html'); + } catch (Exception $e) { + throw new FileCouldNotBeWrittenException($e->getMessage(), $e->getCode(), $e); + } + $template->setVar(['items' => $this->renderItems($node), 'lines' => $this->renderSourceWithPathCoverage($node), 'legend' => '

Fully coveredPartially coveredNot covered

', 'structure' => $this->renderPathStructure($node)]); + try { + $template->renderTo($file . '_path.html'); + } catch (Exception $e) { + throw new FileCouldNotBeWrittenException($e->getMessage(), $e->getCode(), $e); + } + } + } + private function renderItems(FileNode $node): string + { + $templateName = $this->templatePath . ($this->hasBranchCoverage ? 'file_item_branch.html' : 'file_item.html'); + $template = new Template($templateName, '{{', '}}'); + $methodTemplateName = $this->templatePath . ($this->hasBranchCoverage ? 'method_item_branch.html' : 'method_item.html'); + $methodItemTemplate = new Template($methodTemplateName, '{{', '}}'); + $items = $this->renderItemTemplate($template, ['name' => 'Total', 'numClasses' => $node->numberOfClassesAndTraits(), 'numTestedClasses' => $node->numberOfTestedClassesAndTraits(), 'numMethods' => $node->numberOfFunctionsAndMethods(), 'numTestedMethods' => $node->numberOfTestedFunctionsAndMethods(), 'linesExecutedPercent' => $node->percentageOfExecutedLines()->asFloat(), 'linesExecutedPercentAsString' => $node->percentageOfExecutedLines()->asString(), 'numExecutedLines' => $node->numberOfExecutedLines(), 'numExecutableLines' => $node->numberOfExecutableLines(), 'branchesExecutedPercent' => $node->percentageOfExecutedBranches()->asFloat(), 'branchesExecutedPercentAsString' => $node->percentageOfExecutedBranches()->asString(), 'numExecutedBranches' => $node->numberOfExecutedBranches(), 'numExecutableBranches' => $node->numberOfExecutableBranches(), 'pathsExecutedPercent' => $node->percentageOfExecutedPaths()->asFloat(), 'pathsExecutedPercentAsString' => $node->percentageOfExecutedPaths()->asString(), 'numExecutedPaths' => $node->numberOfExecutedPaths(), 'numExecutablePaths' => $node->numberOfExecutablePaths(), 'testedMethodsPercent' => $node->percentageOfTestedFunctionsAndMethods()->asFloat(), 'testedMethodsPercentAsString' => $node->percentageOfTestedFunctionsAndMethods()->asString(), 'testedClassesPercent' => $node->percentageOfTestedClassesAndTraits()->asFloat(), 'testedClassesPercentAsString' => $node->percentageOfTestedClassesAndTraits()->asString(), 'crap' => 'CRAP']); + $items .= $this->renderFunctionItems($node->functions(), $methodItemTemplate); + $items .= $this->renderTraitOrClassItems($node->traits(), $template, $methodItemTemplate); + $items .= $this->renderTraitOrClassItems($node->classes(), $template, $methodItemTemplate); + return $items; + } + /** + * @param array $items + */ + private function renderTraitOrClassItems(array $items, Template $template, Template $methodItemTemplate): string + { + $buffer = ''; + if ($items === []) { + return $buffer; + } + foreach ($items as $name => $item) { + $numMethods = 0; + $numTestedMethods = 0; + foreach ($item->methods as $method) { + if ($method->executableLines > 0) { + $numMethods++; + if ($method->executedLines === $method->executableLines) { + $numTestedMethods++; + } + } + } + if ($item->executableLines > 0) { + $numClasses = 1; + $numTestedClasses = $numTestedMethods === $numMethods ? 1 : 0; + $linesExecutedPercentAsString = Percentage::fromFractionAndTotal($item->executedLines, $item->executableLines)->asString(); + $branchesExecutedPercentAsString = Percentage::fromFractionAndTotal($item->executedBranches, $item->executableBranches)->asString(); + $pathsExecutedPercentAsString = Percentage::fromFractionAndTotal($item->executedPaths, $item->executablePaths)->asString(); + } else { + $numClasses = 0; + $numTestedClasses = 0; + $linesExecutedPercentAsString = 'n/a'; + $branchesExecutedPercentAsString = 'n/a'; + $pathsExecutedPercentAsString = 'n/a'; + } + $testedMethodsPercentage = Percentage::fromFractionAndTotal($numTestedMethods, $numMethods); + $testedClassesPercentage = Percentage::fromFractionAndTotal($numTestedMethods === $numMethods ? 1 : 0, 1); + $buffer .= $this->renderItemTemplate($template, ['name' => $this->abbreviateClassName($name), 'numClasses' => $numClasses, 'numTestedClasses' => $numTestedClasses, 'numMethods' => $numMethods, 'numTestedMethods' => $numTestedMethods, 'linesExecutedPercent' => Percentage::fromFractionAndTotal($item->executedLines, $item->executableLines)->asFloat(), 'linesExecutedPercentAsString' => $linesExecutedPercentAsString, 'numExecutedLines' => $item->executedLines, 'numExecutableLines' => $item->executableLines, 'branchesExecutedPercent' => Percentage::fromFractionAndTotal($item->executedBranches, $item->executableBranches)->asFloat(), 'branchesExecutedPercentAsString' => $branchesExecutedPercentAsString, 'numExecutedBranches' => $item->executedBranches, 'numExecutableBranches' => $item->executableBranches, 'pathsExecutedPercent' => Percentage::fromFractionAndTotal($item->executedPaths, $item->executablePaths)->asFloat(), 'pathsExecutedPercentAsString' => $pathsExecutedPercentAsString, 'numExecutedPaths' => $item->executedPaths, 'numExecutablePaths' => $item->executablePaths, 'testedMethodsPercent' => $testedMethodsPercentage->asFloat(), 'testedMethodsPercentAsString' => $testedMethodsPercentage->asString(), 'testedClassesPercent' => $testedClassesPercentage->asFloat(), 'testedClassesPercentAsString' => $testedClassesPercentage->asString(), 'crap' => $item->crap]); + foreach ($item->methods as $method) { + $buffer .= $this->renderFunctionOrMethodItem($methodItemTemplate, $method, ' '); + } + } + return $buffer; + } + /** + * @param array $functions + */ + private function renderFunctionItems(array $functions, Template $template): string + { + if ($functions === []) { + return ''; + } + $buffer = ''; + foreach ($functions as $function) { + $buffer .= $this->renderFunctionOrMethodItem($template, $function); + } + return $buffer; + } + private function renderFunctionOrMethodItem(Template $template, ProcessedFunctionType|ProcessedMethodType $item, string $indent = ''): string + { + $numMethods = 0; + $numTestedMethods = 0; + if ($item->executableLines > 0) { + $numMethods = 1; + if ($item->executedLines === $item->executableLines) { + $numTestedMethods = 1; + } + } + $executedLinesPercentage = Percentage::fromFractionAndTotal($item->executedLines, $item->executableLines); + $executedBranchesPercentage = Percentage::fromFractionAndTotal($item->executedBranches, $item->executableBranches); + $executedPathsPercentage = Percentage::fromFractionAndTotal($item->executedPaths, $item->executablePaths); + $testedMethodsPercentage = Percentage::fromFractionAndTotal($numTestedMethods, 1); + return $this->renderItemTemplate($template, ['name' => sprintf('%s%s', $indent, $item->startLine, htmlspecialchars($item->signature, self::HTML_SPECIAL_CHARS_FLAGS), $item instanceof ProcessedFunctionType ? $item->functionName : $item->methodName), 'numMethods' => $numMethods, 'numTestedMethods' => $numTestedMethods, 'linesExecutedPercent' => $executedLinesPercentage->asFloat(), 'linesExecutedPercentAsString' => $executedLinesPercentage->asString(), 'numExecutedLines' => $item->executedLines, 'numExecutableLines' => $item->executableLines, 'branchesExecutedPercent' => $executedBranchesPercentage->asFloat(), 'branchesExecutedPercentAsString' => $executedBranchesPercentage->asString(), 'numExecutedBranches' => $item->executedBranches, 'numExecutableBranches' => $item->executableBranches, 'pathsExecutedPercent' => $executedPathsPercentage->asFloat(), 'pathsExecutedPercentAsString' => $executedPathsPercentage->asString(), 'numExecutedPaths' => $item->executedPaths, 'numExecutablePaths' => $item->executablePaths, 'testedMethodsPercent' => $testedMethodsPercentage->asFloat(), 'testedMethodsPercentAsString' => $testedMethodsPercentage->asString(), 'crap' => $item->crap]); + } + private function renderSourceWithLineCoverage(FileNode $node): string + { + $linesTemplate = new Template($this->templatePath . 'lines.html.dist', '{{', '}}'); + $singleLineTemplate = new Template($this->templatePath . 'line.html.dist', '{{', '}}'); + $coverageData = $node->lineCoverageData(); + $testData = $node->testData(); + $codeLines = $this->syntaxHighlighter->highlight($node->pathAsString()); + $lines = ''; + $i = 1; + foreach ($codeLines as $line) { + $trClass = ''; + $popoverContent = ''; + $popoverTitle = ''; + if (array_key_exists($i, $coverageData)) { + $numTests = $coverageData[$i] !== null ? count($coverageData[$i]) : 0; + if ($coverageData[$i] === null) { + $trClass = 'warning'; + } elseif ($numTests === 0) { + $trClass = 'danger'; + } else { + if ($numTests > 1) { + $popoverTitle = $numTests . ' tests cover line ' . $i; + } else { + $popoverTitle = '1 test covers line ' . $i; + } + $lineCss = 'covered-by-large-tests'; + $popoverContent = '
    '; + foreach ($coverageData[$i] as $test) { + if ($lineCss === 'covered-by-large-tests' && $testData[$test]['size'] === 'medium') { + $lineCss = 'covered-by-medium-tests'; + } elseif ($testData[$test]['size'] === 'small') { + $lineCss = 'covered-by-small-tests'; + } + $popoverContent .= $this->createPopoverContentForTest($test, $testData[$test]); + } + $popoverContent .= '
'; + $trClass = $lineCss . ' popin'; + } + } + $popover = ''; + if ($popoverTitle !== '') { + $popover = sprintf(' data-bs-title="%s" data-bs-content="%s" data-bs-placement="top" data-bs-html="true"', $popoverTitle, htmlspecialchars($popoverContent, self::HTML_SPECIAL_CHARS_FLAGS)); + } + $lines .= $this->renderLine($singleLineTemplate, $i, $line, $trClass, $popover); + $i++; + } + $linesTemplate->setVar(['lines' => $lines]); + return $linesTemplate->render(); + } + private function renderSourceWithBranchCoverage(FileNode $node): string + { + $linesTemplate = new Template($this->templatePath . 'lines.html.dist', '{{', '}}'); + $singleLineTemplate = new Template($this->templatePath . 'line.html.dist', '{{', '}}'); + $functionCoverageData = $node->functionCoverageData(); + $testData = $node->testData(); + $codeLines = $this->syntaxHighlighter->highlight($node->pathAsString()); + $lineData = []; + foreach (array_keys($codeLines) as $line) { + $lineData[$line + 1] = ['includedInBranches' => 0, 'includedInHitBranches' => 0, 'tests' => []]; + } + /** @var ProcessedFunctionCoverageData $method */ + foreach ($functionCoverageData as $method) { + /** @var ProcessedBranchCoverageData $branch */ + foreach ($method->branches as $branch) { + foreach (range($branch->line_start, $branch->line_end) as $line) { + if (!isset($lineData[$line])) { + // blank line at end of file is sometimes included here + continue; + } + $lineData[$line]['includedInBranches']++; + if ($branch->hit !== []) { + $lineData[$line]['includedInHitBranches']++; + $lineData[$line]['tests'] = array_unique(array_merge($lineData[$line]['tests'], $branch->hit)); + } + } + } + } + $lines = ''; + $i = 1; + /** @var string $line */ + foreach ($codeLines as $line) { + $trClass = ''; + $popover = ''; + if ($lineData[$i]['includedInBranches'] > 0) { + $lineCss = 'success'; + if ($lineData[$i]['includedInHitBranches'] === 0) { + $lineCss = 'danger'; + } elseif ($lineData[$i]['includedInHitBranches'] !== $lineData[$i]['includedInBranches']) { + $lineCss = 'warning'; + } + $popoverContent = '
    '; + if (count($lineData[$i]['tests']) === 1) { + $popoverTitle = '1 test covers line ' . $i; + } else { + $popoverTitle = count($lineData[$i]['tests']) . ' tests cover line ' . $i; + } + $popoverTitle .= '. These are covering ' . $lineData[$i]['includedInHitBranches'] . ' out of the ' . $lineData[$i]['includedInBranches'] . ' code branches.'; + foreach ($lineData[$i]['tests'] as $test) { + $popoverContent .= $this->createPopoverContentForTest($test, $testData[$test]); + } + $popoverContent .= '
'; + $trClass = $lineCss . ' popin'; + $popover = sprintf(' data-bs-title="%s" data-bs-content="%s" data-bs-placement="top" data-bs-html="true"', $popoverTitle, htmlspecialchars($popoverContent, self::HTML_SPECIAL_CHARS_FLAGS)); + } + $lines .= $this->renderLine($singleLineTemplate, $i, $line, $trClass, $popover); + $i++; + } + $linesTemplate->setVar(['lines' => $lines]); + return $linesTemplate->render(); + } + private function renderSourceWithPathCoverage(FileNode $node): string + { + $linesTemplate = new Template($this->templatePath . 'lines.html.dist', '{{', '}}'); + $singleLineTemplate = new Template($this->templatePath . 'line.html.dist', '{{', '}}'); + $functionCoverageData = $node->functionCoverageData(); + $testData = $node->testData(); + $codeLines = $this->syntaxHighlighter->highlight($node->pathAsString()); + $lineData = []; + foreach (array_keys($codeLines) as $line) { + $lineData[$line + 1] = ['includedInPaths' => [], 'includedInHitPaths' => [], 'tests' => []]; + } + /** @var ProcessedFunctionCoverageData $method */ + foreach ($functionCoverageData as $method) { + /** @var ProcessedPathCoverageData $path */ + foreach ($method->paths as $pathId => $path) { + foreach ($path->path as $branchTaken) { + foreach (range($method->branches[$branchTaken]->line_start, $method->branches[$branchTaken]->line_end) as $line) { + if (!isset($lineData[$line])) { + continue; + } + $lineData[$line]['includedInPaths'][] = $pathId; + if ($path->hit !== []) { + $lineData[$line]['includedInHitPaths'][] = $pathId; + $lineData[$line]['tests'] = array_unique(array_merge($lineData[$line]['tests'], $path->hit)); + } + } + } + } + } + $lines = ''; + $i = 1; + /** @var string $line */ + foreach ($codeLines as $line) { + $trClass = ''; + $popover = ''; + $includedInPathsCount = count(array_unique($lineData[$i]['includedInPaths'])); + $includedInHitPathsCount = count(array_unique($lineData[$i]['includedInHitPaths'])); + if ($includedInPathsCount > 0) { + $lineCss = 'success'; + if ($includedInHitPathsCount === 0) { + $lineCss = 'danger'; + } elseif ($includedInHitPathsCount !== $includedInPathsCount) { + $lineCss = 'warning'; + } + $popoverContent = '
    '; + if (count($lineData[$i]['tests']) === 1) { + $popoverTitle = '1 test covers line ' . $i; + } else { + $popoverTitle = count($lineData[$i]['tests']) . ' tests cover line ' . $i; + } + $popoverTitle .= '. These are covering ' . $includedInHitPathsCount . ' out of the ' . $includedInPathsCount . ' code paths.'; + foreach ($lineData[$i]['tests'] as $test) { + $popoverContent .= $this->createPopoverContentForTest($test, $testData[$test]); + } + $popoverContent .= '
'; + $trClass = $lineCss . ' popin'; + $popover = sprintf(' data-bs-title="%s" data-bs-content="%s" data-bs-placement="top" data-bs-html="true"', $popoverTitle, htmlspecialchars($popoverContent, self::HTML_SPECIAL_CHARS_FLAGS)); + } + $lines .= $this->renderLine($singleLineTemplate, $i, $line, $trClass, $popover); + $i++; + } + $linesTemplate->setVar(['lines' => $lines]); + return $linesTemplate->render(); + } + private function renderBranchStructure(FileNode $node): string + { + $branchesTemplate = new Template($this->templatePath . 'branches.html.dist', '{{', '}}'); + $coverageData = $node->functionCoverageData(); + $testData = $node->testData(); + $codeLines = $this->syntaxHighlighter->highlight($node->pathAsString()); + $branches = ''; + ksort($coverageData); + /** @var ProcessedFunctionCoverageData $methodData */ + foreach ($coverageData as $methodName => $methodData) { + $branchStructure = ''; + /** @var ProcessedBranchCoverageData $branch */ + foreach ($methodData->branches as $branch) { + $branchStructure .= $this->renderBranchLines($branch, $codeLines, $testData); + } + if ($branchStructure !== '') { + // don't show empty branches + $branches .= '
' . $this->abbreviateMethodName($methodName) . '
' . "\n"; + $branches .= $branchStructure; + } + } + $branchesTemplate->setVar(['branches' => $branches]); + return $branchesTemplate->render(); + } + /** + * @param list $codeLines + * @param array $testData + */ + private function renderBranchLines(ProcessedBranchCoverageData $branch, array $codeLines, array $testData): string + { + $linesTemplate = new Template($this->templatePath . 'lines.html.dist', '{{', '}}'); + $singleLineTemplate = new Template($this->templatePath . 'line.html.dist', '{{', '}}'); + $lines = ''; + $branchLines = range($branch->line_start, $branch->line_end); + sort($branchLines); + // sometimes end_line < start_line + /** @var int $line */ + foreach ($branchLines as $line) { + if (!isset($codeLines[$line])) { + // blank line at end of file is sometimes included here + continue; + } + $popoverContent = ''; + $popoverTitle = ''; + $numTests = count($branch->hit); + if ($numTests === 0) { + $trClass = 'danger'; + } else { + $lineCss = 'covered-by-large-tests'; + $popoverContent = '
    '; + if ($numTests > 1) { + $popoverTitle = $numTests . ' tests cover this branch'; + } else { + $popoverTitle = '1 test covers this branch'; + } + foreach ($branch->hit as $test) { + if ($lineCss === 'covered-by-large-tests' && $testData[$test]['size'] === 'medium') { + $lineCss = 'covered-by-medium-tests'; + } elseif ($testData[$test]['size'] === 'small') { + $lineCss = 'covered-by-small-tests'; + } + $popoverContent .= $this->createPopoverContentForTest($test, $testData[$test]); + } + $trClass = $lineCss . ' popin'; + } + $popover = ''; + if ($popoverTitle !== '') { + $popover = sprintf(' data-bs-title="%s" data-bs-content="%s" data-bs-placement="top" data-bs-html="true"', $popoverTitle, htmlspecialchars($popoverContent, self::HTML_SPECIAL_CHARS_FLAGS)); + } + $lines .= $this->renderLine($singleLineTemplate, $line, $codeLines[$line - 1], $trClass, $popover); + } + if ($lines === '') { + return ''; + } + $linesTemplate->setVar(['lines' => $lines]); + return $linesTemplate->render(); + } + private function renderPathStructure(FileNode $node): string + { + $pathsTemplate = new Template($this->templatePath . 'paths.html.dist', '{{', '}}'); + $coverageData = $node->functionCoverageData(); + $testData = $node->testData(); + $codeLines = $this->syntaxHighlighter->highlight($node->pathAsString()); + $paths = ''; + ksort($coverageData); + /** @var ProcessedFunctionCoverageData $methodData */ + foreach ($coverageData as $methodName => $methodData) { + $pathStructure = ''; + if (count($methodData->paths) > 100) { + $pathStructure .= '

    ' . count($methodData->paths) . ' is too many paths to sensibly render, consider refactoring your code to bring this number down.

    '; + continue; + } + foreach ($methodData->paths as $path) { + $pathStructure .= $this->renderPathLines($path, $methodData->branches, $codeLines, $testData); + } + if ($pathStructure !== '') { + $paths .= '
    ' . $this->abbreviateMethodName($methodName) . '
    ' . "\n"; + $paths .= $pathStructure; + } + } + $pathsTemplate->setVar(['paths' => $paths]); + return $pathsTemplate->render(); + } + /** + * @param array $branches + * @param list $codeLines + * @param array $testData + */ + private function renderPathLines(ProcessedPathCoverageData $path, array $branches, array $codeLines, array $testData): string + { + $linesTemplate = new Template($this->templatePath . 'lines.html.dist', '{{', '}}'); + $singleLineTemplate = new Template($this->templatePath . 'line.html.dist', '{{', '}}'); + $lines = ''; + $first = \true; + foreach ($path->path as $branchId) { + if ($first) { + $first = \false; + } else { + $lines .= '  ' . "\n"; + } + $branchLines = range($branches[$branchId]->line_start, $branches[$branchId]->line_end); + sort($branchLines); + // sometimes end_line < start_line + /** @var int $line */ + foreach ($branchLines as $line) { + if (!isset($codeLines[$line])) { + // blank line at end of file is sometimes included here + continue; + } + $popoverContent = ''; + $popoverTitle = ''; + $numTests = count($path->hit); + if ($numTests === 0) { + $trClass = 'danger'; + } else { + $lineCss = 'covered-by-large-tests'; + $popoverContent = '
      '; + if ($numTests > 1) { + $popoverTitle = $numTests . ' tests cover this path'; + } else { + $popoverTitle = '1 test covers this path'; + } + foreach ($path->hit as $test) { + if ($lineCss === 'covered-by-large-tests' && $testData[$test]['size'] === 'medium') { + $lineCss = 'covered-by-medium-tests'; + } elseif ($testData[$test]['size'] === 'small') { + $lineCss = 'covered-by-small-tests'; + } + $popoverContent .= $this->createPopoverContentForTest($test, $testData[$test]); + } + $trClass = $lineCss . ' popin'; + } + $popover = ''; + if ($popoverTitle !== '') { + $popover = sprintf(' data-bs-title="%s" data-bs-content="%s" data-bs-placement="top" data-bs-html="true"', $popoverTitle, htmlspecialchars($popoverContent, self::HTML_SPECIAL_CHARS_FLAGS)); + } + $lines .= $this->renderLine($singleLineTemplate, $line, $codeLines[$line - 1], $trClass, $popover); + } + } + if ($lines === '') { + return ''; + } + $linesTemplate->setVar(['lines' => $lines]); + return $linesTemplate->render(); + } + private function renderLine(Template $template, int $lineNumber, string $lineContent, string $class, string $popover): string + { + $template->setVar(['lineNumber' => (string) $lineNumber, 'lineContent' => $lineContent, 'class' => $class, 'popover' => $popover]); + return $template->render(); + } + private function abbreviateClassName(string $className): string + { + $tmp = explode('\\', $className); + if (count($tmp) > 1) { + $className = sprintf('%s', $className, array_pop($tmp)); + } + return $className; + } + private function abbreviateMethodName(string $methodName): string + { + $parts = explode('->', $methodName); + if (count($parts) === 2) { + return $this->abbreviateClassName($parts[0]) . '->' . $parts[1]; + } + return $methodName; + } + /** + * @param TestType $testData + */ + private function createPopoverContentForTest(string $test, array $testData): string + { + $testCSS = ''; + switch ($testData['status']) { + case 'success': + $testCSS = match ($testData['size']) { + 'small' => ' class="covered-by-small-tests"', + 'medium' => ' class="covered-by-medium-tests"', + // no break + default => ' class="covered-by-large-tests"', + }; + break; + case 'failure': + $testCSS = ' class="danger"'; + break; + } + return sprintf('%s', $testCSS, htmlspecialchars($test, self::HTML_SPECIAL_CHARS_FLAGS)); + } +} +
      +

      Branches

      +

      + Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not + necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once. + Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement + always has an else as part of its logical flow even if you didn't write one. +

      +{{branches}} +
      +
      + {{percent}}% covered ({{level}}) +
      +
      +
      +
      + {{percent}}% covered ({{level}}) +
      +
      +@charset "UTF-8";/*! + * Bootstrap v5.3.6 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-color:#212529;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#6ea8fe;--bs-secondary-text-emphasis:#a7acb1;--bs-success-text-emphasis:#75b798;--bs-info-text-emphasis:#6edff6;--bs-warning-text-emphasis:#ffda6a;--bs-danger-text-emphasis:#ea868f;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#161719;--bs-success-bg-subtle:#051b11;--bs-info-bg-subtle:#032830;--bs-warning-bg-subtle:#332701;--bs-danger-bg-subtle:#2c0b0e;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#084298;--bs-secondary-border-subtle:#41464b;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#087990;--bs-warning-border-subtle:#997404;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherit;--bs-link-color:#6ea8fe;--bs-link-hover-color:#8bb9fe;--bs-link-color-rgb:110,168,254;--bs-link-hover-color-rgb:139,185,254;--bs-code-color:#e685b5;--bs-highlight-color:#dee2e6;--bs-highlight-bg:#664d03;--bs-border-color:#495057;--bs-border-color-translucent:rgba(255, 255, 255, 0.15);--bs-form-valid-color:#75b798;--bs-form-valid-border-color:#75b798;--bs-form-invalid-color:#ea868f;--bs-form-invalid-border-color:#ea868f}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-decoration:underline}a:hover{--bs-link-color-rgb:var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;line-height:inherit;font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-weight:300;line-height:1.2;font-size:calc(1.625rem + 4.5vw)}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-weight:300;line-height:1.2;font-size:calc(1.575rem + 3.9vw)}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-weight:300;line-height:1.2;font-size:calc(1.525rem + 3.3vw)}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-weight:300;line-height:1.2;font-size:calc(1.475rem + 2.7vw)}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-weight:300;line-height:1.2;font-size:calc(1.425rem + 2.1vw)}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-weight:300;line-height:1.2;font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#a6b5cc;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:#e2e3e5;--bs-table-border-color:#b5b6b7;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#d1e7dd;--bs-table-border-color:#a7b9b1;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#cff4fc;--bs-table-border-color:#a6c3ca;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fff3cd;--bs-table-border-color:#ccc2a4;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f8d7da;--bs-table-border-color:#c6acae;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#f8f9fa;--bs-table-border-color:#c6c7c8;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#212529;--bs-table-border-color:#4d5154;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg:var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;max-width:100%;height:100%;padding:1rem .75rem;overflow:hidden;color:rgba(var(--bs-body-color-rgb),.65);text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem;padding-left:.75rem}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>textarea:focus~label::after,.form-floating>textarea:not(:placeholder-shown)~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>textarea:disabled~label::after{background-color:var(--bs-secondary-bg)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#6c757d}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(-1 * var(--bs-border-width));border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:400;--bs-btn-line-height:1.5;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0b5ed7;--bs-btn-hover-border-color:#0a58ca;--bs-btn-focus-shadow-rgb:49,132,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0a58ca;--bs-btn-active-border-color:#0a53be;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#0d6efd;--bs-btn-disabled-border-color:#0d6efd}.btn-secondary{--bs-btn-color:#fff;--bs-btn-bg:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5c636a;--bs-btn-hover-border-color:#565e64;--bs-btn-focus-shadow-rgb:130,138,145;--bs-btn-active-color:#fff;--bs-btn-active-bg:#565e64;--bs-btn-active-border-color:#51585e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6c757d;--bs-btn-disabled-border-color:#6c757d}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#157347;--bs-btn-hover-border-color:#146c43;--bs-btn-focus-shadow-rgb:60,153,110;--bs-btn-active-color:#fff;--bs-btn-active-bg:#146c43;--bs-btn-active-border-color:#13653f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#198754;--bs-btn-disabled-border-color:#198754}.btn-info{--bs-btn-color:#000;--bs-btn-bg:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#31d2f2;--bs-btn-hover-border-color:#25cff2;--bs-btn-focus-shadow-rgb:11,172,204;--bs-btn-active-color:#000;--bs-btn-active-bg:#3dd5f3;--bs-btn-active-border-color:#25cff2;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#0dcaf0;--bs-btn-disabled-border-color:#0dcaf0}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffca2c;--bs-btn-hover-border-color:#ffc720;--bs-btn-focus-shadow-rgb:217,164,6;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffcd39;--bs-btn-active-border-color:#ffc720;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#ffc107;--bs-btn-disabled-border-color:#ffc107}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#bb2d3b;--bs-btn-hover-border-color:#b02a37;--bs-btn-focus-shadow-rgb:225,83,97;--bs-btn-active-color:#fff;--bs-btn-active-bg:#b02a37;--bs-btn-active-border-color:#a52834;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#dc3545;--bs-btn-disabled-border-color:#dc3545}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d3d4d5;--bs-btn-hover-border-color:#c6c7c8;--bs-btn-focus-shadow-rgb:211,212,213;--bs-btn-active-color:#000;--bs-btn-active-bg:#c6c7c8;--bs-btn-active-border-color:#babbbc;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f8f9fa;--bs-btn-disabled-border-color:#f8f9fa}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#424649;--bs-btn-hover-border-color:#373b3e;--bs-btn-focus-shadow-rgb:66,70,73;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4d5154;--bs-btn-active-border-color:#373b3e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#212529;--bs-btn-disabled-border-color:#212529}.btn-outline-primary{--bs-btn-color:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0d6efd;--bs-btn-hover-border-color:#0d6efd;--bs-btn-focus-shadow-rgb:13,110,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0d6efd;--bs-btn-active-border-color:#0d6efd;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0d6efd;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0d6efd;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6c757d;--bs-btn-hover-border-color:#6c757d;--bs-btn-focus-shadow-rgb:108,117,125;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6c757d;--bs-btn-active-border-color:#6c757d;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6c757d;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#198754;--bs-btn-hover-border-color:#198754;--bs-btn-focus-shadow-rgb:25,135,84;--bs-btn-active-color:#fff;--bs-btn-active-bg:#198754;--bs-btn-active-border-color:#198754;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#198754;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#198754;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#0dcaf0;--bs-btn-hover-border-color:#0dcaf0;--bs-btn-focus-shadow-rgb:13,202,240;--bs-btn-active-color:#000;--bs-btn-active-bg:#0dcaf0;--bs-btn-active-border-color:#0dcaf0;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0dcaf0;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0dcaf0;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffc107;--bs-btn-hover-border-color:#ffc107;--bs-btn-focus-shadow-rgb:255,193,7;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffc107;--bs-btn-active-border-color:#ffc107;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#ffc107;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffc107;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#dc3545;--bs-btn-hover-border-color:#dc3545;--bs-btn-focus-shadow-rgb:220,53,69;--bs-btn-active-color:#fff;--bs-btn-active-bg:#dc3545;--bs-btn-active-border-color:#dc3545;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#dc3545;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#dc3545;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f8f9fa;--bs-btn-hover-border-color:#f8f9fa;--bs-btn-focus-shadow-rgb:248,249,250;--bs-btn-active-color:#000;--bs-btn-active-bg:#f8f9fa;--bs-btn-active-border-color:#f8f9fa;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f8f9fa;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f8f9fa;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#212529;--bs-btn-hover-border-color:#212529;--bs-btn-focus-shadow-rgb:33,37,41;--bs-btn-active-color:#fff;--bs-btn-active-bg:#212529;--bs-btn-active-border-color:#212529;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#212529;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#212529;--bs-gradient:none}.btn-link{--bs-btn-font-weight:400;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:49,132,253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.25rem;--bs-btn-padding-x:0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#6c757d;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius,0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#dee2e6;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#dee2e6;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(-1 * var(--bs-border-width))}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(-1 * var(--bs-border-width))}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:nth-child(n+3),.btn-group-vertical>:not(.btn-check)+.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-grow:1;flex-basis:0;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:0.5rem;--bs-navbar-color:rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color:rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-grow:1;flex-basis:100%;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child)>.card-header,.card-group>.card:not(:last-child)>.card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child)>.card-footer,.card-group>.card:not(:last-child)>.card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child)>.card-header,.card-group>.card:not(:first-child)>.card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child)>.card-footer,.card-group>.card:not(:first-child)>.card-img-bottom{border-bottom-left-radius:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}.accordion-flush>.accordion-item>.accordion-collapse,.accordion-flush>.accordion-item>.accordion-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:var(--bs-border-color);--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:var(--bs-border-color);--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#0d6efd;--bs-pagination-active-border-color:#0d6efd;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(-1 * var(--bs-border-width))}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:700;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:var(--bs-progress-height)}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#0d6efd;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:not(.active):focus,.list-group-item-action:not(.active):hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:not(.active):active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;filter:var(--bs-btn-close-filter);border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{--bs-btn-close-filter:invert(1) grayscale(100%) brightness(200%)}:root,[data-bs-theme=light]{--bs-btn-close-filter: }[data-bs-theme=dark]{--bs-btn-close-filter:invert(1) grayscale(100%) brightness(200%)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color:var(--bs-body-color);--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transform:translate(0,-50px);transition:transform .3s ease-out}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin-top:calc(-.5 * var(--bs-modal-header-padding-y));margin-right:calc(-.5 * var(--bs-modal-header-padding-x));margin-bottom:calc(-.5 * var(--bs-modal-header-padding-y));margin-left:auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:inherit;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;filter:var(--bs-carousel-control-icon-filter);border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:var(--bs-carousel-indicator-active-bg);background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:var(--bs-carousel-caption-color);text-align:center}.carousel-dark{--bs-carousel-indicator-active-bg:#000;--bs-carousel-caption-color:#000;--bs-carousel-control-icon-filter:invert(1) grayscale(100)}:root,[data-bs-theme=light]{--bs-carousel-indicator-active-bg:#fff;--bs-carousel-caption-color:#fff;--bs-carousel-control-icon-filter: }[data-bs-theme=dark]{--bs-carousel-indicator-active-bg:#000;--bs-carousel-caption-color:#000;--bs-carousel-control-icon-filter:invert(1) grayscale(100)}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-right:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y));margin-left:auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.visually-hidden *,.visually-hidden-focusable:not(:focus):not(:focus-within) *{overflow:hidden!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */.octicon { + display: inline-block; + vertical-align: text-top; + fill: currentColor; +} + +:root { + /* Implementing an auto-selection of dark/light theme via: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark */ + color-scheme: light dark; + + /* PHPUnit light/dark colors */ + --phpunit-breadcrumbs: light-dark({{breadcrumbs}}, {{breadcrumbs-dark}}); + --phpunit-success-bar: light-dark({{success-bar}}, {{success-bar-dark}}); + --phpunit-success-high: light-dark({{success-high}}, {{success-high-dark}}); + --phpunit-success-medium: light-dark({{success-medium}}, {{success-medium-dark}}); + --phpunit-success-low: light-dark({{success-low}}, {{success-low-dark}}); + --phpunit-warning: light-dark({{warning}}, {{warning-dark}}); + --phpunit-warning-bar: light-dark({{warning-bar}}, {{warning-bar-dark}}); + --phpunit-danger: light-dark({{danger}}, {{danger-dark}}); + --phpunit-danger-bar: light-dark({{danger-bar}}, {{danger-bar-dark}}); + + /* Bootstrap v5.3 default colors (light, dark) */ + --bs-body-bg-rgb: 255, 255, 255; + --bs-body-bg: light-dark(#fff, #212529); + --bs-body-color-rgb: light-dark(33, 37, 41, 222, 226, 230); + --bs-body-color: light-dark(#212529, #dee2e6); + --bs-border-color-translucent: light-dark(rgba(0, 0, 0, 0.175), rgba(255, 255, 255, 0.15)); + --bs-border-color: light-dark(#dee2e6, #495057); + --bs-code-color: light-dark(#d63384, #e685b5); + --bs-danger-bg-subtle: light-dark(#f8d7da, #2c0b0e); + --bs-danger-border-subtle: light-dark(#f1aeb5, #842029); + --bs-danger-text-emphasis: light-dark(#58151c, #ea868f); + --bs-dark-bg-subtle: light-dark(#ced4da, #1a1d20); + --bs-dark-border-subtle: light-dark(#adb5bd, #343a40); + --bs-dark-text-emphasis: light-dark(#495057, #dee2e6); + --bs-emphasis-color-rgb: 0, 0, 0; + --bs-emphasis-color: light-dark(#000, #fff); + --bs-form-invalid-border-color: light-dark(#dc3545, #ea868f); + --bs-form-invalid-color: light-dark(#dc3545, #ea868f); + --bs-form-valid-border-color: light-dark(#198754, #75b798); + --bs-form-valid-color: light-dark(#198754, #75b798); + --bs-highlight-bg: light-dark(#fff3cd, #664d03); + --bs-highlight-color: light-dark(#212529, #dee2e6); + --bs-info-bg-subtle: light-dark(#cff4fc, #032830); + --bs-info-border-subtle: light-dark(#9eeaf9, #087990); + --bs-info-text-emphasis: light-dark(#055160, #6edff6); + --bs-light-bg-subtle: light-dark(#fcfcfd, #343a40); + --bs-light-border-subtle: light-dark(#e9ecef, #495057); + --bs-light-text-emphasis: light-dark(#495057, #f8f9fa); + --bs-link-color-rgb: 13, 110, 253; + --bs-link-color: light-dark(#0d6efd, #6ea8fe); + --bs-link-hover-color-rgb: 10, 88, 202; + --bs-link-hover-color: light-dark(#0a58ca, #8bb9fe); + --bs-primary-bg-subtle: light-dark(#cfe2ff, #031633); + --bs-primary-border-subtle: light-dark(#9ec5fe, #084298); + --bs-primary-text-emphasis: light-dark(#052c65, #6ea8fe); + --bs-secondary-bg-rgb: 233, 236, 239; + --bs-secondary-bg-subtle: light-dark(#e2e3e5, #161719); + --bs-secondary-bg: light-dark(#e9ecef, #343a40); + --bs-secondary-border-subtle: light-dark(#c4c8cb, #41464b); + --bs-secondary-color-rgb: 33, 37, 41; + --bs-secondary-color: light-dark(rgba(33, 37, 41, 0.75), rgba(222, 226, 230, 0.75)); + --bs-secondary-text-emphasis: light-dark(#2b2f32, #a7acb1); + --bs-success-bg-subtle: light-dark(#d1e7dd, #051b11); + --bs-success-border-subtle: light-dark(#a3cfbb, #0f5132); + --bs-success-text-emphasis: light-dark(#0a3622, #75b798); + --bs-tertiary-bg-rgb: light-dark(248, 249, 250, 43, 48, 53); + --bs-tertiary-bg: light-dark(#f8f9fa, #2b3035); + --bs-tertiary-color-rgb: 33, 37, 41; + --bs-tertiary-color: light-dark(rgba(33, 37, 41, 0.5), rgba(222, 226, 230, 0.5)); + --bs-warning-bg-subtle: light-dark(#fff3cd, #332701); + --bs-warning-border-subtle: light-dark(#ffe69c, #997404); + --bs-warning-text-emphasis: light-dark(#664d03, #ffda6a); +} + +@media (prefers-color-scheme: dark) { + :root { + --bs-body-bg-rgb: 33, 37, 41; + --bs-emphasis-color-rgb: 255, 255, 255; + --bs-link-color-rgb: 110, 168, 254; + --bs-link-hover-color-rgb: 139, 185, 254; + --bs-secondary-bg-rgb: 52, 58, 64; + --bs-secondary-color-rgb: 222, 226, 230; + --bs-tertiary-color-rgb: 222, 226, 230; + } + + /* Invert icon's colors on dark mode to improve readability */ + img.octicon { filter: invert(1); } +} + +body { + font-family: sans-serif; + font-size: 1em; + font-kerning: normal; + text-rendering: optimizeLegibility; + padding-top: 10px; +} + +nav .breadcrumb { + border-radius: var(--bs-border-radius); + background-color: var(--phpunit-breadcrumbs); + padding: .75rem 1rem; +} + +.popover { + max-width: none; +} + +.popover-body { + max-height: 90vh; + overflow-y: auto; +} + +.octicon { + margin-right:.25em; + vertical-align: baseline; + width: 0.75em; +} + +.table-bordered>thead>tr>td { + border-bottom-width: 1px; +} + +.table tbody>tr>td, .table thead>tr>td { + padding-top: 3px; + padding-bottom: 3px; +} + +.table-condensed tbody>tr>td { + padding-top: 0; + padding-bottom: 0; +} + +.table .progress { + margin-bottom: inherit; +} + +.table-borderless th, .table-borderless td { + border: 0 !important; +} + +.table tbody tr.covered-by-large-tests, .table tbody tr.covered-by-large-tests td, li.covered-by-large-tests, tr.success, tr.success td, td.success, li.success, span.success { + background-color: var(--phpunit-success-low); +} + +.table tbody tr.covered-by-medium-tests, .table tbody tr.covered-by-medium-tests td, li.covered-by-medium-tests { + background-color: var(--phpunit-success-medium); +} + +.table tbody tr.covered-by-small-tests, .table tbody tr.covered-by-small-tests td, li.covered-by-small-tests { + background-color: var(--phpunit-success-high); +} + +.table tbody tr.warning, .table tbody tr.warning td, .table tbody td.warning, li.warning, span.warning { + background-color: var(--phpunit-warning); +} + +.table tbody tr.danger, .table tbody tr.danger td, .table tbody td.danger, li.danger, span.danger { + background-color: var(--phpunit-danger); +} + +.table tbody td.info { + background-color: rgb(from var(--bs-info) r g b / 0.25); +} + +td.big { + vertical-align: middle; + width: 117px; +} + +td.small { +} + +td.codeLine { + font-family: "Source Code Pro", var(--bs-font-monospace); + white-space: pre-wrap; +} + +td span.comment { + color: var(--bs-secondary-color); +} + +td span.default { + color: var(--bs-body-color); +} + +td span.html { + color: var(--bs-secondary-color); +} + +td span.keyword { + color: var(--bs-body-color); + font-weight: bold; +} + +pre span.string { + color: var(--bs-body-color); +} + +span.success, span.warning, span.danger { + margin-right: 2px; + padding-left: 10px; + padding-right: 10px; + text-align: center; +} + +#toplink { + position: fixed; + left: 5px; + bottom: 5px; + outline: 0; +} + +svg text { + font-family: var(--bs-font-sans-serif); + font-size: 11px; + color: var(--bs-gray); + fill: var(--bs-gray); +} + +.scrollbox { + height:245px; + overflow-x:scroll; + overflow-y:scroll; +} + +table + .structure-heading { + border-top: 1px solid var(--bs-gray-200); + padding-top: 0.5em; +} + +table#code tr { + flex-wrap: nowrap; +} + +table#code td:first-of-type { + flex: 0 0 auto; + width: auto; + padding-left: .75em; + padding-right: .75em; +} + +table#code td.codeLine { + flex: 1 1 auto; + width: auto; +} + +table#code td:first-of-type a { + text-decoration: none; +} + +.legend { + font-weight: bold; + margin-right: 2px; + padding-left: 10px; + padding-right: 10px; + text-align: center; +} + +.covered-by-small-tests { + background-color: var(--phpunit-success-high); +} + +.covered-by-medium-tests { + background-color: var(--phpunit-success-medium); +} + +.covered-by-large-tests { + background-color: var(--phpunit-success-low); +} + +.not-covered { + background-color: var(--phpunit-danger); +} + +.not-coverable { + background-color: var(--phpunit-warning); +} + +.progress-bar.bg-success { + background-color: var(--phpunit-success-bar) !important; +} + +.progress-bar.bg-warning { + background-color: var(--phpunit-warning-bar) !important; +} + +.progress-bar.bg-danger { + background-color: var(--phpunit-danger-bar) !important; +} + +.file-coverage-chart { + width: 100%; + max-width: 900px; +} + +.dashboard-row { + margin-top: 2rem; +} + +.dashboard-column .scrollbox { + height: 400px; +} + + + + + Dashboard for {{full_path}} + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      +
      +

      Classes

      +

      Bubble size = executable lines. Hover for details, click to navigate.

      +
      +{{class_bubble_chart}} +
      +
      +
      +

       

      +

      Sorted by descending CRAP (Change Risk Anti-Patterns) index.

      +
      +{{class_crap_table}} +
      +
      +
      +
      +
      +

      Methods

      +

      Bubble size = executable lines. Hover for details, click to navigate.

      +
      +{{method_bubble_chart}} +
      +
      +
      +

       

      +

      Sorted by descending CRAP (Change Risk Anti-Patterns) index.

      +
      +{{method_crap_table}} +
      +
      +
      + +
      + + + + + + + Dashboard for {{full_path}} + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      +
      +

      Classes

      +

      Bubble size = executable lines. Hover for details, click to navigate.

      +
      +{{class_bubble_chart}} +
      +
      +
      +

       

      +

      Sorted by descending CRAP (Change Risk Anti-Patterns) index.

      +
      +{{class_crap_table}} +
      +
      +
      +
      +
      +

      Methods

      +

      Bubble size = executable lines. Hover for details, click to navigate.

      +
      +{{method_bubble_chart}} +
      +
      +
      +

       

      +

      Sorted by descending CRAP (Change Risk Anti-Patterns) index.

      +
      +{{method_crap_table}} +
      +
      +
      + +
      + + + + + + + Code Coverage for {{full_path}} + + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + + + + + + + + + + + + + + +{{items}} + +
       
      Code Coverage
       
      Lines
      Functions and Methods
      Classes and Traits
      +
      +
      +
      +

      Legend

      +

      + Low: 0% to {{low_upper_bound}}% + Medium: {{low_upper_bound}}% to {{high_lower_bound}}% + High: {{high_lower_bound}}% to 100% +

      +

      + Generated by php-code-coverage {{version}} using {{runtime}}{{generator}} at {{date}}. +

      +
      +
      + + + + + + + Code Coverage for {{full_path}} + + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + + + + + + + + + + + + + + + + +{{items}} + +
       
      Code Coverage
       
      Lines
      Branches
      Paths
      Functions and Methods
      Classes and Traits
      +
      +
      +
      +

      Legend

      +

      + Low: 0% to {{low_upper_bound}}% + Medium: {{low_upper_bound}}% to {{high_lower_bound}}% + High: {{high_lower_bound}}% to 100% +

      +

      + Generated by php-code-coverage {{version}} using {{runtime}}{{generator}} at {{date}}. +

      +
      +
      + + + + {{icon}}{{name}} + {{lines_bar}} +
      {{lines_executed_percent}}
      +
      {{lines_number}}
      + {{methods_bar}} +
      {{methods_tested_percent}}
      +
      {{methods_number}}
      + {{classes_bar}} +
      {{classes_tested_percent}}
      +
      {{classes_number}}
      + + + + {{icon}}{{name}} + {{lines_bar}} +
      {{lines_executed_percent}}
      +
      {{lines_number}}
      + {{branches_bar}} +
      {{branches_executed_percent}}
      +
      {{branches_number}}
      + {{paths_bar}} +
      {{paths_executed_percent}}
      +
      {{paths_number}}
      + {{methods_bar}} +
      {{methods_tested_percent}}
      +
      {{methods_number}}
      + {{classes_bar}} +
      {{classes_tested_percent}}
      +
      {{classes_number}}
      + + + + + + + Code Coverage for {{full_path}} + + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + + + + + + + + + + + + + + +{{items}} + +
       
      Code Coverage
       
      Lines
      Functions and Methods
      Classes and Traits
      +
      +{{lines}} +{{structure}} + +
      + + + + + + + + + + Code Coverage for {{full_path}} + + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + + + + + + + + + + + + + + + + +{{items}} + +
       
      Code Coverage
       
      Lines
      Branches
      Paths
      Functions and Methods
      Classes and Traits
      +
      +{{lines}} +{{structure}} + +
      + + + + + + + {{name}} + {{lines_bar}} +
      {{lines_executed_percent}}
      +
      {{lines_number}}
      + {{methods_bar}} +
      {{methods_tested_percent}}
      +
      {{methods_number}}
      + {{crap}} + {{classes_bar}} +
      {{classes_tested_percent}}
      +
      {{classes_number}}
      + + + + {{name}} + {{lines_bar}} +
      {{lines_executed_percent}}
      +
      {{lines_number}}
      + {{branches_bar}} +
      {{branches_executed_percent}}
      +
      {{branches_number}}
      + {{paths_bar}} +
      {{paths_executed_percent}}
      +
      {{paths_number}}
      + {{methods_bar}} +
      {{methods_tested_percent}}
      +
      {{methods_number}}
      + {{crap}} + {{classes_bar}} +
      {{classes_tested_percent}}
      +
      {{classes_number}}
      + + +/*! + * Bootstrap v5.3.6 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t.call(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function j(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function M(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${M(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${M(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1),e[i]=j(t.dataset[n])}return e},getDataAttribute:(t,e)=>j(t.getAttribute(`data-bs-${M(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.6"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map((t=>n(t))).join(","):null},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="ArrowLeft",lt="ArrowRight",ct="next",ht="prev",dt="left",ut="right",ft=`slide${ot}`,pt=`slid${ot}`,mt=`keydown${ot}`,gt=`mouseenter${ot}`,_t=`mouseleave${ot}`,bt=`dragstart${ot}`,vt=`load${ot}${rt}`,yt=`click${ot}${rt}`,wt="carousel",At="active",Et=".active",Tt=".carousel-item",Ct=Et+Tt,Ot={[at]:ut,[lt]:dt},xt={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},kt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class Lt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===wt&&this.cycle()}static get Default(){return xt}static get DefaultType(){return kt}static get NAME(){return"carousel"}next(){this._slide(ct)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(ht)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,pt,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,pt,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?ct:ht;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,mt,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,gt,(()=>this.pause())),N.on(this._element,_t,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,bt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(dt)),rightCallback:()=>this._slide(this._directionToOrder(ut)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Ot[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(Et,this._indicatorsElement);e.classList.remove(At),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(At),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===ct,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(ft).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(At),i.classList.remove(At,c,l),this._isSliding=!1,r(pt)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Ct,this._element)}_getItems(){return z.find(Tt,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===dt?ht:ct:t===dt?ct:ht}_orderToDirection(t){return p()?t===ht?dt:ut:t===ht?ut:dt}static jQueryInterface(t){return this.each((function(){const e=Lt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,yt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(wt))return;t.preventDefault();const i=Lt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,vt,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)Lt.getOrCreateInstance(e)})),m(Lt);const St=".bs.collapse",Dt=`show${St}`,$t=`shown${St}`,It=`hide${St}`,Nt=`hidden${St}`,Pt=`click${St}.data-api`,jt="show",Mt="collapse",Ft="collapsing",Ht=`:scope .${Mt} .${Mt}`,Wt='[data-bs-toggle="collapse"]',Bt={parent:null,toggle:!0},zt={parent:"(null|element)",toggle:"boolean"};class Rt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Wt);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Bt}static get DefaultType(){return zt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Rt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Dt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Mt),this._element.classList.add(Ft),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Ft),this._element.classList.add(Mt,jt),this._element.style[e]="",N.trigger(this._element,$t)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,It).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(Ft),this._element.classList.remove(Mt,jt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Ft),this._element.classList.add(Mt),N.trigger(this._element,Nt)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(jt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Wt);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(Ht,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Rt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,Pt,Wt,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Rt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Rt);var qt="top",Vt="bottom",Kt="right",Qt="left",Xt="auto",Yt=[qt,Vt,Kt,Qt],Ut="start",Gt="end",Jt="clippingParents",Zt="viewport",te="popper",ee="reference",ie=Yt.reduce((function(t,e){return t.concat([e+"-"+Ut,e+"-"+Gt])}),[]),ne=[].concat(Yt,[Xt]).reduce((function(t,e){return t.concat([e,e+"-"+Ut,e+"-"+Gt])}),[]),se="beforeRead",oe="read",re="afterRead",ae="beforeMain",le="main",ce="afterMain",he="beforeWrite",de="write",ue="afterWrite",fe=[se,oe,re,ae,le,ce,he,de,ue];function pe(t){return t?(t.nodeName||"").toLowerCase():null}function me(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function ge(t){return t instanceof me(t).Element||t instanceof Element}function _e(t){return t instanceof me(t).HTMLElement||t instanceof HTMLElement}function be(t){return"undefined"!=typeof ShadowRoot&&(t instanceof me(t).ShadowRoot||t instanceof ShadowRoot)}const ve={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];_e(s)&&pe(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});_e(n)&&pe(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function ye(t){return t.split("-")[0]}var we=Math.max,Ae=Math.min,Ee=Math.round;function Te(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ce(){return!/^((?!chrome|android).)*safari/i.test(Te())}function Oe(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&_e(t)&&(s=t.offsetWidth>0&&Ee(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&Ee(n.height)/t.offsetHeight||1);var r=(ge(t)?me(t):window).visualViewport,a=!Ce()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function xe(t){var e=Oe(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function ke(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&be(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Le(t){return me(t).getComputedStyle(t)}function Se(t){return["table","td","th"].indexOf(pe(t))>=0}function De(t){return((ge(t)?t.ownerDocument:t.document)||window.document).documentElement}function $e(t){return"html"===pe(t)?t:t.assignedSlot||t.parentNode||(be(t)?t.host:null)||De(t)}function Ie(t){return _e(t)&&"fixed"!==Le(t).position?t.offsetParent:null}function Ne(t){for(var e=me(t),i=Ie(t);i&&Se(i)&&"static"===Le(i).position;)i=Ie(i);return i&&("html"===pe(i)||"body"===pe(i)&&"static"===Le(i).position)?e:i||function(t){var e=/firefox/i.test(Te());if(/Trident/i.test(Te())&&_e(t)&&"fixed"===Le(t).position)return null;var i=$e(t);for(be(i)&&(i=i.host);_e(i)&&["html","body"].indexOf(pe(i))<0;){var n=Le(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Pe(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function je(t,e,i){return we(t,Ae(e,i))}function Me(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Fe(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const He={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=ye(i.placement),l=Pe(a),c=[Qt,Kt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Me("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Fe(t,Yt))}(s.padding,i),d=xe(o),u="y"===l?qt:Qt,f="y"===l?Vt:Kt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=Ne(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=je(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&ke(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function We(t){return t.split("-")[1]}var Be={top:"auto",right:"auto",bottom:"auto",left:"auto"};function ze(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Qt,y=qt,w=window;if(c){var A=Ne(i),E="clientHeight",T="clientWidth";A===me(i)&&"static"!==Le(A=De(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===qt||(s===Qt||s===Kt)&&o===Gt)&&(y=Vt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Qt&&(s!==qt&&s!==Vt||o!==Gt)||(v=Kt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&Be),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:Ee(i*s)/s||0,y:Ee(n*s)/s||0}}({x:f,y:m},me(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Re={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:ye(e.placement),variation:We(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,ze(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,ze(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var qe={passive:!0};const Ve={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=me(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,qe)})),a&&l.addEventListener("resize",i.update,qe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,qe)})),a&&l.removeEventListener("resize",i.update,qe)}},data:{}};var Ke={left:"right",right:"left",bottom:"top",top:"bottom"};function Qe(t){return t.replace(/left|right|bottom|top/g,(function(t){return Ke[t]}))}var Xe={start:"end",end:"start"};function Ye(t){return t.replace(/start|end/g,(function(t){return Xe[t]}))}function Ue(t){var e=me(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ge(t){return Oe(De(t)).left+Ue(t).scrollLeft}function Je(t){var e=Le(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ze(t){return["html","body","#document"].indexOf(pe(t))>=0?t.ownerDocument.body:_e(t)&&Je(t)?t:Ze($e(t))}function ti(t,e){var i;void 0===e&&(e=[]);var n=Ze(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=me(n),r=s?[o].concat(o.visualViewport||[],Je(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(ti($e(r)))}function ei(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ii(t,e,i){return e===Zt?ei(function(t,e){var i=me(t),n=De(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ce();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ge(t),y:l}}(t,i)):ge(e)?function(t,e){var i=Oe(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):ei(function(t){var e,i=De(t),n=Ue(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=we(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=we(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ge(t),l=-n.scrollTop;return"rtl"===Le(s||i).direction&&(a+=we(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(De(t)))}function ni(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?ye(s):null,r=s?We(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case qt:e={x:a,y:i.y-n.height};break;case Vt:e={x:a,y:i.y+i.height};break;case Kt:e={x:i.x+i.width,y:l};break;case Qt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Pe(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Ut:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Gt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function si(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Jt:a,c=i.rootBoundary,h=void 0===c?Zt:c,d=i.elementContext,u=void 0===d?te:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Me("number"!=typeof g?g:Fe(g,Yt)),b=u===te?ee:te,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=ti($e(t)),i=["absolute","fixed"].indexOf(Le(t).position)>=0&&_e(t)?Ne(t):t;return ge(i)?e.filter((function(t){return ge(t)&&ke(t,i)&&"body"!==pe(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ii(t,i,n);return e.top=we(s.top,e.top),e.right=Ae(s.right,e.right),e.bottom=Ae(s.bottom,e.bottom),e.left=we(s.left,e.left),e}),ii(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(ge(y)?y:y.contextElement||De(t.elements.popper),l,h,r),A=Oe(t.elements.reference),E=ni({reference:A,element:v,placement:s}),T=ei(Object.assign({},v,E)),C=u===te?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===te&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[Kt,Vt].indexOf(t)>=0?1:-1,i=[qt,Vt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function oi(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ne:l,h=We(n),d=h?a?ie:ie.filter((function(t){return We(t)===h})):Yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=si(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[ye(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const ri={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=ye(g),b=l||(_!==g&&p?function(t){if(ye(t)===Xt)return[];var e=Qe(t);return[Ye(t),e,Ye(e)]}(g):[Qe(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(ye(i)===Xt?oi(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=si(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?Kt:Qt:k?Vt:qt;y[S]>w[S]&&($=Qe($));var I=Qe($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},j=p?3:1;j>0&&"break"!==P(j);j--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function ai(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function li(t){return[qt,Kt,Vt,Qt].some((function(e){return t[e]>=0}))}const ci={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=si(e,{elementContext:"reference"}),a=si(e,{altBoundary:!0}),l=ai(r,n),c=ai(a,s,o),h=li(l),d=li(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},hi={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ne.reduce((function(t,i){return t[i]=function(t,e,i){var n=ye(t),s=[Qt,qt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Qt,Kt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},di={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ni({reference:e.rects.reference,element:e.rects.popper,placement:e.placement})},data:{}},ui={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=si(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=ye(e.placement),b=We(e.placement),v=!b,y=Pe(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?qt:Qt,D="y"===y?Vt:Kt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],j=f?-T[$]/2:0,M=b===Ut?E[$]:T[$],F=b===Ut?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?xe(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=je(0,E[$],W[$]),V=v?E[$]/2-j-q-z-O.mainAxis:M-q-z-O.mainAxis,K=v?-E[$]/2+j+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&Ne(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=je(f?Ae(N,I+V-Y-X):N,I,f?we(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?qt:Qt,tt="x"===y?Vt:Kt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[qt,Qt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=je(t,e,i);return n>i?i:n}(at,et,lt):je(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function fi(t,e,i){void 0===i&&(i=!1);var n,s,o=_e(e),r=_e(e)&&function(t){var e=t.getBoundingClientRect(),i=Ee(e.width)/t.offsetWidth||1,n=Ee(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=De(e),l=Oe(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==pe(e)||Je(a))&&(c=(n=e)!==me(n)&&_e(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Ue(n)),_e(e)?((h=Oe(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ge(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function pi(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var mi={placement:"bottom",modifiers:[],strategy:"absolute"};function gi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[void 0,t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Oi,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=Ki.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(ji);for(const i of e){const e=Ki.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ci,Oi].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Pi)?this:z.prev(this,Pi)[0]||z.next(this,Pi)[0]||z.findOne(Pi,t.delegateTarget.parentNode),o=Ki.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,$i,Pi,Ki.dataApiKeydownHandler),N.on(document,$i,Mi,Ki.dataApiKeydownHandler),N.on(document,Di,Ki.clearMenus),N.on(document,Ii,Ki.clearMenus),N.on(document,Di,Pi,(function(t){t.preventDefault(),Ki.getOrCreateInstance(this).toggle()})),m(Ki);const Qi="backdrop",Xi="show",Yi=`mousedown.bs.${Qi}`,Ui={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Gi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ji extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Ui}static get DefaultType(){return Gi}static get NAME(){return Qi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Xi),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Xi),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Yi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Yi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Zi=".bs.focustrap",tn=`focusin${Zi}`,en=`keydown.tab${Zi}`,nn="backward",sn={autofocus:!0,trapElement:null},on={autofocus:"boolean",trapElement:"element"};class rn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return sn}static get DefaultType(){return on}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Zi),N.on(document,tn,(t=>this._handleFocusin(t))),N.on(document,en,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Zi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===nn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?nn:"forward")}}const an=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",ln=".sticky-top",cn="padding-right",hn="margin-right";class dn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,cn,(e=>e+t)),this._setElementAttributes(an,cn,(e=>e+t)),this._setElementAttributes(ln,hn,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,cn),this._resetElementAttributes(an,cn),this._resetElementAttributes(ln,hn)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const un=".bs.modal",fn=`hide${un}`,pn=`hidePrevented${un}`,mn=`hidden${un}`,gn=`show${un}`,_n=`shown${un}`,bn=`resize${un}`,vn=`click.dismiss${un}`,yn=`mousedown.dismiss${un}`,wn=`keydown.dismiss${un}`,An=`click${un}.data-api`,En="modal-open",Tn="show",Cn="modal-static",On={backdrop:!0,focus:!0,keyboard:!0},xn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class kn extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new dn,this._addEventListeners()}static get Default(){return On}static get DefaultType(){return xn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,gn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(En),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,fn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Tn),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,un),N.off(this._dialog,un),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ji({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new rn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(Tn),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,_n,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,wn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,bn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,yn,(t=>{N.one(this._element,vn,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(En),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,mn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,pn).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(Cn)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(Cn),this._queueCallback((()=>{this._element.classList.remove(Cn),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=kn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,An,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,gn,(t=>{t.defaultPrevented||N.one(e,mn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&kn.getInstance(i).hide(),kn.getOrCreateInstance(e).toggle(this)})),R(kn),m(kn);const Ln=".bs.offcanvas",Sn=".data-api",Dn=`load${Ln}${Sn}`,$n="show",In="showing",Nn="hiding",Pn=".offcanvas.show",jn=`show${Ln}`,Mn=`shown${Ln}`,Fn=`hide${Ln}`,Hn=`hidePrevented${Ln}`,Wn=`hidden${Ln}`,Bn=`resize${Ln}`,zn=`click${Ln}${Sn}`,Rn=`keydown.dismiss${Ln}`,qn={backdrop:!0,keyboard:!0,scroll:!1},Vn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class Kn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return qn}static get DefaultType(){return Vn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,jn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new dn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(In),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add($n),this._element.classList.remove(In),N.trigger(this._element,Mn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,Fn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(Nn),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove($n,Nn),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new dn).reset(),N.trigger(this._element,Wn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ji({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,Hn)}:null})}_initializeFocusTrap(){return new rn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Rn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,Hn))}))}static jQueryInterface(t){return this.each((function(){const e=Kn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,zn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Wn,(()=>{a(this)&&this.focus()}));const i=z.findOne(Pn);i&&i!==e&&Kn.getInstance(i).hide(),Kn.getOrCreateInstance(e).toggle(this)})),N.on(window,Dn,(()=>{for(const t of z.find(Pn))Kn.getOrCreateInstance(t).show()})),N.on(window,Bn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&Kn.getOrCreateInstance(t).hide()})),R(Kn),m(Kn);const Qn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Xn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Yn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Un=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Xn.has(i)||Boolean(Yn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Gn={allowList:Qn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
      "},Jn={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Zn={entry:"(string|element|function|null)",selector:"(string|element)"};class ts extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Gn}static get DefaultType(){return Jn}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Zn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Un(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[void 0,this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const es=new Set(["sanitize","allowList","sanitizeFn"]),is="fade",ns="show",ss=".tooltip-inner",os=".modal",rs="hide.bs.modal",as="hover",ls="focus",cs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},hs={allowList:Qn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ds={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class us extends W{constructor(t,e){if(void 0===wi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org/docs/v2/)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(os),rs,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(ns),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(ns),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[ls]=!1,this._activeTrigger[as]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(is,ns),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(is),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new ts({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{[ss]:this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(is)}_isShown(){return this.tip&&this.tip.classList.contains(ns)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=cs[e.toUpperCase()];return yi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element,this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[void 0,e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===as?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===as?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?ls:as]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?ls:as]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(os),rs,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))es.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".popover-header",ps=".popover-body",ms={...us.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},gs={...us.DefaultType,content:"(null|string|element|function)"};class _s extends us{static get Default(){return ms}static get DefaultType(){return gs}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{[fs]:this._getTitle(),[ps]:this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=_s.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(_s);const bs=".bs.scrollspy",vs=`activate${bs}`,ys=`click${bs}`,ws=`load${bs}.data-api`,As="active",Es="[href]",Ts=".nav-link",Cs=`${Ts}, .nav-item > ${Ts}, .list-group-item`,Os={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},xs={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class ks extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return Os}static get DefaultType(){return xs}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ys),N.on(this._config.target,ys,Es,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(Es,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(As),this._activateParents(t),N.trigger(this._element,vs,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(As);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,Cs))t.classList.add(As)}_clearActiveClass(t){t.classList.remove(As);const e=z.find(`${Es}.${As}`,t);for(const t of e)t.classList.remove(As)}static jQueryInterface(t){return this.each((function(){const e=ks.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,ws,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))ks.getOrCreateInstance(t)})),m(ks);const Ls=".bs.tab",Ss=`hide${Ls}`,Ds=`hidden${Ls}`,$s=`show${Ls}`,Is=`shown${Ls}`,Ns=`click${Ls}`,Ps=`keydown${Ls}`,js=`load${Ls}`,Ms="ArrowLeft",Fs="ArrowRight",Hs="ArrowUp",Ws="ArrowDown",Bs="Home",zs="End",Rs="active",qs="fade",Vs="show",Ks=".dropdown-toggle",Qs=`:not(${Ks})`,Xs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Ys=`.nav-link${Qs}, .list-group-item${Qs}, [role="tab"]${Qs}, ${Xs}`,Us=`.${Rs}[data-bs-toggle="tab"], .${Rs}[data-bs-toggle="pill"], .${Rs}[data-bs-toggle="list"]`;class Gs extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ps,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Ss,{relatedTarget:t}):null;N.trigger(t,$s,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Rs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,Is,{relatedTarget:e})):t.classList.add(Vs)}),t,t.classList.contains(qs)))}_deactivate(t,e){t&&(t.classList.remove(Rs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Ds,{relatedTarget:e})):t.classList.remove(Vs)}),t,t.classList.contains(qs)))}_keydown(t){if(![Ms,Fs,Hs,Ws,Bs,zs].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([Bs,zs].includes(t.key))i=e[t.key===Bs?0:e.length-1];else{const n=[Fs,Ws].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Gs.getOrCreateInstance(i).show())}_getChildren(){return z.find(Ys,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(Ks,Rs),n(".dropdown-menu",Vs),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Rs)}_getInnerElement(t){return t.matches(Ys)?t:z.findOne(Ys,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Gs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ns,Xs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Gs.getOrCreateInstance(this).show()})),N.on(window,js,(()=>{for(const t of z.find(Us))Gs.getOrCreateInstance(t)})),m(Gs);const Js=".bs.toast",Zs=`mouseover${Js}`,to=`mouseout${Js}`,eo=`focusin${Js}`,io=`focusout${Js}`,no=`hide${Js}`,so=`hidden${Js}`,oo=`show${Js}`,ro=`shown${Js}`,ao="hide",lo="show",co="showing",ho={animation:"boolean",autohide:"boolean",delay:"number"},uo={animation:!0,autohide:!0,delay:5e3};class fo extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return uo}static get DefaultType(){return ho}static get NAME(){return"toast"}show(){N.trigger(this._element,oo).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(ao),d(this._element),this._element.classList.add(lo,co),this._queueCallback((()=>{this._element.classList.remove(co),N.trigger(this._element,ro),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,no).defaultPrevented||(this._element.classList.add(co),this._queueCallback((()=>{this._element.classList.add(ao),this._element.classList.remove(co,lo),N.trigger(this._element,so)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(lo),super.dispose()}isShown(){return this._element.classList.contains(lo)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Zs,(t=>this._onInteraction(t,!0))),N.on(this._element,to,(t=>this._onInteraction(t,!1))),N.on(this._element,eo,(t=>this._onInteraction(t,!0))),N.on(this._element,io,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=fo.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(fo),m(fo),{Alert:Q,Button:Y,Carousel:Lt,Collapse:Rt,Dropdown:Ki,Modal:kn,Offcanvas:Kn,Popover:_s,ScrollSpy:ks,Tab:Gs,Toast:fo,Tooltip:us}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map$(function () { + var $window = $(window) + , $top_link = $('#toplink') + , $body = $('body, html') + , offset = $('#code').offset().top; + + $top_link.hide().click(function (event) { + event.preventDefault(); + $body.animate({scrollTop: 0}, 800); + }); + + $window.scroll(function () { + if ($window.scrollTop() > offset) { + $top_link.fadeIn(); + } else { + $top_link.fadeOut(); + } + }); + + var $popovers = $('.popin > :first-child'); + $('.popin').on({ + 'click.popover': function (event) { + event.stopPropagation(); + + var $container = $(this).children().first(); + + //Close all other popovers: + $popovers.each(function () { + var $current = $(this); + if (!$current.is($container)) { + $current.popover('hide'); + } + }); + + // Toggle this popover: + $container.popover('toggle'); + }, + }); + + //Hide all popovers on outside click: + $(document).click(function (event) { + if ($(event.target).closest($('.popover')).length === 0) { + $popovers.popover('hide'); + } + }); + + //Hide all popovers on escape: + $(document).keyup(function (event) { + if (event.key === 'Escape') { + $popovers.popover('hide'); + } + }); +}); +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
      "],col:[2,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
      ",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0{{lineNumber}}{{lineContent}} + + +{{lines}} + +
      + + {{name}} + {{lines_bar}} +
      {{lines_executed_percent}}
      +
      {{lines_number}}
      + {{methods_bar}} +
      {{methods_tested_percent}}
      +
      {{methods_number}}
      + {{crap}} + + + + + {{name}} + {{lines_bar}} +
      {{lines_executed_percent}}
      +
      {{lines_number}}
      + {{branches_bar}} +
      {{branches_executed_percent}}
      +
      {{branches_number}}
      + {{paths_bar}} +
      {{paths_executed_percent}}
      +
      {{paths_number}}
      + {{methods_bar}} +
      {{methods_tested_percent}}
      +
      {{methods_number}}
      + {{crap}} + + + +
      +

      Paths

      +

      + Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not + necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once. + Please also be aware that some paths may include implicit rather than explicit branches, e.g. an if statement + always has an else as part of its logical flow even if you didn't write one. +

      +{{paths}} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html; + +use const ENT_COMPAT; +use const ENT_HTML401; +use const ENT_SUBSTITUTE; +use const T_ABSTRACT; +use const T_ARRAY; +use const T_AS; +use const T_BREAK; +use const T_CALLABLE; +use const T_CASE; +use const T_CATCH; +use const T_CLASS; +use const T_CLONE; +use const T_COMMENT; +use const T_CONST; +use const T_CONTINUE; +use const T_DECLARE; +use const T_DEFAULT; +use const T_DO; +use const T_DOC_COMMENT; +use const T_ECHO; +use const T_ELSE; +use const T_ELSEIF; +use const T_EMPTY; +use const T_ENDDECLARE; +use const T_ENDFOR; +use const T_ENDFOREACH; +use const T_ENDIF; +use const T_ENDSWITCH; +use const T_ENDWHILE; +use const T_ENUM; +use const T_EVAL; +use const T_EXIT; +use const T_EXTENDS; +use const T_FINAL; +use const T_FINALLY; +use const T_FN; +use const T_FOR; +use const T_FOREACH; +use const T_FUNCTION; +use const T_GLOBAL; +use const T_GOTO; +use const T_HALT_COMPILER; +use const T_IF; +use const T_IMPLEMENTS; +use const T_INCLUDE; +use const T_INCLUDE_ONCE; +use const T_INLINE_HTML; +use const T_INSTANCEOF; +use const T_INSTEADOF; +use const T_INTERFACE; +use const T_ISSET; +use const T_LIST; +use const T_MATCH; +use const T_NAMESPACE; +use const T_NEW; +use const T_PRINT; +use const T_PRIVATE; +use const T_PRIVATE_SET; +use const T_PROTECTED; +use const T_PROTECTED_SET; +use const T_PUBLIC; +use const T_PUBLIC_SET; +use const T_READONLY; +use const T_REQUIRE; +use const T_REQUIRE_ONCE; +use const T_RETURN; +use const T_STATIC; +use const T_SWITCH; +use const T_THROW; +use const T_TRAIT; +use const T_TRY; +use const T_UNSET; +use const T_USE; +use const T_VAR; +use const T_WHILE; +use const T_YIELD; +use const T_YIELD_FROM; +use const TOKEN_PARSE; +use function count; +use function explode; +use function file_get_contents; +use function htmlspecialchars; +use function is_string; +use function sprintf; +use function str_ends_with; +use function str_replace; +use function token_get_all; +use function trim; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class SyntaxHighlighter +{ + /** + * @var array + */ + private const array KEYWORD_TOKENS = [T_ABSTRACT => \true, T_ARRAY => \true, T_AS => \true, T_BREAK => \true, T_CALLABLE => \true, T_CASE => \true, T_CATCH => \true, T_CLASS => \true, T_CLONE => \true, T_CONST => \true, T_CONTINUE => \true, T_DECLARE => \true, T_DEFAULT => \true, T_DO => \true, T_ECHO => \true, T_ELSE => \true, T_ELSEIF => \true, T_EMPTY => \true, T_ENDDECLARE => \true, T_ENDFOR => \true, T_ENDFOREACH => \true, T_ENDIF => \true, T_ENDSWITCH => \true, T_ENDWHILE => \true, T_ENUM => \true, T_EVAL => \true, T_EXIT => \true, T_EXTENDS => \true, T_FINAL => \true, T_FINALLY => \true, T_FN => \true, T_FOR => \true, T_FOREACH => \true, T_FUNCTION => \true, T_GLOBAL => \true, T_GOTO => \true, T_HALT_COMPILER => \true, T_IF => \true, T_IMPLEMENTS => \true, T_INCLUDE => \true, T_INCLUDE_ONCE => \true, T_INSTANCEOF => \true, T_INSTEADOF => \true, T_INTERFACE => \true, T_ISSET => \true, T_LIST => \true, T_MATCH => \true, T_NAMESPACE => \true, T_NEW => \true, T_PRINT => \true, T_PRIVATE => \true, T_PRIVATE_SET => \true, T_PROTECTED => \true, T_PROTECTED_SET => \true, T_PUBLIC => \true, T_PUBLIC_SET => \true, T_READONLY => \true, T_REQUIRE => \true, T_REQUIRE_ONCE => \true, T_RETURN => \true, T_STATIC => \true, T_SWITCH => \true, T_THROW => \true, T_TRAIT => \true, T_TRY => \true, T_UNSET => \true, T_USE => \true, T_VAR => \true, T_WHILE => \true, T_YIELD => \true, T_YIELD_FROM => \true]; + private const int HTML_SPECIAL_CHARS_FLAGS = ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE; + /** + * @var array> + */ + private static array $cache = []; + /** + * @param non-empty-string $file + * + * @return list + */ + public function highlight(string $file): array + { + if (isset(self::$cache[$file])) { + return self::$cache[$file]; + } + $buffer = file_get_contents($file); + $tokens = token_get_all($buffer, TOKEN_PARSE); + $result = ['']; + $i = 0; + $stringFlag = \false; + $fileEndsWithNewLine = str_ends_with($buffer, "\n"); + unset($buffer); + foreach ($tokens as $j => $token) { + if (is_string($token)) { + if ($token === '"' && $tokens[$j - 1] !== '\\') { + $result[$i] .= sprintf('%s', htmlspecialchars($token, self::HTML_SPECIAL_CHARS_FLAGS)); + $stringFlag = !$stringFlag; + } else { + $result[$i] .= sprintf('%s', htmlspecialchars($token, self::HTML_SPECIAL_CHARS_FLAGS)); + } + continue; + } + [$token, $value] = $token; + $value = str_replace(["\t", ' '], ['    ', ' '], htmlspecialchars($value, self::HTML_SPECIAL_CHARS_FLAGS)); + if ($value === "\n") { + $result[++$i] = ''; + } else { + $lines = explode("\n", $value); + foreach ($lines as $jj => $line) { + $line = trim($line); + if ($line !== '') { + if ($stringFlag) { + $colour = 'string'; + } else { + $colour = 'default'; + if ($this->isInlineHtml($token)) { + $colour = 'html'; + } elseif ($this->isComment($token)) { + $colour = 'comment'; + } elseif ($this->isKeyword($token)) { + $colour = 'keyword'; + } + } + $result[$i] .= sprintf('%s', $colour, $line); + } + if (isset($lines[$jj + 1])) { + $result[++$i] = ''; + } + } + } + } + if ($fileEndsWithNewLine) { + unset($result[count($result) - 1]); + } + self::$cache[$file] = $result; + return $result; + } + private function isComment(int $token): bool + { + return $token === T_COMMENT || $token === T_DOC_COMMENT; + } + private function isInlineHtml(int $token): bool + { + return $token === T_INLINE_HTML; + } + private function isKeyword(int $token): bool + { + return isset(self::KEYWORD_TOKENS[$token]); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report; + +use function assert; +use function basename; +use function count; +use function is_string; +use function ksort; +use function max; +use function range; +use function str_replace; +use function time; +use DOMDocument; +use DOMElement; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\EnsuresUtf8; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Xml; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Version; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\WriteOperationFailedException; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class OpenClover +{ + use EnsuresUtf8; + /** + * @throws WriteOperationFailedException + */ + public function process(Directory $report, ?string $target = null, ?string $name = null): string + { + $time = (string) time(); + $xmlDocument = new DOMDocument('1.0', 'UTF-8'); + $xmlDocument->formatOutput = \true; + $xmlCoverage = $xmlDocument->createElement('coverage'); + $xmlCoverage->setAttribute('clover', Version::id()); + $xmlCoverage->setAttribute('generated', $time); + $xmlDocument->appendChild($xmlCoverage); + $xmlProject = $xmlDocument->createElement('project'); + $xmlProject->setAttribute('timestamp', $time); + if (is_string($name)) { + $xmlProject->setAttribute('name', $this->ensureUtf8($name)); + } + $xmlCoverage->appendChild($xmlProject); + /** @var array $packages */ + $packages = []; + foreach ($report as $item) { + if (!$item instanceof File) { + continue; + } + $xmlFile = $xmlDocument->createElement('file'); + $xmlFile->setAttribute('name', $this->ensureUtf8(basename($item->pathAsString()))); + $xmlFile->setAttribute('path', $this->ensureUtf8($item->pathAsString())); + $classes = $item->classesAndTraits(); + $coverageData = $item->lineCoverageData(); + $lines = []; + $namespace = 'global'; + foreach ($classes as $className => $class) { + $classStatements = 0; + $coveredClassStatements = 0; + $coveredMethods = 0; + $classMethods = 0; + // Assumption: one namespace per file + if ($class->namespace !== '') { + $namespace = $class->namespace; + } + foreach ($class->methods as $methodName => $method) { + /** @phpstan-ignore equal.notAllowed */ + if ($method->executableLines == 0) { + continue; + } + $classMethods++; + $classStatements += $method->executableLines; + $coveredClassStatements += $method->executedLines; + /** @phpstan-ignore equal.notAllowed */ + if ($method->coverage == 100) { + $coveredMethods++; + } + $methodCount = 0; + foreach (range($method->startLine, $method->endLine) as $line) { + if (isset($coverageData[$line])) { + $methodCount = max($methodCount, count($coverageData[$line])); + } + } + $lines[$method->startLine] = ['ccn' => $method->ccn, 'count' => $methodCount, 'type' => 'method', 'signature' => $method->signature, 'visibility' => $method->visibility]; + } + $xmlClass = $xmlDocument->createElement('class'); + $xmlClass->setAttribute('name', $this->ensureUtf8(str_replace($class->namespace . '\\', '', $className))); + $xmlFile->appendChild($xmlClass); + $xmlMetrics = $xmlDocument->createElement('metrics'); + $xmlMetrics->setAttribute('complexity', (string) $class->ccn); + $xmlMetrics->setAttribute('elements', (string) ($classMethods + $classStatements + $class->executableBranches)); + $xmlMetrics->setAttribute('coveredelements', (string) ($coveredMethods + $coveredClassStatements + $class->executedBranches)); + $xmlMetrics->setAttribute('conditionals', (string) $class->executableBranches); + $xmlMetrics->setAttribute('coveredconditionals', (string) $class->executedBranches); + $xmlMetrics->setAttribute('statements', (string) $classStatements); + $xmlMetrics->setAttribute('coveredstatements', (string) $coveredClassStatements); + $xmlMetrics->setAttribute('methods', (string) $classMethods); + $xmlMetrics->setAttribute('coveredmethods', (string) $coveredMethods); + $xmlClass->insertBefore($xmlMetrics, $xmlClass->firstChild); + } + foreach ($coverageData as $line => $data) { + if ($data === null || isset($lines[$line])) { + continue; + } + $lines[$line] = ['count' => count($data), 'type' => 'stmt']; + } + ksort($lines); + foreach ($lines as $line => $data) { + $xmlLine = $xmlDocument->createElement('line'); + $xmlLine->setAttribute('num', (string) $line); + $xmlLine->setAttribute('type', $data['type']); + if (isset($data['ccn'])) { + $xmlLine->setAttribute('complexity', (string) $data['ccn']); + } + $xmlLine->setAttribute('count', (string) $data['count']); + if (isset($data['signature'])) { + $xmlLine->setAttribute('signature', $this->ensureUtf8($data['signature'])); + } + if (isset($data['visibility'])) { + $xmlLine->setAttribute('visibility', $data['visibility']); + } + $xmlFile->appendChild($xmlLine); + } + $linesOfCode = $item->linesOfCode(); + $xmlMetrics = $xmlDocument->createElement('metrics'); + $xmlMetrics->setAttribute('loc', (string) $linesOfCode->linesOfCode()); + $xmlMetrics->setAttribute('ncloc', (string) $linesOfCode->nonCommentLinesOfCode()); + $xmlMetrics->setAttribute('classes', (string) $item->numberOfClassesAndTraits()); + $xmlMetrics->setAttribute('complexity', (string) $item->cyclomaticComplexity()); + $xmlMetrics->setAttribute('elements', (string) ($item->numberOfMethods() + $item->numberOfExecutableLines() + $item->numberOfExecutableBranches())); + $xmlMetrics->setAttribute('coveredelements', (string) ($item->numberOfTestedMethods() + $item->numberOfExecutedLines() + $item->numberOfExecutedBranches())); + $xmlMetrics->setAttribute('conditionals', (string) $item->numberOfExecutableBranches()); + $xmlMetrics->setAttribute('coveredconditionals', (string) $item->numberOfExecutedBranches()); + $xmlMetrics->setAttribute('statements', (string) $item->numberOfExecutableLines()); + $xmlMetrics->setAttribute('coveredstatements', (string) $item->numberOfExecutedLines()); + $xmlMetrics->setAttribute('methods', (string) $item->numberOfMethods()); + $xmlMetrics->setAttribute('coveredmethods', (string) $item->numberOfTestedMethods()); + $xmlFile->insertBefore($xmlMetrics, $xmlFile->firstChild); + if (!isset($packages[$namespace])) { + $packages[$namespace] = $xmlDocument->createElement('package'); + $packages[$namespace]->setAttribute('name', $this->ensureUtf8($namespace)); + $xmlPackageMetrics = $xmlDocument->createElement('metrics'); + $xmlPackageMetrics->setAttribute('complexity', '0'); + $xmlPackageMetrics->setAttribute('elements', '0'); + $xmlPackageMetrics->setAttribute('coveredelements', '0'); + $xmlPackageMetrics->setAttribute('conditionals', '0'); + $xmlPackageMetrics->setAttribute('coveredconditionals', '0'); + $xmlPackageMetrics->setAttribute('statements', '0'); + $xmlPackageMetrics->setAttribute('coveredstatements', '0'); + $xmlPackageMetrics->setAttribute('methods', '0'); + $xmlPackageMetrics->setAttribute('coveredmethods', '0'); + $packages[$namespace]->appendChild($xmlPackageMetrics); + $xmlProject->appendChild($packages[$namespace]); + } + $xmlPackageMetrics = $packages[$namespace]->firstChild; + assert($xmlPackageMetrics instanceof DOMElement); + $xmlPackageMetrics->setAttribute('complexity', (string) ((int) $xmlPackageMetrics->getAttribute('complexity') + $item->cyclomaticComplexity())); + $xmlPackageMetrics->setAttribute('elements', (string) ((int) $xmlPackageMetrics->getAttribute('elements') + $item->numberOfMethods() + $item->numberOfExecutableLines() + $item->numberOfExecutableBranches())); + $xmlPackageMetrics->setAttribute('coveredelements', (string) ((int) $xmlPackageMetrics->getAttribute('coveredelements') + $item->numberOfTestedMethods() + $item->numberOfExecutedLines() + $item->numberOfExecutedBranches())); + $xmlPackageMetrics->setAttribute('conditionals', (string) ((int) $xmlPackageMetrics->getAttribute('conditionals') + $item->numberOfExecutableBranches())); + $xmlPackageMetrics->setAttribute('coveredconditionals', (string) ((int) $xmlPackageMetrics->getAttribute('coveredconditionals') + $item->numberOfExecutedBranches())); + $xmlPackageMetrics->setAttribute('statements', (string) ((int) $xmlPackageMetrics->getAttribute('statements') + $item->numberOfExecutableLines())); + $xmlPackageMetrics->setAttribute('coveredstatements', (string) ((int) $xmlPackageMetrics->getAttribute('coveredstatements') + $item->numberOfExecutedLines())); + $xmlPackageMetrics->setAttribute('methods', (string) ((int) $xmlPackageMetrics->getAttribute('methods') + $item->numberOfMethods())); + $xmlPackageMetrics->setAttribute('coveredmethods', (string) ((int) $xmlPackageMetrics->getAttribute('coveredmethods') + $item->numberOfTestedMethods())); + $packages[$namespace]->appendChild($xmlFile); + } + $linesOfCode = $report->linesOfCode(); + $xmlMetrics = $xmlDocument->createElement('metrics'); + $xmlMetrics->setAttribute('files', (string) count($report)); + $xmlMetrics->setAttribute('loc', (string) $linesOfCode->linesOfCode()); + $xmlMetrics->setAttribute('ncloc', (string) $linesOfCode->nonCommentLinesOfCode()); + $xmlMetrics->setAttribute('classes', (string) $report->numberOfClassesAndTraits()); + $xmlMetrics->setAttribute('complexity', (string) $report->cyclomaticComplexity()); + $xmlMetrics->setAttribute('elements', (string) ($report->numberOfMethods() + $report->numberOfExecutableLines() + $report->numberOfExecutableBranches())); + $xmlMetrics->setAttribute('coveredelements', (string) ($report->numberOfTestedMethods() + $report->numberOfExecutedLines() + $report->numberOfExecutedBranches())); + $xmlMetrics->setAttribute('conditionals', (string) $report->numberOfExecutableBranches()); + $xmlMetrics->setAttribute('coveredconditionals', (string) $report->numberOfExecutedBranches()); + $xmlMetrics->setAttribute('statements', (string) $report->numberOfExecutableLines()); + $xmlMetrics->setAttribute('coveredstatements', (string) $report->numberOfExecutedLines()); + $xmlMetrics->setAttribute('methods', (string) $report->numberOfMethods()); + $xmlMetrics->setAttribute('coveredmethods', (string) $report->numberOfTestedMethods()); + $xmlProject->insertBefore($xmlMetrics, $xmlProject->firstChild); + $buffer = Xml::asString($xmlDocument); + if ($target !== null) { + Filesystem::write($target, $buffer); + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Summary +{ + /** + * @var non-negative-int + */ + private int $numberOfExecutableLines; + /** + * @var non-negative-int + */ + private int $numberOfExecutedLines; + /** + * @var non-negative-int + */ + private int $numberOfExecutableBranches; + /** + * @var non-negative-int + */ + private int $numberOfExecutedBranches; + /** + * @var non-negative-int + */ + private int $numberOfExecutablePaths; + /** + * @var non-negative-int + */ + private int $numberOfExecutedPaths; + /** + * @var non-negative-int + */ + private int $numberOfFilesWithoutBranchCoverageData; + /** + * @param non-negative-int $numberOfExecutableLines + * @param non-negative-int $numberOfExecutedLines + * @param non-negative-int $numberOfExecutableBranches + * @param non-negative-int $numberOfExecutedBranches + * @param non-negative-int $numberOfExecutablePaths + * @param non-negative-int $numberOfExecutedPaths + * @param non-negative-int $numberOfFilesWithoutBranchCoverageData + */ + public function __construct(int $numberOfExecutableLines, int $numberOfExecutedLines, int $numberOfExecutableBranches, int $numberOfExecutedBranches, int $numberOfExecutablePaths, int $numberOfExecutedPaths, int $numberOfFilesWithoutBranchCoverageData = 0) + { + $this->numberOfExecutableLines = $numberOfExecutableLines; + $this->numberOfExecutedLines = $numberOfExecutedLines; + $this->numberOfExecutableBranches = $numberOfExecutableBranches; + $this->numberOfExecutedBranches = $numberOfExecutedBranches; + $this->numberOfExecutablePaths = $numberOfExecutablePaths; + $this->numberOfExecutedPaths = $numberOfExecutedPaths; + $this->numberOfFilesWithoutBranchCoverageData = $numberOfFilesWithoutBranchCoverageData; + } + /** + * @return non-negative-int + */ + public function numberOfExecutableLines(): int + { + return $this->numberOfExecutableLines; + } + /** + * @return non-negative-int + */ + public function numberOfExecutedLines(): int + { + return $this->numberOfExecutedLines; + } + public function lineCoverageAsPercentage(): float + { + return $this->percentage($this->numberOfExecutedLines, $this->numberOfExecutableLines); + } + public function hasBranchAndPathCoverage(): bool + { + return $this->numberOfExecutableBranches > 0; + } + /** + * @return non-negative-int + */ + public function numberOfExecutableBranches(): int + { + return $this->numberOfExecutableBranches; + } + /** + * @return non-negative-int + */ + public function numberOfExecutedBranches(): int + { + return $this->numberOfExecutedBranches; + } + public function branchCoverageAsPercentage(): float + { + return $this->percentage($this->numberOfExecutedBranches, $this->numberOfExecutableBranches); + } + /** + * @return non-negative-int + */ + public function numberOfExecutablePaths(): int + { + return $this->numberOfExecutablePaths; + } + /** + * @return non-negative-int + */ + public function numberOfExecutedPaths(): int + { + return $this->numberOfExecutedPaths; + } + public function pathCoverageAsPercentage(): float + { + return $this->percentage($this->numberOfExecutedPaths, $this->numberOfExecutablePaths); + } + /** + * @return non-negative-int + */ + public function numberOfFilesWithoutBranchCoverageData(): int + { + return $this->numberOfFilesWithoutBranchCoverageData; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = sprintf('Lines: %01.2F%% (%d/%d)', $this->lineCoverageAsPercentage(), $this->numberOfExecutedLines, $this->numberOfExecutableLines); + if ($this->hasBranchAndPathCoverage()) { + $buffer .= sprintf(', Branches: %01.2F%% (%d/%d)', $this->branchCoverageAsPercentage(), $this->numberOfExecutedBranches, $this->numberOfExecutableBranches); + $buffer .= sprintf(', Paths: %01.2F%% (%d/%d)', $this->pathCoverageAsPercentage(), $this->numberOfExecutedPaths, $this->numberOfExecutablePaths); + } + return $buffer; + } + /** + * @param non-negative-int $fraction + * @param non-negative-int $total + */ + private function percentage(int $fraction, int $total): float + { + if ($total > 0) { + return $fraction / $total * 100; + } + return 100.0; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report; + +use const PHP_EOL; +use function array_map; +use function date; +use function ksort; +use function max; +use function sprintf; +use function str_pad; +use function strlen; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Percentage; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Text +{ + private const string COLOR_GREEN = "\x1b[30;42m"; + private const string COLOR_YELLOW = "\x1b[30;43m"; + private const string COLOR_RED = "\x1b[37;41m"; + private const string COLOR_HEADER = "\x1b[1;37;40m"; + private const string COLOR_RESET = "\x1b[0m"; + private Thresholds $thresholds; + private bool $showUncoveredFiles; + private bool $showOnlySummary; + public function __construct(Thresholds $thresholds, bool $showUncoveredFiles = \false, bool $showOnlySummary = \false) + { + $this->thresholds = $thresholds; + $this->showUncoveredFiles = $showUncoveredFiles; + $this->showOnlySummary = $showOnlySummary; + } + public function process(Directory $report, bool $showColors = \false): string + { + $hasBranchCoverage = $report->numberOfExecutableBranches() > 0; + $output = PHP_EOL . PHP_EOL; + $colors = ['header' => '', 'classes' => '', 'methods' => '', 'lines' => '', 'branches' => '', 'paths' => '', 'reset' => '']; + if ($showColors) { + $colors['classes'] = $this->coverageColor($report->numberOfTestedClassesAndTraits(), $report->numberOfClassesAndTraits()); + $colors['methods'] = $this->coverageColor($report->numberOfTestedMethods(), $report->numberOfMethods()); + $colors['lines'] = $this->coverageColor($report->numberOfExecutedLines(), $report->numberOfExecutableLines()); + $colors['branches'] = $this->coverageColor($report->numberOfExecutedBranches(), $report->numberOfExecutableBranches()); + $colors['paths'] = $this->coverageColor($report->numberOfExecutedPaths(), $report->numberOfExecutablePaths()); + $colors['reset'] = self::COLOR_RESET; + $colors['header'] = self::COLOR_HEADER; + } + $classes = sprintf(' Classes: %6s (%d/%d)', Percentage::fromFractionAndTotal($report->numberOfTestedClassesAndTraits(), $report->numberOfClassesAndTraits())->asString(), $report->numberOfTestedClassesAndTraits(), $report->numberOfClassesAndTraits()); + $methods = sprintf(' Methods: %6s (%d/%d)', Percentage::fromFractionAndTotal($report->numberOfTestedMethods(), $report->numberOfMethods())->asString(), $report->numberOfTestedMethods(), $report->numberOfMethods()); + $paths = ''; + $branches = ''; + if ($hasBranchCoverage) { + $paths = sprintf(' Paths: %6s (%d/%d)', Percentage::fromFractionAndTotal($report->numberOfExecutedPaths(), $report->numberOfExecutablePaths())->asString(), $report->numberOfExecutedPaths(), $report->numberOfExecutablePaths()); + $branches = sprintf(' Branches: %6s (%d/%d)', Percentage::fromFractionAndTotal($report->numberOfExecutedBranches(), $report->numberOfExecutableBranches())->asString(), $report->numberOfExecutedBranches(), $report->numberOfExecutableBranches()); + } + $lines = sprintf(' Lines: %6s (%d/%d)', Percentage::fromFractionAndTotal($report->numberOfExecutedLines(), $report->numberOfExecutableLines())->asString(), $report->numberOfExecutedLines(), $report->numberOfExecutableLines()); + $padding = max(array_map(strlen(...), [$classes, $methods, $lines])); + if ($this->showOnlySummary) { + $title = 'Code Coverage Report Summary:'; + $padding = max($padding, strlen($title)); + $output .= $this->format($colors['header'], $padding, $title); + } else { + $date = date(' Y-m-d H:i:s'); + $title = 'Code Coverage Report:'; + $output .= $this->format($colors['header'], $padding, $title); + $output .= $this->format($colors['header'], $padding, $date); + $output .= $this->format($colors['header'], $padding, ''); + $output .= $this->format($colors['header'], $padding, ' Summary:'); + } + $output .= $this->format($colors['classes'], $padding, $classes); + $output .= $this->format($colors['methods'], $padding, $methods); + if ($hasBranchCoverage) { + $output .= $this->format($colors['paths'], $padding, $paths); + $output .= $this->format($colors['branches'], $padding, $branches); + $numFilesWithoutBranchCoverageData = $report->numberOfFilesWithoutBranchCoverageData(); + if ($numFilesWithoutBranchCoverageData > 0) { + $output .= sprintf(' * %d %s not loaded during test execution and no branch/path data is available for %s' . PHP_EOL, $numFilesWithoutBranchCoverageData, $numFilesWithoutBranchCoverageData === 1 ? 'file was' : 'files were', $numFilesWithoutBranchCoverageData === 1 ? 'it' : 'them'); + } + } + $output .= $this->format($colors['lines'], $padding, $lines); + if ($this->showOnlySummary) { + return $output . PHP_EOL; + } + $classCoverage = []; + foreach ($report as $item) { + if (!$item instanceof File) { + continue; + } + $classes = $item->classesAndTraits(); + foreach ($classes as $className => $class) { + $classExecutableLines = 0; + $classExecutedLines = 0; + $classExecutableBranches = 0; + $classExecutedBranches = 0; + $classExecutablePaths = 0; + $classExecutedPaths = 0; + $coveredMethods = 0; + $classMethods = 0; + foreach ($class->methods as $method) { + /** @phpstan-ignore equal.notAllowed */ + if ($method->executableLines == 0) { + continue; + } + $classMethods++; + $classExecutableLines += $method->executableLines; + $classExecutedLines += $method->executedLines; + $classExecutableBranches += $method->executableBranches; + $classExecutedBranches += $method->executedBranches; + $classExecutablePaths += $method->executablePaths; + $classExecutedPaths += $method->executedPaths; + /** @phpstan-ignore equal.notAllowed */ + if ($method->coverage == 100) { + $coveredMethods++; + } + } + $classCoverage[$className] = ['namespace' => $class->namespace, 'className' => $className, 'methodsCovered' => $coveredMethods, 'methodCount' => $classMethods, 'statementsCovered' => $classExecutedLines, 'statementCount' => $classExecutableLines, 'branchesCovered' => $classExecutedBranches, 'branchesCount' => $classExecutableBranches, 'pathsCovered' => $classExecutedPaths, 'pathsCount' => $classExecutablePaths]; + } + } + ksort($classCoverage); + $methodColor = ''; + $pathsColor = ''; + $branchesColor = ''; + $linesColor = ''; + $resetColor = ''; + foreach ($classCoverage as $fullQualifiedPath => $classInfo) { + /** @phpstan-ignore notEqual.notAllowed */ + if ($this->showUncoveredFiles || $classInfo['statementsCovered'] != 0) { + if ($showColors) { + $methodColor = $this->coverageColor($classInfo['methodsCovered'], $classInfo['methodCount']); + $pathsColor = $this->coverageColor($classInfo['pathsCovered'], $classInfo['pathsCount']); + $branchesColor = $this->coverageColor($classInfo['branchesCovered'], $classInfo['branchesCount']); + $linesColor = $this->coverageColor($classInfo['statementsCovered'], $classInfo['statementCount']); + $resetColor = $colors['reset']; + } + $output .= PHP_EOL . $fullQualifiedPath . PHP_EOL . ' ' . $methodColor . 'Methods: ' . $this->printCoverageCounts($classInfo['methodsCovered'], $classInfo['methodCount'], 2) . $resetColor . ' '; + if ($hasBranchCoverage) { + $output .= ' ' . $pathsColor . 'Paths: ' . $this->printCoverageCounts($classInfo['pathsCovered'], $classInfo['pathsCount'], 3) . $resetColor . ' ' . ' ' . $branchesColor . 'Branches: ' . $this->printCoverageCounts($classInfo['branchesCovered'], $classInfo['branchesCount'], 3) . $resetColor . ' '; + } + $output .= ' ' . $linesColor . 'Lines: ' . $this->printCoverageCounts($classInfo['statementsCovered'], $classInfo['statementCount'], 3) . $resetColor; + } + } + return $output . PHP_EOL; + } + private function coverageColor(int $numberOfCoveredElements, int $totalNumberOfElements): string + { + $coverage = Percentage::fromFractionAndTotal($numberOfCoveredElements, $totalNumberOfElements); + if ($coverage->asFloat() >= $this->thresholds->highLowerBound()) { + return self::COLOR_GREEN; + } + if ($coverage->asFloat() > $this->thresholds->lowUpperBound()) { + return self::COLOR_YELLOW; + } + return self::COLOR_RED; + } + private function printCoverageCounts(int $numberOfCoveredElements, int $totalNumberOfElements, int $precision): string + { + $format = '%' . $precision . 's'; + return Percentage::fromFractionAndTotal($numberOfCoveredElements, $totalNumberOfElements)->asFixedWidthString() . ' (' . sprintf($format, $numberOfCoveredElements) . '/' . sprintf($format, $totalNumberOfElements) . ')'; + } + private function format(string $color, int $padding, false|string $string): string + { + if ($color === '') { + return (string) $string . PHP_EOL; + } + return $color . str_pad((string) $string, $padding) . self::COLOR_RESET . PHP_EOL; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report; + +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\InvalidArgumentException; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Thresholds +{ + private int $lowUpperBound; + private int $highLowerBound; + public static function default(): self + { + return new self(50, 90); + } + /** + * @throws InvalidArgumentException + */ + public static function from(int $lowUpperBound, int $highLowerBound): self + { + if ($lowUpperBound > $highLowerBound) { + throw new InvalidArgumentException('$lowUpperBound must not be larger than $highLowerBound'); + } + return new self($lowUpperBound, $highLowerBound); + } + private function __construct(int $lowUpperBound, int $highLowerBound) + { + $this->lowUpperBound = $lowUpperBound; + $this->highLowerBound = $highLowerBound; + } + public function lowUpperBound(): int + { + return $this->lowUpperBound; + } + public function highLowerBound(): int + { + return $this->highLowerBound; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use DateTimeImmutable; +use PHPUnitPHAR\SebastianBergmann\Environment\Runtime; +use XMLWriter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class BuildInformation +{ + public function __construct(XMLWriter $xmlWriter, Runtime $runtime, DateTimeImmutable $buildDate, string $phpUnitVersion, string $coverageVersion, string $driverExtensionName, string $driverExtensionVersion) + { + $xmlWriter->startElement('build'); + $xmlWriter->writeAttribute('time', $buildDate->format('D M j G:i:s T Y')); + $xmlWriter->writeAttribute('phpunit', $phpUnitVersion); + $xmlWriter->writeAttribute('coverage', $coverageVersion); + $xmlWriter->startElement('runtime'); + $xmlWriter->writeAttribute('name', $runtime->getName()); + $xmlWriter->writeAttribute('version', $runtime->getVersion()); + $xmlWriter->writeAttribute('url', $runtime->getVendorUrl()); + $xmlWriter->endElement(); + $xmlWriter->startElement('driver'); + $xmlWriter->writeAttribute('name', $driverExtensionName); + $xmlWriter->writeAttribute('version', $driverExtensionVersion); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use XMLWriter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Coverage +{ + private XMLWriter $xmlWriter; + private string $line; + public function __construct(XMLWriter $xmlWriter, string $line) + { + $this->xmlWriter = $xmlWriter; + $this->line = $line; + } + /** + * @param list $tests + */ + public function finalize(array $tests): void + { + $writer = $this->xmlWriter; + $writer->startElement('line'); + $writer->writeAttribute('nr', $this->line); + foreach ($tests as $test) { + $writer->startElement('covered'); + $writer->writeAttribute('by', $test); + $writer->endElement(); + } + $writer->endElement(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Directory extends Node +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use const DIRECTORY_SEPARATOR; +use function count; +use function dirname; +use function file_get_contents; +use function is_array; +use function is_dir; +use function is_file; +use function is_writable; +use function sprintf; +use function strlen; +use function substr; +use DateTimeImmutable; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedClassType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedFunctionType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedTraitType; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\AbstractNode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File as FileNode; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\PathExistsButIsNotDirectoryException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\EnsuresUtf8; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Version; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\WriteOperationFailedException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\XmlException; +use PHPUnitPHAR\SebastianBergmann\Environment\Runtime; +use XMLWriter; +/** + * @phpstan-import-type TestType from CodeCoverage + * + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Facade +{ + use EnsuresUtf8; + public const string XML_NAMESPACE = 'https://schema.phpunit.de/coverage/1.0'; + private string $target; + private Project $project; + private readonly bool $includeSource; + public function __construct(bool $includeSource = \true) + { + $this->includeSource = $includeSource; + } + /** + * @param non-empty-string $target + * @param array $tests + * + * @throws XmlException + */ + public function process(string $target, DirectoryNode $report, array $tests, ?Runtime $runtime = null, ?DateTimeImmutable $buildDate = null, ?string $phpUnitVersion = null, ?string $coverageVersion = null, ?string $driverExtensionName = null, ?string $driverExtensionVersion = null): void + { + if (substr($target, -1, 1) !== DIRECTORY_SEPARATOR) { + $target .= DIRECTORY_SEPARATOR; + } + $this->target = $target; + $this->initTargetDirectory($target); + $writer = new XMLWriter(); + $writer->openUri($this->targetFilePath('index')); + $writer->setIndent(\true); + $writer->setIndentString(' '); + $this->project = new Project($writer, $report->name()); + $this->setBuildInformation($runtime, $buildDate, $phpUnitVersion, $coverageVersion, $driverExtensionName, $driverExtensionVersion); + $this->project->startProject(); + $this->processTests($tests); + $this->processDirectory($report, $this->project); + $this->project->finalize(); + } + private function setBuildInformation(?Runtime $runtime, ?DateTimeImmutable $buildDate, ?string $phpUnitVersion, ?string $coverageVersion, ?string $driverExtensionName, ?string $driverExtensionVersion): void + { + if ($runtime === null) { + return; + } + if ($buildDate === null) { + return; + } + if ($phpUnitVersion === null) { + return; + } + if ($coverageVersion === null) { + return; + } + if ($driverExtensionName === null) { + $driverExtensionName = 'unknown'; + } + if ($driverExtensionVersion === null) { + $driverExtensionVersion = 'unknown'; + } + $this->project->buildInformation($runtime, $buildDate, $phpUnitVersion, Version::id(), $driverExtensionName, $driverExtensionVersion); + } + /** + * @throws PathExistsButIsNotDirectoryException + * @throws WriteOperationFailedException + */ + private function initTargetDirectory(string $directory): void + { + if (is_file($directory)) { + // @codeCoverageIgnoreStart + if (!is_dir($directory)) { + throw new PathExistsButIsNotDirectoryException($directory); + } + if (!is_writable($directory)) { + throw new WriteOperationFailedException($directory); + } + // @codeCoverageIgnoreEnd + } + Filesystem::createDirectory($directory); + } + /** + * @throws XmlException + */ + private function processDirectory(DirectoryNode $directory, Node $context): void + { + $directoryName = $directory->name(); + if ($this->project->projectSourceDirectory() === $directoryName) { + $directoryName = '/'; + } + $writer = $this->project->getWriter(); + $writer->startElement('directory'); + $writer->writeAttribute('name', $this->ensureUtf8($directoryName)); + $directoryObject = $context->addDirectory(); + $this->setTotals($directory, $directoryObject->totals()); + foreach ($directory->directories() as $node) { + $this->processDirectory($node, $directoryObject); + } + foreach ($directory->files() as $node) { + $this->processFile($node, $directoryObject); + } + $writer->endElement(); + } + /** + * @throws XmlException + */ + private function processFile(FileNode $file, Directory $context): void + { + $context->getWriter()->startElement('file'); + $context->getWriter()->writeAttribute('name', $this->ensureUtf8($file->name())); + $context->getWriter()->writeAttribute('href', $file->id() . '.xml'); + $context->getWriter()->writeAttribute('hash', $file->sha1()); + $fileObject = $context->addFile(); + $this->setTotals($file, $fileObject->totals()); + $context->getWriter()->endElement(); + $path = substr($file->pathAsString(), strlen($this->project->projectSourceDirectory())); + $writer = new XMLWriter(); + $writer->openUri($this->targetFilePath($file->id())); + $writer->setIndent(\true); + $writer->setIndentString(' '); + $fileReport = new Report($writer, $path, $file->sha1()); + $this->setTotals($file, $fileReport->totals()); + foreach ($file->classesAndTraits() as $unit) { + $this->processUnit($unit, $fileReport); + } + foreach ($file->functions() as $function) { + $this->processFunction($function, $fileReport); + } + $fileReport->getWriter()->startElement('coverage'); + foreach ($file->lineCoverageData() as $line => $tests) { + if (!is_array($tests) || count($tests) === 0) { + continue; + } + $coverage = $fileReport->lineCoverage((string) $line); + $coverage->finalize($tests); + } + $fileReport->getWriter()->endElement(); + if ($this->includeSource) { + $fileReport->source()->setSourceCode(file_get_contents($file->pathAsString())); + } + $fileReport->finalize(); + } + private function processUnit(ProcessedClassType|ProcessedTraitType $unit, Report $report): void + { + if ($unit instanceof ProcessedClassType) { + $report->getWriter()->startElement('class'); + $unitObject = $report->classObject($unit->className, $unit->namespace, $unit->startLine, $unit->executableLines, $unit->executedLines, (float) $unit->crap); + } else { + $report->getWriter()->startElement('trait'); + $unitObject = $report->traitObject($unit->traitName, $unit->namespace, $unit->startLine, $unit->executableLines, $unit->executedLines, (float) $unit->crap); + } + foreach ($unit->methods as $method) { + $report->getWriter()->startElement('method'); + $unitObject->addMethod($method->methodName, $method->signature, (string) $method->startLine, (string) $method->endLine, (string) $method->executableLines, (string) $method->executedLines, (string) $method->coverage, $method->crap); + $report->getWriter()->endElement(); + } + $report->getWriter()->endElement(); + } + private function processFunction(ProcessedFunctionType $function, Report $report): void + { + $report->getWriter()->startElement('function'); + $report->functionObject($function->functionName, $function->signature, (string) $function->startLine, null, (string) $function->executableLines, (string) $function->executedLines, (string) $function->coverage, $function->crap); + $report->getWriter()->endElement(); + } + /** + * @param array $tests + */ + private function processTests(array $tests): void + { + $this->project->getWriter()->startElement('tests'); + $testsObject = $this->project->tests(); + foreach ($tests as $test => $result) { + $testsObject->addTest($test, $result); + } + $this->project->getWriter()->endElement(); + } + private function setTotals(AbstractNode $node, Totals $totals): void + { + $totals->getWriter()->startElement('totals'); + $loc = $node->linesOfCode(); + $totals->setNumLines($loc->linesOfCode(), $loc->commentLinesOfCode(), $loc->nonCommentLinesOfCode(), $node->numberOfExecutableLines(), $node->numberOfExecutedLines()); + $totals->setNumMethods($node->numberOfMethods(), $node->numberOfTestedMethods()); + $totals->setNumFunctions($node->numberOfFunctions(), $node->numberOfTestedFunctions()); + $totals->setNumClasses($node->numberOfClasses(), $node->numberOfTestedClasses()); + $totals->setNumTraits($node->numberOfTraits(), $node->numberOfTestedTraits()); + $totals->getWriter()->endElement(); + } + private function targetDirectory(): string + { + return $this->target; + } + private function targetFilePath(string $name): string + { + $filename = sprintf('%s/%s.xml', $this->targetDirectory(), $name); + $this->initTargetDirectory(dirname($filename)); + return $filename; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use XMLWriter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +class File +{ + protected XMLWriter $xmlWriter; + public function __construct(XMLWriter $xmlWriter) + { + $this->xmlWriter = $xmlWriter; + } + public function getWriter(): XMLWriter + { + return $this->xmlWriter; + } + public function totals(): Totals + { + return new Totals($this->xmlWriter); + } + public function lineCoverage(string $line): Coverage + { + return new Coverage($this->xmlWriter, $line); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\EnsuresUtf8; +use XMLWriter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Method +{ + use EnsuresUtf8; + private XMLWriter $xmlWriter; + public function __construct(XMLWriter $xmlWriter, string $name, string $signature, string $start, ?string $end, string $executable, string $executed, string $coverage, string $crap) + { + $this->xmlWriter = $xmlWriter; + $this->xmlWriter->writeAttribute('name', $this->ensureUtf8($name)); + $this->xmlWriter->writeAttribute('signature', $this->ensureUtf8($signature)); + $this->xmlWriter->writeAttribute('start', $start); + if ($end !== null) { + $this->xmlWriter->writeAttribute('end', $end); + } + $this->xmlWriter->writeAttribute('crap', $crap); + $this->xmlWriter->writeAttribute('executable', $executable); + $this->xmlWriter->writeAttribute('executed', $executed); + $this->xmlWriter->writeAttribute('coverage', $coverage); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use XMLWriter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +abstract class Node +{ + protected readonly XMLWriter $xmlWriter; + public function __construct(XMLWriter $xmlWriter) + { + $this->xmlWriter = $xmlWriter; + } + public function totals(): Totals + { + return new Totals($this->xmlWriter); + } + public function addDirectory(): Directory + { + return new Directory($this->xmlWriter); + } + public function addFile(): File + { + return new File($this->xmlWriter); + } + public function getWriter(): XMLWriter + { + return $this->xmlWriter; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use DateTimeImmutable; +use PHPUnitPHAR\SebastianBergmann\Environment\Runtime; +use XMLWriter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Project extends Node +{ + private readonly string $directory; + public function __construct(XMLWriter $xmlWriter, string $directory) + { + $this->directory = $directory; + parent::__construct($xmlWriter); + $this->xmlWriter->startDocument(); + $this->xmlWriter->startElement('phpunit'); + $this->xmlWriter->writeAttribute('xmlns', Facade::XML_NAMESPACE); + } + public function projectSourceDirectory(): string + { + return $this->directory; + } + public function buildInformation(Runtime $runtime, DateTimeImmutable $buildDate, string $phpUnitVersion, string $coverageVersion, string $driverExtensionName, string $driverExtensionVersion): void + { + new BuildInformation($this->xmlWriter, $runtime, $buildDate, $phpUnitVersion, $coverageVersion, $driverExtensionName, $driverExtensionVersion); + } + public function tests(): Tests + { + return new Tests($this->xmlWriter); + } + public function getWriter(): XMLWriter + { + return $this->xmlWriter; + } + public function startProject(): void + { + $this->xmlWriter->startElement('project'); + $this->xmlWriter->writeAttribute('source', $this->directory); + } + public function finalize(): void + { + $this->xmlWriter->endElement(); + $this->xmlWriter->endDocument(); + $this->xmlWriter->flush(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use function basename; +use function dirname; +use DOMDocument; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\EnsuresUtf8; +use XMLWriter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Report extends File +{ + use EnsuresUtf8; + private readonly string $name; + private readonly string $sha1; + public function __construct(XMLWriter $xmlWriter, string $name, string $sha1) + { + /* + $dom = new DOMDocument; + $dom->loadXML(''); + + $contextNode = $dom->getElementsByTagNameNS( + Facade::XML_NAMESPACE, + 'file', + )->item(0); + */ + parent::__construct($xmlWriter); + $this->name = $name; + $this->sha1 = $sha1; + $xmlWriter->startDocument(); + $xmlWriter->startElement('phpunit'); + $xmlWriter->writeAttribute('xmlns', Facade::XML_NAMESPACE); + $xmlWriter->startElement('file'); + $xmlWriter->writeAttribute('name', $this->ensureUtf8(basename($this->name))); + $xmlWriter->writeAttribute('path', $this->ensureUtf8(dirname($this->name))); + $xmlWriter->writeAttribute('hash', $this->sha1); + } + public function finalize(): void + { + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + $this->xmlWriter->endDocument(); + $this->xmlWriter->flush(); + } + public function functionObject(string $name, string $signature, string $start, ?string $end, string $executable, string $executed, string $coverage, string $crap): void + { + new Method($this->xmlWriter, $name, $signature, $start, $end, $executable, $executed, $coverage, $crap); + } + public function classObject(string $name, string $namespace, int $start, int $executable, int $executed, float $crap): Unit + { + return new Unit($this->xmlWriter, $name, $namespace, $start, $executable, $executed, $crap); + } + public function traitObject(string $name, string $namespace, int $start, int $executable, int $executed, float $crap): Unit + { + return new Unit($this->xmlWriter, $name, $namespace, $start, $executable, $executed, $crap); + } + public function source(): Source + { + return new Source($this->xmlWriter); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use PHPUnitPHAR\TheSeer\Tokenizer\NamespaceUri; +use PHPUnitPHAR\TheSeer\Tokenizer\Tokenizer; +use PHPUnitPHAR\TheSeer\Tokenizer\XMLSerializer; +use XMLWriter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Source +{ + private XMLWriter $xmlWriter; + public function __construct(XMLWriter $xmlWriter) + { + $this->xmlWriter = $xmlWriter; + } + public function setSourceCode(string $source): void + { + $tokens = (new Tokenizer())->parse($source); + (new XMLSerializer(new NamespaceUri(Facade::XML_NAMESPACE)))->appendToWriter($this->xmlWriter, $tokens); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use function sprintf; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\EnsuresUtf8; +use XMLWriter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type TestType from CodeCoverage + */ +final readonly class Tests +{ + use EnsuresUtf8; + private readonly XMLWriter $xmlWriter; + public function __construct(XMLWriter $xmlWriter) + { + $this->xmlWriter = $xmlWriter; + } + /** + * @param TestType $result + */ + public function addTest(string $test, array $result): void + { + $this->xmlWriter->startElement('test'); + $this->xmlWriter->writeAttribute('name', $this->ensureUtf8($test)); + $this->xmlWriter->writeAttribute('size', $result['size']); + $this->xmlWriter->writeAttribute('status', $result['status']); + $this->xmlWriter->writeAttribute('time', sprintf('%F', $result['time'])); + $this->xmlWriter->endElement(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use function sprintf; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Percentage; +use XMLWriter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Totals +{ + private XMLWriter $xmlWriter; + public function __construct(XMLWriter $xmlWriter) + { + $this->xmlWriter = $xmlWriter; + } + public function setNumLines(int $loc, int $cloc, int $ncloc, int $executable, int $executed): void + { + $this->xmlWriter->startElement('lines'); + $this->xmlWriter->writeAttribute('total', (string) $loc); + $this->xmlWriter->writeAttribute('comments', (string) $cloc); + $this->xmlWriter->writeAttribute('code', (string) $ncloc); + $this->xmlWriter->writeAttribute('executable', (string) $executable); + $this->xmlWriter->writeAttribute('executed', (string) $executed); + $this->xmlWriter->writeAttribute('percent', $executable === 0 ? '0' : sprintf('%01.2F', Percentage::fromFractionAndTotal($executed, $executable)->asFloat())); + $this->xmlWriter->endElement(); + } + public function setNumClasses(int $count, int $tested): void + { + $this->xmlWriter->startElement('classes'); + $this->xmlWriter->writeAttribute('count', (string) $count); + $this->xmlWriter->writeAttribute('tested', (string) $tested); + $this->xmlWriter->writeAttribute('percent', $count === 0 ? '0' : sprintf('%01.2F', Percentage::fromFractionAndTotal($tested, $count)->asFloat())); + $this->xmlWriter->endElement(); + } + public function setNumTraits(int $count, int $tested): void + { + $this->xmlWriter->startElement('traits'); + $this->xmlWriter->writeAttribute('count', (string) $count); + $this->xmlWriter->writeAttribute('tested', (string) $tested); + $this->xmlWriter->writeAttribute('percent', $count === 0 ? '0' : sprintf('%01.2F', Percentage::fromFractionAndTotal($tested, $count)->asFloat())); + $this->xmlWriter->endElement(); + } + public function setNumMethods(int $count, int $tested): void + { + $this->xmlWriter->startElement('methods'); + $this->xmlWriter->writeAttribute('count', (string) $count); + $this->xmlWriter->writeAttribute('tested', (string) $tested); + $this->xmlWriter->writeAttribute('percent', $count === 0 ? '0' : sprintf('%01.2F', Percentage::fromFractionAndTotal($tested, $count)->asFloat())); + $this->xmlWriter->endElement(); + } + public function setNumFunctions(int $count, int $tested): void + { + $this->xmlWriter->startElement('functions'); + $this->xmlWriter->writeAttribute('count', (string) $count); + $this->xmlWriter->writeAttribute('tested', (string) $tested); + $this->xmlWriter->writeAttribute('percent', $count === 0 ? '0' : sprintf('%01.2F', Percentage::fromFractionAndTotal($tested, $count)->asFloat())); + $this->xmlWriter->endElement(); + } + public function getWriter(): XMLWriter + { + return $this->xmlWriter; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml; + +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\EnsuresUtf8; +use XMLWriter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Unit +{ + use EnsuresUtf8; + private XMLWriter $xmlWriter; + public function __construct(XMLWriter $xmlWriter, string $name, string $namespace, int $start, int $executable, int $executed, float $crap) + { + $this->xmlWriter = $xmlWriter; + $this->xmlWriter->writeAttribute('name', $this->ensureUtf8($name)); + $this->xmlWriter->writeAttribute('start', (string) $start); + $this->xmlWriter->writeAttribute('executable', (string) $executable); + $this->xmlWriter->writeAttribute('executed', (string) $executed); + $this->xmlWriter->writeAttribute('crap', (string) $crap); + $this->xmlWriter->startElement('namespace'); + $this->xmlWriter->writeAttribute('name', $this->ensureUtf8($namespace)); + $this->xmlWriter->endElement(); + } + public function addMethod(string $name, string $signature, string $start, ?string $end, string $executable, string $executed, string $coverage, string $crap): void + { + new Method($this->xmlWriter, $name, $signature, $start, $end, $executable, $executed, $coverage, $crap); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use function array_key_exists; +use function array_merge; +use function array_slice; +use DateTimeImmutable; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Version; +/** + * @phpstan-import-type SerializedCoverage from Serializer + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Merger +{ + /** + * @param list $paths + * + * @throws DriverMismatchException + * @throws EmptyPathListException + * @throws GitInformationMismatchException + * @throws MixedGitInformationException + * @throws RuntimeMismatchException + * + * @return SerializedCoverage + */ + public function merge(array $paths, bool $requireMatchingGitInformation = \true, bool $requireMatchingPhpVersion = \true, bool $requireMatchingCodeCoverageDriver = \true): array + { + if ($paths === []) { + throw new EmptyPathListException(); + } + $unserializer = new Unserializer(); + $first = $unserializer->unserialize($paths[0]); + $refRuntime = $first['buildInformation']['runtime']; + $refDriver = $first['buildInformation']['phpCodeCoverage']['driverInformation']; + $refHasGit = array_key_exists('git', $first['buildInformation']); + $refGit = $first['buildInformation']['git'] ?? null; + $mergedCoverage = clone $first['codeCoverage']; + $mergedTestResults = [$first['testResults']]; + foreach (array_slice($paths, 1) as $path) { + $item = $unserializer->unserialize($path); + $runtime = $item['buildInformation']['runtime']; + if ($requireMatchingPhpVersion) { + if ($runtime['name'] !== $refRuntime['name'] || $runtime['version'] !== $refRuntime['version']) { + throw new RuntimeMismatchException(); + } + } + if ($requireMatchingCodeCoverageDriver) { + $driver = $item['buildInformation']['phpCodeCoverage']['driverInformation']; + if ($driver['name'] !== $refDriver['name'] || $driver['version'] !== $refDriver['version']) { + throw new DriverMismatchException(); + } + } + if ($requireMatchingGitInformation) { + $hasGit = array_key_exists('git', $item['buildInformation']); + if ($hasGit !== $refHasGit) { + throw new MixedGitInformationException(); + } + if ($hasGit) { + $git = $item['buildInformation']['git']; + foreach (['originUrl', 'branch', 'commit', 'status'] as $field) { + if ($git[$field] !== $refGit[$field]) { + throw new GitInformationMismatchException($field, (string) $refGit[$field], (string) $git[$field]); + } + } + if ($git['isClean'] !== $refGit['isClean']) { + throw new GitInformationMismatchException('isClean', $refGit['isClean'] ? 'true' : 'false', $git['isClean'] ? 'true' : 'false'); + } + } + } + $mergedCoverage->merge($item['codeCoverage']); + $mergedTestResults[] = $item['testResults']; + } + $buildInformation = ['timestamp' => (new DateTimeImmutable())->format('D M j G:i:s T Y'), 'runtime' => $refRuntime, 'phpCodeCoverage' => ['version' => Version::id(), 'serializationFormat' => Serializer::SERIALIZATION_FORMAT, 'driverInformation' => $refDriver]]; + if ($refHasGit) { + $buildInformation['git'] = $refGit; + } + return ['buildInformation' => $buildInformation, 'basePath' => $first['basePath'], 'codeCoverage' => $mergedCoverage, 'testResults' => array_merge(...$mergedTestResults)]; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use const PHP_EOL; +use function preg_replace_callback; +use function serialize; +use function str_starts_with; +use DateTimeImmutable; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedCodeCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\PathReducer; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Version; +use PHPUnitPHAR\SebastianBergmann\Environment\Runtime; +use PHPUnitPHAR\SebastianBergmann\GitState\Builder as GitStateBuilder; +/** + * @phpstan-type SerializedCoverage array{ + * buildInformation: array{ + * timestamp: string, + * runtime: array{ + * name: string, + * version: string, + * vendorUrl: string, + * }, + * phpCodeCoverage: array{ + * version: string, + * serializationFormat: int, + * driverInformation: array{ + * name: non-empty-string, + * version: non-empty-string, + * }, + * }, + * git?: array{ + * originUrl: string, + * branch: string, + * commit: string, + * isClean: bool, + * status: string, + * }, + * }, + * basePath: string, + * codeCoverage: ProcessedCodeCoverageData, + * testResults: array, + * } + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Serializer +{ + public const int SERIALIZATION_FORMAT = 1; + /** + * @param non-empty-string $target + * + * @throws PharPrefixCouldNotBeStrippedException + */ + public function serialize(string $target, CodeCoverage $codeCoverage, bool $includeGitInformation = \false): void + { + $runtime = new Runtime(); + $buildInformation = ['timestamp' => (new DateTimeImmutable())->format('D M j G:i:s T Y'), 'runtime' => ['name' => $runtime->getName(), 'version' => $runtime->getVersion(), 'vendorUrl' => $runtime->getVendorUrl()], 'phpCodeCoverage' => ['version' => Version::id(), 'serializationFormat' => self::SERIALIZATION_FORMAT, 'driverInformation' => $codeCoverage->driverInformation()]]; + if ($includeGitInformation) { + $gitInformation = (new GitStateBuilder())->build(); + if ($gitInformation !== \false) { + $buildInformation['git'] = ['originUrl' => $gitInformation->originUrl(), 'branch' => $gitInformation->branch(), 'commit' => $gitInformation->commit(), 'isClean' => $gitInformation->isClean(), 'status' => $gitInformation->status()]; + } + } + $coverageData = clone $codeCoverage->getData(); + $basePath = (new PathReducer())->reduce($coverageData); + $data = ['buildInformation' => $buildInformation, 'basePath' => $basePath, 'codeCoverage' => $coverageData, 'testResults' => $codeCoverage->getTests()]; + $serializedData = serialize($data); + if (str_starts_with(self::class, 'PHPUnitPHAR\\')) { + // @codeCoverageIgnoreStart + $serializedData = $this->stripPharPrefix($serializedData); + // @codeCoverageIgnoreEnd + } + Filesystem::write($target, ' + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization; + +use function array_key_exists; +use function fclose; +use function fgets; +use function fopen; +use function is_array; +use function is_bool; +use function is_int; +use function is_string; +use function preg_match; +use function restore_error_handler; +use function set_error_handler; +use function trim; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedCodeCoverageData; +/** + * @phpstan-import-type SerializedCoverage from Serializer + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Unserializer +{ + /** + * @param non-empty-string $path + * + * @throws FileCouldNotBeReadException + * @throws InvalidCoverageDataException + * @throws VersionMismatchException + * + * @return SerializedCoverage + */ + public function unserialize(string $path): array + { + $file = @fopen($path, 'r'); + if ($file === \false) { + throw new FileCouldNotBeReadException('Cannot open file: ' . $path); + } + $firstLine = fgets($file); + fclose($file); + if ($firstLine === \false) { + throw new FileCouldNotBeReadException('Cannot read from file: ' . $path); + } + if (preg_match('/^<\?php \/\/ phpunit\/php-code-coverage serialization format (\d+)$/', trim($firstLine), $matches) !== 1) { + throw new FileCouldNotBeReadException('File does not contain phpunit/php-code-coverage serialization format information: ' . $path); + } + $storedFormat = (int) $matches[1]; + if ($storedFormat !== Serializer::SERIALIZATION_FORMAT) { + throw new VersionMismatchException($storedFormat, Serializer::SERIALIZATION_FORMAT); + } + set_error_handler(static function (int $errno, string $errstr) use ($path): never { + throw new InvalidCoverageDataException('Failed to unserialize coverage data from ' . $path . ': ' . $errstr); + }); + try { + $data = require $path; + } finally { + restore_error_handler(); + } + $this->validate($data); + return $data; + } + /** + * @throws InvalidCoverageDataException + */ + private function validate(mixed $data): void + { + if (!is_array($data)) { + throw new InvalidCoverageDataException('Coverage data is not an array'); + } + if (!array_key_exists('buildInformation', $data) || !is_array($data['buildInformation'])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'buildInformation\' key'); + } + $buildInformation = $data['buildInformation']; + if (!array_key_exists('timestamp', $buildInformation) || !is_string($buildInformation['timestamp'])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'buildInformation.timestamp\' key'); + } + if (!array_key_exists('runtime', $buildInformation) || !is_array($buildInformation['runtime'])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'buildInformation.runtime\' key'); + } + $runtime = $buildInformation['runtime']; + foreach (['name', 'version', 'vendorUrl'] as $key) { + if (!array_key_exists($key, $runtime) || !is_string($runtime[$key])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'buildInformation.runtime.' . $key . '\' key'); + } + } + if (!array_key_exists('phpCodeCoverage', $buildInformation) || !is_array($buildInformation['phpCodeCoverage'])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'buildInformation.phpCodeCoverage\' key'); + } + $phpCodeCoverage = $buildInformation['phpCodeCoverage']; + if (!array_key_exists('version', $phpCodeCoverage) || !is_string($phpCodeCoverage['version'])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'buildInformation.phpCodeCoverage.version\' key'); + } + if (!array_key_exists('serializationFormat', $phpCodeCoverage) || !is_int($phpCodeCoverage['serializationFormat'])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'buildInformation.phpCodeCoverage.serializationFormat\' key'); + } + if (!array_key_exists('driverInformation', $phpCodeCoverage) || !is_array($phpCodeCoverage['driverInformation'])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'buildInformation.phpCodeCoverage.driverInformation\' key'); + } + $driverInformation = $phpCodeCoverage['driverInformation']; + foreach (['name', 'version'] as $key) { + if (!array_key_exists($key, $driverInformation) || !is_string($driverInformation[$key]) || $driverInformation[$key] === '') { + throw new InvalidCoverageDataException('Coverage data is missing valid \'buildInformation.phpCodeCoverage.driverInformation.' . $key . '\' key'); + } + } + if (array_key_exists('git', $buildInformation)) { + if (!is_array($buildInformation['git'])) { + throw new InvalidCoverageDataException('Coverage data has invalid \'buildInformation.git\' key'); + } + $git = $buildInformation['git']; + foreach (['originUrl', 'branch', 'commit', 'status'] as $key) { + if (!array_key_exists($key, $git) || !is_string($git[$key])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'buildInformation.git.' . $key . '\' key'); + } + } + if (!array_key_exists('isClean', $git) || !is_bool($git['isClean'])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'buildInformation.git.isClean\' key'); + } + } + if (!array_key_exists('basePath', $data) || !is_string($data['basePath'])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'basePath\' key'); + } + if (!array_key_exists('codeCoverage', $data) || !$data['codeCoverage'] instanceof ProcessedCodeCoverageData) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'codeCoverage\' key'); + } + if (!array_key_exists('testResults', $data) || !is_array($data['testResults'])) { + throw new InvalidCoverageDataException('Coverage data is missing valid \'testResults\' key'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +use function file_get_contents; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Filter; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class CacheWarmer +{ + /** + * @return array{cacheHits: non-negative-int, cacheMisses: non-negative-int} + */ + public function warmCache(string $cacheDirectory, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode, Filter $filter): array + { + $analyser = new CachingSourceAnalyser($cacheDirectory, new ParsingSourceAnalyser()); + foreach ($filter->files() as $file) { + $analyser->analyse($file, file_get_contents($file), $useAnnotationsForIgnoringCode, $ignoreDeprecatedCode); + } + return ['cacheHits' => $analyser->cacheHits(), 'cacheMisses' => $analyser->cacheMisses()]; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +use const DIRECTORY_SEPARATOR; +use function file_get_contents; +use function file_put_contents; +use function hash; +use function implode; +use function is_file; +use function serialize; +use function unserialize; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Version; +/** + * @internal This interface is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class CachingSourceAnalyser implements SourceAnalyser +{ + /** + * @var non-empty-string + */ + private readonly string $directory; + private readonly SourceAnalyser $sourceAnalyser; + /** + * @var non-negative-int + */ + private int $cacheHits = 0; + /** + * @var non-negative-int + */ + private int $cacheMisses = 0; + public function __construct(string $directory, SourceAnalyser $sourceAnalyser) + { + Filesystem::createDirectory($directory); + $this->directory = $directory; + $this->sourceAnalyser = $sourceAnalyser; + } + /** + * @param non-empty-string $sourceCodeFile + */ + public function analyse(string $sourceCodeFile, string $sourceCode, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode): AnalysisResult + { + $cacheFile = $this->cacheFile($sourceCode, $useAnnotationsForIgnoringCode, $ignoreDeprecatedCode); + $cachedAnalysisResult = $this->read($cacheFile); + if ($cachedAnalysisResult !== \false) { + $this->cacheHits++; + return $cachedAnalysisResult; + } + $this->cacheMisses++; + $analysisResult = $this->sourceAnalyser->analyse($sourceCodeFile, $sourceCode, $useAnnotationsForIgnoringCode, $ignoreDeprecatedCode); + $this->write($cacheFile, $analysisResult); + return $analysisResult; + } + /** + * @return non-negative-int + */ + public function cacheHits(): int + { + return $this->cacheHits; + } + /** + * @return non-negative-int + */ + public function cacheMisses(): int + { + return $this->cacheMisses; + } + /** + * @param non-empty-string $cacheFile + */ + private function read(string $cacheFile): AnalysisResult|false + { + if (!is_file($cacheFile)) { + return \false; + } + $data = file_get_contents($cacheFile); + if ($data === \false) { + return \false; + } + return unserialize($data, ['allowed_classes' => [AnalysisResult::class, Class_::class, Function_::class, Interface_::class, LinesOfCode::class, Method::class, Trait_::class]]); + } + /** + * @param non-empty-string $cacheFile + */ + private function write(string $cacheFile, AnalysisResult $result): void + { + file_put_contents($cacheFile, serialize($result)); + } + private function cacheFile(string $source, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode): string + { + $cacheKey = hash('sha256', implode("\x00", [$source, Version::id(), $useAnnotationsForIgnoringCode, $ignoreDeprecatedCode])); + return $this->directory . DIRECTORY_SEPARATOR . $cacheKey; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +use function file_get_contents; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class FileAnalyser +{ + private readonly SourceAnalyser $sourceAnalyser; + private readonly bool $useAnnotationsForIgnoringCode; + private readonly bool $ignoreDeprecatedCode; + /** + * @var array + */ + private array $cache = []; + public function __construct(SourceAnalyser $sourceAnalyser, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode) + { + $this->sourceAnalyser = $sourceAnalyser; + $this->useAnnotationsForIgnoringCode = $useAnnotationsForIgnoringCode; + $this->ignoreDeprecatedCode = $ignoreDeprecatedCode; + } + /** + * @param non-empty-string $sourceCodeFile + */ + public function analyse(string $sourceCodeFile): AnalysisResult + { + if (isset($this->cache[$sourceCodeFile])) { + return $this->cache[$sourceCodeFile]; + } + $this->cache[$sourceCodeFile] = $this->sourceAnalyser->analyse($sourceCodeFile, file_get_contents($sourceCodeFile), $this->useAnnotationsForIgnoringCode, $this->ignoreDeprecatedCode); + return $this->cache[$sourceCodeFile]; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +use const T_COMMENT; +use const T_DOC_COMMENT; +use function array_merge; +use function array_unique; +use function assert; +use function is_array; +use function max; +use function range; +use function sort; +use function sprintf; +use function substr_count; +use function token_get_all; +use function trim; +use PHPUnitPHAR\PhpParser\Error; +use PHPUnitPHAR\PhpParser\NodeTraverser; +use PHPUnitPHAR\PhpParser\NodeVisitor\NameResolver; +use PHPUnitPHAR\PhpParser\ParserFactory; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\ParserException; +use PHPUnitPHAR\SebastianBergmann\LinesOfCode\LineCountingVisitor; +/** + * @internal This interface is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class ParsingSourceAnalyser implements SourceAnalyser +{ + /** + * @param non-empty-string $sourceCodeFile + */ + public function analyse(string $sourceCodeFile, string $sourceCode, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode): AnalysisResult + { + $linesOfCode = max(substr_count($sourceCode, "\n") + 1, substr_count($sourceCode, "\r") + 1); + assert($linesOfCode > 0); + $parser = (new ParserFactory())->createForHostVersion(); + try { + $nodes = $parser->parse($sourceCode); + assert($nodes !== null); + $traverser = new NodeTraverser(); + $codeUnitFindingVisitor = new CodeUnitFindingVisitor($sourceCodeFile); + $lineCountingVisitor = new LineCountingVisitor($linesOfCode); + $ignoredLinesFindingVisitor = new IgnoredLinesFindingVisitor($useAnnotationsForIgnoringCode, $ignoreDeprecatedCode); + $executableLinesFindingVisitor = new ExecutableLinesFindingVisitor($sourceCode); + $traverser->addVisitor(new NameResolver()); + $traverser->addVisitor(new AttributeParentConnectingVisitor()); + $traverser->addVisitor($codeUnitFindingVisitor); + $traverser->addVisitor($lineCountingVisitor); + $traverser->addVisitor($ignoredLinesFindingVisitor); + $traverser->addVisitor($executableLinesFindingVisitor); + /* @noinspection UnusedFunctionResultInspection */ + $traverser->traverse($nodes); + // @codeCoverageIgnoreStart + } catch (Error $error) { + throw new ParserException(sprintf('Cannot parse %s: %s', $sourceCodeFile, $error->getMessage()), $error->getCode(), $error); + } + // @codeCoverageIgnoreEnd + $ignoredLines = array_unique(array_merge($this->findLinesIgnoredByLineBasedAnnotations($sourceCodeFile, $sourceCode, $useAnnotationsForIgnoringCode), $ignoredLinesFindingVisitor->ignoredLines())); + sort($ignoredLines); + return new AnalysisResult($codeUnitFindingVisitor->interfaces(), $codeUnitFindingVisitor->classes(), $codeUnitFindingVisitor->traits(), $codeUnitFindingVisitor->functions(), new LinesOfCode($lineCountingVisitor->result()->linesOfCode(), $lineCountingVisitor->result()->commentLinesOfCode(), $lineCountingVisitor->result()->nonCommentLinesOfCode()), $executableLinesFindingVisitor->executableLinesGroupedByBranch(), $executableLinesFindingVisitor->branchOperatorLines(), $ignoredLines); + } + /** + * @return array + */ + private function findLinesIgnoredByLineBasedAnnotations(string $filename, string $source, bool $useAnnotationsForIgnoringCode): array + { + if (!$useAnnotationsForIgnoringCode) { + return []; + } + $result = []; + $start = \false; + foreach (token_get_all($source) as $token) { + if (!is_array($token) || !(T_COMMENT === $token[0] || T_DOC_COMMENT === $token[0])) { + continue; + } + $comment = trim($token[1]); + if ($comment === '// @codeCoverageIgnore' || $comment === '//@codeCoverageIgnore') { + $result[] = $token[2]; + continue; + } + if ($comment === '// @codeCoverageIgnoreStart' || $comment === '//@codeCoverageIgnoreStart') { + $start = $token[2]; + continue; + } + if ($comment === '// @codeCoverageIgnoreEnd' || $comment === '//@codeCoverageIgnoreEnd') { + if (\false === $start) { + $start = $token[2]; + } + $result = array_merge($result, range($start, $token[2])); + } + } + return $result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +/** + * @internal This interface is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +interface SourceAnalyser +{ + /** + * @param non-empty-string $sourceCodeFile + */ + public function analyse(string $sourceCodeFile, string $sourceCode, bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode): AnalysisResult; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +/** + * @phpstan-type LinesType array + * + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class AnalysisResult +{ + /** + * @var array + */ + private array $interfaces; + /** + * @var array + */ + private array $classes; + /** + * @var array + */ + private array $traits; + /** + * @var array + */ + private array $functions; + private LinesOfCode $linesOfCode; + /** + * @var LinesType + */ + private array $executableLines; + /** + * @var array + */ + private array $branchOperatorLines; + /** + * @var LinesType + */ + private array $ignoredLines; + /** + * @param array $interfaces + * @param array $classes + * @param array $traits + * @param array $functions + * @param LinesType $executableLines + * @param array $branchOperatorLines + * @param LinesType $ignoredLines + */ + public function __construct(array $interfaces, array $classes, array $traits, array $functions, LinesOfCode $linesOfCode, array $executableLines, array $branchOperatorLines, array $ignoredLines) + { + $this->interfaces = $interfaces; + $this->classes = $classes; + $this->traits = $traits; + $this->functions = $functions; + $this->linesOfCode = $linesOfCode; + $this->executableLines = $executableLines; + $this->branchOperatorLines = $branchOperatorLines; + $this->ignoredLines = $ignoredLines; + } + /** + * @return array + */ + public function interfaces(): array + { + return $this->interfaces; + } + /** + * @return array + */ + public function classes(): array + { + return $this->classes; + } + /** + * @return array + */ + public function traits(): array + { + return $this->traits; + } + /** + * @return array + */ + public function functions(): array + { + return $this->functions; + } + public function linesOfCode(): LinesOfCode + { + return $this->linesOfCode; + } + /** + * @return LinesType + */ + public function executableLines(): array + { + return $this->executableLines; + } + /** + * @return array + */ + public function branchOperatorLines(): array + { + return $this->branchOperatorLines; + } + /** + * @return LinesType + */ + public function ignoredLines(): array + { + return $this->ignoredLines; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Class_ +{ + /** + * @var non-empty-string + */ + private string $name; + /** + * @var non-empty-string + */ + private string $namespacedName; + private string $namespace; + /** + * @var non-empty-string + */ + private string $file; + /** + * @var non-negative-int + */ + private int $startLine; + /** + * @var non-negative-int + */ + private int $endLine; + /** + * @var ?non-empty-string + */ + private ?string $parentClass; + /** + * @var list + */ + private array $interfaces; + /** + * @var list + */ + private array $traits; + /** + * @var array + */ + private array $methods; + /** + * @param non-empty-string $name + * @param non-empty-string $namespacedName + * @param non-empty-string $file + * @param non-negative-int $startLine + * @param non-negative-int $endLine + * @param ?non-empty-string $parentClass + * @param list $interfaces + * @param list $traits + * @param array $methods + */ + public function __construct(string $name, string $namespacedName, string $namespace, string $file, int $startLine, int $endLine, ?string $parentClass, array $interfaces, array $traits, array $methods) + { + $this->name = $name; + $this->namespacedName = $namespacedName; + $this->namespace = $namespace; + $this->file = $file; + $this->startLine = $startLine; + $this->endLine = $endLine; + $this->parentClass = $parentClass; + $this->interfaces = $interfaces; + $this->traits = $traits; + $this->methods = $methods; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + /** + * @return non-empty-string + */ + public function namespacedName(): string + { + return $this->namespacedName; + } + public function isNamespaced(): bool + { + return $this->namespace !== ''; + } + public function namespace(): string + { + return $this->namespace; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @return non-negative-int + */ + public function startLine(): int + { + return $this->startLine; + } + /** + * @return non-negative-int + */ + public function endLine(): int + { + return $this->endLine; + } + public function hasParent(): bool + { + return $this->parentClass !== null; + } + /** + * @return ?non-empty-string + */ + public function parentClass(): ?string + { + return $this->parentClass; + } + /** + * @return list + */ + public function interfaces(): array + { + return $this->interfaces; + } + /** + * @return list + */ + public function traits(): array + { + return $this->traits; + } + /** + * @return array + */ + public function methods(): array + { + return $this->methods; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Function_ +{ + /** + * @var non-empty-string + */ + private string $name; + /** + * @var non-empty-string + */ + private string $namespacedName; + private string $namespace; + /** + * @var non-negative-int + */ + private int $startLine; + /** + * @var non-negative-int + */ + private int $endLine; + /** + * @var non-empty-string + */ + private string $signature; + /** + * @var positive-int + */ + private int $cyclomaticComplexity; + /** + * @param non-empty-string $name + * @param non-empty-string $namespacedName + * @param non-negative-int $startLine + * @param non-negative-int $endLine + * @param non-empty-string $signature + * @param positive-int $cyclomaticComplexity + */ + public function __construct(string $name, string $namespacedName, string $namespace, int $startLine, int $endLine, string $signature, int $cyclomaticComplexity) + { + $this->name = $name; + $this->namespacedName = $namespacedName; + $this->namespace = $namespace; + $this->startLine = $startLine; + $this->endLine = $endLine; + $this->signature = $signature; + $this->cyclomaticComplexity = $cyclomaticComplexity; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + /** + * @return non-empty-string + */ + public function namespacedName(): string + { + return $this->namespacedName; + } + public function isNamespaced(): bool + { + return $this->namespace !== ''; + } + public function namespace(): string + { + return $this->namespace; + } + /** + * @return non-negative-int + */ + public function startLine(): int + { + return $this->startLine; + } + /** + * @return non-negative-int + */ + public function endLine(): int + { + return $this->endLine; + } + /** + * @return non-empty-string + */ + public function signature(): string + { + return $this->signature; + } + /** + * @return positive-int + */ + public function cyclomaticComplexity(): int + { + return $this->cyclomaticComplexity; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Interface_ +{ + /** + * @var non-empty-string + */ + private string $name; + /** + * @var non-empty-string + */ + private string $namespacedName; + private string $namespace; + /** + * @var non-negative-int + */ + private int $startLine; + /** + * @var non-negative-int + */ + private int $endLine; + /** + * @var list + */ + private array $parentInterfaces; + /** + * @param non-empty-string $name + * @param non-empty-string $namespacedName + * @param non-negative-int $startLine + * @param non-negative-int $endLine + * @param list $parentInterfaces + */ + public function __construct(string $name, string $namespacedName, string $namespace, int $startLine, int $endLine, array $parentInterfaces) + { + $this->name = $name; + $this->namespacedName = $namespacedName; + $this->namespace = $namespace; + $this->startLine = $startLine; + $this->endLine = $endLine; + $this->parentInterfaces = $parentInterfaces; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + /** + * @return non-empty-string + */ + public function namespacedName(): string + { + return $this->namespacedName; + } + public function isNamespaced(): bool + { + return $this->namespace !== ''; + } + public function namespace(): string + { + return $this->namespace; + } + /** + * @return non-negative-int + */ + public function startLine(): int + { + return $this->startLine; + } + /** + * @return non-negative-int + */ + public function endLine(): int + { + return $this->endLine; + } + /** + * @return list + */ + public function parentInterfaces(): array + { + return $this->parentInterfaces; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class LinesOfCode +{ + /** + * @var non-negative-int + */ + private int $linesOfCode; + /** + * @var non-negative-int + */ + private int $commentLinesOfCode; + /** + * @var non-negative-int + */ + private int $nonCommentLinesOfCode; + /** + * @param non-negative-int $linesOfCode + * @param non-negative-int $commentLinesOfCode + * @param non-negative-int $nonCommentLinesOfCode + */ + public function __construct(int $linesOfCode, int $commentLinesOfCode, int $nonCommentLinesOfCode) + { + $this->linesOfCode = $linesOfCode; + $this->commentLinesOfCode = $commentLinesOfCode; + $this->nonCommentLinesOfCode = $nonCommentLinesOfCode; + } + /** + * @return non-negative-int + */ + public function linesOfCode(): int + { + return $this->linesOfCode; + } + /** + * @return non-negative-int + */ + public function commentLinesOfCode(): int + { + return $this->commentLinesOfCode; + } + /** + * @return non-negative-int + */ + public function nonCommentLinesOfCode(): int + { + return $this->nonCommentLinesOfCode; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Method +{ + /** + * @var non-empty-string + */ + private string $name; + /** + * @var non-negative-int + */ + private int $startLine; + /** + * @var non-negative-int + */ + private int $endLine; + private Visibility $visibility; + /** + * @var non-empty-string + */ + private string $signature; + /** + * @var positive-int + */ + private int $cyclomaticComplexity; + /** + * @param non-empty-string $name + * @param non-negative-int $startLine + * @param non-negative-int $endLine + * @param non-empty-string $signature + * @param positive-int $cyclomaticComplexity + */ + public function __construct(string $name, int $startLine, int $endLine, string $signature, Visibility $visibility, int $cyclomaticComplexity) + { + $this->name = $name; + $this->startLine = $startLine; + $this->endLine = $endLine; + $this->signature = $signature; + $this->visibility = $visibility; + $this->cyclomaticComplexity = $cyclomaticComplexity; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + /** + * @return non-negative-int + */ + public function startLine(): int + { + return $this->startLine; + } + /** + * @return non-negative-int + */ + public function endLine(): int + { + return $this->endLine; + } + /** + * @return non-empty-string + */ + public function signature(): string + { + return $this->signature; + } + public function visibility(): Visibility + { + return $this->visibility; + } + /** + * @return positive-int + */ + public function cyclomaticComplexity(): int + { + return $this->cyclomaticComplexity; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Trait_ +{ + /** + * @var non-empty-string + */ + private string $name; + /** + * @var non-empty-string + */ + private string $namespacedName; + private string $namespace; + /** + * @var non-empty-string + */ + private string $file; + /** + * @var non-negative-int + */ + private int $startLine; + /** + * @var non-negative-int + */ + private int $endLine; + /** + * @var list + */ + private array $traits; + /** + * @var array + */ + private array $methods; + /** + * @param non-empty-string $name + * @param non-empty-string $namespacedName + * @param non-empty-string $file + * @param non-negative-int $startLine + * @param non-negative-int $endLine + * @param list $traits + * @param array $methods + */ + public function __construct(string $name, string $namespacedName, string $namespace, string $file, int $startLine, int $endLine, array $traits, array $methods) + { + $this->name = $name; + $this->namespacedName = $namespacedName; + $this->namespace = $namespace; + $this->file = $file; + $this->startLine = $startLine; + $this->endLine = $endLine; + $this->traits = $traits; + $this->methods = $methods; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + /** + * @return non-empty-string + */ + public function namespacedName(): string + { + return $this->namespacedName; + } + public function isNamespaced(): bool + { + return $this->namespace !== ''; + } + public function namespace(): string + { + return $this->namespace; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @return non-negative-int + */ + public function startLine(): int + { + return $this->startLine; + } + /** + * @return non-negative-int + */ + public function endLine(): int + { + return $this->endLine; + } + /** + * @return list + */ + public function traits(): array + { + return $this->traits; + } + /** + * @return array + */ + public function methods(): array + { + return $this->methods; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +/** + * @internal This enumeration is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +enum Visibility : string +{ + case Public = 'public'; + case Protected = 'protected'; + case Private = 'private'; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +use function array_pop; +use function count; +use PHPUnitPHAR\PhpParser\Node; +use PHPUnitPHAR\PhpParser\NodeVisitor; +/** + * Visitor that connects a child node to its parent node optimized for Attribute nodes. + * + * On the child node, the parent node can be accessed through + * $node->getAttribute('parent'). + * + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class AttributeParentConnectingVisitor implements NodeVisitor +{ + /** + * @var Node[] + */ + private array $stack = []; + public function beforeTraverse(array $nodes): null + { + $this->stack = []; + return null; + } + public function enterNode(Node $node): null + { + if ($this->stack !== [] && ($node instanceof Node\Attribute || $node instanceof Node\AttributeGroup)) { + $node->setAttribute('parent', $this->stack[count($this->stack) - 1]); + } + $this->stack[] = $node; + return null; + } + public function leaveNode(Node $node): null + { + array_pop($this->stack); + return null; + } + public function afterTraverse(array $nodes): null + { + return null; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +use function assert; +use function implode; +use function rtrim; +use function trim; +use PHPUnitPHAR\PhpParser\Node; +use PHPUnitPHAR\PhpParser\Node\ComplexType; +use PHPUnitPHAR\PhpParser\Node\Identifier; +use PHPUnitPHAR\PhpParser\Node\IntersectionType; +use PHPUnitPHAR\PhpParser\Node\Name; +use PHPUnitPHAR\PhpParser\Node\NullableType; +use PHPUnitPHAR\PhpParser\Node\Stmt\Class_; +use PHPUnitPHAR\PhpParser\Node\Stmt\ClassMethod; +use PHPUnitPHAR\PhpParser\Node\Stmt\Enum_; +use PHPUnitPHAR\PhpParser\Node\Stmt\Function_; +use PHPUnitPHAR\PhpParser\Node\Stmt\Interface_; +use PHPUnitPHAR\PhpParser\Node\Stmt\Trait_; +use PHPUnitPHAR\PhpParser\Node\UnionType; +use PHPUnitPHAR\PhpParser\NodeTraverser; +use PHPUnitPHAR\PhpParser\NodeVisitorAbstract; +use PHPUnitPHAR\SebastianBergmann\Complexity\CyclomaticComplexityCalculatingVisitor; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class CodeUnitFindingVisitor extends NodeVisitorAbstract +{ + /** + * @var non-empty-string + */ + private string $file; + /** + * @var array + */ + private array $interfaces = []; + /** + * @var array + */ + private array $classes = []; + /** + * @var array + */ + private array $traits = []; + /** + * @var array + */ + private array $functions = []; + /** + * @param non-empty-string $file + */ + public function __construct(string $file) + { + $this->file = $file; + } + public function enterNode(Node $node): null + { + if ($node instanceof Interface_) { + $this->processInterface($node); + } + if ($node instanceof Class_) { + if ($node->isAnonymous()) { + return null; + } + $this->processClass($node); + } + if ($node instanceof Enum_) { + $this->processClass($node); + } + if ($node instanceof Trait_) { + $this->processTrait($node); + } + if (!$node instanceof Function_) { + return null; + } + $this->processFunction($node); + return null; + } + public function leaveNode(Node $node): null + { + if ($node instanceof Class_ && $node->isAnonymous()) { + return null; + } + if (!$node instanceof Class_ && !$node instanceof Enum_ && !$node instanceof Trait_) { + return null; + } + $traits = []; + foreach ($node->getTraitUses() as $traitUse) { + foreach ($traitUse->traits as $trait) { + $traits[] = $trait->toString(); + } + } + if ($traits === []) { + return null; + } + $this->postProcessClassOrTrait($node, $traits); + return null; + } + /** + * @return array + */ + public function interfaces(): array + { + return $this->interfaces; + } + /** + * @return array + */ + public function classes(): array + { + return $this->classes; + } + /** + * @return array + */ + public function traits(): array + { + return $this->traits; + } + /** + * @return array + */ + public function functions(): array + { + return $this->functions; + } + private function cyclomaticComplexity(ClassMethod|Function_ $node): int + { + $nodes = $node->getStmts(); + if ($nodes === null) { + return 0; + } + $traverser = new NodeTraverser(); + $cyclomaticComplexityCalculatingVisitor = new CyclomaticComplexityCalculatingVisitor(); + $traverser->addVisitor($cyclomaticComplexityCalculatingVisitor); + /* @noinspection UnusedFunctionResultInspection */ + $traverser->traverse($nodes); + return $cyclomaticComplexityCalculatingVisitor->cyclomaticComplexity(); + } + private function signature(ClassMethod|Function_ $node): string + { + $signature = ($node->returnsByRef() ? '&' : '') . $node->name->toString() . '('; + $parameters = []; + foreach ($node->getParams() as $parameter) { + assert(isset($parameter->var->name)); + $parameterAsString = ''; + if ($parameter->type !== null) { + $parameterAsString = $this->type($parameter->type) . ' '; + } + $parameterAsString .= '$' . $parameter->var->name; + /* @todo Handle default values */ + $parameters[] = $parameterAsString; + } + $signature .= implode(', ', $parameters) . ')'; + $returnType = $node->getReturnType(); + if ($returnType !== null) { + $signature .= ': ' . $this->type($returnType); + } + return $signature; + } + private function type(ComplexType|Identifier|Name $type): string + { + if ($type instanceof NullableType) { + return '?' . $type->type; + } + if ($type instanceof UnionType) { + return $this->unionTypeAsString($type); + } + if ($type instanceof IntersectionType) { + return $this->intersectionTypeAsString($type); + } + return $type->toString(); + } + private function visibility(ClassMethod $node): Visibility + { + if ($node->isPrivate()) { + return Visibility::Private; + } + if ($node->isProtected()) { + return Visibility::Protected; + } + return Visibility::Public; + } + private function processInterface(Interface_ $node): void + { + $name = $node->name->toString(); + $namespacedName = $node->namespacedName->toString(); + $parentInterfaces = []; + foreach ($node->extends as $parentInterface) { + $parentInterfaces[] = $parentInterface->toString(); + } + $this->interfaces[$namespacedName] = new \PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Interface_($name, $namespacedName, $this->namespace($namespacedName, $name), $this->startLine($node), $node->getEndLine(), $parentInterfaces); + } + private function processClass(Class_|Enum_ $node): void + { + $name = $node->name->toString(); + $namespacedName = $node->namespacedName->toString(); + $parentClass = null; + $interfaces = []; + if (!$node instanceof Enum_) { + if ($node->extends instanceof Name) { + $parentClass = $node->extends->toString(); + } + foreach ($node->implements as $interface) { + $interfaces[] = $interface->toString(); + } + } + $this->classes[$namespacedName] = new \PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Class_($name, $namespacedName, $this->namespace($namespacedName, $name), $this->file, $this->startLine($node), $node->getEndLine(), $parentClass, $interfaces, [], $this->processMethods($node->getMethods())); + } + private function processTrait(Trait_ $node): void + { + $name = $node->name->toString(); + $namespacedName = $node->namespacedName->toString(); + $this->traits[$namespacedName] = new \PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_($name, $namespacedName, $this->namespace($namespacedName, $name), $this->file, $this->startLine($node), $node->getEndLine(), [], $this->processMethods($node->getMethods())); + } + /** + * @param list $nodes + * + * @return array + */ + private function processMethods(array $nodes): array + { + $methods = []; + foreach ($nodes as $node) { + $methods[$node->name->toString()] = new Method($node->name->toString(), $this->startLine($node), $node->getEndLine(), $this->signature($node), $this->visibility($node), $this->cyclomaticComplexity($node)); + } + return $methods; + } + private function processFunction(Function_ $node): void + { + assert(isset($node->name)); + assert(isset($node->namespacedName)); + assert($node->namespacedName instanceof Name); + $name = $node->name->toString(); + $namespacedName = $node->namespacedName->toString(); + $this->functions[$namespacedName] = new \PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Function_($name, $namespacedName, $this->namespace($namespacedName, $name), $this->startLine($node), $node->getEndLine(), $this->signature($node), $this->cyclomaticComplexity($node)); + } + private function startLine(Class_|ClassMethod|Enum_|Function_|Interface_|Trait_ $node): int + { + return $node->name->getStartLine(); + } + private function namespace(string $namespacedName, string $name): string + { + return trim(rtrim($namespacedName, $name), '\\'); + } + private function unionTypeAsString(UnionType $node): string + { + $types = []; + foreach ($node->types as $type) { + if ($type instanceof IntersectionType) { + $types[] = '(' . $this->intersectionTypeAsString($type) . ')'; + continue; + } + $types[] = $this->typeAsString($type); + } + return implode('|', $types); + } + private function intersectionTypeAsString(IntersectionType $node): string + { + $types = []; + foreach ($node->types as $type) { + $types[] = $this->typeAsString($type); + } + return implode('&', $types); + } + private function typeAsString(Identifier|Name $node): string + { + if ($node instanceof Name) { + return $node->toCodeString(); + } + return $node->toString(); + } + /** + * @param list $traits + */ + private function postProcessClassOrTrait(Class_|Enum_|Trait_ $node, array $traits): void + { + $name = $node->namespacedName->toString(); + if ($node instanceof Class_ || $node instanceof Enum_) { + assert(isset($this->classes[$name])); + $this->classes[$name] = new \PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Class_($this->classes[$name]->name(), $this->classes[$name]->namespacedName(), $this->classes[$name]->namespace(), $this->classes[$name]->file(), $this->classes[$name]->startLine(), $this->classes[$name]->endLine(), $this->classes[$name]->parentClass(), $this->classes[$name]->interfaces(), $traits, $this->classes[$name]->methods()); + return; + } + assert(isset($this->traits[$name])); + $this->traits[$name] = new \PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_($this->traits[$name]->name(), $this->traits[$name]->namespacedName(), $this->traits[$name]->namespace(), $this->traits[$name]->file(), $this->traits[$name]->startLine(), $this->traits[$name]->endLine(), $traits, $this->traits[$name]->methods()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +use function array_diff_key; +use function array_intersect_key; +use function assert; +use function count; +use function current; +use function end; +use function explode; +use function max; +use function preg_match; +use function preg_quote; +use function range; +use function reset; +use function sprintf; +use function strtolower; +use PHPUnitPHAR\PhpParser\Node; +use PHPUnitPHAR\PhpParser\NodeVisitorAbstract; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type LinesType from AnalysisResult + */ +final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract +{ + private int $nextBranch = 0; + private readonly string $source; + /** + * @var LinesType + */ + private array $executableLinesGroupedByBranch = []; + /** + * @var array + */ + private array $branchOperatorLines = []; + /** + * @var array + */ + private array $unsets = []; + /** + * @var array + */ + private array $commentsToCheckForUnset = []; + private int $spreadDepth = 0; + public function __construct(string $source) + { + $this->source = $source; + } + public function enterNode(Node $node): null + { + if ($node instanceof Node\ArrayItem && $node->unpack) { + $this->spreadDepth++; + } + foreach ($node->getComments() as $comment) { + $commentLine = $comment->getStartLine(); + if (!isset($this->executableLinesGroupedByBranch[$commentLine])) { + continue; + } + foreach (explode("\n", $comment->getText()) as $text) { + $this->commentsToCheckForUnset[$commentLine] = $text; + $commentLine++; + } + } + if ($node instanceof Node\Scalar\String_ || $node instanceof Node\Scalar\EncapsedStringPart) { + $startLine = $node->getStartLine() + 1; + $endLine = $node->getEndLine() - 1; + if ($startLine <= $endLine) { + foreach (range($startLine, $endLine) as $line) { + unset($this->executableLinesGroupedByBranch[$line]); + } + } + return null; + } + if ($node instanceof Node\Stmt\Interface_ || $node instanceof Node\Attribute) { + foreach (range($node->getStartLine(), $node->getEndLine()) as $line) { + $this->unsets[$line] = \true; + } + return null; + } + if ($node instanceof Node\Stmt\Declare_ || $node instanceof Node\Stmt\DeclareDeclare || $node instanceof Node\Stmt\Else_ || $node instanceof Node\Stmt\EnumCase || $node instanceof Node\Stmt\Finally_ || $node instanceof Node\Stmt\GroupUse || $node instanceof Node\Stmt\Label || $node instanceof Node\Stmt\Namespace_ || $node instanceof Node\Stmt\Nop || $node instanceof Node\Stmt\Switch_ || $node instanceof Node\Stmt\TryCatch || $node instanceof Node\Stmt\Use_ || $node instanceof Node\Stmt\UseUse || $node instanceof Node\Expr\ConstFetch || $node instanceof Node\Expr\Variable || $node instanceof Node\Expr\Throw_ || $node instanceof Node\ComplexType || $node instanceof Node\Const_ || $node instanceof Node\Identifier || $node instanceof Node\Name || $node instanceof Node\Param || $node instanceof Node\Scalar) { + return null; + } + if ($node instanceof Node\Expr\Match_) { + foreach ($node->arms as $arm) { + $this->setLineBranch($arm->body->getStartLine(), $arm->body->getEndLine(), ++$this->nextBranch); + } + if ([] !== $node->arms) { + $firstArmLine = $node->arms[0]->getStartLine(); + $lastArmLine = $node->arms[count($node->arms) - 1]->getEndLine(); + if ($node->getStartLine() < $firstArmLine && $this->matchConditionHasNoOpcode($node->cond)) { + foreach (range($node->getStartLine(), $firstArmLine - 1) as $line) { + $this->unsets[$line] = \true; + } + } + if ($node->getEndLine() > $lastArmLine) { + foreach (range($lastArmLine + 1, $node->getEndLine()) as $line) { + $this->unsets[$line] = \true; + } + } + } + return null; + } + if ($node instanceof Node\Stmt\Expression && $node->expr instanceof Node\Expr\Throw_) { + $this->setLineBranch($node->expr->expr->getEndLine(), $node->expr->expr->getEndLine(), ++$this->nextBranch); + return null; + } + if ($node instanceof Node\Stmt\Expression && $this->isSideEffectFreeExpressionStatement($node)) { + return null; + } + if ($node instanceof Node\Stmt\Enum_ || $node instanceof Node\Stmt\Function_ || $node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\ClassMethod || $node instanceof Node\Expr\Closure || $node instanceof Node\Stmt\Trait_) { + if ($node instanceof Node\Stmt\ClassMethod && $node->isAbstract()) { + return null; + } + if ($node instanceof Node\Stmt\Function_ || $node instanceof Node\Stmt\ClassMethod) { + $unsets = []; + foreach ($node->getParams() as $param) { + foreach (range($param->getStartLine(), $param->getEndLine()) as $line) { + $unsets[$line] = \true; + } + } + unset($unsets[$node->getEndLine()]); + $this->unsets += $unsets; + } + $isConcreteClassLike = $node instanceof Node\Stmt\Enum_ || $node instanceof Node\Stmt\Class_ || $node instanceof Node\Stmt\Trait_; + if (null !== $node->stmts) { + foreach ($node->stmts as $stmt) { + if ($stmt instanceof Node\Stmt\Nop) { + continue; + } + foreach (range($stmt->getStartLine(), $stmt->getEndLine()) as $line) { + unset($this->executableLinesGroupedByBranch[$line], $this->branchOperatorLines[$line]); + if ($isConcreteClassLike && !$stmt instanceof Node\Stmt\ClassMethod) { + $this->unsets[$line] = \true; + } + } + } + } + if ($isConcreteClassLike) { + return null; + } + $hasEmptyBody = [] === $node->stmts || null === $node->stmts || 1 === count($node->stmts) && $node->stmts[0] instanceof Node\Stmt\Nop; + if ($hasEmptyBody) { + if ($node->getEndLine() === $node->getStartLine() && isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) { + return null; + } + $this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch); + return null; + } + return null; + } + if ($node instanceof Node\Expr\ArrowFunction) { + $startLine = max($node->getStartLine() + 1, $node->expr->getStartLine()); + $endLine = $node->expr->getEndLine(); + if ($endLine < $startLine) { + return null; + } + $this->setLineBranch($startLine, $endLine, ++$this->nextBranch); + return null; + } + if ($node instanceof Node\Expr\Ternary) { + if ($this->spreadDepth > 0) { + return null; + } + if (null !== $node->if && $node->getStartLine() !== $node->if->getEndLine()) { + $this->setLineBranch($node->if->getStartLine(), $node->if->getEndLine(), ++$this->nextBranch); + } + if ($node->getStartLine() !== $node->else->getEndLine()) { + $this->setLineBranch($node->else->getStartLine(), $node->else->getEndLine(), ++$this->nextBranch); + } + return null; + } + if ($node instanceof Node\Expr\BinaryOp\Coalesce) { + if ($node->getStartLine() !== $node->getEndLine()) { + $this->setLineBranch($node->getEndLine(), $node->getEndLine(), ++$this->nextBranch); + } + return null; + } + if ($node instanceof Node\Stmt\If_ || $node instanceof Node\Stmt\ElseIf_) { + $this->setLineBranch($node->cond->getStartLine(), $node->cond->getStartLine(), ++$this->nextBranch); + return null; + } + if ($node instanceof Node\Stmt\Case_) { + if (null === $node->cond) { + return null; + } + $line = $node->cond->getStartLine(); + $this->executableLinesGroupedByBranch[$line] = ++$this->nextBranch; + return null; + } + if ($node instanceof Node\Stmt\For_) { + $startLine = null; + $endLine = null; + if ([] !== $node->init) { + $startLine = $node->init[0]->getStartLine(); + end($node->init); + $endLine = current($node->init)->getEndLine(); + reset($node->init); + } + if ([] !== $node->cond) { + if (null === $startLine) { + $startLine = $node->cond[0]->getStartLine(); + } + end($node->cond); + $endLine = current($node->cond)->getEndLine(); + reset($node->cond); + } + if ([] !== $node->loop) { + if (null === $startLine) { + $startLine = $node->loop[0]->getStartLine(); + } + end($node->loop); + $endLine = current($node->loop)->getEndLine(); + reset($node->loop); + } + if (null === $startLine || null === $endLine) { + return null; + } + $this->setLineBranch($startLine, $endLine, ++$this->nextBranch); + return null; + } + if ($node instanceof Node\Stmt\Foreach_) { + $this->setLineBranch($node->expr->getStartLine(), $node->valueVar->getEndLine(), ++$this->nextBranch); + return null; + } + if ($node instanceof Node\Stmt\While_ || $node instanceof Node\Stmt\Do_) { + $this->setLineBranch($node->cond->getStartLine(), $node->cond->getEndLine(), ++$this->nextBranch); + return null; + } + if ($node instanceof Node\Stmt\Catch_) { + assert([] !== $node->types); + $startLine = $node->types[0]->getStartLine(); + end($node->types); + $endLine = current($node->types)->getEndLine(); + $this->setLineBranch($startLine, $endLine, ++$this->nextBranch); + return null; + } + if ($node instanceof Node\Expr\CallLike) { + if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) { + $branch = $this->executableLinesGroupedByBranch[$node->getStartLine()]; + } else { + $branch = ++$this->nextBranch; + } + $this->setLineBranch($node->getStartLine(), $node->getEndLine(), $branch); + return null; + } + if (isset($this->executableLinesGroupedByBranch[$node->getStartLine()])) { + return null; + } + $branch = ++$this->nextBranch; + foreach (range($node->getStartLine(), $node->getEndLine()) as $line) { + $this->executableLinesGroupedByBranch[$line] = $branch; + } + return null; + } + public function leaveNode(Node $node): null + { + if ($node instanceof Node\ArrayItem && $node->unpack) { + $this->spreadDepth--; + } + return null; + } + public function afterTraverse(array $nodes): null + { + $lines = explode("\n", $this->source); + foreach ($lines as $lineNumber => $line) { + $lineNumber++; + if (1 === preg_match('/^\s*$/', $line) || isset($this->commentsToCheckForUnset[$lineNumber]) && 1 === preg_match(sprintf('/^\s*%s\s*$/', preg_quote($this->commentsToCheckForUnset[$lineNumber], '/')), $line)) { + unset($this->executableLinesGroupedByBranch[$lineNumber]); + } + } + $this->executableLinesGroupedByBranch = array_diff_key($this->executableLinesGroupedByBranch, $this->unsets); + $this->branchOperatorLines = array_intersect_key($this->branchOperatorLines, $this->executableLinesGroupedByBranch); + return null; + } + /** + * @return LinesType + */ + public function executableLinesGroupedByBranch(): array + { + return $this->executableLinesGroupedByBranch; + } + /** + * @return array + */ + public function branchOperatorLines(): array + { + return $this->branchOperatorLines; + } + private function setLineBranch(int $start, int $end, int $branch): void + { + foreach (range($start, $end) as $line) { + $this->executableLinesGroupedByBranch[$line] = $branch; + $this->branchOperatorLines[$line] = \true; + } + } + private function matchConditionHasNoOpcode(Node\Expr $cond): bool + { + if (!$cond instanceof Node\Expr\ConstFetch) { + return \false; + } + $name = strtolower($cond->name->toString()); + return $name === 'true' || $name === 'false' || $name === 'null'; + } + /** + * A statement consisting solely of a literal scalar (`'foo';`, `42;`) or + * one of the named constants `true`, `false`, `null` produces no opcodes: + * the Zend compiler discards it as dead code, so the driver cannot report + * it as executed and the analyser must not record it as executable. + */ + private function isSideEffectFreeExpressionStatement(Node\Stmt\Expression $node): bool + { + $expr = $node->expr; + if ($expr instanceof Node\Scalar\String_ || $expr instanceof Node\Scalar\Int_ || $expr instanceof Node\Scalar\Float_) { + return \true; + } + if ($expr instanceof Node\Expr\ConstFetch) { + $name = strtolower($expr->name->toString()); + return $name === 'true' || $name === 'false' || $name === 'null'; + } + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis; + +use function assert; +use function str_contains; +use PHPUnitPHAR\PhpParser\Node; +use PHPUnitPHAR\PhpParser\Node\Attribute; +use PHPUnitPHAR\PhpParser\Node\Stmt\Class_; +use PHPUnitPHAR\PhpParser\Node\Stmt\ClassMethod; +use PHPUnitPHAR\PhpParser\Node\Stmt\Enum_; +use PHPUnitPHAR\PhpParser\Node\Stmt\Function_; +use PHPUnitPHAR\PhpParser\Node\Stmt\Interface_; +use PHPUnitPHAR\PhpParser\Node\Stmt\Trait_; +use PHPUnitPHAR\PhpParser\NodeVisitorAbstract; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class IgnoredLinesFindingVisitor extends NodeVisitorAbstract +{ + /** + * @var array + */ + private array $ignoredLines = []; + private readonly bool $useAnnotationsForIgnoringCode; + private readonly bool $ignoreDeprecated; + public function __construct(bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecated) + { + $this->useAnnotationsForIgnoringCode = $useAnnotationsForIgnoringCode; + $this->ignoreDeprecated = $ignoreDeprecated; + } + public function enterNode(Node $node): null + { + if (!$node instanceof Class_ && !$node instanceof Trait_ && !$node instanceof Interface_ && !$node instanceof Enum_ && !$node instanceof ClassMethod && !$node instanceof Function_ && !$node instanceof Attribute) { + return null; + } + if ($node instanceof Class_ && $node->isAnonymous()) { + return null; + } + if ($node instanceof Interface_) { + for ($line = $node->getStartLine(); $line <= $node->getEndLine(); $line++) { + $this->ignoredLines[] = $line; + } + return null; + } + if ($node instanceof Class_ || $node instanceof Trait_ || $node instanceof Attribute) { + $this->ignoredLines[] = $node->getStartLine(); + assert($node->name !== null); + // Workaround for https://github.com/nikic/PHP-Parser/issues/886 + $this->ignoredLines[] = $node->name->getStartLine(); + } + if (!$this->useAnnotationsForIgnoringCode) { + return null; + } + if ($node instanceof Attribute && $node->name->toString() === 'PHPUnit\Framework\Attributes\CodeCoverageIgnore') { + $attributeGroup = $node->getAttribute('parent'); + $attributedNode = $attributeGroup->getAttribute('parent'); + for ($line = $attributedNode->getStartLine(); $line <= $attributedNode->getEndLine(); $line++) { + $this->ignoredLines[] = $line; + } + return null; + } + $this->processDocComment($node); + return null; + } + /** + * @return array + */ + public function ignoredLines(): array + { + return $this->ignoredLines; + } + private function processDocComment(Node $node): void + { + $docComment = $node->getDocComment(); + if ($docComment === null) { + return; + } + if (str_contains($docComment->getText(), '@codeCoverageIgnore')) { + for ($line = $node->getStartLine(); $line <= $node->getEndLine(); $line++) { + $this->ignoredLines[] = $line; + } + } + if ($this->ignoreDeprecated && str_contains($docComment->getText(), '@deprecated')) { + for ($line = $node->getStartLine(); $line <= $node->getEndLine(); $line++) { + $this->ignoredLines[] = $line; + } + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Class_ extends Target +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + protected function __construct(string $className) + { + $this->className = $className; + } + public function isClass(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function key(): string + { + return 'classes'; + } + /** + * @return non-empty-string + */ + public function target(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function description(): string + { + return 'Class ' . $this->target(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class ClassesThatExtendClass extends Target +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + protected function __construct(string $className) + { + $this->className = $className; + } + public function isClassesThatExtendClass(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function key(): string + { + return 'classesThatExtendClass'; + } + /** + * @return non-empty-string + */ + public function target(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function description(): string + { + return 'Classes that extend class ' . $this->target(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class ClassesThatImplementInterface extends Target +{ + /** + * @var class-string + */ + private string $interfaceName; + /** + * @param class-string $interfaceName + */ + protected function __construct(string $interfaceName) + { + $this->interfaceName = $interfaceName; + } + public function isClassesThatImplementInterface(): true + { + return \true; + } + /** + * @return class-string + */ + public function interfaceName(): string + { + return $this->interfaceName; + } + /** + * @return non-empty-string + */ + public function key(): string + { + return 'classesThatImplementInterface'; + } + /** + * @return non-empty-string + */ + public function target(): string + { + return $this->interfaceName; + } + /** + * @return non-empty-string + */ + public function description(): string + { + return 'Classes that implement interface ' . $this->target(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Function_ extends Target +{ + /** + * @var non-empty-string + */ + private string $functionName; + /** + * @param non-empty-string $functionName + */ + protected function __construct(string $functionName) + { + $this->functionName = $functionName; + } + public function isFunction(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } + /** + * @return non-empty-string + */ + public function key(): string + { + return 'functions'; + } + /** + * @return non-empty-string + */ + public function target(): string + { + return $this->functionName; + } + /** + * @return non-empty-string + */ + public function description(): string + { + return 'Function ' . $this->target(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +use function array_keys; +use function array_merge; +use function array_slice; +use function array_unique; +use function count; +use function explode; +use function implode; +use function range; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Filter; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Class_; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\Trait_; +/** + * @phpstan-import-type TargetMap from Mapper + * @phpstan-import-type TargetMapPart from Mapper + * @phpstan-import-type ReverseLookup from Mapper + * + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class MapBuilder +{ + /** + * @return TargetMap + */ + public function build(Filter $filter, FileAnalyser $analyser): array + { + /** + * @var array $classDetails + */ + $classDetails = []; + $namespaces = []; + $classes = []; + $classesThatExtendClass = []; + $classesThatImplementInterface = []; + $traits = []; + $methods = []; + $functions = []; + $reverseLookup = []; + foreach ($filter->files() as $file) { + foreach ($analyser->analyse($file)->traits() as $trait) { + if ($trait->isNamespaced()) { + $this->processNamespace($namespaces, $trait->namespace(), $file, $trait->startLine(), $trait->endLine()); + } + $this->process($traits, $trait->namespacedName(), $file, $trait->startLine(), $trait->endLine()); + $this->processMethods($trait, $file, $methods, $reverseLookup); + } + } + foreach ($filter->files() as $file) { + foreach ($analyser->analyse($file)->traits() as $trait) { + foreach ($trait->traits() as $traitName) { + if (!isset($traits[$traitName])) { + continue; + } + $this->mergeLines($trait->namespacedName(), $traits[$traitName], $traits); + } + } + } + foreach ($filter->files() as $file) { + $analysisResult = $analyser->analyse($file); + foreach ($analysisResult->interfaces() as $interface) { + $classesThatImplementInterface[$interface->namespacedName()] = []; + } + foreach ($analysisResult->classes() as $class) { + if ($class->isNamespaced()) { + $this->processNamespace($namespaces, $class->namespace(), $file, $class->startLine(), $class->endLine()); + } + $this->process($classes, $class->namespacedName(), $file, $class->startLine(), $class->endLine()); + foreach ($class->traits() as $traitName) { + if (!isset($traits[$traitName])) { + continue; + } + $this->mergeLines($class->namespacedName(), $traits[$traitName], $classes); + } + $this->processMethods($class, $file, $methods, $reverseLookup); + $classesThatExtendClass[$class->namespacedName()] = []; + $classDetails[$class->namespacedName()] = $class; + } + foreach ($analysisResult->functions() as $function) { + if ($function->isNamespaced()) { + $this->processNamespace($namespaces, $function->namespace(), $file, $function->startLine(), $function->endLine()); + } + $this->process($functions, $function->namespacedName(), $file, $function->startLine(), $function->endLine()); + foreach (range($function->startLine(), $function->endLine()) as $line) { + $reverseLookup[$file . ':' . $line] = $function->namespacedName(); + } + } + } + foreach ($namespaces as $namespace => $files) { + foreach (array_keys($files) as $file) { + $namespaces[$namespace][$file] = array_unique($namespaces[$namespace][$file]); + } + } + foreach ($classDetails as $class) { + foreach ($class->interfaces() as $interfaceName) { + if (!isset($classesThatImplementInterface[$interfaceName])) { + continue; + } + $this->process($classesThatImplementInterface, $interfaceName, $class->file(), $class->startLine(), $class->endLine()); + } + foreach ($this->parentClasses($classDetails, $class) as $parentClass) { + $this->mergeLines($class->namespacedName(), $classes[$parentClass->namespacedName()], $classes); + if (isset($classesThatExtendClass[$parentClass->namespacedName()])) { + $this->process($classesThatExtendClass, $parentClass->namespacedName(), $class->file(), $class->startLine(), $class->endLine()); + } + } + } + foreach (array_keys($classesThatImplementInterface) as $className) { + if ($classesThatImplementInterface[$className] !== []) { + continue; + } + unset($classesThatImplementInterface[$className]); + } + foreach (array_keys($classesThatExtendClass) as $className) { + if ($classesThatExtendClass[$className] !== []) { + continue; + } + unset($classesThatExtendClass[$className]); + } + return ['namespaces' => $namespaces, 'traits' => $traits, 'classes' => $classes, 'classesThatExtendClass' => $classesThatExtendClass, 'classesThatImplementInterface' => $classesThatImplementInterface, 'methods' => $methods, 'functions' => $functions, 'reverseLookup' => $reverseLookup]; + } + /** + * @param array> $sourceData + * @param array>> $data + */ + private function mergeLines(string $targetClass, array $sourceData, array &$data): void + { + /** + * In large inheritance trees we might handle a lot of data. + * This loop needs to prevent unnecessary work whenever possible. + */ + foreach ($sourceData as $file => $lines) { + if (!isset($data[$targetClass][$file])) { + $data[$targetClass][$file] = $lines; + continue; + } + if ($data[$targetClass][$file] === $lines) { + continue; + } + $data[$targetClass][$file] = array_unique(array_merge($data[$targetClass][$file], $lines)); + } + } + /** + * @param TargetMapPart $methods + * @param ReverseLookup $reverseLookup + * + * @param-out TargetMapPart $methods + * @param-out ReverseLookup $reverseLookup + */ + private function processMethods(Class_|Trait_ $classOrTrait, string $file, array &$methods, array &$reverseLookup): void + { + foreach ($classOrTrait->methods() as $method) { + $methodName = $classOrTrait->namespacedName() . '::' . $method->name(); + $this->process($methods, $methodName, $file, $method->startLine(), $method->endLine()); + foreach (range($method->startLine(), $method->endLine()) as $line) { + $reverseLookup[$file . ':' . $line] = $methodName; + } + } + } + /** + * @param TargetMapPart $data + * @param non-empty-string $namespace + * @param non-empty-string $file + * @param positive-int $startLine + * @param positive-int $endLine + * + * @param-out TargetMapPart $data + */ + private function processNamespace(array &$data, string $namespace, string $file, int $startLine, int $endLine): void + { + $parts = explode('\\', $namespace); + foreach (range(1, count($parts)) as $i) { + $this->process($data, implode('\\', array_slice($parts, 0, $i)), $file, $startLine, $endLine); + } + } + /** + * @param TargetMapPart $data + * @param non-empty-string $unit + * @param non-empty-string $file + * @param positive-int $startLine + * @param positive-int $endLine + * + * @param-out TargetMapPart $data + */ + private function process(array &$data, string $unit, string $file, int $startLine, int $endLine): void + { + if (!isset($data[$unit])) { + $data[$unit] = []; + } + if (!isset($data[$unit][$file])) { + $data[$unit][$file] = []; + } + $data[$unit][$file] = array_merge($data[$unit][$file], range($startLine, $endLine)); + } + /** + * @param array $classDetails + * + * @return array + */ + private function parentClasses(array $classDetails, Class_ $class): array + { + if (!$class->hasParent()) { + return []; + } + if (!isset($classDetails[$class->parentClass()])) { + return []; + } + return array_merge([$classDetails[$class->parentClass()]], $this->parentClasses($classDetails, $classDetails[$class->parentClass()])); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +use function array_keys; +use function array_merge; +use function array_unique; +use function strcasecmp; +/** + * @phpstan-type TargetMap array{namespaces: TargetMapPart, traits: TargetMapPart, classes: TargetMapPart, classesThatExtendClass: TargetMapPart, classesThatImplementInterface: TargetMapPart, methods: TargetMapPart, functions: TargetMapPart, reverseLookup: ReverseLookup} + * @phpstan-type TargetMapPart array>> + * @phpstan-type ReverseLookup array + * + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Mapper +{ + /** + * @var TargetMap + */ + private array $map; + /** + * @param TargetMap $map + */ + public function __construct(array $map) + { + $this->map = $map; + } + /** + * @return array> + */ + public function mapTargets(TargetCollection $targets): array + { + $result = []; + foreach ($targets as $target) { + foreach ($this->mapTarget($target) as $file => $lines) { + if (!isset($result[$file])) { + $result[$file] = $lines; + continue; + } + $result[$file] = array_unique(array_merge($result[$file], $lines)); + } + } + return $result; + } + /** + * @throws InvalidCodeCoverageTargetException + * + * @return array> + */ + public function mapTarget(Target $target): array + { + if (isset($this->map[$target->key()][$target->target()])) { + return $this->map[$target->key()][$target->target()]; + } + foreach (array_keys($this->map[$target->key()]) as $key) { + if (strcasecmp($key, $target->target()) === 0) { + return $this->map[$target->key()][$key]; + } + } + throw new InvalidCodeCoverageTargetException($target); + } + /** + * @param non-empty-string $file + * @param positive-int $line + * + * @return non-empty-string + */ + public function lookup(string $file, int $line): string + { + $key = $file . ':' . $line; + if (isset($this->map['reverseLookup'][$key])) { + return $this->map['reverseLookup'][$key]; + } + return $key; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Method extends Target +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + public function isMethod(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + /** + * @return non-empty-string + */ + public function key(): string + { + return 'methods'; + } + /** + * @return non-empty-string + */ + public function target(): string + { + return $this->className . '::' . $this->methodName; + } + /** + * @return non-empty-string + */ + public function description(): string + { + return 'Method ' . $this->target(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Namespace_ extends Target +{ + /** + * @var non-empty-string + */ + private string $namespace; + /** + * @param non-empty-string $namespace + */ + protected function __construct(string $namespace) + { + $this->namespace = $namespace; + } + public function isNamespace(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function namespace(): string + { + return $this->namespace; + } + /** + * @return non-empty-string + */ + public function key(): string + { + return 'namespaces'; + } + /** + * @return non-empty-string + */ + public function target(): string + { + return $this->namespace; + } + /** + * @return non-empty-string + */ + public function description(): string + { + return 'Namespace ' . $this->target(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +abstract class Target +{ + /** + * @param non-empty-string $namespace + */ + public static function forNamespace(string $namespace): Namespace_ + { + return new Namespace_($namespace); + } + /** + * @param class-string $className + */ + public static function forClass(string $className): Class_ + { + return new Class_($className); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function forMethod(string $className, string $methodName): Method + { + return new Method($className, $methodName); + } + /** + * @param class-string $interfaceName + */ + public static function forClassesThatImplementInterface(string $interfaceName): ClassesThatImplementInterface + { + return new ClassesThatImplementInterface($interfaceName); + } + /** + * @param class-string $className + */ + public static function forClassesThatExtendClass(string $className): ClassesThatExtendClass + { + return new ClassesThatExtendClass($className); + } + /** + * @param non-empty-string $functionName + */ + public static function forFunction(string $functionName): Function_ + { + return new Function_($functionName); + } + /** + * @param trait-string $traitName + */ + public static function forTrait(string $traitName): Trait_ + { + return new Trait_($traitName); + } + public function isNamespace(): bool + { + return \false; + } + public function isClass(): bool + { + return \false; + } + public function isMethod(): bool + { + return \false; + } + public function isClassesThatImplementInterface(): bool + { + return \false; + } + public function isClassesThatExtendClass(): bool + { + return \false; + } + public function isFunction(): bool + { + return \false; + } + public function isTrait(): bool + { + return \false; + } + /** + * @return non-empty-string + */ + abstract public function key(): string; + /** + * @return non-empty-string + */ + abstract public function target(): string; + /** + * @return non-empty-string + */ + abstract public function description(): string; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @template-implements IteratorAggregate + * + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class TargetCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $targets; + /** + * @param list $targets + */ + public static function fromArray(array $targets): self + { + return new self(...$targets); + } + private function __construct(Target ...$targets) + { + $this->targets = $targets; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->targets; + } + public function count(): int + { + return count($this->targets); + } + public function isEmpty(): bool + { + return $this->count() === 0; + } + public function isNotEmpty(): bool + { + return $this->count() > 0; + } + public function getIterator(): TargetCollectionIterator + { + return new TargetCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +use function count; +use Iterator; +/** + * @template-implements Iterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class TargetCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $targets; + private int $position = 0; + public function __construct(TargetCollection $metadata) + { + $this->targets = $metadata->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return $this->position < count($this->targets); + } + public function key(): int + { + return $this->position; + } + public function current(): Target + { + return $this->targets[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +use function implode; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class TargetCollectionValidator +{ + public function validate(Mapper $mapper, TargetCollection $targets): ValidationResult + { + $errors = []; + foreach ($targets as $target) { + try { + $mapper->mapTarget($target); + } catch (InvalidCodeCoverageTargetException $e) { + $errors[] = $e->getMessage(); + } + } + if ($errors === []) { + return ValidationResult::success(); + } + return ValidationResult::failure(implode("\n", $errors)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Trait_ extends Target +{ + /** + * @var trait-string + */ + private string $traitName; + /** + * @param trait-string $traitName + */ + protected function __construct(string $traitName) + { + $this->traitName = $traitName; + } + public function isTrait(): true + { + return \true; + } + /** + * @return trait-string + */ + public function traitName(): string + { + return $this->traitName; + } + /** + * @return non-empty-string + */ + public function key(): string + { + return 'traits'; + } + /** + * @return non-empty-string + */ + public function target(): string + { + return $this->traitName; + } + /** + * @return non-empty-string + */ + public function description(): string + { + return 'Trait ' . $this->target(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class ValidationFailure extends ValidationResult +{ + /** + * @var non-empty-string + */ + private string $message; + /** + * @param non-empty-string $message + * + * @noinspection PhpMissingParentConstructorInspection + */ + protected function __construct(string $message) + { + $this->message = $message; + } + public function isFailure(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +abstract readonly class ValidationResult +{ + public static function success(): ValidationSuccess + { + return new ValidationSuccess(); + } + /** + * @param non-empty-string $message + */ + public static function failure(string $message): ValidationFailure + { + return new ValidationFailure($message); + } + /** + * @phpstan-assert-if-true ValidationSuccess $this + */ + public function isSuccess(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true ValidationFailure $this + */ + public function isFailure(): bool + { + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class ValidationSuccess extends ValidationResult +{ + public function isSuccess(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +enum TestSize : string +{ + public function isKnown(): bool + { + return $this !== self::Unknown; + } + public function isUnknown(): bool + { + return $this === self::Unknown; + } + public function isSmall(): bool + { + return $this === self::Small; + } + public function isMedium(): bool + { + return $this === self::Medium; + } + public function isLarge(): bool + { + return $this === self::Large; + } + public function isGreaterThan(self $other): bool + { + return $this->order() > $other->order(); + } + public function asString(): string + { + return $this->value; + } + private function order(): int + { + return match ($this) { + self::Unknown => -1, + self::Small => 0, + self::Medium => 1, + self::Large => 2, + }; + } + case Unknown = 'unknown'; + case Small = 'small'; + case Medium = 'medium'; + case Large = 'large'; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +enum TestStatus : string +{ + public function isKnown(): bool + { + return $this !== self::Unknown; + } + public function isUnknown(): bool + { + return $this === self::Unknown; + } + public function isSuccess(): bool + { + return $this === self::Success; + } + public function isFailure(): bool + { + return $this === self::Failure; + } + public function asString(): string + { + return $this->value; + } + case Unknown = 'unknown'; + case Success = 'success'; + case Failure = 'failure'; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use function array_flip; +use function array_keys; +use function array_merge; +use function array_unique; +use function count; +use function explode; +use function sort; +use ReflectionClass; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\Mapper; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\Method; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\TargetCollection; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @phpstan-import-type TargetedLines from CodeCoverage + */ +final readonly class UnintentionallyCoveredCodeChecker +{ + /** + * @param TargetedLines $linesToBeCovered + * @param TargetedLines $linesToBeUsed + * @param list $parentClassesExcludedFromCheck + * + * @throws ReflectionException + * @throws UnintentionallyCoveredCodeException + */ + public function check(RawCodeCoverageData $data, array $linesToBeCovered, array $linesToBeUsed, Mapper $targetMapper, array $parentClassesExcludedFromCheck, TargetCollection $covers, TargetCollection $uses): true + { + $allowedLines = $this->allowedLines($linesToBeCovered, $linesToBeUsed); + $unintentionallyCoveredUnits = []; + foreach ($data->lineCoverage() as $file => $_data) { + foreach ($_data as $line => $flag) { + if ($flag === 1 && !isset($allowedLines[$file][$line])) { + $unintentionallyCoveredUnits[] = $targetMapper->lookup($file, $line); + } + } + } + $unintentionallyCoveredUnits = $this->process($unintentionallyCoveredUnits, $parentClassesExcludedFromCheck, $this->hasMethodLevelTargets($covers, $uses)); + if ($unintentionallyCoveredUnits !== []) { + throw new UnintentionallyCoveredCodeException($unintentionallyCoveredUnits); + } + return \true; + } + /** + * @param list $unintentionallyCoveredUnits + * @param list $parentClassesExcludedFromCheck + * + * @throws ReflectionException + * + * @return list + */ + public function process(array $unintentionallyCoveredUnits, array $parentClassesExcludedFromCheck, bool $methodLevelReporting = \false): array + { + $unintentionallyCoveredUnits = array_unique($unintentionallyCoveredUnits); + $processed = []; + foreach ($unintentionallyCoveredUnits as $unintentionallyCoveredUnit) { + $tmp = explode('::', $unintentionallyCoveredUnit); + if (count($tmp) !== 2) { + $processed[] = $unintentionallyCoveredUnit; + continue; + } + try { + $class = new ReflectionClass($tmp[0]); + foreach ($parentClassesExcludedFromCheck as $parentClass) { + if ($class->isSubclassOf($parentClass)) { + continue 2; + } + } + } catch (\ReflectionException $e) { + throw new ReflectionException($e->getMessage(), $e->getCode(), $e); + } + if ($methodLevelReporting) { + $processed[] = $unintentionallyCoveredUnit; + } else { + $processed[] = $tmp[0]; + } + } + $processed = array_unique($processed); + sort($processed); + return $processed; + } + /** + * @param TargetedLines $linesToBeCovered + * @param TargetedLines $linesToBeUsed + * + * @return TargetedLines + */ + public function allowedLines(array $linesToBeCovered, array $linesToBeUsed): array + { + $allowedLines = []; + foreach (array_keys($linesToBeCovered) as $file) { + if (!isset($allowedLines[$file])) { + $allowedLines[$file] = []; + } + $allowedLines[$file] = array_merge($allowedLines[$file], $linesToBeCovered[$file]); + } + foreach (array_keys($linesToBeUsed) as $file) { + if (!isset($allowedLines[$file])) { + $allowedLines[$file] = []; + } + $allowedLines[$file] = array_merge($allowedLines[$file], $linesToBeUsed[$file]); + } + foreach (array_keys($allowedLines) as $file) { + $allowedLines[$file] = array_flip(array_unique($allowedLines[$file])); + } + return $allowedLines; + } + private function hasMethodLevelTargets(TargetCollection $covers, TargetCollection $uses): bool + { + foreach ([$covers, $uses] as $targets) { + foreach ($targets as $target) { + if ($target instanceof Method) { + return \true; + } + } + } + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util; + +use function assert; +use function mb_check_encoding; +use function mb_convert_encoding; +use function mb_detect_encoding; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +trait EnsuresUtf8 +{ + private function ensureUtf8(string $value): string + { + if (mb_check_encoding($value, 'UTF-8')) { + return $value; + } + $encoding = mb_detect_encoding($value, ['Windows-1252', 'ISO-8859-1'], \true); + assert($encoding !== \false); + return mb_convert_encoding($value, 'UTF-8', $encoding); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util; + +use function dirname; +use function file_put_contents; +use function is_dir; +use function mkdir; +use function sprintf; +use function str_contains; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\WriteOperationFailedException; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Filesystem +{ + /** + * @throws DirectoryCouldNotBeCreatedException + */ + public static function createDirectory(string $directory): void + { + $success = !(!is_dir($directory) && !@mkdir($directory, 0777, \true) && !is_dir($directory)); + if (!$success) { + throw new DirectoryCouldNotBeCreatedException(sprintf('Directory "%s" could not be created', $directory)); + } + } + /** + * @param non-empty-string $target + * + * @throws WriteOperationFailedException + */ + public static function write(string $target, string $buffer): void + { + if (!str_contains($target, '://')) { + self::createDirectory(dirname($target)); + } + if (@file_put_contents($target, $buffer) === \false) { + throw new WriteOperationFailedException($target); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util; + +use const DIRECTORY_SEPARATOR; +use function array_shift; +use function basename; +use function count; +use function dirname; +use function explode; +use function implode; +use function str_replace; +use function str_starts_with; +use function substr; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedCodeCoverageData; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class PathReducer +{ + /** + * Reduces the paths by cutting the longest common start path, renames the + * files in the coverage data accordingly, and returns the common path. + * + * Returns an empty string when there are no covered files. + */ + public function reduce(ProcessedCodeCoverageData $data): string + { + $coveredFiles = $data->coveredFiles(); + if ($coveredFiles === []) { + return ''; + } + if (count($coveredFiles) === 1) { + $file = $coveredFiles[0]; + $normalised = $file; + if (str_starts_with($file, 'phar://')) { + $normalised = str_replace('/', DIRECTORY_SEPARATOR, substr($file, 7)); + } + $data->renameFile($file, basename($normalised)); + return dirname($normalised); + } + $original = $coveredFiles; + $paths = $coveredFiles; + $max = count($paths); + for ($i = 0; $i < $max; $i++) { + if (str_starts_with($paths[$i], 'phar://')) { + $paths[$i] = substr($paths[$i], 7); + $paths[$i] = str_replace('/', DIRECTORY_SEPARATOR, $paths[$i]); + } + $paths[$i] = explode(DIRECTORY_SEPARATOR, $paths[$i]); + if ($paths[$i][0] === '') { + $paths[$i][0] = DIRECTORY_SEPARATOR; + } + } + $commonPath = ''; + $done = \false; + while (!$done) { + for ($i = 0; $i < $max - 1; $i++) { + if (!isset($paths[$i][0]) || !isset($paths[$i + 1][0]) || $paths[$i][0] !== $paths[$i + 1][0]) { + $done = \true; + break; + } + } + if (!$done) { + $commonPath .= $paths[0][0]; + if ($paths[0][0] !== DIRECTORY_SEPARATOR) { + $commonPath .= DIRECTORY_SEPARATOR; + } + for ($i = 0; $i < $max; $i++) { + array_shift($paths[$i]); + } + } + } + for ($i = 0; $i < $max; $i++) { + $newPath = implode(DIRECTORY_SEPARATOR, $paths[$i]); + if ($newPath !== $original[$i]) { + $data->renameFile($original[$i], $newPath); + } + } + return substr($commonPath, 0, -1); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util; + +use function sprintf; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Percentage +{ + private float $fraction; + private float $total; + public static function fromFractionAndTotal(float $fraction, float $total): self + { + return new self($fraction, $total); + } + private function __construct(float $fraction, float $total) + { + $this->fraction = $fraction; + $this->total = $total; + } + public function asFloat(): float + { + if ($this->total > 0) { + return $this->fraction / $this->total * 100; + } + return 100.0; + } + public function asString(): string + { + if ($this->total > 0) { + return sprintf('%01.2F%%', $this->asFloat()); + } + return ''; + } + public function asFixedWidthString(): string + { + if ($this->total > 0) { + return sprintf('%6.2F%%', $this->asFloat()); + } + return ''; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util; + +use const PHP_EOL; +use function libxml_clear_errors; +use function libxml_get_errors; +use function libxml_use_internal_errors; +use DOMDocument; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\XmlException; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final readonly class Xml +{ + /** + * @throws XmlException + * + * @see https://bugs.php.net/bug.php?id=79191 + */ + public static function asString(DOMDocument $document): string + { + $xmlErrorHandling = libxml_use_internal_errors(\true); + $document->formatOutput = \true; + $document->preserveWhiteSpace = \false; + $buffer = $document->saveXML(); + if ($buffer === \false) { + // @codeCoverageIgnoreStart + $message = 'Unable to generate the XML'; + foreach (libxml_get_errors() as $error) { + $message .= PHP_EOL . $error->message; + } + throw new XmlException($message); + // @codeCoverageIgnoreEnd + } + libxml_clear_errors(); + libxml_use_internal_errors($xmlErrorHandling); + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage; + +use function dirname; +use PHPUnitPHAR\SebastianBergmann\Version as VersionId; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for phpunit/php-code-coverage + */ +final class Version +{ + private static string $version = ''; + public static function id(): string + { + if (self::$version === '') { + self::$version = (new VersionId('14.1.9', dirname(__DIR__)))->asString(); + } + return self::$version; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\FileIterator; + +use function array_all; +use function assert; +use function str_starts_with; +use RecursiveDirectoryIterator; +use RecursiveFilterIterator; +use SplFileInfo; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-file-iterator + */ +final class ExcludeIterator extends RecursiveFilterIterator +{ + /** + * @var list + */ + private array $exclude; + /** + * @param list $exclude + */ + public function __construct(RecursiveDirectoryIterator $iterator, array $exclude) + { + parent::__construct($iterator); + $this->exclude = $exclude; + } + public function accept(): bool + { + $current = $this->current(); + assert($current instanceof SplFileInfo); + $path = $current->getRealPath(); + if ($path === \false) { + return \false; + } + return array_all($this->exclude, static fn(string $exclude) => !str_starts_with($path, $exclude)); + } + public function hasChildren(): bool + { + return $this->getInnerIterator()->hasChildren(); + } + public function getChildren(): self + { + return new self($this->getInnerIterator()->getChildren(), $this->exclude); + } + public function getInnerIterator(): RecursiveDirectoryIterator + { + $innerIterator = parent::getInnerIterator(); + assert($innerIterator instanceof RecursiveDirectoryIterator); + return $innerIterator; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\FileIterator; + +use function array_unique; +use function assert; +use function sort; +use SplFileInfo; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class Facade +{ + /** + * @param list|non-empty-string $paths + * @param list|string $suffixes + * @param list|string $prefixes + * @param list $exclude + * + * @return list + */ + public function getFilesAsArray(array|string $paths, array|string $suffixes = '', array|string $prefixes = '', array $exclude = []): array + { + $iterator = (new Factory())->getFileIterator($paths, $suffixes, $prefixes, $exclude); + $files = []; + foreach ($iterator as $file) { + assert($file instanceof SplFileInfo); + $file = $file->getRealPath(); + if ($file) { + $files[] = $file; + } + } + $files = array_unique($files); + sort($files); + return $files; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\FileIterator; + +use const DIRECTORY_SEPARATOR; +use const GLOB_ONLYDIR; +use function array_filter; +use function array_map; +use function array_merge; +use function array_unique; +use function array_values; +use function glob; +use function is_dir; +use function is_string; +use function realpath; +use function sort; +use function str_ends_with; +use function stripos; +use function substr; +use AppendIterator; +use FilesystemIterator; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-file-iterator + */ +final class Factory +{ + /** + * @param list|non-empty-string $paths + * @param list|string $suffixes + * @param list|string $prefixes + * @param list $exclude + * + * @phpstan-ignore missingType.generics + */ + public function getFileIterator(array|string $paths, array|string $suffixes = '', array|string $prefixes = '', array $exclude = []): AppendIterator + { + if (is_string($paths)) { + $paths = [$paths]; + } + $paths = $this->resolveWildcards($paths); + $exclude = $this->resolveWildcards($exclude); + if (is_string($prefixes)) { + if ($prefixes !== '') { + $prefixes = [$prefixes]; + } else { + $prefixes = []; + } + } + if (is_string($suffixes)) { + if ($suffixes !== '') { + $suffixes = [$suffixes]; + } else { + $suffixes = []; + } + } + $iterator = new AppendIterator(); + foreach ($paths as $path) { + if (is_dir($path)) { + $iterator->append(new Iterator($path, new RecursiveIteratorIterator(new ExcludeIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::FOLLOW_SYMLINKS | FilesystemIterator::SKIP_DOTS), $exclude)), $suffixes, $prefixes)); + } + } + return $iterator; + } + /** + * @param list $paths + * + * @return list + */ + private function resolveWildcards(array $paths): array + { + $_paths = [[]]; + foreach ($paths as $path) { + $pathEndsWithDirectorySeparator = str_ends_with($path, '/') || str_ends_with($path, DIRECTORY_SEPARATOR); + $locals = $this->globstar($path); + if ($locals !== []) { + $_paths[] = array_map(static function (string $local) use ($pathEndsWithDirectorySeparator): string|false { + $realPath = realpath($local); + if ($realPath !== \false && $pathEndsWithDirectorySeparator && is_dir($realPath)) { + return $realPath . DIRECTORY_SEPARATOR; + } + return $realPath; + }, $locals); + } else { + // @codeCoverageIgnoreStart + $realPath = realpath($path); + if ($realPath !== \false && $pathEndsWithDirectorySeparator && is_dir($realPath)) { + $_paths[] = [$realPath . DIRECTORY_SEPARATOR]; + } else { + $_paths[] = [$realPath]; + } + // @codeCoverageIgnoreEnd + } + } + return array_values(array_filter(array_merge(...$_paths))); + } + /** + * @see https://gist.github.com/funkjedi/3feee27d873ae2297b8e2370a7082aad + * + * @return list + */ + private function globstar(string $pattern): array + { + if (stripos($pattern, '**') === \false) { + $files = glob($pattern, GLOB_ONLYDIR); + } else { + $position = stripos($pattern, '**'); + $rootPattern = substr($pattern, 0, $position - 1); + $restPattern = substr($pattern, $position + 2); + $patterns = [$rootPattern . $restPattern]; + $rootPattern .= '/*'; + while ($directories = glob($rootPattern, GLOB_ONLYDIR)) { + $rootPattern .= '/*'; + foreach ($directories as $directory) { + $patterns[] = $directory . $restPattern; + } + } + $files = []; + foreach ($patterns as $_pattern) { + $files = array_merge($files, $this->globstar($_pattern)); + } + } + if ($files !== \false) { + $files = array_unique($files); + sort($files); + return $files; + } + // @codeCoverageIgnoreStart + return []; + // @codeCoverageIgnoreEnd + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\FileIterator; + +use function array_any; +use function preg_match; +use function realpath; +use function str_ends_with; +use function str_replace; +use function str_starts_with; +use FilterIterator; +use SplFileInfo; +/** + * @template-extends FilterIterator + * + * @internal This class is not covered by the backward compatibility promise for phpunit/php-file-iterator + */ +final class Iterator extends FilterIterator +{ + public const int PREFIX = 0; + public const int SUFFIX = 1; + private false|string $basePath; + /** + * @var list + */ + private array $suffixes; + /** + * @var list + */ + private array $prefixes; + /** + * @param list $suffixes + * @param list $prefixes + */ + public function __construct(string $basePath, \Iterator $iterator, array $suffixes = [], array $prefixes = []) + { + $this->basePath = realpath($basePath); + $this->prefixes = $prefixes; + $this->suffixes = $suffixes; + parent::__construct($iterator); + } + public function accept(): bool + { + $current = $this->getInnerIterator()->current(); + $filename = $current->getFilename(); + $realPath = $current->getRealPath(); + if ($realPath === \false) { + // @codeCoverageIgnoreStart + return \false; + // @codeCoverageIgnoreEnd + } + return $this->acceptPath($realPath) && $this->acceptPrefix($filename) && $this->acceptSuffix($filename); + } + private function acceptPath(string $path): bool + { + // Filter files in hidden directories by checking path that is relative to the base path. + if (preg_match('=/\.[^/]*/=', str_replace((string) $this->basePath, '', $path)) === 1) { + return \false; + } + return \true; + } + private function acceptPrefix(string $filename): bool + { + return $this->acceptSubString($filename, $this->prefixes, self::PREFIX); + } + private function acceptSuffix(string $filename): bool + { + return $this->acceptSubString($filename, $this->suffixes, self::SUFFIX); + } + /** + * @param list $subStrings + */ + private function acceptSubString(string $filename, array $subStrings, int $type): bool + { + if ($subStrings === []) { + return \true; + } + return array_any($subStrings, static fn(string $string) => $type === self::PREFIX && str_starts_with($filename, $string) || $type === self::SUFFIX && str_ends_with($filename, $string)); + } +} +BSD 3-Clause License + +Copyright (c) 2009-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Invoker; + +use const SIGALRM; +use function call_user_func_array; +use function extension_loaded; +use function function_exists; +use function pcntl_alarm; +use function pcntl_async_signals; +use function pcntl_signal; +use function sprintf; +use Throwable; +final class Invoker +{ + /** + * @param array $arguments + * + * @throws Throwable + */ + public function invoke(callable $callable, array $arguments, int $timeout): mixed + { + if (!$this->canInvokeWithTimeout()) { + // @codeCoverageIgnoreStart + throw new ProcessControlExtensionNotLoadedException(); + // @codeCoverageIgnoreEnd + } + pcntl_signal(SIGALRM, static function () use ($timeout): void { + throw new TimeoutException(sprintf('Execution aborted after %d second%s', $timeout, $timeout === 1 ? '' : 's')); + }); + pcntl_async_signals(\true); + pcntl_alarm($timeout); + try { + return call_user_func_array($callable, $arguments); + } finally { + pcntl_alarm(0); + } + } + public function canInvokeWithTimeout(): bool + { + return extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_async_signals') && function_exists('pcntl_alarm'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Invoker; + +use Throwable; +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Invoker; + +use const PHP_EOL; +use function extension_loaded; +use function function_exists; +use function implode; +use RuntimeException; +final class ProcessControlExtensionNotLoadedException extends RuntimeException implements Exception +{ + public function __construct() + { + $message = []; + if (!extension_loaded('pcntl')) { + $message[] = 'The pcntl (process control) extension for PHP must be loaded.'; + } + if (!function_exists('pcntl_signal')) { + $message[] = 'The pcntl_signal() function must not be disabled.'; + } + if (!function_exists('pcntl_async_signals')) { + $message[] = 'The pcntl_async_signals() function must not be disabled.'; + } + if (!function_exists('pcntl_alarm')) { + $message[] = 'The pcntl_alarm() function must not be disabled.'; + } + parent::__construct(implode(PHP_EOL, $message)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Invoker; + +use RuntimeException; +final class TimeoutException extends RuntimeException implements Exception +{ +} +BSD 3-Clause License + +Copyright (c) 2009-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Template; + +use function array_keys; +use function array_merge; +use function file_get_contents; +use function file_put_contents; +use function is_file; +use function is_string; +use function sprintf; +use function str_replace; +final class Template +{ + /** + * @var non-empty-string + */ + private readonly string $template; + /** + * @var non-empty-string + */ + private readonly string $openDelimiter; + /** + * @var non-empty-string + */ + private readonly string $closeDelimiter; + /** + * @var array + */ + private array $values = []; + /** + * @param non-empty-string $templateFile + * @param non-empty-string $openDelimiter + * @param non-empty-string $closeDelimiter + * + * @throws InvalidArgumentException + */ + public function __construct(string $templateFile, string $openDelimiter = '{', string $closeDelimiter = '}') + { + $this->template = $this->loadTemplateFile($templateFile); + $this->openDelimiter = $openDelimiter; + $this->closeDelimiter = $closeDelimiter; + } + /** + * @param array $values + */ + public function setVar(array $values, bool $merge = \true): void + { + if (!$merge || $this->values === []) { + $this->values = $values; + return; + } + $this->values = array_merge($this->values, $values); + } + public function render(): string + { + $keys = []; + foreach (array_keys($this->values) as $key) { + $keys[] = $this->openDelimiter . $key . $this->closeDelimiter; + } + return str_replace($keys, $this->values, $this->template); + } + /** + * @codeCoverageIgnore + */ + public function renderTo(string $target): void + { + if (@file_put_contents($target, $this->render()) === \false) { + throw new RuntimeException(sprintf('Writing rendered result to "%s" failed', $target)); + } + } + /** + * @param non-empty-string $file + * + * @throws InvalidArgumentException + * + * @return non-empty-string + */ + private function loadTemplateFile(string $file): string + { + if (is_file($file)) { + $template = file_get_contents($file); + if (is_string($template) && $template !== '') { + return $template; + } + } + $distFile = $file . '.dist'; + if (is_file($distFile)) { + $template = file_get_contents($distFile); + if (is_string($template) && $template !== '') { + return $template; + } + } + throw new InvalidArgumentException(sprintf('Failed to load template "%s"', $file)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Template; + +use Throwable; +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Template; + +final class InvalidArgumentException extends \InvalidArgumentException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Template; + +use InvalidArgumentException; +final class RuntimeException extends InvalidArgumentException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Timer; + +use function floor; +use function sprintf; +/** + * @immutable + */ +final readonly class Duration +{ + private float $nanoseconds; + private int $hours; + private int $minutes; + private int $seconds; + private int $milliseconds; + public static function fromMicroseconds(float $microseconds): self + { + return new self($microseconds * 1000); + } + public static function fromNanoseconds(float $nanoseconds): self + { + return new self($nanoseconds); + } + private function __construct(float $nanoseconds) + { + $this->nanoseconds = $nanoseconds; + $timeInMilliseconds = $nanoseconds / 1000000; + $hours = floor($timeInMilliseconds / 60 / 60 / 1000); + $hoursInMilliseconds = $hours * 60 * 60 * 1000; + $minutes = floor($timeInMilliseconds / 60 / 1000) % 60; + $minutesInMilliseconds = $minutes * 60 * 1000; + $seconds = floor(($timeInMilliseconds - $hoursInMilliseconds - $minutesInMilliseconds) / 1000); + $secondsInMilliseconds = $seconds * 1000; + $milliseconds = $timeInMilliseconds - $hoursInMilliseconds - $minutesInMilliseconds - $secondsInMilliseconds; + $this->hours = (int) $hours; + $this->minutes = $minutes; + $this->seconds = (int) $seconds; + $this->milliseconds = (int) $milliseconds; + } + public function asNanoseconds(): float + { + return $this->nanoseconds; + } + public function asMicroseconds(): float + { + return $this->nanoseconds / 1000; + } + public function asMilliseconds(): float + { + return $this->nanoseconds / 1000000; + } + public function asSeconds(): float + { + return $this->nanoseconds / 1000000000; + } + public function asString(): string + { + $result = ''; + if ($this->hours > 0) { + $result = sprintf('%02d', $this->hours) . ':'; + } + $result .= sprintf('%02d', $this->minutes) . ':'; + $result .= sprintf('%02d', $this->seconds); + if ($this->milliseconds > 0) { + $result .= '.' . sprintf('%03d', $this->milliseconds); + } + return $result; + } +} +BSD 3-Clause License + +Copyright (c) 2010-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Timer; + +use function is_float; +use function memory_get_peak_usage; +use function microtime; +use function sprintf; +final class ResourceUsageFormatter +{ + /** + * @var array + */ + private const array SIZES = ['GB' => 1073741824, 'MB' => 1048576, 'KB' => 1024]; + public function resourceUsage(Duration $duration): string + { + return sprintf('Time: %s, Memory: %s', $duration->asString(), $this->bytesToString(memory_get_peak_usage(\true))); + } + /** + * @throws TimeSinceStartOfRequestNotAvailableException + */ + public function resourceUsageSinceStartOfRequest(): string + { + if (!isset($_SERVER['REQUEST_TIME_FLOAT'])) { + throw new TimeSinceStartOfRequestNotAvailableException('Cannot determine time at which the request started because $_SERVER[\'REQUEST_TIME_FLOAT\'] is not available'); + } + if (!is_float($_SERVER['REQUEST_TIME_FLOAT'])) { + throw new TimeSinceStartOfRequestNotAvailableException('Cannot determine time at which the request started because $_SERVER[\'REQUEST_TIME_FLOAT\'] is not of type float'); + } + return $this->resourceUsage(Duration::fromMicroseconds(1000000 * (microtime(\true) - $_SERVER['REQUEST_TIME_FLOAT']))); + } + private function bytesToString(int $bytes): string + { + foreach (self::SIZES as $unit => $value) { + if ($bytes >= $value) { + return sprintf('%.2f %s', $bytes / $value, $unit); + } + } + // @codeCoverageIgnoreStart + return $bytes . ' byte' . ($bytes !== 1 ? 's' : ''); + // @codeCoverageIgnoreEnd + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Timer; + +use function array_pop; +use function hrtime; +final class Timer +{ + /** + * @var list + */ + private array $startTimes = []; + public function start(): void + { + $this->startTimes[] = (float) hrtime(\true); + } + /** + * @throws NoActiveTimerException + */ + public function stop(): Duration + { + if ($this->startTimes === []) { + throw new NoActiveTimerException('Timer::start() has to be called before Timer::stop()'); + } + return Duration::fromNanoseconds((float) hrtime(\true) - array_pop($this->startTimes)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Timer; + +use Throwable; +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Timer; + +use LogicException; +final class NoActiveTimerException extends LogicException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Timer; + +use RuntimeException; +final class TimeSinceStartOfRequestNotAvailableException extends RuntimeException implements Exception +{ +} + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 13.1 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollector; +use PHPUnit\Runner\DeprecationCollector\TestTriggeredDeprecationSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CollectingDispatcher implements \PHPUnit\Event\Dispatcher +{ + private \PHPUnit\Event\EventCollection $events; + private \PHPUnit\Event\DirectDispatcher $isolatedDirectDispatcher; + public function __construct(\PHPUnit\Event\DirectDispatcher $directDispatcher) + { + $this->isolatedDirectDispatcher = $directDispatcher; + $this->events = new \PHPUnit\Event\EventCollection(); + $this->isolatedDirectDispatcher->registerSubscriber(new TestTriggeredDeprecationSubscriber(DeprecationCollector::collector())); + } + public function dispatch(\PHPUnit\Event\Event $event): void + { + $this->events->add($event); + try { + $this->isolatedDirectDispatcher->dispatch($event); + } catch (\PHPUnit\Event\UnknownEventTypeException) { + // Do nothing. + } + } + public function flush(): \PHPUnit\Event\EventCollection + { + $events = $this->events; + $this->events = new \PHPUnit\Event\EventCollection(); + return $events; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DeferringDispatcher implements \PHPUnit\Event\SubscribableDispatcher +{ + private readonly \PHPUnit\Event\SubscribableDispatcher $dispatcher; + private \PHPUnit\Event\EventCollection $events; + private bool $recording = \true; + public function __construct(\PHPUnit\Event\SubscribableDispatcher $dispatcher) + { + $this->dispatcher = $dispatcher; + $this->events = new \PHPUnit\Event\EventCollection(); + } + public function registerTracer(\PHPUnit\Event\Tracer\Tracer $tracer): void + { + $this->dispatcher->registerTracer($tracer); + } + public function registerSubscriber(\PHPUnit\Event\Subscriber $subscriber): void + { + $this->dispatcher->registerSubscriber($subscriber); + } + public function dispatch(\PHPUnit\Event\Event $event): void + { + if ($this->recording) { + $this->events->add($event); + return; + } + $this->dispatcher->dispatch($event); + } + public function flush(): void + { + $this->recording = \false; + foreach ($this->events as $event) { + $this->dispatcher->dispatch($event); + } + $this->events = new \PHPUnit\Event\EventCollection(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use const PHP_EOL; +use function array_key_exists; +use function dirname; +use function sprintf; +use function str_starts_with; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DirectDispatcher implements \PHPUnit\Event\SubscribableDispatcher +{ + private readonly \PHPUnit\Event\TypeMap $typeMap; + /** + * @var array> + */ + private array $subscribers = []; + /** + * @var list + */ + private array $tracers = []; + public function __construct(\PHPUnit\Event\TypeMap $map) + { + $this->typeMap = $map; + } + public function registerTracer(\PHPUnit\Event\Tracer\Tracer $tracer): void + { + $this->tracers[] = $tracer; + } + /** + * @throws MapError + * @throws UnknownSubscriberTypeException + */ + public function registerSubscriber(\PHPUnit\Event\Subscriber $subscriber): void + { + if (!$this->typeMap->isKnownSubscriberType($subscriber)) { + throw new \PHPUnit\Event\UnknownSubscriberTypeException(sprintf('Subscriber "%s" does not implement any known interface - did you forget to register it?', $subscriber::class)); + } + $eventClassName = $this->typeMap->map($subscriber); + if (!array_key_exists($eventClassName, $this->subscribers)) { + $this->subscribers[$eventClassName] = []; + } + $this->subscribers[$eventClassName][] = $subscriber; + } + /** + * @throws Throwable + * @throws UnknownEventTypeException + */ + public function dispatch(\PHPUnit\Event\Event $event): void + { + $eventClassName = $event::class; + if (!$this->typeMap->isKnownEventType($event)) { + throw new \PHPUnit\Event\UnknownEventTypeException(sprintf('Unknown event type "%s"', $eventClassName)); + } + foreach ($this->tracers as $tracer) { + try { + $tracer->trace($event); + // @codeCoverageIgnoreStart + } catch (Throwable $t) { + $this->handleThrowable($t); + } + // @codeCoverageIgnoreEnd + } + if (!array_key_exists($eventClassName, $this->subscribers)) { + return; + } + foreach ($this->subscribers[$eventClassName] as $subscriber) { + try { + /** @phpstan-ignore method.notFound */ + $subscriber->notify($event); + } catch (Throwable $t) { + $this->handleThrowable($t); + } + } + } + /** + * @throws Throwable + */ + public function handleThrowable(Throwable $t): void + { + if ($this->isThrowableFromThirdPartySubscriber($t)) { + \PHPUnit\Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Exception in third-party event subscriber: %s%s%s', $t->getMessage(), PHP_EOL, $t->getTraceAsString())); + return; + } + // @codeCoverageIgnoreStart + throw $t; + // @codeCoverageIgnoreEnd + } + private function isThrowableFromThirdPartySubscriber(Throwable $t): bool + { + return !str_starts_with($t->getFile(), dirname(__DIR__, 2)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Dispatcher +{ + /** + * @throws UnknownEventTypeException + */ + public function dispatch(\PHPUnit\Event\Event $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface SubscribableDispatcher extends \PHPUnit\Event\Dispatcher +{ + /** + * @throws UnknownSubscriberTypeException + */ + public function registerSubscriber(\PHPUnit\Event\Subscriber $subscriber): void; + public function registerTracer(\PHPUnit\Event\Tracer\Tracer $tracer): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use function assert; +use function memory_reset_peak_usage; +use function preg_match; +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Event\Code\ComparisonFailure; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\NoTestCaseObjectOnCallStackException; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\TestMethodBuilder; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Test\DataProviderMethodCalled; +use PHPUnit\Event\Test\DataProviderMethodFinished; +use PHPUnit\Event\TestSuite\Filtered as TestSuiteFiltered; +use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished; +use PHPUnit\Event\TestSuite\Loaded as TestSuiteLoaded; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\Event\TestSuite\Sorted as TestSuiteSorted; +use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; +use PHPUnit\Event\TestSuite\TestSuite; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\IgnorePhpunitWarnings; +use PHPUnit\Metadata\Parser\Registry; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnitPHAR\SebastianBergmann\Comparator\Comparator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DispatchingEmitter implements \PHPUnit\Event\Emitter +{ + private readonly \PHPUnit\Event\Dispatcher $dispatcher; + private readonly \PHPUnit\Event\Telemetry\System $system; + private readonly \PHPUnit\Event\Telemetry\Snapshot $startSnapshot; + private \PHPUnit\Event\Telemetry\Snapshot $previousSnapshot; + public function __construct(\PHPUnit\Event\Dispatcher $dispatcher, \PHPUnit\Event\Telemetry\System $system) + { + $this->dispatcher = $dispatcher; + $this->system = $system; + $this->startSnapshot = $system->snapshot(); + $this->previousSnapshot = $this->startSnapshot; + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function applicationStarted(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Application\Started($this->telemetryInfo(), new \PHPUnit\Event\Runtime\Runtime())); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerStarted(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\Started($this->telemetryInfo())); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerConfigured(Configuration $configuration): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\Configured($this->telemetryInfo(), $configuration)); + } + /** + * @param non-empty-string $filename + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerBootstrapFinished(string $filename): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\BootstrapFinished($this->telemetryInfo(), $filename)); + } + /** + * @param non-empty-string $filename + * @param non-empty-string $name + * @param non-empty-string $version + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerLoadedExtensionFromPhar(string $filename, string $name, string $version): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\ExtensionLoadedFromPhar($this->telemetryInfo(), $filename, $name, $version)); + } + /** + * @param class-string $className + * @param array $parameters + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerBootstrappedExtension(string $className, array $parameters): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\ExtensionBootstrapped($this->telemetryInfo(), $className, $parameters)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function dataProviderMethodCalled(ClassMethod $testMethod, ClassMethod $dataProviderMethod): void + { + $this->dispatcher->dispatch(new DataProviderMethodCalled($this->telemetryInfo(), $testMethod, $dataProviderMethod)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function dataProviderMethodFinished(ClassMethod $testMethod, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch(new DataProviderMethodFinished($this->telemetryInfo(), $testMethod, ...$calledMethods)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteLoaded(TestSuite $testSuite): void + { + $this->dispatcher->dispatch(new TestSuiteLoaded($this->telemetryInfo(), $testSuite)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteFiltered(TestSuite $testSuite): void + { + $this->dispatcher->dispatch(new TestSuiteFiltered($this->telemetryInfo(), $testSuite)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteSorted(int $executionOrder, int $executionOrderDefects, bool $resolveDependencies): void + { + $this->dispatcher->dispatch(new TestSuiteSorted($this->telemetryInfo(), $executionOrder, $executionOrderDefects, $resolveDependencies)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerEventFacadeSealed(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\EventFacadeSealed($this->telemetryInfo())); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerExecutionStarted(TestSuite $testSuite): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\ExecutionStarted($this->telemetryInfo(), $testSuite)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerDisabledGarbageCollection(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\GarbageCollectionDisabled($this->telemetryInfo())); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerTriggeredGarbageCollection(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\GarbageCollectionTriggered($this->telemetryInfo())); + } + public function childProcessStarted(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\ChildProcessStarted($this->telemetryInfo())); + } + public function childProcessErrored(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\ChildProcessErrored($this->telemetryInfo())); + } + public function childProcessFinished(string $stdout, string $stderr): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\ChildProcessFinished($this->telemetryInfo(), $stdout, $stderr)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteSkipped(TestSuite $testSuite, string $message): void + { + $this->dispatcher->dispatch(new TestSuiteSkipped($this->telemetryInfo(), $testSuite, $message)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteStarted(TestSuite $testSuite): void + { + $this->dispatcher->dispatch(new TestSuiteStarted($this->telemetryInfo(), $testSuite)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPreparationStarted(\PHPUnit\Event\Code\Test $test): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PreparationStarted($this->telemetryInfo(), $test)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPreparationErrored(\PHPUnit\Event\Code\Test $test, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PreparationErrored($this->telemetryInfo(), $test, $throwable)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPreparationFailed(\PHPUnit\Event\Code\Test $test, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PreparationFailed($this->telemetryInfo(), $test, $throwable)); + } + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeFirstTestMethodCalled(string $testClassName, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\BeforeFirstTestMethodCalled($this->telemetryInfo(), $testClassName, $calledMethod)); + } + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeFirstTestMethodErrored(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\BeforeFirstTestMethodErrored($this->telemetryInfo(), $testClassName, $calledMethod, $throwable)); + } + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeFirstTestMethodFailed(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\BeforeFirstTestMethodFailed($this->telemetryInfo(), $testClassName, $calledMethod, $throwable)); + } + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeFirstTestMethodFinished(string $testClassName, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\BeforeFirstTestMethodFinished($this->telemetryInfo(), $testClassName, ...$calledMethods)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeTestMethodCalled(TestMethod $test, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\BeforeTestMethodCalled($this->telemetryInfo(), $test, $calledMethod)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeTestMethodErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\BeforeTestMethodErrored($this->telemetryInfo(), $test, $calledMethod, $throwable)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeTestMethodFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\BeforeTestMethodFailed($this->telemetryInfo(), $test, $calledMethod, $throwable)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeTestMethodFinished(TestMethod $test, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\BeforeTestMethodFinished($this->telemetryInfo(), $test, ...$calledMethods)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function preConditionCalled(TestMethod $test, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PreConditionCalled($this->telemetryInfo(), $test, $calledMethod)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function preConditionErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PreConditionErrored($this->telemetryInfo(), $test, $calledMethod, $throwable)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function preConditionFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PreConditionFailed($this->telemetryInfo(), $test, $calledMethod, $throwable)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function preConditionFinished(TestMethod $test, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PreConditionFinished($this->telemetryInfo(), $test, ...$calledMethods)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPrepared(\PHPUnit\Event\Code\Test $test): void + { + memory_reset_peak_usage(); + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\Prepared($this->telemetryInfo(), $test)); + } + /** + * @param class-string $className + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRegisteredComparator(string $className): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\ComparatorRegistered($this->telemetryInfo(), $className)); + } + public function testUsedCustomMethodInvocation(TestMethod $test, ClassMethod $customTestMethodInvocation): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\CustomTestMethodInvocationUsed($this->telemetryInfo(), $test, $customTestMethodInvocation)); + } + /** + * @param class-string $className + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testCreatedMockObject(string $className): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\MockObjectCreated($this->telemetryInfo(), $className)); + } + /** + * @param list $interfaces + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testCreatedMockObjectForIntersectionOfInterfaces(array $interfaces): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\MockObjectForIntersectionOfInterfacesCreated($this->telemetryInfo(), $interfaces)); + } + /** + * @param class-string $className + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testCreatedPartialMockObject(string $className, string ...$methodNames): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PartialMockObjectCreated($this->telemetryInfo(), $className, ...$methodNames)); + } + /** + * @param class-string $className + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testCreatedStub(string $className): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\TestStubCreated($this->telemetryInfo(), $className)); + } + /** + * @param list $interfaces + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testCreatedStubForIntersectionOfInterfaces(array $interfaces): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\TestStubForIntersectionOfInterfacesCreated($this->telemetryInfo(), $interfaces)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testErrored(\PHPUnit\Event\Code\Test $test, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\Errored($this->telemetryInfo(), $test, $throwable)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testFailed(\PHPUnit\Event\Code\Test $test, Throwable $throwable, ?ComparisonFailure $comparisonFailure): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\Failed($this->telemetryInfo(), $test, $throwable, $comparisonFailure)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPassed(\PHPUnit\Event\Code\Test $test): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\Passed($this->telemetryInfo(), $test)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testConsideredRisky(\PHPUnit\Event\Code\Test $test, string $message): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\ConsideredRisky($this->telemetryInfo(), $test, $message)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testMarkedAsIncomplete(\PHPUnit\Event\Code\Test $test, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\MarkedIncomplete($this->telemetryInfo(), $test, $throwable)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSkipped(\PHPUnit\Event\Code\Test $test, string $message): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\Skipped($this->telemetryInfo(), $test, $message)); + } + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws NoTestCaseObjectOnCallStackException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpunitDeprecation(?\PHPUnit\Event\Code\Test $test, string $message): void + { + if ($test === null) { + $test = TestMethodBuilder::fromCallStack(); + } + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + if ($test->metadata()->isIgnorePhpunitDeprecations()->isNotEmpty()) { + return; + } + } + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PhpunitDeprecationTriggered($this->telemetryInfo(), $test, $message)); + } + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws NoTestCaseObjectOnCallStackException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpunitNotice(\PHPUnit\Event\Code\Test $test, string $message): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PhpunitNoticeTriggered($this->telemetryInfo(), $test, $message)); + } + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpDeprecation(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PhpDeprecationTriggered($this->telemetryInfo(), $test, $message, $file, $line, $suppressed, $ignoredByBaseline, $ignoredByTest, $trigger)); + } + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $stackTrace + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredDeprecation(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger, string $stackTrace): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\DeprecationTriggered($this->telemetryInfo(), $test, $message, $file, $line, $suppressed, $ignoredByBaseline, $ignoredByTest, $trigger, $stackTrace)); + } + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredError(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\ErrorTriggered($this->telemetryInfo(), $test, $message, $file, $line, $suppressed)); + } + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredNotice(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\NoticeTriggered($this->telemetryInfo(), $test, $message, $file, $line, $suppressed, $ignoredByBaseline)); + } + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpNotice(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PhpNoticeTriggered($this->telemetryInfo(), $test, $message, $file, $line, $suppressed, $ignoredByBaseline)); + } + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredWarning(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\WarningTriggered($this->telemetryInfo(), $test, $message, $file, $line, $suppressed, $ignoredByBaseline)); + } + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpWarning(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PhpWarningTriggered($this->telemetryInfo(), $test, $message, $file, $line, $suppressed, $ignoredByBaseline)); + } + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpunitError(\PHPUnit\Event\Code\Test $test, string $message): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PhpunitErrorTriggered($this->telemetryInfo(), $test, $message)); + } + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpunitWarning(\PHPUnit\Event\Code\Test $test, string $message): void + { + $ignoredByTest = \false; + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + $metadata = Registry::parser()->forMethod($test->className(), $test->methodName())->isIgnorePhpunitWarnings()->asArray(); + if (isset($metadata[0])) { + assert($metadata[0] instanceof IgnorePhpunitWarnings); + $messagePattern = $metadata[0]->messagePattern(); + if ($messagePattern === null || (bool) preg_match('{' . $messagePattern . '}', $message)) { + $ignoredByTest = \true; + } + } + } + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PhpunitWarningTriggered($this->telemetryInfo(), $test, $message, $ignoredByTest)); + } + /** + * @param non-empty-string $output + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPrintedUnexpectedOutput(string $output): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PrintedUnexpectedOutput($this->telemetryInfo(), $output)); + } + /** + * @param non-empty-string $additionalInformation + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testProvidedAdditionalInformation(TestMethod $test, string $additionalInformation): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\AdditionalInformationProvided($this->telemetryInfo(), $test, $additionalInformation)); + } + /** + * @param non-negative-int $numberOfAssertionsPerformed + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testFinished(\PHPUnit\Event\Code\Test $test, int $numberOfAssertionsPerformed): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\Finished($this->telemetryInfo(), $test, $numberOfAssertionsPerformed)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function postConditionCalled(TestMethod $test, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PostConditionCalled($this->telemetryInfo(), $test, $calledMethod)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function postConditionErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PostConditionErrored($this->telemetryInfo(), $test, $calledMethod, $throwable)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function postConditionFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PostConditionFailed($this->telemetryInfo(), $test, $calledMethod, $throwable)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function postConditionFinished(TestMethod $test, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\PostConditionFinished($this->telemetryInfo(), $test, ...$calledMethods)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterTestMethodCalled(TestMethod $test, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\AfterTestMethodCalled($this->telemetryInfo(), $test, $calledMethod)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterTestMethodErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\AfterTestMethodErrored($this->telemetryInfo(), $test, $calledMethod, $throwable)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterTestMethodFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\AfterTestMethodFailed($this->telemetryInfo(), $test, $calledMethod, $throwable)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterTestMethodFinished(TestMethod $test, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\AfterTestMethodFinished($this->telemetryInfo(), $test, ...$calledMethods)); + } + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterLastTestMethodCalled(string $testClassName, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\AfterLastTestMethodCalled($this->telemetryInfo(), $testClassName, $calledMethod)); + } + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterLastTestMethodErrored(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\AfterLastTestMethodErrored($this->telemetryInfo(), $testClassName, $calledMethod, $throwable)); + } + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterLastTestMethodFailed(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\AfterLastTestMethodFailed($this->telemetryInfo(), $testClassName, $calledMethod, $throwable)); + } + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterLastTestMethodFinished(string $testClassName, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Test\AfterLastTestMethodFinished($this->telemetryInfo(), $testClassName, ...$calledMethods)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteFinished(TestSuite $testSuite): void + { + $this->dispatcher->dispatch(new TestSuiteFinished($this->telemetryInfo(), $testSuite)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerStartedStaticAnalysisForCodeCoverage(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\StaticAnalysisForCodeCoverageStarted($this->telemetryInfo())); + } + /** + * @param non-negative-int $cacheHits + * @param non-negative-int $cacheMisses + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerFinishedStaticAnalysisForCodeCoverage(int $cacheHits, int $cacheMisses): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\StaticAnalysisForCodeCoverageFinished($this->telemetryInfo(), $cacheHits, $cacheMisses)); + } + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerTriggeredPhpunitDeprecation(string $message): void + { + try { + if (TestMethodBuilder::fromCallStack()->metadata()->isIgnorePhpunitDeprecations()->isNotEmpty()) { + return; + } + } catch (NoTestCaseObjectOnCallStackException) { + } + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\DeprecationTriggered($this->telemetryInfo(), $message)); + } + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerTriggeredPhpunitNotice(string $message): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\NoticeTriggered($this->telemetryInfo(), $message)); + } + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerTriggeredPhpunitWarning(string $message): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\WarningTriggered($this->telemetryInfo(), $message)); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerEnabledGarbageCollection(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\GarbageCollectionEnabled($this->telemetryInfo())); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerExecutionAborted(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\ExecutionAborted($this->telemetryInfo())); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerExecutionFinished(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\ExecutionFinished($this->telemetryInfo())); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerFinished(): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\TestRunner\Finished($this->telemetryInfo())); + } + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function applicationFinished(int $shellExitCode): void + { + $this->dispatcher->dispatch(new \PHPUnit\Event\Application\Finished($this->telemetryInfo(), $shellExitCode)); + } + /** + * @throws InvalidArgumentException + */ + private function telemetryInfo(): \PHPUnit\Event\Telemetry\Info + { + $current = $this->system->snapshot(); + $info = new \PHPUnit\Event\Telemetry\Info($current, $current->time()->duration($this->startSnapshot->time()), $current->memoryUsage()->diff($this->startSnapshot->memoryUsage()), $current->time()->duration($this->previousSnapshot->time()), $current->memoryUsage()->diff($this->previousSnapshot->memoryUsage())); + $this->previousSnapshot = $current; + return $info; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Event\Code\ComparisonFailure; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\TestSuite\TestSuite; +use PHPUnit\Framework\TestCase; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnitPHAR\SebastianBergmann\Comparator\Comparator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Emitter +{ + public function applicationStarted(): void; + public function testRunnerStarted(): void; + public function testRunnerConfigured(Configuration $configuration): void; + /** + * @param non-empty-string $filename + */ + public function testRunnerBootstrapFinished(string $filename): void; + /** + * @param non-empty-string $filename + * @param non-empty-string $name + * @param non-empty-string $version + */ + public function testRunnerLoadedExtensionFromPhar(string $filename, string $name, string $version): void; + /** + * @param class-string $className + * @param array $parameters + */ + public function testRunnerBootstrappedExtension(string $className, array $parameters): void; + public function dataProviderMethodCalled(ClassMethod $testMethod, ClassMethod $dataProviderMethod): void; + public function dataProviderMethodFinished(ClassMethod $testMethod, ClassMethod ...$calledMethods): void; + public function testSuiteLoaded(TestSuite $testSuite): void; + public function testSuiteFiltered(TestSuite $testSuite): void; + public function testSuiteSorted(int $executionOrder, int $executionOrderDefects, bool $resolveDependencies): void; + public function testRunnerEventFacadeSealed(): void; + public function testRunnerExecutionStarted(TestSuite $testSuite): void; + public function testRunnerDisabledGarbageCollection(): void; + public function testRunnerTriggeredGarbageCollection(): void; + /** + * @param non-empty-string $message + */ + public function testSuiteSkipped(TestSuite $testSuite, string $message): void; + public function testSuiteStarted(TestSuite $testSuite): void; + public function testPreparationStarted(\PHPUnit\Event\Code\Test $test): void; + public function testPreparationErrored(\PHPUnit\Event\Code\Test $test, Throwable $throwable): void; + public function testPreparationFailed(\PHPUnit\Event\Code\Test $test, Throwable $throwable): void; + /** + * @param class-string $testClassName + */ + public function beforeFirstTestMethodCalled(string $testClassName, ClassMethod $calledMethod): void; + /** + * @param class-string $testClassName + */ + public function beforeFirstTestMethodErrored(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void; + /** + * @param class-string $testClassName + */ + public function beforeFirstTestMethodFailed(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void; + /** + * @param class-string $testClassName + */ + public function beforeFirstTestMethodFinished(string $testClassName, ClassMethod ...$calledMethods): void; + public function beforeTestMethodCalled(TestMethod $test, ClassMethod $calledMethod): void; + public function beforeTestMethodErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + public function beforeTestMethodFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + public function beforeTestMethodFinished(TestMethod $test, ClassMethod ...$calledMethods): void; + public function preConditionCalled(TestMethod $test, ClassMethod $calledMethod): void; + public function preConditionErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + public function preConditionFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + public function preConditionFinished(TestMethod $test, ClassMethod ...$calledMethods): void; + public function testPrepared(\PHPUnit\Event\Code\Test $test): void; + /** + * @param class-string $className + */ + public function testRegisteredComparator(string $className): void; + public function testUsedCustomMethodInvocation(TestMethod $test, ClassMethod $customTestMethodInvocation): void; + /** + * @param class-string $className + */ + public function testCreatedMockObject(string $className): void; + /** + * @param list $interfaces + */ + public function testCreatedMockObjectForIntersectionOfInterfaces(array $interfaces): void; + /** + * @param class-string $className + */ + public function testCreatedPartialMockObject(string $className, string ...$methodNames): void; + /** + * @param class-string $className + */ + public function testCreatedStub(string $className): void; + /** + * @param list $interfaces + */ + public function testCreatedStubForIntersectionOfInterfaces(array $interfaces): void; + public function testErrored(\PHPUnit\Event\Code\Test $test, Throwable $throwable): void; + public function testFailed(\PHPUnit\Event\Code\Test $test, Throwable $throwable, ?ComparisonFailure $comparisonFailure): void; + public function testPassed(\PHPUnit\Event\Code\Test $test): void; + /** + * @param non-empty-string $message + */ + public function testConsideredRisky(\PHPUnit\Event\Code\Test $test, string $message): void; + public function testMarkedAsIncomplete(\PHPUnit\Event\Code\Test $test, Throwable $throwable): void; + /** + * @param non-empty-string $message + */ + public function testSkipped(\PHPUnit\Event\Code\Test $test, string $message): void; + /** + * @param non-empty-string $message + */ + public function testTriggeredPhpunitDeprecation(?\PHPUnit\Event\Code\Test $test, string $message): void; + /** + * @param non-empty-string $message + */ + public function testTriggeredPhpunitNotice(\PHPUnit\Event\Code\Test $test, string $message): void; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredPhpDeprecation(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger): void; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $stackTrace + */ + public function testTriggeredDeprecation(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger, string $stackTrace): void; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredError(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed): void; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredNotice(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredPhpNotice(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredWarning(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredPhpWarning(\PHPUnit\Event\Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void; + /** + * @param non-empty-string $message + */ + public function testTriggeredPhpunitError(\PHPUnit\Event\Code\Test $test, string $message): void; + /** + * @param non-empty-string $message + */ + public function testTriggeredPhpunitWarning(\PHPUnit\Event\Code\Test $test, string $message): void; + /** + * @param non-empty-string $output + */ + public function testPrintedUnexpectedOutput(string $output): void; + /** + * @param non-empty-string $additionalInformation + */ + public function testProvidedAdditionalInformation(TestMethod $test, string $additionalInformation): void; + /** + * @param non-negative-int $numberOfAssertionsPerformed + */ + public function testFinished(\PHPUnit\Event\Code\Test $test, int $numberOfAssertionsPerformed): void; + public function postConditionCalled(TestMethod $test, ClassMethod $calledMethod): void; + public function postConditionErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + public function postConditionFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + public function postConditionFinished(TestMethod $test, ClassMethod ...$calledMethods): void; + public function afterTestMethodCalled(TestMethod $test, ClassMethod $calledMethod): void; + public function afterTestMethodErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + public function afterTestMethodFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + public function afterTestMethodFinished(TestMethod $test, ClassMethod ...$calledMethods): void; + /** + * @param class-string $testClassName + */ + public function afterLastTestMethodCalled(string $testClassName, ClassMethod $calledMethod): void; + /** + * @param class-string $testClassName + */ + public function afterLastTestMethodErrored(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void; + /** + * @param class-string $testClassName + */ + public function afterLastTestMethodFailed(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void; + /** + * @param class-string $testClassName + */ + public function afterLastTestMethodFinished(string $testClassName, ClassMethod ...$calledMethods): void; + public function testSuiteFinished(TestSuite $testSuite): void; + public function childProcessStarted(): void; + public function childProcessErrored(): void; + public function childProcessFinished(string $stdout, string $stderr): void; + public function testRunnerStartedStaticAnalysisForCodeCoverage(): void; + /** + * @param non-negative-int $cacheHits + * @param non-negative-int $cacheMisses + */ + public function testRunnerFinishedStaticAnalysisForCodeCoverage(int $cacheHits, int $cacheMisses): void; + /** + * @param non-empty-string $message + */ + public function testRunnerTriggeredPhpunitDeprecation(string $message): void; + /** + * @param non-empty-string $message + */ + public function testRunnerTriggeredPhpunitNotice(string $message): void; + /** + * @param non-empty-string $message + */ + public function testRunnerTriggeredPhpunitWarning(string $message): void; + public function testRunnerEnabledGarbageCollection(): void; + public function testRunnerExecutionAborted(): void; + public function testRunnerExecutionFinished(): void; + public function testRunnerFinished(): void; + public function applicationFinished(int $shellExitCode): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Application; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Finished implements Event +{ + private Telemetry\Info $telemetryInfo; + private int $shellExitCode; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, int $shellExitCode) + { + $this->telemetryInfo = $telemetryInfo; + $this->shellExitCode = $shellExitCode; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function shellExitCode(): int + { + return $this->shellExitCode; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('PHPUnit Finished (Shell Exit Code: %d)', $this->shellExitCode); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Application; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Application\Finished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Application; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Runtime\Runtime; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Started implements Event +{ + private Telemetry\Info $telemetryInfo; + private Runtime $runtime; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Runtime $runtime) + { + $this->telemetryInfo = $telemetryInfo; + $this->runtime = $runtime; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function runtime(): Runtime + { + return $this->runtime; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('PHPUnit Started (%s)', $this->runtime->asString()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Application; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface StartedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Application\Started $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Event +{ + public function telemetryInfo(): \PHPUnit\Event\Telemetry\Info; + /** + * @return non-empty-string + */ + public function asString(): string; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @template-implements IteratorAggregate + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class EventCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $events = []; + public function add(\PHPUnit\Event\Event ...$events): void + { + foreach ($events as $event) { + $this->events[] = $event; + } + } + /** + * @return list + */ + public function asArray(): array + { + return $this->events; + } + public function count(): int + { + return count($this->events); + } + public function isEmpty(): bool + { + return $this->count() === 0; + } + public function isNotEmpty(): bool + { + return $this->count() > 0; + } + public function getIterator(): \PHPUnit\Event\EventCollectionIterator + { + return new \PHPUnit\Event\EventCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use Iterator; +/** + * @template-implements Iterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class EventCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $events; + /** + * @var non-negative-int + */ + private int $position = 0; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(\PHPUnit\Event\EventCollection $events) + { + $this->events = $events->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->events[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\Event\Event + { + return $this->events[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AdditionalInformationProvided implements Event +{ + private Telemetry\Info $telemetryInfo; + private TestMethod $test; + /** + * @var non-empty-string + */ + private string $additionalInformation; + /** + * @param non-empty-string $additionalInformation + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, TestMethod $test, string $additionalInformation) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->additionalInformation = $additionalInformation; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): TestMethod + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function additionalInformation(): string + { + return $this->additionalInformation; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Provided Additional Information%s%s', PHP_EOL, $this->additionalInformation); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AdditionalInformationProvidedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\AdditionalInformationProvided $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnitPHAR\SebastianBergmann\Comparator\Comparator; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ComparatorRegistered implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $className) + { + $this->telemetryInfo = $telemetryInfo; + $this->className = $className; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Comparator Registered (%s)', $this->className); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ComparatorRegisteredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\ComparatorRegistered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CustomTestMethodInvocationUsed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $customTestMethodInvocation; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $customTestMethodInvocation) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->customTestMethodInvocation = $customTestMethodInvocation; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function customTestMethodInvocation(): Code\ClassMethod + { + return $this->customTestMethodInvocation; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Custom Test Method Invocation Used (%s::%s)', $this->customTestMethodInvocation->className(), $this->customTestMethodInvocation->methodName()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface CustomTestMethodInvocationUsedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\CustomTestMethodInvocationUsed $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodCalled implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + /** + * @param class-string $testClassName + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('After Last Test Method Called (%s::%s)', $this->calledMethod->className(), $this->calledMethod->methodName()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterLastTestMethodCalledSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\AfterLastTestMethodCalled $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @param class-string $testClassName + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('After Last Test Method Errored (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterLastTestMethodErroredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\AfterLastTestMethodErrored $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @param class-string $testClassName + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('After Last Test Method Failed (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterLastTestMethodFailedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\AfterLastTestMethodFailed $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $testClassName; + /** + * @var list + */ + private array $calledMethods; + /** + * @param class-string $testClassName + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethods = $calledMethods; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'After Last Test Method Finished:'; + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf(PHP_EOL . '- %s::%s', $calledMethod->className(), $calledMethod->methodName()); + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterLastTestMethodFinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\AfterLastTestMethodFinished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestMethodCalled implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('After Test Method Called (%s::%s)', $this->calledMethod->className(), $this->calledMethod->methodName()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterTestMethodCalledSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\AfterTestMethodCalled $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestMethodErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('After Test Method Errored (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterTestMethodErroredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\AfterTestMethodErrored $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestMethodFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('After Test Method Failed (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterTestMethodFailedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\AfterTestMethodFailed $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestMethodFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + /** + * @var list + */ + private array $calledMethods; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethods = $calledMethods; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'After Test Method Finished:'; + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf(PHP_EOL . '- %s::%s', $calledMethod->className(), $calledMethod->methodName()); + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterTestMethodFinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\AfterTestMethodFinished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodCalled implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + /** + * @param class-string $testClassName + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Before First Test Method Called (%s::%s)', $this->calledMethod->className(), $this->calledMethod->methodName()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeFirstTestMethodCalledSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\BeforeFirstTestMethodCalled $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @param class-string $testClassName + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Before First Test Method Errored (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeFirstTestMethodErroredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\BeforeFirstTestMethodErrored $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @param class-string $testClassName + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Before First Test Method Failed (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeFirstTestMethodFailedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\BeforeFirstTestMethodFailed $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $testClassName; + /** + * @var list + */ + private array $calledMethods; + /** + * @param class-string $testClassName + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethods = $calledMethods; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'Before First Test Method Finished:'; + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf(PHP_EOL . '- %s::%s', $calledMethod->className(), $calledMethod->methodName()); + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeFirstTestMethodFinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\BeforeFirstTestMethodFinished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestMethodCalled implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Before Test Method Called (%s::%s)', $this->calledMethod->className(), $this->calledMethod->methodName()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeTestMethodCalledSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\BeforeTestMethodCalled $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestMethodErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Before Test Method Errored (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeTestMethodErroredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\BeforeTestMethodErrored $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestMethodFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Before Test Method Failed (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeTestMethodFailedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\BeforeTestMethodFailed $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestMethodFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + /** + * @var list + */ + private array $calledMethods; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethods = $calledMethods; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'Before Test Method Finished:'; + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf(PHP_EOL . '- %s::%s', $calledMethod->className(), $calledMethod->methodName()); + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeTestMethodFinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\BeforeTestMethodFinished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PostConditionCalled implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Post Condition Method Called (%s::%s)', $this->calledMethod->className(), $this->calledMethod->methodName()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PostConditionCalledSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PostConditionCalled $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PostConditionErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Post Condition Method Errored (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PostConditionErroredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PostConditionErrored $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PostConditionFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Post Condition Method Failed (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PostConditionFailedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PostConditionFailed $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PostConditionFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + /** + * @var list + */ + private array $calledMethods; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethods = $calledMethods; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'Post Condition Method Finished:'; + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf(PHP_EOL . '- %s::%s', $calledMethod->className(), $calledMethod->methodName()); + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PostConditionFinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PostConditionFinished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreConditionCalled implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Pre Condition Method Called (%s::%s)', $this->calledMethod->className(), $this->calledMethod->methodName()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreConditionCalledSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PreConditionCalled $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreConditionErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Pre Condition Method Errored (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreConditionErroredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PreConditionErrored $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreConditionFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Pre Condition Method Failed (%s::%s)%s', $this->calledMethod->className(), $this->calledMethod->methodName(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreConditionFailedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PreConditionFailed $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreConditionFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + /** + * @var list + */ + private array $calledMethods; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethods = $calledMethods; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\TestMethod + { + return $this->test; + } + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'Pre Condition Method Finished:'; + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf(PHP_EOL . '- %s::%s', $calledMethod->className(), $calledMethod->methodName()); + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreConditionFinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PreConditionFinished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ConsideredRisky implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + /** + * @var non-empty-string + */ + private string $message; + /** + * @param non-empty-string $message + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Considered Risky (%s)%s%s', $this->test->id(), PHP_EOL, $this->message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ConsideredRiskySubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\ConsideredRisky $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DeprecationTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + /** + * @var non-empty-string + */ + private string $message; + /** + * @var non-empty-string + */ + private string $file; + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + private bool $ignoredByTest; + private IssueTrigger $trigger; + /** + * @var non-empty-string + */ + private string $stackTrace; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $stackTrace + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger, string $stackTrace) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + $this->ignoredByTest = $ignoredByTest; + $this->trigger = $trigger; + $this->stackTrace = $stackTrace; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + public function wasSuppressed(): bool + { + return $this->suppressed; + } + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + public function ignoredByTest(): bool + { + return $this->ignoredByTest; + } + public function trigger(): IssueTrigger + { + return $this->trigger; + } + /** + * @return non-empty-string + */ + public function stackTrace(): string + { + return $this->stackTrace; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + if ($message !== '') { + $message = PHP_EOL . $message; + } + $details = [$this->test->id(), $this->trigger->asString()]; + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + if ($this->ignoredByTest) { + $details[] = 'ignored by test'; + } + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + return sprintf('Test Triggered Deprecation (%s) in %s:%d%s', implode(', ', $details), $this->file, $this->line, $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface DeprecationTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\DeprecationTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ErrorTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + /** + * @var non-empty-string + */ + private string $message; + /** + * @var non-empty-string + */ + private string $file; + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + public function wasSuppressed(): bool + { + return $this->suppressed; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + if ($message !== '') { + $message = PHP_EOL . $message; + } + $details = [$this->test->id()]; + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + return sprintf('Test Triggered Error (%s) in %s:%d%s', implode(', ', $details), $this->file, $this->line, $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ErrorTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\ErrorTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class NoticeTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + /** + * @var non-empty-string + */ + private string $message; + /** + * @var non-empty-string + */ + private string $file; + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + public function wasSuppressed(): bool + { + return $this->suppressed; + } + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + if ($message !== '') { + $message = PHP_EOL . $message; + } + $details = [$this->test->id()]; + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + return sprintf('Test Triggered Notice (%s) in %s:%d%s', implode(', ', $details), $this->file, $this->line, $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface NoticeTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\NoticeTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpDeprecationTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + /** + * @var non-empty-string + */ + private string $message; + /** + * @var non-empty-string + */ + private string $file; + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + private bool $ignoredByTest; + private IssueTrigger $trigger; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + $this->ignoredByTest = $ignoredByTest; + $this->trigger = $trigger; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + public function wasSuppressed(): bool + { + return $this->suppressed; + } + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + public function ignoredByTest(): bool + { + return $this->ignoredByTest; + } + public function trigger(): IssueTrigger + { + return $this->trigger; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + if ($message !== '') { + $message = PHP_EOL . $message; + } + $details = [$this->test->id(), $this->trigger->asString()]; + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + if ($this->ignoredByTest) { + $details[] = 'ignored by test'; + } + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + return sprintf('Test Triggered PHP Deprecation (%s) in %s:%d%s', implode(', ', $details), $this->file, $this->line, $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpDeprecationTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PhpDeprecationTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpNoticeTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + /** + * @var non-empty-string + */ + private string $message; + /** + * @var non-empty-string + */ + private string $file; + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + public function wasSuppressed(): bool + { + return $this->suppressed; + } + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + if ($message !== '') { + $message = PHP_EOL . $message; + } + $details = [$this->test->id()]; + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + return sprintf('Test Triggered PHP Notice (%s) in %s:%d%s', implode(', ', $details), $this->file, $this->line, $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpNoticeTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PhpNoticeTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpWarningTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + /** + * @var non-empty-string + */ + private string $message; + /** + * @var non-empty-string + */ + private string $file; + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + public function wasSuppressed(): bool + { + return $this->suppressed; + } + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + if ($message !== '') { + $message = PHP_EOL . $message; + } + $details = [$this->test->id()]; + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + return sprintf('Test Triggered PHP Warning (%s) in %s:%d%s', implode(', ', $details), $this->file, $this->line, $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpWarningTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PhpWarningTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpunitDeprecationTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + /** + * @var non-empty-string + */ + private string $message; + /** + * @param non-empty-string $message + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Test Triggered PHPUnit Deprecation (%s)%s', $this->test->id(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpunitDeprecationTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PhpunitDeprecationTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use function trim; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpunitErrorTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + /** + * @var non-empty-string + */ + private string $message; + /** + * @param non-empty-string $message + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = trim($this->message); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Test Triggered PHPUnit Error (%s)%s', $this->test->id(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpunitErrorTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PhpunitErrorTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use function trim; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpunitNoticeTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + /** + * @var non-empty-string + */ + private string $message; + /** + * @param non-empty-string $message + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = trim($this->message); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Test Triggered PHPUnit Notice (%s)%s', $this->test->id(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpunitNoticeTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PhpunitNoticeTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpunitWarningTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + /** + * @var non-empty-string + */ + private string $message; + private bool $ignoredByTest; + /** + * @param non-empty-string $message + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, bool $ignoredByTest) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->ignoredByTest = $ignoredByTest; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + public function ignoredByTest(): bool + { + return $this->ignoredByTest; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + if ($message !== '') { + $message = PHP_EOL . $message; + } + $details = [$this->test->id()]; + if ($this->ignoredByTest) { + $details[] = 'ignored by test'; + } + return sprintf('Test Triggered PHPUnit Warning (%s)%s', implode(', ', $details), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpunitWarningTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PhpunitWarningTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class WarningTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + /** + * @var non-empty-string + */ + private string $message; + /** + * @var non-empty-string + */ + private string $file; + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + public function wasSuppressed(): bool + { + return $this->suppressed; + } + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + if ($message !== '') { + $message = PHP_EOL . $message; + } + $details = [$this->test->id()]; + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + return sprintf('Test Triggered Warning (%s) in %s:%d%s', implode(', ', $details), $this->file, $this->line, $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface WarningTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\WarningTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry\Info; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataProviderMethodCalled implements Event +{ + private Info $telemetryInfo; + private ClassMethod $testMethod; + private ClassMethod $dataProviderMethod; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Info $telemetryInfo, ClassMethod $testMethod, ClassMethod $dataProviderMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->testMethod = $testMethod; + $this->dataProviderMethod = $dataProviderMethod; + } + public function telemetryInfo(): Info + { + return $this->telemetryInfo; + } + public function testMethod(): ClassMethod + { + return $this->testMethod; + } + public function dataProviderMethod(): ClassMethod + { + return $this->dataProviderMethod; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Data Provider Method Called (%s::%s for test method %s::%s)', $this->dataProviderMethod->className(), $this->dataProviderMethod->methodName(), $this->testMethod->className(), $this->testMethod->methodName()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface DataProviderMethodCalledSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\DataProviderMethodCalled $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataProviderMethodFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private ClassMethod $testMethod; + /** + * @var list + */ + private array $calledMethods; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, ClassMethod $testMethod, ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->testMethod = $testMethod; + $this->calledMethods = $calledMethods; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function testMethod(): ClassMethod + { + return $this->testMethod; + } + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = sprintf('Data Provider Method Finished for %s::%s:', $this->testMethod->className(), $this->testMethod->methodName()); + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf(PHP_EOL . '- %s::%s', $calledMethod->className(), $calledMethod->methodName()); + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface DataProviderMethodFinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\DataProviderMethodFinished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Finished implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + /** + * @var non-negative-int + */ + private int $numberOfAssertionsPerformed; + /** + * @param non-negative-int $numberOfAssertionsPerformed + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, int $numberOfAssertionsPerformed) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->numberOfAssertionsPerformed = $numberOfAssertionsPerformed; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\Test + { + return $this->test; + } + /** + * @return non-negative-int + */ + public function numberOfAssertionsPerformed(): int + { + return $this->numberOfAssertionsPerformed; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Finished (%s)', $this->test->id()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\Finished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreparationErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\Test + { + return $this->test; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Test Preparation Errored (%s)%s', $this->test->id(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreparationErroredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PreparationErrored $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreparationFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\Test + { + return $this->test; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Test Preparation Failed (%s)%s', $this->test->id(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreparationFailedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PreparationFailed $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreparationStarted implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Preparation Started (%s)', $this->test->id()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreparationStartedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PreparationStarted $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Prepared implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Prepared (%s)', $this->test->id()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreparedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\Prepared $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use function trim; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Errored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\Test + { + return $this->test; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = trim($this->throwable->message()); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Test Errored (%s)%s', $this->test->id(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ErroredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\Errored $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use function trim; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\ComparisonFailure; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Failed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private Throwable $throwable; + private ?ComparisonFailure $comparisonFailure; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, Throwable $throwable, ?ComparisonFailure $comparisonFailure) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->throwable = $throwable; + $this->comparisonFailure = $comparisonFailure; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\Test + { + return $this->test; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @phpstan-assert-if-true !null $this->comparisonFailure + */ + public function hasComparisonFailure(): bool + { + return $this->comparisonFailure !== null; + } + /** + * @throws NoComparisonFailureException + */ + public function comparisonFailure(): ComparisonFailure + { + if ($this->comparisonFailure === null) { + throw new \PHPUnit\Event\Test\NoComparisonFailureException(); + } + return $this->comparisonFailure; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = trim($this->throwable->message()); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Test Failed (%s)%s', $this->test->id(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FailedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\Failed $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use function trim; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MarkedIncomplete implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private Throwable $throwable; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->throwable = $throwable; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\Test + { + return $this->test; + } + public function throwable(): Throwable + { + return $this->throwable; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = trim($this->throwable->message()); + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Test Marked Incomplete (%s)%s', $this->test->id(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface MarkedIncompleteSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\MarkedIncomplete $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Passed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\Test + { + return $this->test; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Passed (%s)', $this->test->id()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PassedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\Passed $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Skipped implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private string $message; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function test(): Code\Test + { + return $this->test; + } + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + if ($message !== '') { + $message = PHP_EOL . $message; + } + return sprintf('Test Skipped (%s)%s', $this->test->id(), $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface SkippedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\Skipped $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PrintedUnexpectedOutput implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var non-empty-string + */ + private string $output; + /** + * @param non-empty-string $output + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $output) + { + $this->telemetryInfo = $telemetryInfo; + $this->output = $output; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function output(): string + { + return $this->output; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Printed Unexpected Output%s%s', PHP_EOL, $this->output); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PrintedUnexpectedOutputSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PrintedUnexpectedOutput $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MockObjectCreated implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $className) + { + $this->telemetryInfo = $telemetryInfo; + $this->className = $className; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Mock Object Created (%s)', $this->className); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface MockObjectCreatedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\MockObjectCreated $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function implode; +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MockObjectForIntersectionOfInterfacesCreated implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var list + */ + private array $interfaces; + /** + * @param list $interfaces + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, array $interfaces) + { + $this->telemetryInfo = $telemetryInfo; + $this->interfaces = $interfaces; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return list + */ + public function interfaces(): array + { + return $this->interfaces; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Mock Object Created (%s)', implode('&', $this->interfaces)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface MockObjectForIntersectionOfInterfacesCreatedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\MockObjectForIntersectionOfInterfacesCreated $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PartialMockObjectCreated implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $className; + /** + * @var list + */ + private array $methodNames; + /** + * @param class-string $className + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $className, string ...$methodNames) + { + $this->telemetryInfo = $telemetryInfo; + $this->className = $className; + $this->methodNames = $methodNames; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return list + */ + public function methodNames(): array + { + return $this->methodNames; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Partial Mock Object Created (%s)', $this->className); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PartialMockObjectCreatedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\PartialMockObjectCreated $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestStubCreated implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $className) + { + $this->telemetryInfo = $telemetryInfo; + $this->className = $className; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Stub Created (%s)', $this->className); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface TestStubCreatedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\TestStubCreated $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function implode; +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestStubForIntersectionOfInterfacesCreated implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var list + */ + private array $interfaces; + /** + * @param list $interfaces + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, array $interfaces) + { + $this->telemetryInfo = $telemetryInfo; + $this->interfaces = $interfaces; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return list + */ + public function interfaces(): array + { + return $this->interfaces; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Stub Created (%s)', implode('&', $this->interfaces)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface TestStubForIntersectionOfInterfacesCreatedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\Test\TestStubForIntersectionOfInterfacesCreated $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BootstrapFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var non-empty-string + */ + private string $filename; + /** + * @param non-empty-string $filename + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $filename) + { + $this->telemetryInfo = $telemetryInfo; + $this->filename = $filename; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function filename(): string + { + return $this->filename; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Bootstrap Finished (%s)', $this->filename); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BootstrapFinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\BootstrapFinished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Child Process Errored'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ChildProcessErroredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\ChildProcessErrored $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private string $stdout; + private string $stderr; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $stdout, string $stderr) + { + $this->telemetryInfo = $telemetryInfo; + $this->stdout = $stdout; + $this->stderr = $stderr; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function stdout(): string + { + return $this->stdout; + } + public function stderr(): string + { + return $this->stderr; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Child Process Finished'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ChildProcessFinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\ChildProcessFinished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessStarted implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Child Process Started'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ChildProcessStartedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\ChildProcessStarted $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\TextUI\Configuration\Configuration; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Configured implements Event +{ + private Telemetry\Info $telemetryInfo; + private Configuration $configuration; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, Configuration $configuration) + { + $this->telemetryInfo = $telemetryInfo; + $this->configuration = $configuration; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function configuration(): Configuration + { + return $this->configuration; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Configured'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ConfiguredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\Configured $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DeprecationTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var non-empty-string + */ + private string $message; + /** + * @param non-empty-string $message + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->message = $message; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Runner Triggered Deprecation (%s)', $this->message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface DeprecationTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\DeprecationTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class EventFacadeSealed implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Event Facade Sealed'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface EventFacadeSealedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\EventFacadeSealed $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionAborted implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Execution Aborted'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ExecutionAbortedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\ExecutionAborted $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Execution Finished'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ExecutionFinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\ExecutionFinished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Event\TestSuite\TestSuite; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionStarted implements Event +{ + private Telemetry\Info $telemetryInfo; + private TestSuite $testSuite; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, TestSuite $testSuite) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function testSuite(): TestSuite + { + return $this->testSuite; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Runner Execution Started (%d test%s)', $this->testSuite->count(), $this->testSuite->count() !== 1 ? 's' : ''); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ExecutionStartedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\ExecutionStarted $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExtensionBootstrapped implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var class-string + */ + private string $className; + /** + * @var array + */ + private array $parameters; + /** + * @param class-string $className + * @param array $parameters + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $className, array $parameters) + { + $this->telemetryInfo = $telemetryInfo; + $this->className = $className; + $this->parameters = $parameters; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return array + */ + public function parameters(): array + { + return $this->parameters; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Extension Bootstrapped (%s)', $this->className); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ExtensionBootstrappedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\ExtensionBootstrapped $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExtensionLoadedFromPhar implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var non-empty-string + */ + private string $filename; + /** + * @var non-empty-string + */ + private string $name; + /** + * @var non-empty-string + */ + private string $version; + /** + * @param non-empty-string $filename + * @param non-empty-string $name + * @param non-empty-string $version + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $filename, string $name, string $version) + { + $this->telemetryInfo = $telemetryInfo; + $this->filename = $filename; + $this->name = $name; + $this->version = $version; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function filename(): string + { + return $this->filename; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + /** + * @return non-empty-string + */ + public function version(): string + { + return $this->version; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Extension Loaded from PHAR (%s %s)', $this->name, $this->version); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ExtensionLoadedFromPharSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\ExtensionLoadedFromPhar $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Finished implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Finished'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\Finished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GarbageCollectionDisabled implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Disabled Garbage Collection'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface GarbageCollectionDisabledSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\GarbageCollectionDisabled $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GarbageCollectionEnabled implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Enabled Garbage Collection'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface GarbageCollectionEnabledSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\GarbageCollectionEnabled $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GarbageCollectionTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Triggered Garbage Collection'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface GarbageCollectionTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\GarbageCollectionTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class NoticeTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private string $message; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->message = $message; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Runner Triggered Notice (%s)', $this->message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface NoticeTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\NoticeTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Started implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Started'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface StartedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\Started $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class StaticAnalysisForCodeCoverageFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var non-negative-int + */ + private int $cacheHits; + /** + * @var non-negative-int + */ + private int $cacheMisses; + /** + * @param non-negative-int $cacheHits + * @param non-negative-int $cacheMisses + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, int $cacheHits, int $cacheMisses) + { + $this->telemetryInfo = $telemetryInfo; + $this->cacheHits = $cacheHits; + $this->cacheMisses = $cacheMisses; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-negative-int + */ + public function cacheHits(): int + { + return $this->cacheHits; + } + /** + * @return non-negative-int + */ + public function cacheMisses(): int + { + return $this->cacheMisses; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Static Analysis for Code Coverage Finished (%d cache hits, %d cache misses)', $this->cacheHits, $this->cacheMisses); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface StaticAnalysisForCodeCoverageFinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\StaticAnalysisForCodeCoverageFinished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class StaticAnalysisForCodeCoverageStarted implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Static Analysis for Code Coverage Started'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface StaticAnalysisForCodeCoverageStartedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\StaticAnalysisForCodeCoverageStarted $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class WarningTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + /** + * @var non-empty-string + */ + private string $message; + /** + * @param non-empty-string $message + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->message = $message; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Runner Triggered Warning (%s)', $this->message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface WarningTriggeredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestRunner\WarningTriggered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Filtered implements Event +{ + private Telemetry\Info $telemetryInfo; + private \PHPUnit\Event\TestSuite\TestSuite $testSuite; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, \PHPUnit\Event\TestSuite\TestSuite $testSuite) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function testSuite(): \PHPUnit\Event\TestSuite\TestSuite + { + return $this->testSuite; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Suite Filtered (%d test%s)', $this->testSuite->count(), $this->testSuite->count() !== 1 ? 's' : ''); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FilteredSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestSuite\Filtered $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Finished implements Event +{ + private Telemetry\Info $telemetryInfo; + private \PHPUnit\Event\TestSuite\TestSuite $testSuite; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, \PHPUnit\Event\TestSuite\TestSuite $testSuite) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function testSuite(): \PHPUnit\Event\TestSuite\TestSuite + { + return $this->testSuite; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Suite Finished (%s, %d test%s)', $this->testSuite->name(), $this->testSuite->count(), $this->testSuite->count() !== 1 ? 's' : ''); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FinishedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestSuite\Finished $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Loaded implements Event +{ + private Telemetry\Info $telemetryInfo; + private \PHPUnit\Event\TestSuite\TestSuite $testSuite; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, \PHPUnit\Event\TestSuite\TestSuite $testSuite) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function testSuite(): \PHPUnit\Event\TestSuite\TestSuite + { + return $this->testSuite; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Suite Loaded (%d test%s)', $this->testSuite->count(), $this->testSuite->count() !== 1 ? 's' : ''); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface LoadedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestSuite\Loaded $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Skipped implements Event +{ + private Telemetry\Info $telemetryInfo; + private \PHPUnit\Event\TestSuite\TestSuite $testSuite; + private string $message; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, \PHPUnit\Event\TestSuite\TestSuite $testSuite, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + $this->message = $message; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function testSuite(): \PHPUnit\Event\TestSuite\TestSuite + { + return $this->testSuite; + } + public function message(): string + { + return $this->message; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Suite Skipped (%s, %s)', $this->testSuite->name(), $this->message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface SkippedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestSuite\Skipped $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Sorted implements Event +{ + private Telemetry\Info $telemetryInfo; + private int $executionOrder; + private int $executionOrderDefects; + private bool $resolveDependencies; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, int $executionOrder, int $executionOrderDefects, bool $resolveDependencies) + { + $this->telemetryInfo = $telemetryInfo; + $this->executionOrder = $executionOrder; + $this->executionOrderDefects = $executionOrderDefects; + $this->resolveDependencies = $resolveDependencies; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function executionOrder(): int + { + return $this->executionOrder; + } + public function executionOrderDefects(): int + { + return $this->executionOrderDefects; + } + public function resolveDependencies(): bool + { + return $this->resolveDependencies; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Suite Sorted'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface SortedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestSuite\Sorted $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Started implements Event +{ + private Telemetry\Info $telemetryInfo; + private \PHPUnit\Event\TestSuite\TestSuite $testSuite; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(Telemetry\Info $telemetryInfo, \PHPUnit\Event\TestSuite\TestSuite $testSuite) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + } + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + public function testSuite(): \PHPUnit\Event\TestSuite\TestSuite + { + return $this->testSuite; + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf('Test Suite Started (%s, %d test%s)', $this->testSuite->name(), $this->testSuite->count(), $this->testSuite->count() !== 1 ? 's' : ''); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface StartedSubscriber extends Subscriber +{ + public function notify(\PHPUnit\Event\TestSuite\Started $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class EventAlreadyAssignedException extends RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class EventFacadeIsSealedException extends RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends \PHPUnit\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidArgumentException extends \InvalidArgumentException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidEventException extends RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidSubscriberException extends RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class MapError extends RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Exception; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class NoComparisonFailureException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +use PHPUnit\Event\Exception; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class NoDataSetFromDataProviderException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class NoPreviousThrowableException extends RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use PHPUnit\Event\Exception; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoTestCaseObjectOnCallStackException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('Cannot find TestCase object on call stack'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class RuntimeException extends \RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class SubscriberTypeAlreadyRegisteredException extends RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownEventException extends RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownEventTypeException extends RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownSubscriberException extends RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownSubscriberTypeException extends RuntimeException implements \PHPUnit\Event\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use function assert; +use function interface_exists; +use PHPUnit\Event\Telemetry\HRTime; +use PHPUnit\Event\Telemetry\SystemGarbageCollectorStatusProvider; +use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollector; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Facade +{ + private static ?self $instance = null; + private \PHPUnit\Event\Emitter $emitter; + private ?\PHPUnit\Event\TypeMap $typeMap = null; + private ?\PHPUnit\Event\DeferringDispatcher $deferringDispatcher = null; + private bool $sealed = \false; + public static function instance(): self + { + if (self::$instance === null) { + self::$instance = new self(); + } + return self::$instance; + } + public static function emitter(): \PHPUnit\Event\Emitter + { + return self::instance()->emitter; + } + public function __construct() + { + $this->emitter = $this->createDispatchingEmitter(); + } + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public function registerSubscribers(\PHPUnit\Event\Subscriber ...$subscribers): void + { + foreach ($subscribers as $subscriber) { + $this->registerSubscriber($subscriber); + } + } + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public function registerSubscriber(\PHPUnit\Event\Subscriber $subscriber): void + { + if ($this->sealed) { + throw new \PHPUnit\Event\EventFacadeIsSealedException(); + } + $this->deferredDispatcher()->registerSubscriber($subscriber); + } + /** + * @throws EventFacadeIsSealedException + */ + public function registerTracer(\PHPUnit\Event\Tracer\Tracer $tracer): void + { + if ($this->sealed) { + throw new \PHPUnit\Event\EventFacadeIsSealedException(); + } + $this->deferredDispatcher()->registerTracer($tracer); + } + /** + * @codeCoverageIgnore + * + * @noinspection PhpUnused + */ + public function initForIsolation(HRTime $offset): \PHPUnit\Event\CollectingDispatcher + { + DeprecationCollector::initForIsolation(); + $dispatcher = new \PHPUnit\Event\CollectingDispatcher(new \PHPUnit\Event\DirectDispatcher($this->typeMap())); + $this->emitter = new \PHPUnit\Event\DispatchingEmitter($dispatcher, new \PHPUnit\Event\Telemetry\System(new \PHPUnit\Event\Telemetry\SystemStopWatchWithOffset($offset), new \PHPUnit\Event\Telemetry\SystemMemoryMeter(), new SystemGarbageCollectorStatusProvider())); + $this->sealed = \true; + return $dispatcher; + } + public function forward(\PHPUnit\Event\EventCollection $events): void + { + $dispatcher = $this->deferredDispatcher(); + foreach ($events as $event) { + $dispatcher->dispatch($event); + } + } + public function seal(): void + { + $this->deferredDispatcher()->flush(); + $this->sealed = \true; + $this->emitter->testRunnerEventFacadeSealed(); + } + private function createDispatchingEmitter(): \PHPUnit\Event\DispatchingEmitter + { + return new \PHPUnit\Event\DispatchingEmitter($this->deferredDispatcher(), $this->createTelemetrySystem()); + } + private function createTelemetrySystem(): \PHPUnit\Event\Telemetry\System + { + return new \PHPUnit\Event\Telemetry\System(new \PHPUnit\Event\Telemetry\SystemStopWatch(), new \PHPUnit\Event\Telemetry\SystemMemoryMeter(), new SystemGarbageCollectorStatusProvider()); + } + private function deferredDispatcher(): \PHPUnit\Event\DeferringDispatcher + { + if ($this->deferringDispatcher === null) { + $this->deferringDispatcher = new \PHPUnit\Event\DeferringDispatcher(new \PHPUnit\Event\DirectDispatcher($this->typeMap())); + } + return $this->deferringDispatcher; + } + private function typeMap(): \PHPUnit\Event\TypeMap + { + if ($this->typeMap === null) { + $typeMap = new \PHPUnit\Event\TypeMap(); + $this->registerDefaultTypes($typeMap); + $this->typeMap = $typeMap; + } + return $this->typeMap; + } + private function registerDefaultTypes(\PHPUnit\Event\TypeMap $typeMap): void + { + $defaultEvents = [\PHPUnit\Event\Application\Started::class, \PHPUnit\Event\Application\Finished::class, \PHPUnit\Event\Test\DataProviderMethodCalled::class, \PHPUnit\Event\Test\DataProviderMethodFinished::class, \PHPUnit\Event\Test\MarkedIncomplete::class, \PHPUnit\Event\Test\AfterLastTestMethodCalled::class, \PHPUnit\Event\Test\AfterLastTestMethodErrored::class, \PHPUnit\Event\Test\AfterLastTestMethodFailed::class, \PHPUnit\Event\Test\AfterLastTestMethodFinished::class, \PHPUnit\Event\Test\AfterTestMethodCalled::class, \PHPUnit\Event\Test\AfterTestMethodErrored::class, \PHPUnit\Event\Test\AfterTestMethodFailed::class, \PHPUnit\Event\Test\AfterTestMethodFinished::class, \PHPUnit\Event\Test\BeforeFirstTestMethodCalled::class, \PHPUnit\Event\Test\BeforeFirstTestMethodErrored::class, \PHPUnit\Event\Test\BeforeFirstTestMethodFailed::class, \PHPUnit\Event\Test\BeforeFirstTestMethodFinished::class, \PHPUnit\Event\Test\BeforeTestMethodCalled::class, \PHPUnit\Event\Test\BeforeTestMethodErrored::class, \PHPUnit\Event\Test\BeforeTestMethodFailed::class, \PHPUnit\Event\Test\BeforeTestMethodFinished::class, \PHPUnit\Event\Test\AdditionalInformationProvided::class, \PHPUnit\Event\Test\ComparatorRegistered::class, \PHPUnit\Event\Test\CustomTestMethodInvocationUsed::class, \PHPUnit\Event\Test\ConsideredRisky::class, \PHPUnit\Event\Test\DeprecationTriggered::class, \PHPUnit\Event\Test\Errored::class, \PHPUnit\Event\Test\ErrorTriggered::class, \PHPUnit\Event\Test\Failed::class, \PHPUnit\Event\Test\Finished::class, \PHPUnit\Event\Test\NoticeTriggered::class, \PHPUnit\Event\Test\Passed::class, \PHPUnit\Event\Test\PhpDeprecationTriggered::class, \PHPUnit\Event\Test\PhpNoticeTriggered::class, \PHPUnit\Event\Test\PhpunitDeprecationTriggered::class, \PHPUnit\Event\Test\PhpunitNoticeTriggered::class, \PHPUnit\Event\Test\PhpunitErrorTriggered::class, \PHPUnit\Event\Test\PhpunitWarningTriggered::class, \PHPUnit\Event\Test\PhpWarningTriggered::class, \PHPUnit\Event\Test\PostConditionCalled::class, \PHPUnit\Event\Test\PostConditionErrored::class, \PHPUnit\Event\Test\PostConditionFailed::class, \PHPUnit\Event\Test\PostConditionFinished::class, \PHPUnit\Event\Test\PreConditionCalled::class, \PHPUnit\Event\Test\PreConditionErrored::class, \PHPUnit\Event\Test\PreConditionFailed::class, \PHPUnit\Event\Test\PreConditionFinished::class, \PHPUnit\Event\Test\PreparationStarted::class, \PHPUnit\Event\Test\Prepared::class, \PHPUnit\Event\Test\PreparationErrored::class, \PHPUnit\Event\Test\PreparationFailed::class, \PHPUnit\Event\Test\PrintedUnexpectedOutput::class, \PHPUnit\Event\Test\Skipped::class, \PHPUnit\Event\Test\WarningTriggered::class, \PHPUnit\Event\Test\MockObjectCreated::class, \PHPUnit\Event\Test\MockObjectForIntersectionOfInterfacesCreated::class, \PHPUnit\Event\Test\PartialMockObjectCreated::class, \PHPUnit\Event\Test\TestStubCreated::class, \PHPUnit\Event\Test\TestStubForIntersectionOfInterfacesCreated::class, \PHPUnit\Event\TestRunner\BootstrapFinished::class, \PHPUnit\Event\TestRunner\Configured::class, \PHPUnit\Event\TestRunner\EventFacadeSealed::class, \PHPUnit\Event\TestRunner\ExecutionAborted::class, \PHPUnit\Event\TestRunner\ExecutionFinished::class, \PHPUnit\Event\TestRunner\ExecutionStarted::class, \PHPUnit\Event\TestRunner\ExtensionLoadedFromPhar::class, \PHPUnit\Event\TestRunner\ExtensionBootstrapped::class, \PHPUnit\Event\TestRunner\Finished::class, \PHPUnit\Event\TestRunner\Started::class, \PHPUnit\Event\TestRunner\DeprecationTriggered::class, \PHPUnit\Event\TestRunner\NoticeTriggered::class, \PHPUnit\Event\TestRunner\WarningTriggered::class, \PHPUnit\Event\TestRunner\GarbageCollectionDisabled::class, \PHPUnit\Event\TestRunner\GarbageCollectionTriggered::class, \PHPUnit\Event\TestRunner\GarbageCollectionEnabled::class, \PHPUnit\Event\TestRunner\ChildProcessStarted::class, \PHPUnit\Event\TestRunner\ChildProcessErrored::class, \PHPUnit\Event\TestRunner\ChildProcessFinished::class, \PHPUnit\Event\TestRunner\StaticAnalysisForCodeCoverageFinished::class, \PHPUnit\Event\TestRunner\StaticAnalysisForCodeCoverageStarted::class, \PHPUnit\Event\TestSuite\Filtered::class, \PHPUnit\Event\TestSuite\Finished::class, \PHPUnit\Event\TestSuite\Loaded::class, \PHPUnit\Event\TestSuite\Skipped::class, \PHPUnit\Event\TestSuite\Sorted::class, \PHPUnit\Event\TestSuite\Started::class]; + foreach ($defaultEvents as $eventClass) { + $subscriberInterface = $eventClass . 'Subscriber'; + assert(interface_exists($subscriberInterface)); + $typeMap->addMapping($subscriberInterface, $eventClass); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Subscriber +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Tracer; + +use PHPUnit\Event\Event; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Tracer +{ + public function trace(Event $event): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use function array_any; +use function array_key_exists; +use function class_exists; +use function class_implements; +use function in_array; +use function interface_exists; +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TypeMap +{ + /** + * @var array + */ + private array $mapping = []; + /** + * @param class-string $subscriberInterface + * @param class-string $eventClass + * + * @throws EventAlreadyAssignedException + * @throws InvalidEventException + * @throws InvalidSubscriberException + * @throws SubscriberTypeAlreadyRegisteredException + * @throws UnknownEventException + * @throws UnknownSubscriberException + */ + public function addMapping(string $subscriberInterface, string $eventClass): void + { + $this->ensureSubscriberInterfaceExists($subscriberInterface); + $this->ensureSubscriberInterfaceExtendsInterface($subscriberInterface); + $this->ensureEventClassExists($eventClass); + $this->ensureEventClassImplementsEventInterface($eventClass); + $this->ensureSubscriberWasNotAlreadyRegistered($subscriberInterface); + $this->ensureEventWasNotAlreadyAssigned($eventClass); + $this->mapping[$subscriberInterface] = $eventClass; + } + public function isKnownSubscriberType(\PHPUnit\Event\Subscriber $subscriber): bool + { + return array_any(class_implements($subscriber), fn(string $interface) => array_key_exists($interface, $this->mapping)); + } + public function isKnownEventType(\PHPUnit\Event\Event $event): bool + { + return in_array($event::class, $this->mapping, \true); + } + /** + * @throws MapError + * + * @return class-string + */ + public function map(\PHPUnit\Event\Subscriber $subscriber): string + { + foreach (class_implements($subscriber) as $interface) { + if (array_key_exists($interface, $this->mapping)) { + return $this->mapping[$interface]; + } + } + throw new \PHPUnit\Event\MapError(sprintf('Subscriber "%s" does not implement a known interface', $subscriber::class)); + } + /** + * @param class-string $subscriberInterface + * + * @throws UnknownSubscriberException + */ + private function ensureSubscriberInterfaceExists(string $subscriberInterface): void + { + if (!interface_exists($subscriberInterface)) { + throw new \PHPUnit\Event\UnknownSubscriberException(sprintf('Subscriber "%s" does not exist or is not an interface', $subscriberInterface)); + } + } + /** + * @param class-string $eventClass + * + * @throws UnknownEventException + */ + private function ensureEventClassExists(string $eventClass): void + { + if (!class_exists($eventClass)) { + throw new \PHPUnit\Event\UnknownEventException(sprintf('Event class "%s" does not exist', $eventClass)); + } + } + /** + * @param class-string $subscriberInterface + * + * @throws InvalidSubscriberException + */ + private function ensureSubscriberInterfaceExtendsInterface(string $subscriberInterface): void + { + if (!in_array(\PHPUnit\Event\Subscriber::class, class_implements($subscriberInterface), \true)) { + throw new \PHPUnit\Event\InvalidSubscriberException(sprintf('Subscriber "%s" does not extend Subscriber interface', $subscriberInterface)); + } + } + /** + * @param class-string $eventClass + * + * @throws InvalidEventException + */ + private function ensureEventClassImplementsEventInterface(string $eventClass): void + { + if (!in_array(\PHPUnit\Event\Event::class, class_implements($eventClass), \true)) { + throw new \PHPUnit\Event\InvalidEventException(sprintf('Event "%s" does not implement Event interface', $eventClass)); + } + } + /** + * @param class-string $subscriberInterface + * + * @throws SubscriberTypeAlreadyRegisteredException + */ + private function ensureSubscriberWasNotAlreadyRegistered(string $subscriberInterface): void + { + if (array_key_exists($subscriberInterface, $this->mapping)) { + throw new \PHPUnit\Event\SubscriberTypeAlreadyRegisteredException(sprintf('Subscriber type "%s" already registered', $subscriberInterface)); + } + } + /** + * @param class-string $eventClass + * + * @throws EventAlreadyAssignedException + */ + private function ensureEventWasNotAlreadyAssigned(string $eventClass): void + { + if (in_array($eventClass, $this->mapping, \true)) { + throw new \PHPUnit\Event\EventAlreadyAssignedException(sprintf('Event "%s" already assigned', $eventClass)); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ClassMethod +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ComparisonFailure +{ + private string $expected; + private string $actual; + private string $diff; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(string $expected, string $actual, string $diff) + { + $this->expected = $expected; + $this->actual = $actual; + $this->diff = $diff; + } + public function expected(): string + { + return $this->expected; + } + public function actual(): string + { + return $this->actual; + } + public function diff(): string + { + return $this->diff; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use function is_bool; +use function is_scalar; +use function print_r; +use PHPUnit\Framework\ExpectationFailedException; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ComparisonFailureBuilder +{ + public static function from(Throwable $t): ?\PHPUnit\Event\Code\ComparisonFailure + { + if (!$t instanceof ExpectationFailedException) { + return null; + } + if ($t->getComparisonFailure() === null) { + return null; + } + $expectedAsString = $t->getComparisonFailure()->getExpectedAsString(); + if ($expectedAsString === '') { + $expectedAsString = self::mapScalarValueToString($t->getComparisonFailure()->getExpected()); + } + $actualAsString = $t->getComparisonFailure()->getActualAsString(); + if ($actualAsString === '') { + $actualAsString = self::mapScalarValueToString($t->getComparisonFailure()->getActual()); + } + return new \PHPUnit\Event\Code\ComparisonFailure($expectedAsString, $actualAsString, $t->getComparisonFailure()->getDiff()); + } + private static function mapScalarValueToString(mixed $value): string + { + if ($value === null) { + return 'null'; + } + if (is_bool($value)) { + return $value ? 'true' : 'false'; + } + if (is_scalar($value)) { + return print_r($value, \true); + } + return ''; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use const PHP_OS; +use const PHP_OS_FAMILY; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class OperatingSystem +{ + private string $operatingSystem; + private string $operatingSystemFamily; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct() + { + $this->operatingSystem = PHP_OS; + $this->operatingSystemFamily = PHP_OS_FAMILY; + } + public function operatingSystem(): string + { + return $this->operatingSystem; + } + public function operatingSystemFamily(): string + { + return $this->operatingSystemFamily; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use const PHP_EXTRA_VERSION; +use const PHP_MAJOR_VERSION; +use const PHP_MINOR_VERSION; +use const PHP_RELEASE_VERSION; +use const PHP_SAPI; +use const PHP_VERSION; +use const PHP_VERSION_ID; +use function array_merge; +use function get_loaded_extensions; +use function sort; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PHP +{ + private string $version; + private int $versionId; + private int $majorVersion; + private int $minorVersion; + private int $releaseVersion; + private string $extraVersion; + private string $sapi; + /** + * @var list + */ + private array $extensions; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct() + { + $this->version = PHP_VERSION; + $this->versionId = PHP_VERSION_ID; + $this->majorVersion = PHP_MAJOR_VERSION; + $this->minorVersion = PHP_MINOR_VERSION; + $this->releaseVersion = PHP_RELEASE_VERSION; + $this->extraVersion = PHP_EXTRA_VERSION; + $this->sapi = PHP_SAPI; + $extensions = array_merge(get_loaded_extensions(\true), get_loaded_extensions()); + sort($extensions); + $this->extensions = $extensions; + } + public function version(): string + { + return $this->version; + } + public function sapi(): string + { + return $this->sapi; + } + public function majorVersion(): int + { + return $this->majorVersion; + } + public function minorVersion(): int + { + return $this->minorVersion; + } + public function releaseVersion(): int + { + return $this->releaseVersion; + } + public function extraVersion(): string + { + return $this->extraVersion; + } + public function versionId(): int + { + return $this->versionId; + } + /** + * @return list + */ + public function extensions(): array + { + return $this->extensions; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use PHPUnit\Runner\Version; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PHPUnit +{ + private string $versionId; + private string $releaseSeries; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct() + { + $this->versionId = Version::id(); + $this->releaseSeries = Version::series(); + } + public function versionId(): string + { + return $this->versionId; + } + public function releaseSeries(): string + { + return $this->releaseSeries; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use function sprintf; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Runtime +{ + private \PHPUnit\Event\Runtime\OperatingSystem $operatingSystem; + private \PHPUnit\Event\Runtime\PHP $php; + private \PHPUnit\Event\Runtime\PHPUnit $phpunit; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct() + { + $this->operatingSystem = new \PHPUnit\Event\Runtime\OperatingSystem(); + $this->php = new \PHPUnit\Event\Runtime\PHP(); + $this->phpunit = new \PHPUnit\Event\Runtime\PHPUnit(); + } + public function asString(): string + { + $php = $this->php(); + return sprintf('PHPUnit %s using PHP %s (%s) on %s', $this->phpunit()->versionId(), $php->version(), $php->sapi(), $this->operatingSystem()->operatingSystem()); + } + public function operatingSystem(): \PHPUnit\Event\Runtime\OperatingSystem + { + return $this->operatingSystem; + } + public function php(): \PHPUnit\Event\Runtime\PHP + { + return $this->php; + } + public function phpunit(): \PHPUnit\Event\Runtime\PHPUnit + { + return $this->phpunit; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function floor; +use function sprintf; +use PHPUnit\Event\InvalidArgumentException; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Duration +{ + private int $seconds; + private int $nanoseconds; + /** + * @throws InvalidArgumentException + */ + public static function fromSecondsAndNanoseconds(int $seconds, int $nanoseconds): self + { + return new self($seconds, $nanoseconds); + } + /** + * @throws InvalidArgumentException + */ + private function __construct(int $seconds, int $nanoseconds) + { + $this->ensureNotNegative($seconds, 'seconds'); + $this->ensureNotNegative($nanoseconds, 'nanoseconds'); + $this->ensureNanoSecondsInRange($nanoseconds); + $this->seconds = $seconds; + $this->nanoseconds = $nanoseconds; + } + public function seconds(): int + { + return $this->seconds; + } + public function nanoseconds(): int + { + return $this->nanoseconds; + } + public function asFloat(): float + { + return $this->seconds() + $this->nanoseconds() / 1000000000; + } + public function asString(): string + { + $seconds = $this->seconds(); + $minutes = 0; + $hours = 0; + if ($seconds > 60 * 60) { + $hours = floor($seconds / 60 / 60); + $seconds -= $hours * 60 * 60; + } + if ($seconds > 60) { + $minutes = floor($seconds / 60); + $seconds -= $minutes * 60; + } + return sprintf('%02d:%02d:%02d.%09d', (int) $hours, (int) $minutes, (int) $seconds, $this->nanoseconds()); + } + public function equals(self $other): bool + { + return $this->seconds === $other->seconds && $this->nanoseconds === $other->nanoseconds; + } + public function isLessThan(self $other): bool + { + if ($this->seconds < $other->seconds) { + return \true; + } + if ($this->seconds > $other->seconds) { + return \false; + } + return $this->nanoseconds < $other->nanoseconds; + } + public function isGreaterThan(self $other): bool + { + if ($this->seconds > $other->seconds) { + return \true; + } + if ($this->seconds < $other->seconds) { + return \false; + } + return $this->nanoseconds > $other->nanoseconds; + } + /** + * @throws InvalidArgumentException + */ + private function ensureNotNegative(int $value, string $type): void + { + if ($value < 0) { + throw new InvalidArgumentException(sprintf('Value for %s must not be negative.', $type)); + } + } + /** + * @throws InvalidArgumentException + */ + private function ensureNanoSecondsInRange(int $nanoseconds): void + { + if ($nanoseconds > 999999999) { + throw new InvalidArgumentException('Value for nanoseconds must not be greater than 999999999.'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GarbageCollectorStatus +{ + private int $runs; + private int $collected; + private int $threshold; + private int $roots; + private float $applicationTime; + private float $collectorTime; + private float $destructorTime; + private float $freeTime; + private bool $running; + private bool $protected; + private bool $full; + private int $bufferSize; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(int $runs, int $collected, int $threshold, int $roots, float $applicationTime, float $collectorTime, float $destructorTime, float $freeTime, bool $running, bool $protected, bool $full, int $bufferSize) + { + $this->runs = $runs; + $this->collected = $collected; + $this->threshold = $threshold; + $this->roots = $roots; + $this->applicationTime = $applicationTime; + $this->collectorTime = $collectorTime; + $this->destructorTime = $destructorTime; + $this->freeTime = $freeTime; + $this->running = $running; + $this->protected = $protected; + $this->full = $full; + $this->bufferSize = $bufferSize; + } + public function runs(): int + { + return $this->runs; + } + public function collected(): int + { + return $this->collected; + } + public function threshold(): int + { + return $this->threshold; + } + public function roots(): int + { + return $this->roots; + } + public function applicationTime(): float + { + return $this->applicationTime; + } + public function collectorTime(): float + { + return $this->collectorTime; + } + public function destructorTime(): float + { + return $this->destructorTime; + } + public function freeTime(): float + { + return $this->freeTime; + } + public function isRunning(): bool + { + return $this->running; + } + public function isProtected(): bool + { + return $this->protected; + } + public function isFull(): bool + { + return $this->full; + } + public function bufferSize(): int + { + return $this->bufferSize; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface GarbageCollectorStatusProvider +{ + public function status(): \PHPUnit\Event\Telemetry\GarbageCollectorStatus; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function sprintf; +use PHPUnit\Event\InvalidArgumentException; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class HRTime +{ + private int $seconds; + private int $nanoseconds; + /** + * @throws InvalidArgumentException + */ + public static function fromSecondsAndNanoseconds(int $seconds, int $nanoseconds): self + { + return new self($seconds, $nanoseconds); + } + /** + * @throws InvalidArgumentException + */ + private function __construct(int $seconds, int $nanoseconds) + { + $this->ensureNotNegative($seconds, 'seconds'); + $this->ensureNotNegative($nanoseconds, 'nanoseconds'); + $this->ensureNanoSecondsInRange($nanoseconds); + $this->seconds = $seconds; + $this->nanoseconds = $nanoseconds; + } + public function seconds(): int + { + return $this->seconds; + } + public function nanoseconds(): int + { + return $this->nanoseconds; + } + public function duration(self $start): \PHPUnit\Event\Telemetry\Duration + { + $seconds = $this->seconds - $start->seconds(); + $nanoseconds = $this->nanoseconds - $start->nanoseconds(); + if ($nanoseconds < 0) { + $seconds--; + $nanoseconds += 1000000000; + } + if ($seconds < 0) { + return \PHPUnit\Event\Telemetry\Duration::fromSecondsAndNanoseconds(0, 0); + } + return \PHPUnit\Event\Telemetry\Duration::fromSecondsAndNanoseconds($seconds, $nanoseconds); + } + /** + * @throws InvalidArgumentException + */ + private function ensureNotNegative(int $value, string $type): void + { + if ($value < 0) { + throw new InvalidArgumentException(sprintf('Value for %s must not be negative.', $type)); + } + } + /** + * @throws InvalidArgumentException + */ + private function ensureNanoSecondsInRange(int $nanoseconds): void + { + if ($nanoseconds > 999999999) { + throw new InvalidArgumentException('Value for nanoseconds must not be greater than 999999999.'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function sprintf; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Info +{ + private \PHPUnit\Event\Telemetry\Snapshot $current; + private \PHPUnit\Event\Telemetry\Duration $durationSinceStart; + private \PHPUnit\Event\Telemetry\MemoryUsage $memorySinceStart; + private \PHPUnit\Event\Telemetry\Duration $durationSincePrevious; + private \PHPUnit\Event\Telemetry\MemoryUsage $memorySincePrevious; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(\PHPUnit\Event\Telemetry\Snapshot $current, \PHPUnit\Event\Telemetry\Duration $durationSinceStart, \PHPUnit\Event\Telemetry\MemoryUsage $memorySinceStart, \PHPUnit\Event\Telemetry\Duration $durationSincePrevious, \PHPUnit\Event\Telemetry\MemoryUsage $memorySincePrevious) + { + $this->current = $current; + $this->durationSinceStart = $durationSinceStart; + $this->memorySinceStart = $memorySinceStart; + $this->durationSincePrevious = $durationSincePrevious; + $this->memorySincePrevious = $memorySincePrevious; + } + public function time(): \PHPUnit\Event\Telemetry\HRTime + { + return $this->current->time(); + } + public function memoryUsage(): \PHPUnit\Event\Telemetry\MemoryUsage + { + return $this->current->memoryUsage(); + } + public function peakMemoryUsage(): \PHPUnit\Event\Telemetry\MemoryUsage + { + return $this->current->peakMemoryUsage(); + } + public function durationSinceStart(): \PHPUnit\Event\Telemetry\Duration + { + return $this->durationSinceStart; + } + public function memoryUsageSinceStart(): \PHPUnit\Event\Telemetry\MemoryUsage + { + return $this->memorySinceStart; + } + public function durationSincePrevious(): \PHPUnit\Event\Telemetry\Duration + { + return $this->durationSincePrevious; + } + public function memoryUsageSincePrevious(): \PHPUnit\Event\Telemetry\MemoryUsage + { + return $this->memorySincePrevious; + } + public function garbageCollectorStatus(): \PHPUnit\Event\Telemetry\GarbageCollectorStatus + { + return $this->current->garbageCollectorStatus(); + } + public function asString(): string + { + return sprintf('[%s / %s] [%d bytes]', $this->durationSinceStart()->asString(), $this->durationSincePrevious()->asString(), $this->peakMemoryUsage()->bytes()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface MemoryMeter +{ + public function memoryUsage(): \PHPUnit\Event\Telemetry\MemoryUsage; + public function peakMemoryUsage(): \PHPUnit\Event\Telemetry\MemoryUsage; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MemoryUsage +{ + private int $bytes; + public static function fromBytes(int $bytes): self + { + return new self($bytes); + } + private function __construct(int $bytes) + { + $this->bytes = $bytes; + } + public function bytes(): int + { + return $this->bytes; + } + public function diff(self $other): self + { + return self::fromBytes($this->bytes - $other->bytes); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Snapshot +{ + private \PHPUnit\Event\Telemetry\HRTime $time; + private \PHPUnit\Event\Telemetry\MemoryUsage $memoryUsage; + private \PHPUnit\Event\Telemetry\MemoryUsage $peakMemoryUsage; + private \PHPUnit\Event\Telemetry\GarbageCollectorStatus $garbageCollectorStatus; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(\PHPUnit\Event\Telemetry\HRTime $time, \PHPUnit\Event\Telemetry\MemoryUsage $memoryUsage, \PHPUnit\Event\Telemetry\MemoryUsage $peakMemoryUsage, \PHPUnit\Event\Telemetry\GarbageCollectorStatus $garbageCollectorStatus) + { + $this->time = $time; + $this->memoryUsage = $memoryUsage; + $this->peakMemoryUsage = $peakMemoryUsage; + $this->garbageCollectorStatus = $garbageCollectorStatus; + } + public function time(): \PHPUnit\Event\Telemetry\HRTime + { + return $this->time; + } + public function memoryUsage(): \PHPUnit\Event\Telemetry\MemoryUsage + { + return $this->memoryUsage; + } + public function peakMemoryUsage(): \PHPUnit\Event\Telemetry\MemoryUsage + { + return $this->peakMemoryUsage; + } + public function garbageCollectorStatus(): \PHPUnit\Event\Telemetry\GarbageCollectorStatus + { + return $this->garbageCollectorStatus; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface StopWatch +{ + public function current(): \PHPUnit\Event\Telemetry\HRTime; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class System +{ + private \PHPUnit\Event\Telemetry\StopWatch $stopWatch; + private \PHPUnit\Event\Telemetry\MemoryMeter $memoryMeter; + private \PHPUnit\Event\Telemetry\GarbageCollectorStatusProvider $garbageCollectorStatusProvider; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(\PHPUnit\Event\Telemetry\StopWatch $stopWatch, \PHPUnit\Event\Telemetry\MemoryMeter $memoryMeter, \PHPUnit\Event\Telemetry\GarbageCollectorStatusProvider $garbageCollectorStatusProvider) + { + $this->stopWatch = $stopWatch; + $this->memoryMeter = $memoryMeter; + $this->garbageCollectorStatusProvider = $garbageCollectorStatusProvider; + } + public function snapshot(): \PHPUnit\Event\Telemetry\Snapshot + { + return new \PHPUnit\Event\Telemetry\Snapshot($this->stopWatch->current(), $this->memoryMeter->memoryUsage(), $this->memoryMeter->peakMemoryUsage(), $this->garbageCollectorStatusProvider->status()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function gc_status; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class SystemGarbageCollectorStatusProvider implements \PHPUnit\Event\Telemetry\GarbageCollectorStatusProvider +{ + public function status(): \PHPUnit\Event\Telemetry\GarbageCollectorStatus + { + $status = gc_status(); + return new \PHPUnit\Event\Telemetry\GarbageCollectorStatus($status['runs'], $status['collected'], $status['threshold'], $status['roots'], $status['application_time'], $status['collector_time'], $status['destructor_time'], $status['free_time'], $status['running'], $status['protected'], $status['full'], $status['buffer_size']); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function memory_get_peak_usage; +use function memory_get_usage; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class SystemMemoryMeter implements \PHPUnit\Event\Telemetry\MemoryMeter +{ + public function memoryUsage(): \PHPUnit\Event\Telemetry\MemoryUsage + { + return \PHPUnit\Event\Telemetry\MemoryUsage::fromBytes(memory_get_usage()); + } + public function peakMemoryUsage(): \PHPUnit\Event\Telemetry\MemoryUsage + { + return \PHPUnit\Event\Telemetry\MemoryUsage::fromBytes(memory_get_peak_usage()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function hrtime; +use PHPUnit\Event\InvalidArgumentException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class SystemStopWatch implements \PHPUnit\Event\Telemetry\StopWatch +{ + /** + * @throws InvalidArgumentException + */ + public function current(): \PHPUnit\Event\Telemetry\HRTime + { + return \PHPUnit\Event\Telemetry\HRTime::fromSecondsAndNanoseconds(...hrtime()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function hrtime; +use PHPUnit\Event\InvalidArgumentException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ +final class SystemStopWatchWithOffset implements \PHPUnit\Event\Telemetry\StopWatch +{ + private ?\PHPUnit\Event\Telemetry\HRTime $offset; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(\PHPUnit\Event\Telemetry\HRTime $offset) + { + $this->offset = $offset; + } + /** + * @throws InvalidArgumentException + */ + public function current(): \PHPUnit\Event\Telemetry\HRTime + { + if ($this->offset !== null) { + $offset = $this->offset; + $this->offset = null; + return $offset; + } + return \PHPUnit\Event\Telemetry\HRTime::fromSecondsAndNanoseconds(...hrtime()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code\IssueTrigger; + +enum Code : string +{ + public function isFirstPartyOrTest(): bool + { + return $this === self::FirstParty || $this === self::Test; + } + public function isThirdPartyOrPhpunitOrPhp(): bool + { + return $this === self::ThirdParty || $this === self::PHPUnit || $this === self::PHP; + } + case FirstParty = 'first-party code'; + case ThirdParty = 'third-party code'; + case Test = 'test code'; + case PHP = 'PHP runtime'; + case PHPUnit = 'PHPUnit'; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code\IssueTrigger; + +use function sprintf; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IssueTrigger +{ + private ?\PHPUnit\Event\Code\IssueTrigger\Code $callee; + private ?\PHPUnit\Event\Code\IssueTrigger\Code $caller; + public static function from(?\PHPUnit\Event\Code\IssueTrigger\Code $callee, ?\PHPUnit\Event\Code\IssueTrigger\Code $caller): self + { + return new self($callee, $caller); + } + private function __construct(?\PHPUnit\Event\Code\IssueTrigger\Code $callee, ?\PHPUnit\Event\Code\IssueTrigger\Code $caller) + { + $this->callee = $callee; + $this->caller = $caller; + } + /** + * An issue is triggered in first-party code or in test code. + */ + public function isSelf(): bool + { + return $this->callee !== null && $this->callee->isFirstPartyOrTest(); + } + /** + * First-party code triggers an issue in third-party code. + */ + public function isDirect(): bool + { + return $this->caller !== null && $this->caller->isFirstPartyOrTest() && $this->callee !== null && $this->callee->isThirdPartyOrPhpunitOrPhp(); + } + /** + * Third-party code triggers an issue. + */ + public function isIndirect(): bool + { + return $this->caller !== null && $this->caller->isThirdPartyOrPhpunitOrPhp() && $this->callee !== null && $this->callee->isThirdPartyOrPhpunitOrPhp(); + } + public function isUnknown(): bool + { + return !$this->isSelf() && !$this->isDirect() && !$this->isIndirect(); + } + /** + * @return non-empty-string + */ + public function callerAsString(): string + { + return $this->codeAsString($this->caller); + } + /** + * @return non-empty-string + */ + public function calleeAsString(): string + { + return $this->codeAsString($this->callee); + } + /** + * @return non-empty-string + */ + public function asString(): string + { + if ($this->callee === null || $this->caller === null) { + return 'unknown if issue was triggered in first-party code or third-party code'; + } + return sprintf('issue triggered by %s calling into %s', $this->caller->value, $this->callee->value); + } + /** + * @return non-empty-string + */ + private function codeAsString(?\PHPUnit\Event\Code\IssueTrigger\Code $code): string + { + if ($code === null) { + return 'unknown'; + } + return $code->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Phpt extends \PHPUnit\Event\Code\Test +{ + public function isPhpt(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function id(): string + { + return $this->file(); + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->file(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Test +{ + /** + * @var non-empty-string + */ + private string $file; + /** + * @param non-empty-string $file + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(string $file) + { + $this->file = $file; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @phpstan-assert-if-true TestMethod $this + */ + public function isTestMethod(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Phpt $this + */ + public function isPhpt(): bool + { + return \false; + } + /** + * @return non-empty-string + */ + abstract public function id(): string; + /** + * @return non-empty-string + */ + abstract public function name(): string; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @template-implements IteratorAggregate + * + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $tests; + /** + * @param list $tests + */ + public static function fromArray(array $tests): self + { + return new self(...$tests); + } + private function __construct(\PHPUnit\Event\Code\Test ...$tests) + { + $this->tests = $tests; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->tests; + } + public function count(): int + { + return count($this->tests); + } + public function getIterator(): \PHPUnit\Event\Code\TestCollectionIterator + { + return new \PHPUnit\Event\Code\TestCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use Iterator; +/** + * @template-implements Iterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TestCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $tests; + /** + * @var non-negative-int + */ + private int $position = 0; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(\PHPUnit\Event\Code\TestCollection $tests) + { + $this->tests = $tests->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->tests[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\Event\Code\Test + { + return $this->tests[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataFromDataProvider extends \PHPUnit\Event\TestData\TestData +{ + private int|string $dataSetName; + private string $dataAsStringForResultOutput; + public static function from(int|string $dataSetName, string $data, string $dataAsStringForResultOutput): self + { + return new self($dataSetName, $data, $dataAsStringForResultOutput); + } + protected function __construct(int|string $dataSetName, string $data, string $dataAsStringForResultOutput) + { + $this->dataSetName = $dataSetName; + $this->dataAsStringForResultOutput = $dataAsStringForResultOutput; + parent::__construct($data); + } + public function dataSetName(): int|string + { + return $this->dataSetName; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function dataAsStringForResultOutput(): string + { + return $this->dataAsStringForResultOutput; + } + public function isFromDataProvider(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataFromTestDependency extends \PHPUnit\Event\TestData\TestData +{ + public static function from(string $data): self + { + return new self($data); + } + public function isFromTestDependency(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class TestData +{ + private string $data; + protected function __construct(string $data) + { + $this->data = $data; + } + public function data(): string + { + return $this->data; + } + /** + * @phpstan-assert-if-true DataFromDataProvider $this + */ + public function isFromDataProvider(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true DataFromTestDependency $this + */ + public function isFromTestDependency(): bool + { + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @template-implements IteratorAggregate + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestDataCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $data; + private ?\PHPUnit\Event\TestData\DataFromDataProvider $fromDataProvider; + /** + * @param list $data + */ + public static function fromArray(array $data): self + { + return new self(...$data); + } + private function __construct(\PHPUnit\Event\TestData\TestData ...$data) + { + $fromDataProvider = null; + foreach ($data as $_data) { + if ($_data->isFromDataProvider()) { + $fromDataProvider = $_data; + } + } + $this->data = $data; + $this->fromDataProvider = $fromDataProvider; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->data; + } + public function count(): int + { + return count($this->data); + } + /** + * @phpstan-assert-if-true !null $this->fromDataProvider + */ + public function hasDataFromDataProvider(): bool + { + return $this->fromDataProvider !== null; + } + /** + * @throws NoDataSetFromDataProviderException + */ + public function dataFromDataProvider(): \PHPUnit\Event\TestData\DataFromDataProvider + { + if (!$this->hasDataFromDataProvider()) { + throw new \PHPUnit\Event\TestData\NoDataSetFromDataProviderException(); + } + return $this->fromDataProvider; + } + public function getIterator(): \PHPUnit\Event\TestData\TestDataCollectionIterator + { + return new \PHPUnit\Event\TestData\TestDataCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +use Iterator; +/** + * @template-implements Iterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TestDataCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $data; + /** + * @var non-negative-int + */ + private int $position = 0; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(\PHPUnit\Event\TestData\TestDataCollection $data) + { + $this->data = $data->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->data[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\Event\TestData\TestData + { + return $this->data[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestDox +{ + private string $prettifiedClassName; + private string $prettifiedMethodName; + private string $prettifiedAndColorizedMethodName; + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(string $prettifiedClassName, string $prettifiedMethodName, string $prettifiedAndColorizedMethodName) + { + $this->prettifiedClassName = $prettifiedClassName; + $this->prettifiedMethodName = $prettifiedMethodName; + $this->prettifiedAndColorizedMethodName = $prettifiedAndColorizedMethodName; + } + public function prettifiedClassName(): string + { + return $this->prettifiedClassName; + } + public function prettifiedMethodName(bool $colorize = \false): string + { + if ($colorize) { + return $this->prettifiedAndColorizedMethodName; + } + return $this->prettifiedMethodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use PHPUnit\Framework\TestCase; +use PHPUnit\Logging\TestDox\NamePrettifier; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestDoxBuilder +{ + private static ?NamePrettifier $namePrettifier = null; + public static function fromTestCase(TestCase $testCase): \PHPUnit\Event\Code\TestDox + { + $prettifier = self::namePrettifier(); + return new \PHPUnit\Event\Code\TestDox($prettifier->prettifyTestClassName($testCase::class), $prettifier->prettifyTestCase($testCase, \false), $prettifier->prettifyTestCase($testCase, \true)); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function fromClassNameAndMethodName(string $className, string $methodName): \PHPUnit\Event\Code\TestDox + { + $prettifier = self::namePrettifier(); + $prettifiedMethodName = $prettifier->prettifyTestMethodName($methodName); + return new \PHPUnit\Event\Code\TestDox($prettifier->prettifyTestClassName($className), $prettifiedMethodName, $prettifiedMethodName); + } + private static function namePrettifier(): NamePrettifier + { + if (self::$namePrettifier === null) { + self::$namePrettifier = new NamePrettifier(); + } + return self::$namePrettifier; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use function is_int; +use function sprintf; +use PHPUnit\Event\TestData\TestDataCollection; +use PHPUnit\Metadata\MetadataCollection; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMethod extends \PHPUnit\Event\Code\Test +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @var non-negative-int + */ + private int $line; + private \PHPUnit\Event\Code\TestDox $testDox; + private MetadataCollection $metadata; + private TestDataCollection $testData; + /** + * @param class-string $className + * @param non-empty-string $methodName + * @param non-empty-string $file + * @param non-negative-int $line + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(string $className, string $methodName, string $file, int $line, \PHPUnit\Event\Code\TestDox $testDox, MetadataCollection $metadata, TestDataCollection $testData) + { + parent::__construct($file); + $this->className = $className; + $this->methodName = $methodName; + $this->line = $line; + $this->testDox = $testDox; + $this->metadata = $metadata; + $this->testData = $testData; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + /** + * @return non-negative-int + */ + public function line(): int + { + return $this->line; + } + public function testDox(): \PHPUnit\Event\Code\TestDox + { + return $this->testDox; + } + public function metadata(): MetadataCollection + { + return $this->metadata; + } + public function testData(): TestDataCollection + { + return $this->testData; + } + public function isTestMethod(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function id(): string + { + $buffer = $this->className . '::' . $this->methodName; + if ($this->testData()->hasDataFromDataProvider()) { + $buffer .= '#' . $this->testData->dataFromDataProvider()->dataSetName(); + } + return $buffer; + } + /** + * @return non-empty-string + */ + public function nameWithClass(): string + { + return $this->className . '::' . $this->name(); + } + /** + * @return non-empty-string + */ + public function name(): string + { + if (!$this->testData->hasDataFromDataProvider()) { + return $this->methodName; + } + $dataSetName = $this->testData->dataFromDataProvider()->dataSetName(); + if (is_int($dataSetName)) { + $dataSetName = sprintf(' with data set #%d', $dataSetName); + } else { + $dataSetName = sprintf(' with data set "%s"', $dataSetName); + } + return $this->methodName . $dataSetName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use function is_numeric; +use PHPUnit\Event\TestData\DataFromDataProvider; +use PHPUnit\Event\TestData\DataFromTestDependency; +use PHPUnit\Event\TestData\TestDataCollection; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Util\Exporter; +use PHPUnit\Util\Reflection; +use PHPUnit\Util\Test as TestUtil; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMethodBuilder +{ + public static function fromTestCase(TestCase $testCase, bool $useTestCaseForTestDox = \true): \PHPUnit\Event\Code\TestMethod + { + $methodName = $testCase->name(); + $location = Reflection::sourceLocationFor($testCase::class, $methodName); + if ($useTestCaseForTestDox) { + $testDox = \PHPUnit\Event\Code\TestDoxBuilder::fromTestCase($testCase); + } else { + $testDox = \PHPUnit\Event\Code\TestDoxBuilder::fromClassNameAndMethodName($testCase::class, $testCase->name()); + } + return new \PHPUnit\Event\Code\TestMethod($testCase::class, $methodName, $location['file'], $location['line'], $testDox, MetadataRegistry::parser()->forClassAndMethod($testCase::class, $methodName), self::dataFor($testCase)); + } + /** + * @throws NoTestCaseObjectOnCallStackException + */ + public static function fromCallStack(): \PHPUnit\Event\Code\TestMethod + { + return TestUtil::currentTestCase()->valueObjectForEvents(); + } + private static function dataFor(TestCase $testCase): TestDataCollection + { + $testData = []; + if ($testCase->usesDataProvider()) { + $dataSetName = $testCase->dataName(); + if (is_numeric($dataSetName)) { + $dataSetName = (int) $dataSetName; + } + $testData[] = DataFromDataProvider::from($dataSetName, Exporter::shortenedRecursiveExport($testCase->providedData()), $testCase->dataSetAsStringWithData()); + } + if ($testCase->hasDependencyInput()) { + $testData[] = DataFromTestDependency::from(Exporter::shortenedRecursiveExport($testCase->dependencyInput())); + } + return TestDataCollection::fromArray($testData); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Code\TestCollection; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class TestSuite +{ + /** + * @var non-empty-string + */ + private string $name; + private int $count; + private TestCollection $tests; + /** + * @param non-empty-string $name + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(string $name, int $size, TestCollection $tests) + { + $this->name = $name; + $this->count = $size; + $this->tests = $tests; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + public function count(): int + { + return $this->count; + } + public function tests(): TestCollection + { + return $this->tests; + } + /** + * @phpstan-assert-if-true TestSuiteWithName $this + */ + public function isWithName(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true TestSuiteForTestClass $this + */ + public function isForTestClass(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true TestSuiteForTestMethodWithDataProvider $this + */ + public function isForTestMethodWithDataProvider(): bool + { + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function assert; +use function class_exists; +use function count; +use function explode; +use function method_exists; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Code\TestCollection; +use PHPUnit\Event\RuntimeException; +use PHPUnit\Framework\DataProviderTestSuite; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite as FrameworkTestSuite; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use ReflectionClass; +use ReflectionMethod; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteBuilder +{ + /** + * @throws RuntimeException + */ + public static function from(FrameworkTestSuite $testSuite): \PHPUnit\Event\TestSuite\TestSuite + { + $tests = []; + self::process($testSuite, $tests); + if ($testSuite instanceof DataProviderTestSuite) { + assert(count(explode('::', $testSuite->name())) === 2); + [$className, $methodName] = explode('::', $testSuite->name()); + assert(class_exists($className)); + assert($methodName !== '' && method_exists($className, $methodName)); + $reflector = new ReflectionMethod($className, $methodName); + $file = $reflector->getFileName(); + $line = $reflector->getStartLine(); + assert($file !== \false); + assert($line !== \false); + return new \PHPUnit\Event\TestSuite\TestSuiteForTestMethodWithDataProvider($testSuite->name(), $testSuite->count(), TestCollection::fromArray($tests), $className, $methodName, $file, $line); + } + if ($testSuite->isForTestClass()) { + $testClassName = $testSuite->name(); + assert(class_exists($testClassName)); + $reflector = new ReflectionClass($testClassName); + $file = $reflector->getFileName(); + $line = $reflector->getStartLine(); + assert($file !== \false); + assert($line !== \false); + return new \PHPUnit\Event\TestSuite\TestSuiteForTestClass($testClassName, $testSuite->count(), TestCollection::fromArray($tests), $file, $line); + } + return new \PHPUnit\Event\TestSuite\TestSuiteWithName($testSuite->name(), $testSuite->count(), TestCollection::fromArray($tests)); + } + /** + * @param list $tests + */ + private static function process(FrameworkTestSuite $testSuite, array &$tests): void + { + foreach ($testSuite->getIterator() as $test) { + if ($test instanceof FrameworkTestSuite) { + self::process($test, $tests); + continue; + } + if ($test instanceof TestCase || $test instanceof PhptTestCase) { + $tests[] = $test->valueObjectForEvents(); + } + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Code\TestCollection; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteForTestClass extends \PHPUnit\Event\TestSuite\TestSuite +{ + /** + * @var class-string + */ + private string $className; + private string $file; + private int $line; + /** + * @param class-string $name + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(string $name, int $size, TestCollection $tests, string $file, int $line) + { + parent::__construct($name, $size, $tests); + $this->className = $name; + $this->file = $file; + $this->line = $line; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + public function file(): string + { + return $this->file; + } + public function line(): int + { + return $this->line; + } + public function isForTestClass(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Code\TestCollection; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteForTestMethodWithDataProvider extends \PHPUnit\Event\TestSuite\TestSuite +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + private string $file; + private int $line; + /** + * @param non-empty-string $name + * @param class-string $className + * @param non-empty-string $methodName + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(string $name, int $size, TestCollection $tests, string $className, string $methodName, string $file, int $line) + { + parent::__construct($name, $size, $tests); + $this->className = $className; + $this->methodName = $methodName; + $this->file = $file; + $this->line = $line; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + public function file(): string + { + return $this->file; + } + public function line(): int + { + return $this->line; + } + public function isForTestMethodWithDataProvider(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteWithName extends \PHPUnit\Event\TestSuite\TestSuite +{ + public function isWithName(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use const PHP_EOL; +use PHPUnit\Event\NoPreviousThrowableException; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Throwable +{ + /** + * @var class-string + */ + private string $className; + private string $message; + private string $description; + private string $stackTrace; + private ?\PHPUnit\Event\Code\Throwable $previous; + /** + * @param class-string $className + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function __construct(string $className, string $message, string $description, string $stackTrace, ?self $previous) + { + $this->className = $className; + $this->message = $message; + $this->description = $description; + $this->stackTrace = $stackTrace; + $this->previous = $previous; + } + /** + * @throws NoPreviousThrowableException + */ + public function asString(): string + { + $buffer = $this->description(); + if ($this->stackTrace() !== '') { + $buffer .= PHP_EOL . $this->stackTrace(); + } + if ($this->hasPrevious()) { + $buffer .= PHP_EOL . 'Caused by' . PHP_EOL . $this->previous()->asString(); + } + return $buffer; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + public function message(): string + { + return $this->message; + } + public function description(): string + { + return $this->description; + } + public function stackTrace(): string + { + return $this->stackTrace; + } + /** + * @phpstan-assert-if-true !null $this->previous + */ + public function hasPrevious(): bool + { + return $this->previous !== null; + } + /** + * @throws NoPreviousThrowableException + */ + public function previous(): self + { + if ($this->previous === null) { + throw new NoPreviousThrowableException(); + } + return $this->previous; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use PHPUnit\Event\NoPreviousThrowableException; +use PHPUnit\Framework\Exception; +use PHPUnit\Util\Filter; +use PHPUnit\Util\ThrowableToStringMapper; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ThrowableBuilder +{ + /** + * @throws Exception + * @throws NoPreviousThrowableException + */ + public static function from(\Throwable $t): \PHPUnit\Event\Code\Throwable + { + $previous = $t->getPrevious(); + if ($previous !== null) { + $previous = self::from($previous); + } + return new \PHPUnit\Event\Code\Throwable($t::class, $t->getMessage(), ThrowableToStringMapper::map($t), Filter::stackTraceFromThrowableAsString($t, \false), $previous); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit; + +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function array_combine; +use function array_intersect_key; +use function class_exists; +use function count; +use function file_get_contents; +use function interface_exists; +use function is_bool; +use ArrayAccess; +use Countable; +use Generator; +use PHPUnit\Framework\Constraint\ArrayHasKey; +use PHPUnit\Framework\Constraint\ArraysAreEqual; +use PHPUnit\Framework\Constraint\ArraysAreIdentical; +use PHPUnit\Framework\Constraint\Callback; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\Constraint\Count; +use PHPUnit\Framework\Constraint\DirectoryExists; +use PHPUnit\Framework\Constraint\FileExists; +use PHPUnit\Framework\Constraint\GreaterThan; +use PHPUnit\Framework\Constraint\IsAnything; +use PHPUnit\Framework\Constraint\IsEmpty; +use PHPUnit\Framework\Constraint\IsEqual; +use PHPUnit\Framework\Constraint\IsEqualCanonicalizing; +use PHPUnit\Framework\Constraint\IsEqualIgnoringCase; +use PHPUnit\Framework\Constraint\IsEqualWithDelta; +use PHPUnit\Framework\Constraint\IsFalse; +use PHPUnit\Framework\Constraint\IsFinite; +use PHPUnit\Framework\Constraint\IsIdentical; +use PHPUnit\Framework\Constraint\IsInfinite; +use PHPUnit\Framework\Constraint\IsInstanceOf; +use PHPUnit\Framework\Constraint\IsJson; +use PHPUnit\Framework\Constraint\IsList; +use PHPUnit\Framework\Constraint\IsNan; +use PHPUnit\Framework\Constraint\IsNull; +use PHPUnit\Framework\Constraint\IsReadable; +use PHPUnit\Framework\Constraint\IsTrue; +use PHPUnit\Framework\Constraint\IsType; +use PHPUnit\Framework\Constraint\IsWritable; +use PHPUnit\Framework\Constraint\JsonMatches; +use PHPUnit\Framework\Constraint\LessThan; +use PHPUnit\Framework\Constraint\LogicalAnd; +use PHPUnit\Framework\Constraint\LogicalNot; +use PHPUnit\Framework\Constraint\LogicalOr; +use PHPUnit\Framework\Constraint\LogicalXor; +use PHPUnit\Framework\Constraint\ObjectEquals; +use PHPUnit\Framework\Constraint\ObjectHasProperty; +use PHPUnit\Framework\Constraint\RegularExpression; +use PHPUnit\Framework\Constraint\SameSize; +use PHPUnit\Framework\Constraint\StringContains; +use PHPUnit\Framework\Constraint\StringEndsWith; +use PHPUnit\Framework\Constraint\StringEqualsStringIgnoringLineEndings; +use PHPUnit\Framework\Constraint\StringMatchesFormatDescription; +use PHPUnit\Framework\Constraint\StringStartsWith; +use PHPUnit\Framework\Constraint\TraversableContainsEqual; +use PHPUnit\Framework\Constraint\TraversableContainsIdentical; +use PHPUnit\Framework\Constraint\TraversableContainsOnly; +use PHPUnit\Util\Xml\Loader as XmlLoader; +use PHPUnit\Util\Xml\XmlException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class Assert +{ + private static int $count = 0; + /** + * Asserts that two arrays are equal while only considering a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeConsidered + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayIsEqualToArrayOnlyConsideringListOfKeys(array $expected, array $actual, array $keysToBeConsidered, string $message = ''): void + { + $filteredExpected = []; + foreach ($keysToBeConsidered as $key) { + if (isset($expected[$key])) { + $filteredExpected[$key] = $expected[$key]; + } + } + $filteredActual = []; + foreach ($keysToBeConsidered as $key) { + if (isset($actual[$key])) { + $filteredActual[$key] = $actual[$key]; + } + } + self::assertEquals($filteredExpected, $filteredActual, $message); + } + /** + * Asserts that two arrays are equal while ignoring a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeIgnored + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayIsEqualToArrayIgnoringListOfKeys(array $expected, array $actual, array $keysToBeIgnored, string $message = ''): void + { + foreach ($keysToBeIgnored as $key) { + unset($expected[$key], $actual[$key]); + } + self::assertEquals($expected, $actual, $message); + } + /** + * Asserts that two arrays are identical while only considering a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeConsidered + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys(array $expected, array $actual, array $keysToBeConsidered, string $message = ''): void + { + $keysToBeConsidered = array_combine($keysToBeConsidered, $keysToBeConsidered); + $expected = array_intersect_key($expected, $keysToBeConsidered); + $actual = array_intersect_key($actual, $keysToBeConsidered); + self::assertSame($expected, $actual, $message); + } + /** + * Asserts that two arrays are equal while ignoring a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeIgnored + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayIsIdenticalToArrayIgnoringListOfKeys(array $expected, array $actual, array $keysToBeIgnored, string $message = ''): void + { + foreach ($keysToBeIgnored as $key) { + unset($expected[$key], $actual[$key]); + } + self::assertSame($expected, $actual, $message); + } + /** + * Asserts that an array has a specified key. + * + * @param array|ArrayAccess $array + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayHasKey(mixed $key, array|ArrayAccess $array, string $message = ''): void + { + $constraint = new ArrayHasKey($key); + self::assertThat($array, $constraint, $message); + } + /** + * Asserts that an array does not have a specified key. + * + * @param array|ArrayAccess $array + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayNotHasKey(mixed $key, array|ArrayAccess $array, string $message = ''): void + { + $constraint = new LogicalNot(new ArrayHasKey($key)); + self::assertThat($array, $constraint, $message); + } + /** + * @phpstan-assert list $array + * + * @throws ExpectationFailedException + */ + final public static function assertIsList(mixed $array, string $message = ''): void + { + self::assertThat($array, new IsList(), $message); + } + /** + * Assert that two arrays are identical. + * + * The (key, value) relationship matters, the order of the (key, value) pairs in the array matters, and keys as well as values are compared strictly. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + */ + final public static function assertArraysAreIdentical(array $expected, array $actual, string $message = ''): void + { + self::assertThat($actual, new ArraysAreIdentical($expected, \true, \true), $message); + } + /** + * Assert that two arrays are identical while ignoring the order of their values. + * + * The (key, value) relationship matters, the order of the (key, value) pairs in the array does not matter, and keys as well as values are compared strictly. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + */ + final public static function assertArraysAreIdenticalIgnoringOrder(array $expected, array $actual, string $message = ''): void + { + self::assertThat($actual, new ArraysAreIdentical($expected, \true, \false), $message); + } + /** + * Assert that two arrays have identical values. + * + * The (key, value) relationship does not matter, the order of the (key, value) pairs in the array matters, and values are compared strictly. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + */ + final public static function assertArraysHaveIdenticalValues(array $expected, array $actual, string $message = ''): void + { + self::assertThat($actual, new ArraysAreIdentical($expected, \false, \true), $message); + } + /** + * Assert that two arrays have identical values while ignoring the order of these values. + * + * The (key, value) relationship does not matter, the order of the (key, value) pairs in the array does not matter, and values are compared strictly. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + */ + final public static function assertArraysHaveIdenticalValuesIgnoringOrder(array $expected, array $actual, string $message = ''): void + { + self::assertThat($actual, new ArraysAreIdentical($expected, \false, \false), $message); + } + /** + * Assert that two arrays are equal. + * + * The (key, value) relationship matters, the order of the (key, value) pairs in the array matters, and keys as well as values are compared loosely. + * + * @param array $expected + * @param array $actual + */ + final public static function assertArraysAreEqual(array $expected, array $actual, string $message = ''): void + { + self::assertThat($actual, new ArraysAreEqual($expected, \true, \true), $message); + } + /** + * Assert that two arrays are equal while ignoring the order of their values. + * + * The (key, value) relationship matters, the order of the (key, value) pairs in the array does not matter, and keys as well as values are compared loosely. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + */ + final public static function assertArraysAreEqualIgnoringOrder(array $expected, array $actual, string $message = ''): void + { + self::assertThat($actual, new ArraysAreEqual($expected, \true, \false), $message); + } + /** + * Assert that two arrays have equal values. + * + * The (key, value) relationship does not matter, the order of the (key, value) pairs in the array matters, and values are compared loosely. + * + * @param array $expected + * @param array $actual + */ + final public static function assertArraysHaveEqualValues(array $expected, array $actual, string $message = ''): void + { + self::assertThat($actual, new ArraysAreEqual($expected, \false, \true), $message); + } + /** + * Assert that two arrays have equal values while ignoring the order of these values. + * + * The (key, value) relationship does not matter, the order of the (key, value) pairs in the array does not matter, and values are compared loosely. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + */ + final public static function assertArraysHaveEqualValuesIgnoringOrder(array $expected, array $actual, string $message = ''): void + { + self::assertThat($actual, new ArraysAreEqual($expected, \false, \false), $message); + } + /** + * Asserts that a haystack contains a needle. + * + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertContains(mixed $needle, iterable $haystack, string $message = ''): void + { + $constraint = new TraversableContainsIdentical($needle); + self::assertThat($haystack, $constraint, $message); + } + /** + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsEquals(mixed $needle, iterable $haystack, string $message = ''): void + { + $constraint = new TraversableContainsEqual($needle); + self::assertThat($haystack, $constraint, $message); + } + /** + * Asserts that a haystack does not contain a needle. + * + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertNotContains(mixed $needle, iterable $haystack, string $message = ''): void + { + $constraint = new LogicalNot(new TraversableContainsIdentical($needle)); + self::assertThat($haystack, $constraint, $message); + } + /** + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertNotContainsEquals(mixed $needle, iterable $haystack, string $message = ''): void + { + $constraint = new LogicalNot(new TraversableContainsEqual($needle)); + self::assertThat($haystack, $constraint, $message); + } + /** + * Asserts that a haystack contains only values of type array. + * + * @phpstan-assert iterable> $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyArray(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Array), $message); + } + /** + * Asserts that a haystack contains only values of type bool. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyBool(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Bool), $message); + } + /** + * Asserts that a haystack contains only values of type callable. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyCallable(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Callable), $message); + } + /** + * Asserts that a haystack contains only values of type float. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyFloat(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Float), $message); + } + /** + * Asserts that a haystack contains only values of type int. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyInt(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Int), $message); + } + /** + * Asserts that a haystack contains only values of type iterable. + * + * @phpstan-assert iterable> $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyIterable(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Iterable), $message); + } + /** + * Asserts that a haystack contains only values of type null. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyNull(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Null), $message); + } + /** + * Asserts that a haystack contains only values of type numeric. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyNumeric(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Numeric), $message); + } + /** + * Asserts that a haystack contains only values of type object. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyObject(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Object), $message); + } + /** + * Asserts that a haystack contains only values of type resource. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyResource(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Resource), $message); + } + /** + * Asserts that a haystack contains only values of type closed resource. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyClosedResource(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::ClosedResource), $message); + } + /** + * Asserts that a haystack contains only values of type scalar. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyScalar(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Scalar), $message); + } + /** + * Asserts that a haystack contains only values of type string. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyString(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::String), $message); + } + /** + * Asserts that a haystack contains only instances of a specified interface or class name. + * + * @template T + * + * @phpstan-assert iterable $haystack + * + * @param class-string $className + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, TraversableContainsOnly::forClassOrInterface($className), $message); + } + /** + * Asserts that a haystack does not contain only values of type array. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyArray(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Array)), $message); + } + /** + * Asserts that a haystack does not contain only values of type bool. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyBool(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Bool)), $message); + } + /** + * Asserts that a haystack does not contain only values of type callable. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyCallable(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Callable)), $message); + } + /** + * Asserts that a haystack does not contain only values of type float. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyFloat(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Float)), $message); + } + /** + * Asserts that a haystack does not contain only values of type int. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyInt(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Int)), $message); + } + /** + * Asserts that a haystack does not contain only values of type iterable. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyIterable(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Iterable)), $message); + } + /** + * Asserts that a haystack does not contain only values of type null. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyNull(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Null)), $message); + } + /** + * Asserts that a haystack does not contain only values of type numeric. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyNumeric(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Numeric)), $message); + } + /** + * Asserts that a haystack does not contain only values of type object. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyObject(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Object)), $message); + } + /** + * Asserts that a haystack does not contain only values of type resource. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyResource(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Resource)), $message); + } + /** + * Asserts that a haystack does not contain only values of type closed resource. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyClosedResource(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::ClosedResource)), $message); + } + /** + * Asserts that a haystack does not contain only values of type scalar. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyScalar(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Scalar)), $message); + } + /** + * Asserts that a haystack does not contain only values of type string. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyString(iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::String)), $message); + } + /** + * Asserts that a haystack does not contain only instances of a specified interface or class name. + * + * @param class-string $className + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void + { + self::assertThat($haystack, new LogicalNot(TraversableContainsOnly::forClassOrInterface($className)), $message); + } + /** + * Asserts the number of elements of an array, Countable or Traversable. + * + * @param Countable|iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertCount(int $expectedCount, Countable|iterable $haystack, string $message = ''): void + { + if ($haystack instanceof Generator) { + throw \PHPUnit\Framework\GeneratorNotSupportedException::fromParameterName('$haystack'); + } + self::assertThat($haystack, new Count($expectedCount), $message); + } + /** + * Asserts the number of elements of an array, Countable or Traversable. + * + * @param Countable|iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertNotCount(int $expectedCount, Countable|iterable $haystack, string $message = ''): void + { + if ($haystack instanceof Generator) { + throw \PHPUnit\Framework\GeneratorNotSupportedException::fromParameterName('$haystack'); + } + $constraint = new LogicalNot(new Count($expectedCount)); + self::assertThat($haystack, $constraint, $message); + } + /** + * Asserts that two variables are equal. + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + */ + final public static function assertEquals(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new IsEqual($expected); + self::assertThat($actual, $constraint, $message); + } + /** + * Asserts that two variables are equal (canonicalizing). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + */ + final public static function assertEqualsCanonicalizing(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new IsEqualCanonicalizing($expected); + self::assertThat($actual, $constraint, $message); + } + /** + * Asserts that two variables are equal (ignoring case). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + */ + final public static function assertEqualsIgnoringCase(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new IsEqualIgnoringCase($expected); + self::assertThat($actual, $constraint, $message); + } + /** + * Asserts that two variables are equal (with delta). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + */ + final public static function assertEqualsWithDelta(mixed $expected, mixed $actual, float $delta, string $message = ''): void + { + $constraint = new IsEqualWithDelta($expected, $delta); + self::assertThat($actual, $constraint, $message); + } + /** + * Asserts that two variables are not equal. + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + */ + final public static function assertNotEquals(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new LogicalNot(new IsEqual($expected)); + self::assertThat($actual, $constraint, $message); + } + /** + * Asserts that two variables are not equal (canonicalizing). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + */ + final public static function assertNotEqualsCanonicalizing(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new LogicalNot(new IsEqualCanonicalizing($expected)); + self::assertThat($actual, $constraint, $message); + } + /** + * Asserts that two variables are not equal (ignoring case). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + */ + final public static function assertNotEqualsIgnoringCase(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new LogicalNot(new IsEqualIgnoringCase($expected)); + self::assertThat($actual, $constraint, $message); + } + /** + * Asserts that two variables are not equal (with delta). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + */ + final public static function assertNotEqualsWithDelta(mixed $expected, mixed $actual, float $delta, string $message = ''): void + { + $constraint = new LogicalNot(new IsEqualWithDelta($expected, $delta)); + self::assertThat($actual, $constraint, $message); + } + /** + * @throws ExpectationFailedException + */ + final public static function assertObjectEquals(object $expected, object $actual, string $method = 'equals', string $message = ''): void + { + self::assertThat($actual, self::objectEquals($expected, $method), $message); + } + /** + * @throws ExpectationFailedException + */ + final public static function assertObjectNotEquals(object $expected, object $actual, string $method = 'equals', string $message = ''): void + { + self::assertThat($actual, self::logicalNot(self::objectEquals($expected, $method)), $message); + } + /** + * Asserts that a variable is empty. + * + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertEmpty(mixed $actual, string $message = ''): void + { + if ($actual instanceof Generator) { + throw \PHPUnit\Framework\GeneratorNotSupportedException::fromParameterName('$actual'); + } + self::assertThat($actual, self::isEmpty(), $message); + } + /** + * Asserts that a variable is not empty. + * + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertNotEmpty(mixed $actual, string $message = ''): void + { + if ($actual instanceof Generator) { + throw \PHPUnit\Framework\GeneratorNotSupportedException::fromParameterName('$actual'); + } + self::assertThat($actual, self::logicalNot(self::isEmpty()), $message); + } + /** + * Asserts that a value is greater than another value. + * + * @throws ExpectationFailedException + */ + final public static function assertGreaterThan(mixed $minimum, mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::greaterThan($minimum), $message); + } + /** + * Asserts that a value is greater than or equal to another value. + * + * @throws ExpectationFailedException + */ + final public static function assertGreaterThanOrEqual(mixed $minimum, mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::greaterThanOrEqual($minimum), $message); + } + /** + * Asserts that a value is smaller than another value. + * + * @throws ExpectationFailedException + */ + final public static function assertLessThan(mixed $maximum, mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::lessThan($maximum), $message); + } + /** + * Asserts that a value is smaller than or equal to another value. + * + * @throws ExpectationFailedException + */ + final public static function assertLessThanOrEqual(mixed $maximum, mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::lessThanOrEqual($maximum), $message); + } + /** + * Asserts that the contents of one file is equal to the contents of another + * file. + * + * @throws ExpectationFailedException + */ + final public static function assertFileEquals(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + $constraint = new IsEqual(file_get_contents($expected)); + self::assertThat(file_get_contents($actual), $constraint, $message); + } + /** + * Asserts that the contents of one file is equal to the contents of another + * file (canonicalizing). + * + * @throws ExpectationFailedException + */ + final public static function assertFileEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + $constraint = new IsEqualCanonicalizing(file_get_contents($expected)); + self::assertThat(file_get_contents($actual), $constraint, $message); + } + /** + * Asserts that the contents of one file is equal to the contents of another + * file (ignoring case). + * + * @throws ExpectationFailedException + */ + final public static function assertFileEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + $constraint = new IsEqualIgnoringCase(file_get_contents($expected)); + self::assertThat(file_get_contents($actual), $constraint, $message); + } + /** + * Asserts that the contents of one file is not equal to the contents of + * another file. + * + * @throws ExpectationFailedException + */ + final public static function assertFileNotEquals(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + $constraint = new LogicalNot(new IsEqual(file_get_contents($expected))); + self::assertThat(file_get_contents($actual), $constraint, $message); + } + /** + * Asserts that the contents of one file is not equal to the contents of another + * file (canonicalizing). + * + * @throws ExpectationFailedException + */ + final public static function assertFileNotEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + $constraint = new LogicalNot(new IsEqualCanonicalizing(file_get_contents($expected))); + self::assertThat(file_get_contents($actual), $constraint, $message); + } + /** + * Asserts that the contents of one file is not equal to the contents of another + * file (ignoring case). + * + * @throws ExpectationFailedException + */ + final public static function assertFileNotEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + $constraint = new LogicalNot(new IsEqualIgnoringCase(file_get_contents($expected))); + self::assertThat(file_get_contents($actual), $constraint, $message); + } + /** + * Asserts that the contents of a string is equal + * to the contents of a file. + * + * @throws ExpectationFailedException + */ + final public static function assertStringEqualsFile(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + $constraint = new IsEqual(file_get_contents($expectedFile)); + self::assertThat($actualString, $constraint, $message); + } + /** + * Asserts that the contents of a string is equal + * to the contents of a file (canonicalizing). + * + * @throws ExpectationFailedException + */ + final public static function assertStringEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + $constraint = new IsEqualCanonicalizing(file_get_contents($expectedFile)); + self::assertThat($actualString, $constraint, $message); + } + /** + * Asserts that the contents of a string is equal + * to the contents of a file (ignoring case). + * + * @throws ExpectationFailedException + */ + final public static function assertStringEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + $constraint = new IsEqualIgnoringCase(file_get_contents($expectedFile)); + self::assertThat($actualString, $constraint, $message); + } + /** + * Asserts that the contents of a string is not equal + * to the contents of a file. + * + * @throws ExpectationFailedException + */ + final public static function assertStringNotEqualsFile(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + $constraint = new LogicalNot(new IsEqual(file_get_contents($expectedFile))); + self::assertThat($actualString, $constraint, $message); + } + /** + * Asserts that the contents of a string is not equal + * to the contents of a file (canonicalizing). + * + * @throws ExpectationFailedException + */ + final public static function assertStringNotEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + $constraint = new LogicalNot(new IsEqualCanonicalizing(file_get_contents($expectedFile))); + self::assertThat($actualString, $constraint, $message); + } + /** + * Asserts that the contents of a string is not equal + * to the contents of a file (ignoring case). + * + * @throws ExpectationFailedException + */ + final public static function assertStringNotEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + $constraint = new LogicalNot(new IsEqualIgnoringCase(file_get_contents($expectedFile))); + self::assertThat($actualString, $constraint, $message); + } + /** + * Asserts that a file/dir is readable. + * + * @throws ExpectationFailedException + */ + final public static function assertIsReadable(string $filename, string $message = ''): void + { + self::assertThat($filename, new IsReadable(), $message); + } + /** + * Asserts that a file/dir exists and is not readable. + * + * @throws ExpectationFailedException + */ + final public static function assertIsNotReadable(string $filename, string $message = ''): void + { + self::assertThat($filename, new LogicalNot(new IsReadable()), $message); + } + /** + * Asserts that a file/dir exists and is writable. + * + * @throws ExpectationFailedException + */ + final public static function assertIsWritable(string $filename, string $message = ''): void + { + self::assertThat($filename, new IsWritable(), $message); + } + /** + * Asserts that a file/dir exists and is not writable. + * + * @throws ExpectationFailedException + */ + final public static function assertIsNotWritable(string $filename, string $message = ''): void + { + self::assertThat($filename, new LogicalNot(new IsWritable()), $message); + } + /** + * Asserts that a directory exists. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryExists(string $directory, string $message = ''): void + { + self::assertThat($directory, new DirectoryExists(), $message); + } + /** + * Asserts that a directory does not exist. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryDoesNotExist(string $directory, string $message = ''): void + { + self::assertThat($directory, new LogicalNot(new DirectoryExists()), $message); + } + /** + * Asserts that a directory exists and is readable. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryIsReadable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertIsReadable($directory, $message); + } + /** + * Asserts that a directory exists and is not readable. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryIsNotReadable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertIsNotReadable($directory, $message); + } + /** + * Asserts that a directory exists and is writable. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryIsWritable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertIsWritable($directory, $message); + } + /** + * Asserts that a directory exists and is not writable. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryIsNotWritable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertIsNotWritable($directory, $message); + } + /** + * Asserts that a file exists. + * + * @throws ExpectationFailedException + */ + final public static function assertFileExists(string $filename, string $message = ''): void + { + self::assertThat($filename, new FileExists(), $message); + } + /** + * Asserts that a file does not exist. + * + * @throws ExpectationFailedException + */ + final public static function assertFileDoesNotExist(string $filename, string $message = ''): void + { + self::assertThat($filename, new LogicalNot(new FileExists()), $message); + } + /** + * Asserts that a file exists and is readable. + * + * @throws ExpectationFailedException + */ + final public static function assertFileIsReadable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertIsReadable($file, $message); + } + /** + * Asserts that a file exists and is not readable. + * + * @throws ExpectationFailedException + */ + final public static function assertFileIsNotReadable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertIsNotReadable($file, $message); + } + /** + * Asserts that a file exists and is writable. + * + * @throws ExpectationFailedException + */ + final public static function assertFileIsWritable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertIsWritable($file, $message); + } + /** + * Asserts that a file exists and is not writable. + * + * @throws ExpectationFailedException + */ + final public static function assertFileIsNotWritable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertIsNotWritable($file, $message); + } + /** + * Asserts that a condition is true. + * + * @throws ExpectationFailedException + * + * @phpstan-assert true $condition + */ + final public static function assertTrue(mixed $condition, string $message = ''): void + { + self::assertThat($condition, self::isTrue(), $message); + } + /** + * Asserts that a condition is not true. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !true $condition + */ + final public static function assertNotTrue(mixed $condition, string $message = ''): void + { + self::assertThat($condition, self::logicalNot(self::isTrue()), $message); + } + /** + * Asserts that a condition is false. + * + * @throws ExpectationFailedException + * + * @phpstan-assert false $condition + */ + final public static function assertFalse(mixed $condition, string $message = ''): void + { + self::assertThat($condition, self::isFalse(), $message); + } + /** + * Asserts that a condition is not false. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !false $condition + */ + final public static function assertNotFalse(mixed $condition, string $message = ''): void + { + self::assertThat($condition, self::logicalNot(self::isFalse()), $message); + } + /** + * Asserts that a variable is null. + * + * @throws ExpectationFailedException + * + * @phpstan-assert null $actual + */ + final public static function assertNull(mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::isNull(), $message); + } + /** + * Asserts that a variable is not null. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !null $actual + */ + final public static function assertNotNull(mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::logicalNot(self::isNull()), $message); + } + /** + * Asserts that a variable is finite. + * + * @throws ExpectationFailedException + */ + final public static function assertFinite(mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::isFinite(), $message); + } + /** + * Asserts that a variable is infinite. + * + * @throws ExpectationFailedException + */ + final public static function assertInfinite(mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::isInfinite(), $message); + } + /** + * Asserts that a variable is nan. + * + * @throws ExpectationFailedException + */ + final public static function assertNan(mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::isNan(), $message); + } + /** + * Asserts that an object has a specified property. + * + * @throws ExpectationFailedException + */ + final public static function assertObjectHasProperty(string $propertyName, object $object, string $message = ''): void + { + self::assertThat($object, new ObjectHasProperty($propertyName), $message); + } + /** + * Asserts that an object does not have a specified property. + * + * @throws ExpectationFailedException + */ + final public static function assertObjectNotHasProperty(string $propertyName, object $object, string $message = ''): void + { + self::assertThat($object, new LogicalNot(new ObjectHasProperty($propertyName)), $message); + } + /** + * Asserts that two variables have the same type and value. + * Used on objects, it asserts that two variables reference + * the same object. + * + * Comparison is performed using the === operator. + * + * @template ExpectedType + * + * @param ExpectedType $expected + * + * @throws ExpectationFailedException + * + * @phpstan-assert =ExpectedType $actual + */ + final public static function assertSame(mixed $expected, mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsIdentical($expected), $message); + } + /** + * Asserts that two variables do not have the same type and value. + * Used on objects, it asserts that two variables do not reference + * the same object. + * + * Comparison is performed using the === operator. + * + * @throws ExpectationFailedException + */ + final public static function assertNotSame(mixed $expected, mixed $actual, string $message = ''): void + { + if (is_bool($expected) && is_bool($actual)) { + self::assertNotEquals($expected, $actual, $message); + } + self::assertThat($actual, new LogicalNot(new IsIdentical($expected)), $message); + } + /** + * Asserts that a variable is of a given type. + * + * @template ExpectedType of object + * + * @param class-string $expected + * + * @throws Exception + * @throws ExpectationFailedException + * @throws UnknownClassOrInterfaceException + * + * @phpstan-assert =ExpectedType $actual + */ + final public static function assertInstanceOf(string $expected, mixed $actual, string $message = ''): void + { + if (!class_exists($expected) && !interface_exists($expected)) { + throw new \PHPUnit\Framework\UnknownClassOrInterfaceException($expected); + } + self::assertThat($actual, new IsInstanceOf($expected), $message); + } + /** + * Asserts that a variable is not of a given type. + * + * @template ExpectedType of object + * + * @param class-string $expected + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !ExpectedType $actual + */ + final public static function assertNotInstanceOf(string $expected, mixed $actual, string $message = ''): void + { + if (!class_exists($expected) && !interface_exists($expected)) { + throw new \PHPUnit\Framework\UnknownClassOrInterfaceException($expected); + } + self::assertThat($actual, new LogicalNot(new IsInstanceOf($expected)), $message); + } + /** + * Asserts that a variable is of type array. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert array $actual + */ + final public static function assertIsArray(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::Array), $message); + } + /** + * Asserts that a variable is of type bool. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert bool $actual + */ + final public static function assertIsBool(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::Bool), $message); + } + /** + * Asserts that a variable is of type float. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert float $actual + */ + final public static function assertIsFloat(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::Float), $message); + } + /** + * Asserts that a variable is of type int. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert int $actual + */ + final public static function assertIsInt(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::Int), $message); + } + /** + * Asserts that a variable is of type numeric. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert numeric $actual + */ + final public static function assertIsNumeric(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::Numeric), $message); + } + /** + * Asserts that a variable is of type object. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert object $actual + */ + final public static function assertIsObject(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::Object), $message); + } + /** + * Asserts that a variable is of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert resource $actual + */ + final public static function assertIsResource(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::Resource), $message); + } + /** + * Asserts that a variable is of type resource and is closed. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert resource $actual + */ + final public static function assertIsClosedResource(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::ClosedResource), $message); + } + /** + * Asserts that a variable is of type string. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert string $actual + */ + final public static function assertIsString(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::String), $message); + } + /** + * Asserts that a variable is of type scalar. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert scalar $actual + */ + final public static function assertIsScalar(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::Scalar), $message); + } + /** + * Asserts that a variable is of type callable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert callable $actual + */ + final public static function assertIsCallable(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::Callable), $message); + } + /** + * Asserts that a variable is of type iterable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert iterable $actual + */ + final public static function assertIsIterable(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new IsType(\PHPUnit\Framework\NativeType::Iterable), $message); + } + /** + * Asserts that a variable is not of type array. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !array $actual + */ + final public static function assertIsNotArray(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::Array)), $message); + } + /** + * Asserts that a variable is not of type bool. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !bool $actual + */ + final public static function assertIsNotBool(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::Bool)), $message); + } + /** + * Asserts that a variable is not of type float. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !float $actual + */ + final public static function assertIsNotFloat(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::Float)), $message); + } + /** + * Asserts that a variable is not of type int. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !int $actual + */ + final public static function assertIsNotInt(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::Int)), $message); + } + /** + * Asserts that a variable is not of type numeric. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !numeric $actual + */ + final public static function assertIsNotNumeric(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::Numeric)), $message); + } + /** + * Asserts that a variable is not of type object. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !object $actual + */ + final public static function assertIsNotObject(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::Object)), $message); + } + /** + * Asserts that a variable is not of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !resource $actual + */ + final public static function assertIsNotResource(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::Resource)), $message); + } + /** + * Asserts that a variable is not of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !resource $actual + */ + final public static function assertIsNotClosedResource(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::ClosedResource)), $message); + } + /** + * Asserts that a variable is not of type string. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !string $actual + */ + final public static function assertIsNotString(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::String)), $message); + } + /** + * Asserts that a variable is not of type scalar. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !scalar $actual + */ + final public static function assertIsNotScalar(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::Scalar)), $message); + } + /** + * Asserts that a variable is not of type callable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !callable $actual + */ + final public static function assertIsNotCallable(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::Callable)), $message); + } + /** + * Asserts that a variable is not of type iterable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !iterable $actual + */ + final public static function assertIsNotIterable(mixed $actual, string $message = ''): void + { + self::assertThat($actual, new LogicalNot(new IsType(\PHPUnit\Framework\NativeType::Iterable)), $message); + } + /** + * Asserts that a string matches a given regular expression. + * + * @throws ExpectationFailedException + */ + final public static function assertMatchesRegularExpression(string $pattern, string $string, string $message = ''): void + { + self::assertThat($string, new RegularExpression($pattern), $message); + } + /** + * Asserts that a string does not match a given regular expression. + * + * @throws ExpectationFailedException + */ + final public static function assertDoesNotMatchRegularExpression(string $pattern, string $string, string $message = ''): void + { + self::assertThat($string, new LogicalNot(new RegularExpression($pattern)), $message); + } + /** + * Assert that the size of two arrays (or `Countable` or `Traversable` objects) + * is the same. + * + * @param Countable|iterable $expected + * @param Countable|iterable $actual + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertSameSize(Countable|iterable $expected, Countable|iterable $actual, string $message = ''): void + { + if ($expected instanceof Generator) { + throw \PHPUnit\Framework\GeneratorNotSupportedException::fromParameterName('$expected'); + } + if ($actual instanceof Generator) { + throw \PHPUnit\Framework\GeneratorNotSupportedException::fromParameterName('$actual'); + } + self::assertThat($actual, new SameSize($expected), $message); + } + /** + * Assert that the size of two arrays (or `Countable` or `Traversable` objects) + * is not the same. + * + * @param Countable|iterable $expected + * @param Countable|iterable $actual + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertNotSameSize(Countable|iterable $expected, Countable|iterable $actual, string $message = ''): void + { + if ($expected instanceof Generator) { + throw \PHPUnit\Framework\GeneratorNotSupportedException::fromParameterName('$expected'); + } + if ($actual instanceof Generator) { + throw \PHPUnit\Framework\GeneratorNotSupportedException::fromParameterName('$actual'); + } + self::assertThat($actual, new LogicalNot(new SameSize($expected)), $message); + } + /** + * @throws ExpectationFailedException + */ + final public static function assertStringContainsStringIgnoringLineEndings(string $needle, string $haystack, string $message = ''): void + { + self::assertThat($haystack, new StringContains($needle, \false, \true), $message); + } + /** + * Asserts that two strings are equal except for line endings. + * + * @throws ExpectationFailedException + */ + final public static function assertStringEqualsStringIgnoringLineEndings(string $expected, string $actual, string $message = ''): void + { + self::assertThat($actual, new StringEqualsStringIgnoringLineEndings($expected), $message); + } + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + */ + final public static function assertFileMatchesFormat(string $format, string $actualFile, string $message = ''): void + { + self::assertFileExists($actualFile, $message); + self::assertThat(file_get_contents($actualFile), new StringMatchesFormatDescription($format), $message); + } + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + */ + final public static function assertFileMatchesFormatFile(string $formatFile, string $actualFile, string $message = ''): void + { + self::assertFileExists($formatFile, $message); + self::assertFileExists($actualFile, $message); + $formatDescription = file_get_contents($formatFile); + self::assertIsString($formatDescription); + self::assertThat(file_get_contents($actualFile), new StringMatchesFormatDescription($formatDescription), $message); + } + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + */ + final public static function assertStringMatchesFormat(string $format, string $string, string $message = ''): void + { + self::assertThat($string, new StringMatchesFormatDescription($format), $message); + } + /** + * Asserts that a string matches a given format file. + * + * @throws ExpectationFailedException + */ + final public static function assertStringMatchesFormatFile(string $formatFile, string $string, string $message = ''): void + { + self::assertFileExists($formatFile, $message); + $formatDescription = file_get_contents($formatFile); + self::assertIsString($formatDescription); + self::assertThat($string, new StringMatchesFormatDescription($formatDescription), $message); + } + /** + * Asserts that a string starts with a given prefix. + * + * @param non-empty-string $prefix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + */ + final public static function assertStringStartsWith(string $prefix, string $string, string $message = ''): void + { + self::assertThat($string, new StringStartsWith($prefix), $message); + } + /** + * Asserts that a string starts not with a given prefix. + * + * @param non-empty-string $prefix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + */ + final public static function assertStringStartsNotWith(string $prefix, string $string, string $message = ''): void + { + self::assertThat($string, new LogicalNot(new StringStartsWith($prefix)), $message); + } + /** + * @throws ExpectationFailedException + */ + final public static function assertStringContainsString(string $needle, string $haystack, string $message = ''): void + { + $constraint = new StringContains($needle); + self::assertThat($haystack, $constraint, $message); + } + /** + * @throws ExpectationFailedException + */ + final public static function assertStringContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void + { + $constraint = new StringContains($needle, \true); + self::assertThat($haystack, $constraint, $message); + } + /** + * @throws ExpectationFailedException + */ + final public static function assertStringNotContainsString(string $needle, string $haystack, string $message = ''): void + { + $constraint = new LogicalNot(new StringContains($needle)); + self::assertThat($haystack, $constraint, $message); + } + /** + * @throws ExpectationFailedException + */ + final public static function assertStringNotContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void + { + $constraint = new LogicalNot(new StringContains($needle, \true)); + self::assertThat($haystack, $constraint, $message); + } + /** + * Asserts that a string ends with a given suffix. + * + * @param non-empty-string $suffix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + */ + final public static function assertStringEndsWith(string $suffix, string $string, string $message = ''): void + { + self::assertThat($string, new StringEndsWith($suffix), $message); + } + /** + * Asserts that a string ends not with a given suffix. + * + * @param non-empty-string $suffix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + */ + final public static function assertStringEndsNotWith(string $suffix, string $string, string $message = ''): void + { + self::assertThat($string, new LogicalNot(new StringEndsWith($suffix)), $message); + } + /** + * Asserts that two XML files are equal, ignoring comments. + * + * @throws Exception + * @throws ExpectationFailedException + * @throws XmlException + */ + final public static function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void + { + $expected = (new XmlLoader())->loadFile($expectedFile, \true); + $actual = (new XmlLoader())->loadFile($actualFile, \true); + self::assertEquals($expected, $actual, $message); + } + /** + * Asserts that two XML files are not equal, ignoring comments. + * + * @throws \PHPUnit\Util\Exception + * @throws ExpectationFailedException + */ + final public static function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void + { + $expected = (new XmlLoader())->loadFile($expectedFile, \true); + $actual = (new XmlLoader())->loadFile($actualFile, \true); + self::assertNotEquals($expected, $actual, $message); + } + /** + * Asserts that two XML documents are equal, ignoring comments. + * + * @throws ExpectationFailedException + * @throws XmlException + */ + final public static function assertXmlStringEqualsXmlFile(string $expectedFile, string $actualXml, string $message = ''): void + { + $expected = (new XmlLoader())->loadFile($expectedFile, \true); + $actual = (new XmlLoader())->load($actualXml, \true); + self::assertEquals($expected, $actual, $message); + } + /** + * Asserts that two XML documents are not equal, ignoring comments. + * + * @throws ExpectationFailedException + * @throws XmlException + */ + final public static function assertXmlStringNotEqualsXmlFile(string $expectedFile, string $actualXml, string $message = ''): void + { + $expected = (new XmlLoader())->loadFile($expectedFile, \true); + $actual = (new XmlLoader())->load($actualXml, \true); + self::assertNotEquals($expected, $actual, $message); + } + /** + * Asserts that two XML documents are equal, ignoring comments. + * + * @throws ExpectationFailedException + * @throws XmlException + */ + final public static function assertXmlStringEqualsXmlString(string $expectedXml, string $actualXml, string $message = ''): void + { + $expected = (new XmlLoader())->load($expectedXml, \true); + $actual = (new XmlLoader())->load($actualXml, \true); + self::assertEquals($expected, $actual, $message); + } + /** + * Asserts that two XML documents are not equal, ignoring comments. + * + * @throws ExpectationFailedException + * @throws XmlException + */ + final public static function assertXmlStringNotEqualsXmlString(string $expectedXml, string $actualXml, string $message = ''): void + { + $expected = (new XmlLoader())->load($expectedXml, \true); + $actual = (new XmlLoader())->load($actualXml, \true); + self::assertNotEquals($expected, $actual, $message); + } + /** + * Evaluates a PHPUnit\Framework\Constraint matcher object. + * + * @throws ExpectationFailedException + */ + final public static function assertThat(mixed $value, Constraint $constraint, string $message = ''): void + { + self::$count += count($constraint); + $constraint->evaluate($value, $message); + } + /** + * Asserts that a string is a valid JSON string. + * + * @throws ExpectationFailedException + */ + final public static function assertJson(string $actual, string $message = ''): void + { + self::assertThat($actual, self::isJson(), $message); + } + /** + * Asserts that two given JSON encoded objects or arrays are equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void + { + self::assertJson($expectedJson, $message); + self::assertJson($actualJson, $message); + self::assertThat($actualJson, new JsonMatches($expectedJson), $message); + } + /** + * Asserts that two given JSON encoded objects or arrays are not equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonStringNotEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void + { + self::assertJson($expectedJson, $message); + self::assertJson($actualJson, $message); + self::assertThat($actualJson, new LogicalNot(new JsonMatches($expectedJson)), $message); + } + /** + * Asserts that the generated JSON encoded object and the content of the given file are equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + $expectedJson = file_get_contents($expectedFile); + self::assertIsString($expectedJson); + self::assertJson($expectedJson, $message); + self::assertJson($actualJson, $message); + self::assertThat($actualJson, new JsonMatches($expectedJson), $message); + } + /** + * Asserts that the generated JSON encoded object and the content of the given file are not equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + $expectedJson = file_get_contents($expectedFile); + self::assertIsString($expectedJson); + self::assertJson($expectedJson, $message); + self::assertJson($actualJson, $message); + self::assertThat($actualJson, new LogicalNot(new JsonMatches($expectedJson)), $message); + } + /** + * Asserts that two JSON files are equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + $expectedJson = file_get_contents($expectedFile); + self::assertIsString($expectedJson); + self::assertJson($expectedJson, $message); + self::assertFileExists($actualFile, $message); + $actualJson = file_get_contents($actualFile); + self::assertIsString($actualJson); + self::assertJson($actualJson, $message); + self::assertThat($actualJson, new JsonMatches($expectedJson), $message); + } + /** + * Asserts that two JSON files are not equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonFileNotEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + $expectedJson = file_get_contents($expectedFile); + self::assertIsString($expectedJson); + self::assertJson($expectedJson, $message); + self::assertFileExists($actualFile, $message); + $actualJson = file_get_contents($actualFile); + self::assertIsString($actualJson); + self::assertJson($actualJson, $message); + self::assertThat($actualJson, self::logicalNot(new JsonMatches($expectedJson)), $message); + } + /** + * @throws Exception + */ + final public static function logicalAnd(mixed ...$constraints): LogicalAnd + { + return LogicalAnd::fromConstraints(...$constraints); + } + final public static function logicalOr(mixed ...$constraints): LogicalOr + { + return LogicalOr::fromConstraints(...$constraints); + } + final public static function logicalNot(Constraint $constraint): LogicalNot + { + return new LogicalNot($constraint); + } + final public static function logicalXor(mixed ...$constraints): LogicalXor + { + return LogicalXor::fromConstraints(...$constraints); + } + final public static function anything(): IsAnything + { + return new IsAnything(); + } + final public static function isTrue(): IsTrue + { + return new IsTrue(); + } + /** + * @template CallbackInput of mixed + * + * @param callable(CallbackInput $callback): bool $callback + * + * @return Callback + */ + final public static function callback(callable $callback): Callback + { + return new Callback($callback); + } + final public static function isFalse(): IsFalse + { + return new IsFalse(); + } + final public static function isJson(): IsJson + { + return new IsJson(); + } + final public static function isNull(): IsNull + { + return new IsNull(); + } + final public static function isFinite(): IsFinite + { + return new IsFinite(); + } + final public static function isInfinite(): IsInfinite + { + return new IsInfinite(); + } + final public static function isNan(): IsNan + { + return new IsNan(); + } + final public static function containsEqual(mixed $value): TraversableContainsEqual + { + return new TraversableContainsEqual($value); + } + final public static function containsIdentical(mixed $value): TraversableContainsIdentical + { + return new TraversableContainsIdentical($value); + } + final public static function containsOnlyArray(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Array); + } + final public static function containsOnlyBool(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Bool); + } + final public static function containsOnlyCallable(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Callable); + } + final public static function containsOnlyFloat(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Float); + } + final public static function containsOnlyInt(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Int); + } + final public static function containsOnlyIterable(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Iterable); + } + final public static function containsOnlyNull(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Null); + } + final public static function containsOnlyNumeric(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Numeric); + } + final public static function containsOnlyObject(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Object); + } + final public static function containsOnlyResource(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Resource); + } + final public static function containsOnlyClosedResource(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::ClosedResource); + } + final public static function containsOnlyScalar(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::Scalar); + } + final public static function containsOnlyString(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(\PHPUnit\Framework\NativeType::String); + } + /** + * @param class-string $className + * + * @throws Exception + */ + final public static function containsOnlyInstancesOf(string $className): TraversableContainsOnly + { + return TraversableContainsOnly::forClassOrInterface($className); + } + final public static function arrayHasKey(mixed $key): ArrayHasKey + { + return new ArrayHasKey($key); + } + final public static function isList(): IsList + { + return new IsList(); + } + final public static function equalTo(mixed $value): IsEqual + { + return new IsEqual($value); + } + final public static function equalToCanonicalizing(mixed $value): IsEqualCanonicalizing + { + return new IsEqualCanonicalizing($value); + } + final public static function equalToIgnoringCase(mixed $value): IsEqualIgnoringCase + { + return new IsEqualIgnoringCase($value); + } + final public static function equalToWithDelta(mixed $value, float $delta): IsEqualWithDelta + { + return new IsEqualWithDelta($value, $delta); + } + final public static function isEmpty(): IsEmpty + { + return new IsEmpty(); + } + final public static function isWritable(): IsWritable + { + return new IsWritable(); + } + final public static function isReadable(): IsReadable + { + return new IsReadable(); + } + final public static function directoryExists(): DirectoryExists + { + return new DirectoryExists(); + } + final public static function fileExists(): FileExists + { + return new FileExists(); + } + final public static function greaterThan(mixed $value): GreaterThan + { + return new GreaterThan($value); + } + final public static function greaterThanOrEqual(mixed $value): LogicalOr + { + return self::logicalOr(new IsEqual($value), new GreaterThan($value)); + } + final public static function identicalTo(mixed $value): IsIdentical + { + return new IsIdentical($value); + } + /** + * @throws UnknownClassOrInterfaceException + */ + final public static function isInstanceOf(string $className): IsInstanceOf + { + return new IsInstanceOf($className); + } + final public static function isArray(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::Array); + } + final public static function isBool(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::Bool); + } + final public static function isCallable(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::Callable); + } + final public static function isFloat(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::Float); + } + final public static function isInt(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::Int); + } + final public static function isIterable(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::Iterable); + } + final public static function isNumeric(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::Numeric); + } + final public static function isObject(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::Object); + } + final public static function isResource(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::Resource); + } + final public static function isClosedResource(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::ClosedResource); + } + final public static function isScalar(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::Scalar); + } + final public static function isString(): IsType + { + return new IsType(\PHPUnit\Framework\NativeType::String); + } + final public static function lessThan(mixed $value): LessThan + { + return new LessThan($value); + } + final public static function lessThanOrEqual(mixed $value): LogicalOr + { + return self::logicalOr(new IsEqual($value), new LessThan($value)); + } + final public static function matchesRegularExpression(string $pattern): RegularExpression + { + return new RegularExpression($pattern); + } + final public static function matches(string $string): StringMatchesFormatDescription + { + return new StringMatchesFormatDescription($string); + } + /** + * @param non-empty-string $prefix + * + * @throws InvalidArgumentException + */ + final public static function stringStartsWith(string $prefix): StringStartsWith + { + return new StringStartsWith($prefix); + } + final public static function stringContains(string $string, bool $case = \true): StringContains + { + return new StringContains($string, $case); + } + /** + * @param non-empty-string $suffix + * + * @throws InvalidArgumentException + */ + final public static function stringEndsWith(string $suffix): StringEndsWith + { + return new StringEndsWith($suffix); + } + final public static function stringEqualsStringIgnoringLineEndings(string $string): StringEqualsStringIgnoringLineEndings + { + return new StringEqualsStringIgnoringLineEndings($string); + } + final public static function countOf(int $count): Count + { + return new Count($count); + } + final public static function objectEquals(object $object, string $method = 'equals'): ObjectEquals + { + return new ObjectEquals($object, $method); + } + /** + * Fails a test with the given message. + * + * @throws AssertionFailedError + */ + final public static function fail(string $message = ''): never + { + self::$count++; + throw new \PHPUnit\Framework\AssertionFailedError($message); + } + /** + * Mark the test as incomplete. + * + * @throws IncompleteTestError + */ + final public static function markTestIncomplete(string $message = ''): never + { + throw new \PHPUnit\Framework\IncompleteTestError($message); + } + /** + * Mark the test as skipped. + * + * @throws SkippedWithMessageException + */ + final public static function markTestSkipped(string $message = ''): never + { + throw new \PHPUnit\Framework\SkippedWithMessageException($message); + } + /** + * Return the current assertion count. + */ + final public static function getCount(): int + { + return self::$count; + } + /** + * Reset the assertion counter. + */ + final public static function resetCount(): void + { + self::$count = 0; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function func_get_args; +use function function_exists; +use ArrayAccess; +use Countable; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\Constraint\ArrayHasKey; +use PHPUnit\Framework\Constraint\Callback; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\Constraint\Count; +use PHPUnit\Framework\Constraint\DirectoryExists; +use PHPUnit\Framework\Constraint\FileExists; +use PHPUnit\Framework\Constraint\GreaterThan; +use PHPUnit\Framework\Constraint\IsAnything; +use PHPUnit\Framework\Constraint\IsEmpty; +use PHPUnit\Framework\Constraint\IsEqual; +use PHPUnit\Framework\Constraint\IsEqualCanonicalizing; +use PHPUnit\Framework\Constraint\IsEqualIgnoringCase; +use PHPUnit\Framework\Constraint\IsEqualWithDelta; +use PHPUnit\Framework\Constraint\IsFalse; +use PHPUnit\Framework\Constraint\IsFinite; +use PHPUnit\Framework\Constraint\IsIdentical; +use PHPUnit\Framework\Constraint\IsInfinite; +use PHPUnit\Framework\Constraint\IsInstanceOf; +use PHPUnit\Framework\Constraint\IsJson; +use PHPUnit\Framework\Constraint\IsList; +use PHPUnit\Framework\Constraint\IsNan; +use PHPUnit\Framework\Constraint\IsNull; +use PHPUnit\Framework\Constraint\IsReadable; +use PHPUnit\Framework\Constraint\IsTrue; +use PHPUnit\Framework\Constraint\IsType; +use PHPUnit\Framework\Constraint\IsWritable; +use PHPUnit\Framework\Constraint\LessThan; +use PHPUnit\Framework\Constraint\LogicalAnd; +use PHPUnit\Framework\Constraint\LogicalNot; +use PHPUnit\Framework\Constraint\LogicalOr; +use PHPUnit\Framework\Constraint\LogicalXor; +use PHPUnit\Framework\Constraint\ObjectEquals; +use PHPUnit\Framework\Constraint\RegularExpression; +use PHPUnit\Framework\Constraint\StringContains; +use PHPUnit\Framework\Constraint\StringEndsWith; +use PHPUnit\Framework\Constraint\StringEqualsStringIgnoringLineEndings; +use PHPUnit\Framework\Constraint\StringMatchesFormatDescription; +use PHPUnit\Framework\Constraint\StringStartsWith; +use PHPUnit\Framework\Constraint\TraversableContainsEqual; +use PHPUnit\Framework\Constraint\TraversableContainsIdentical; +use PHPUnit\Framework\Constraint\TraversableContainsOnly; +use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount as AnyInvokedCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastCount as InvokedAtLeastCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastOnce as InvokedAtLeastOnceMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtMostCount as InvokedAtMostCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedCount as InvokedCountMatcher; +use PHPUnit\Framework\MockObject\Stub\Exception as ExceptionStub; +use PHPUnit\Util\Xml\XmlException; +use Throwable; +if (!function_exists('PHPUnit\Framework\assertArrayIsEqualToArrayOnlyConsideringListOfKeys')) { + /** + * Asserts that two arrays are equal while only considering a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeConsidered + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayIsEqualToArrayOnlyConsideringListOfKeys + */ + function assertArrayIsEqualToArrayOnlyConsideringListOfKeys(array $expected, array $actual, array $keysToBeConsidered, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArrayIsEqualToArrayOnlyConsideringListOfKeys(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArrayIsEqualToArrayIgnoringListOfKeys')) { + /** + * Asserts that two arrays are equal while ignoring a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeIgnored + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayIsEqualToArrayIgnoringListOfKeys + */ + function assertArrayIsEqualToArrayIgnoringListOfKeys(array $expected, array $actual, array $keysToBeIgnored, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArrayIsEqualToArrayIgnoringListOfKeys(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys')) { + /** + * Asserts that two arrays are identical while only considering a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeConsidered + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys + */ + function assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys(array $expected, array $actual, array $keysToBeConsidered, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArrayIsIdenticalToArrayIgnoringListOfKeys')) { + /** + * Asserts that two arrays are equal while ignoring a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeIgnored + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayIsIdenticalToArrayIgnoringListOfKeys + */ + function assertArrayIsIdenticalToArrayIgnoringListOfKeys(array $expected, array $actual, array $keysToBeIgnored, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArrayIsIdenticalToArrayIgnoringListOfKeys(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArrayHasKey')) { + /** + * Asserts that an array has a specified key. + * + * @param array|ArrayAccess $array + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayHasKey + */ + function assertArrayHasKey(mixed $key, array|ArrayAccess $array, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArrayHasKey(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArrayNotHasKey')) { + /** + * Asserts that an array does not have a specified key. + * + * @param array|ArrayAccess $array + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayNotHasKey + */ + function assertArrayNotHasKey(mixed $key, array|ArrayAccess $array, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArrayNotHasKey(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsList')) { + /** + * @phpstan-assert list $array + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsList + */ + function assertIsList(mixed $array, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsList(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArraysAreIdentical')) { + /** + * Assert that two arrays are identical. + * + * The (key, value) relationship matters, the order of the (key, value) pairs in the array matters, and keys as well as values are compared strictly. + * This is essentially an alias for assertSame(). + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArraysAreIdentical + */ + function assertArraysAreIdentical(array $expected, array $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArraysAreIdentical(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArraysAreEqual')) { + /** + * Assert that two arrays are equal. + * + * The (key, value) relationship matters, the order of the (key, value) pairs in the array matters, and keys as well as values are compared loosely. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArraysAreEqual + */ + function assertArraysAreEqual(array $expected, array $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArraysAreEqual(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArraysAreIdenticalIgnoringOrder')) { + /** + * Assert that two arrays are identical while ignoring the order of their values. + * + * The (key, value) relationship matters, the order of the (key, value) pairs in the array does not matter, and keys as well as values are compared strictly. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArraysAreIdenticalIgnoringOrder + */ + function assertArraysAreIdenticalIgnoringOrder(array $expected, array $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArraysAreIdenticalIgnoringOrder(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArraysAreEqualIgnoringOrder')) { + /** + * Assert that two arrays are equal while ignoring the order of their values. + * + * The (key, value) relationship matters, the order of the (key, value) pairs in the array does not matter, and keys as well as values are compared loosely. + * This is essentially an alias for assertEquals(). + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArraysAreEqualIgnoringOrder + */ + function assertArraysAreEqualIgnoringOrder(array $expected, array $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArraysAreEqualIgnoringOrder(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArraysHaveIdenticalValues')) { + /** + * Assert that two arrays have identical values. + * + * The (key, value) relationship does not matter, the order of the (key, value) pairs in the array matters, and values are compared strictly. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArraysHaveIdenticalValues + */ + function assertArraysHaveIdenticalValues(array $expected, array $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArraysHaveIdenticalValues(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArraysHaveEqualValues')) { + /** + * Assert that two arrays have equal values. + * + * The (key, value) relationship does not matter, the order of the (key, value) pairs in the array matters, and values are compared loosely. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArraysHaveEqualValues + */ + function assertArraysHaveEqualValues(array $expected, array $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArraysHaveEqualValues(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArraysHaveIdenticalValuesIgnoringOrder')) { + /** + * Assert that two arrays have identical values while ignoring the order of these values. + * + * The (key, value) relationship does not matter, the order of the (key, value) pairs in the array does not matter, and values are compared strictly. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArraysHaveIdenticalValuesIgnoringOrder + */ + function assertArraysHaveIdenticalValuesIgnoringOrder(array $expected, array $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArraysHaveIdenticalValuesIgnoringOrder(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertArraysHaveEqualValuesIgnoringOrder')) { + /** + * Assert that two arrays have equal values while ignoring the order of these values. + * + * The (key, value) relationship does not matter, the order of the (key, value) pairs in the array does not matter, and values are compared loosely. + * + * @param array $expected + * @param array $actual + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArraysHaveEqualValuesIgnoringOrder + */ + function assertArraysHaveEqualValuesIgnoringOrder(array $expected, array $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertArraysHaveEqualValuesIgnoringOrder(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContains')) { + /** + * Asserts that a haystack contains a needle. + * + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContains + */ + function assertContains(mixed $needle, iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContains(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsEquals')) { + /** + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsEquals + */ + function assertContainsEquals(mixed $needle, iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsEquals(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotContains')) { + /** + * Asserts that a haystack does not contain a needle. + * + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotContains + */ + function assertNotContains(mixed $needle, iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotContains(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotContainsEquals')) { + /** + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotContainsEquals + */ + function assertNotContainsEquals(mixed $needle, iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotContainsEquals(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyArray')) { + /** + * Asserts that a haystack contains only values of type array. + * + * @phpstan-assert iterable> $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyArray + */ + function assertContainsOnlyArray(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyArray(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyBool')) { + /** + * Asserts that a haystack contains only values of type bool. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyBool + */ + function assertContainsOnlyBool(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyBool(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyCallable')) { + /** + * Asserts that a haystack contains only values of type callable. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyCallable + */ + function assertContainsOnlyCallable(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyCallable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyFloat')) { + /** + * Asserts that a haystack contains only values of type float. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyFloat + */ + function assertContainsOnlyFloat(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyFloat(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyInt')) { + /** + * Asserts that a haystack contains only values of type int. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyInt + */ + function assertContainsOnlyInt(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyInt(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyIterable')) { + /** + * Asserts that a haystack contains only values of type iterable. + * + * @phpstan-assert iterable> $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyIterable + */ + function assertContainsOnlyIterable(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyIterable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyNull')) { + /** + * Asserts that a haystack contains only values of type null. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyNull + */ + function assertContainsOnlyNull(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyNull(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyNumeric')) { + /** + * Asserts that a haystack contains only values of type numeric. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyNumeric + */ + function assertContainsOnlyNumeric(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyNumeric(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyObject')) { + /** + * Asserts that a haystack contains only values of type object. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyObject + */ + function assertContainsOnlyObject(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyObject(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyResource')) { + /** + * Asserts that a haystack contains only values of type resource. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyResource + */ + function assertContainsOnlyResource(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyClosedResource')) { + /** + * Asserts that a haystack contains only values of type closed resource. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyClosedResource + */ + function assertContainsOnlyClosedResource(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyClosedResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyScalar')) { + /** + * Asserts that a haystack contains only values of type scalar. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyScalar + */ + function assertContainsOnlyScalar(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyScalar(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyString')) { + /** + * Asserts that a haystack contains only values of type string. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyString + */ + function assertContainsOnlyString(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsOnlyInstancesOf')) { + /** + * Asserts that a haystack contains only instances of a specified interface or class name. + * + * @template T + * + * @phpstan-assert iterable $haystack + * + * @param class-string $className + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyInstancesOf + */ + function assertContainsOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsOnlyInstancesOf(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyArray')) { + /** + * Asserts that a haystack does not contain only values of type array. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyArray + */ + function assertContainsNotOnlyArray(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyArray(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyBool')) { + /** + * Asserts that a haystack does not contain only values of type bool. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyBool + */ + function assertContainsNotOnlyBool(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyBool(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyCallable')) { + /** + * Asserts that a haystack does not contain only values of type callable. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyCallable + */ + function assertContainsNotOnlyCallable(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyCallable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyFloat')) { + /** + * Asserts that a haystack does not contain only values of type float. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyFloat + */ + function assertContainsNotOnlyFloat(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyFloat(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyInt')) { + /** + * Asserts that a haystack does not contain only values of type int. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyInt + */ + function assertContainsNotOnlyInt(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyInt(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyIterable')) { + /** + * Asserts that a haystack does not contain only values of type iterable. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyIterable + */ + function assertContainsNotOnlyIterable(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyIterable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyNull')) { + /** + * Asserts that a haystack does not contain only values of type null. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyNull + */ + function assertContainsNotOnlyNull(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyNull(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyNumeric')) { + /** + * Asserts that a haystack does not contain only values of type numeric. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyNumeric + */ + function assertContainsNotOnlyNumeric(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyNumeric(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyObject')) { + /** + * Asserts that a haystack does not contain only values of type object. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyObject + */ + function assertContainsNotOnlyObject(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyObject(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyResource')) { + /** + * Asserts that a haystack does not contain only values of type resource. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyResource + */ + function assertContainsNotOnlyResource(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyClosedResource')) { + /** + * Asserts that a haystack does not contain only values of type closed resource. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyClosedResource + */ + function assertContainsNotOnlyClosedResource(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyClosedResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyScalar')) { + /** + * Asserts that a haystack does not contain only values of type scalar. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyScalar + */ + function assertContainsNotOnlyScalar(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyScalar(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyString')) { + /** + * Asserts that a haystack does not contain only values of type string. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyString + */ + function assertContainsNotOnlyString(iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyInstancesOf')) { + /** + * Asserts that a haystack does not contain only instances of a specified interface or class name. + * + * @param class-string $className + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyInstancesOf + */ + function assertContainsNotOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertContainsNotOnlyInstancesOf(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertCount')) { + /** + * Asserts the number of elements of an array, Countable or Traversable. + * + * @param Countable|iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertCount + */ + function assertCount(int $expectedCount, Countable|iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertCount(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotCount')) { + /** + * Asserts the number of elements of an array, Countable or Traversable. + * + * @param Countable|iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotCount + */ + function assertNotCount(int $expectedCount, Countable|iterable $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotCount(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertEquals')) { + /** + * Asserts that two variables are equal. + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertEquals + */ + function assertEquals(mixed $expected, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertEquals(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertEqualsCanonicalizing')) { + /** + * Asserts that two variables are equal (canonicalizing). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertEqualsCanonicalizing + */ + function assertEqualsCanonicalizing(mixed $expected, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertEqualsCanonicalizing(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertEqualsIgnoringCase')) { + /** + * Asserts that two variables are equal (ignoring case). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertEqualsIgnoringCase + */ + function assertEqualsIgnoringCase(mixed $expected, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertEqualsIgnoringCase(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertEqualsWithDelta')) { + /** + * Asserts that two variables are equal (with delta). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertEqualsWithDelta + */ + function assertEqualsWithDelta(mixed $expected, mixed $actual, float $delta, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertEqualsWithDelta(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotEquals')) { + /** + * Asserts that two variables are not equal. + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotEquals + */ + function assertNotEquals(mixed $expected, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotEquals(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotEqualsCanonicalizing')) { + /** + * Asserts that two variables are not equal (canonicalizing). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotEqualsCanonicalizing + */ + function assertNotEqualsCanonicalizing(mixed $expected, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotEqualsCanonicalizing(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotEqualsIgnoringCase')) { + /** + * Asserts that two variables are not equal (ignoring case). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotEqualsIgnoringCase + */ + function assertNotEqualsIgnoringCase(mixed $expected, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotEqualsIgnoringCase(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotEqualsWithDelta')) { + /** + * Asserts that two variables are not equal (with delta). + * + * Comparison is performed using the == operator (loose comparison) and may be performed by a type-specific comparator which may apply type coercion. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotEqualsWithDelta + */ + function assertNotEqualsWithDelta(mixed $expected, mixed $actual, float $delta, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotEqualsWithDelta(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertObjectEquals')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertObjectEquals + */ + function assertObjectEquals(object $expected, object $actual, string $method = 'equals', string $message = ''): void + { + \PHPUnit\Framework\Assert::assertObjectEquals(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertObjectNotEquals')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertObjectNotEquals + */ + function assertObjectNotEquals(object $expected, object $actual, string $method = 'equals', string $message = ''): void + { + \PHPUnit\Framework\Assert::assertObjectNotEquals(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertEmpty')) { + /** + * Asserts that a variable is empty. + * + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertEmpty + */ + function assertEmpty(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertEmpty(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotEmpty')) { + /** + * Asserts that a variable is not empty. + * + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotEmpty + */ + function assertNotEmpty(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotEmpty(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertGreaterThan')) { + /** + * Asserts that a value is greater than another value. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertGreaterThan + */ + function assertGreaterThan(mixed $minimum, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertGreaterThan(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertGreaterThanOrEqual')) { + /** + * Asserts that a value is greater than or equal to another value. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertGreaterThanOrEqual + */ + function assertGreaterThanOrEqual(mixed $minimum, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertGreaterThanOrEqual(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertLessThan')) { + /** + * Asserts that a value is smaller than another value. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertLessThan + */ + function assertLessThan(mixed $maximum, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertLessThan(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertLessThanOrEqual')) { + /** + * Asserts that a value is smaller than or equal to another value. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertLessThanOrEqual + */ + function assertLessThanOrEqual(mixed $maximum, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertLessThanOrEqual(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileEquals')) { + /** + * Asserts that the contents of one file is equal to the contents of another + * file. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileEquals + */ + function assertFileEquals(string $expected, string $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileEquals(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileEqualsCanonicalizing')) { + /** + * Asserts that the contents of one file is equal to the contents of another + * file (canonicalizing). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileEqualsCanonicalizing + */ + function assertFileEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileEqualsCanonicalizing(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileEqualsIgnoringCase')) { + /** + * Asserts that the contents of one file is equal to the contents of another + * file (ignoring case). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileEqualsIgnoringCase + */ + function assertFileEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileEqualsIgnoringCase(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileNotEquals')) { + /** + * Asserts that the contents of one file is not equal to the contents of + * another file. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileNotEquals + */ + function assertFileNotEquals(string $expected, string $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileNotEquals(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileNotEqualsCanonicalizing')) { + /** + * Asserts that the contents of one file is not equal to the contents of another + * file (canonicalizing). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileNotEqualsCanonicalizing + */ + function assertFileNotEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileNotEqualsCanonicalizing(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileNotEqualsIgnoringCase')) { + /** + * Asserts that the contents of one file is not equal to the contents of another + * file (ignoring case). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileNotEqualsIgnoringCase + */ + function assertFileNotEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileNotEqualsIgnoringCase(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringEqualsFile')) { + /** + * Asserts that the contents of a string is equal + * to the contents of a file. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEqualsFile + */ + function assertStringEqualsFile(string $expectedFile, string $actualString, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringEqualsFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringEqualsFileCanonicalizing')) { + /** + * Asserts that the contents of a string is equal + * to the contents of a file (canonicalizing). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEqualsFileCanonicalizing + */ + function assertStringEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringEqualsFileCanonicalizing(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringEqualsFileIgnoringCase')) { + /** + * Asserts that the contents of a string is equal + * to the contents of a file (ignoring case). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEqualsFileIgnoringCase + */ + function assertStringEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringEqualsFileIgnoringCase(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringNotEqualsFile')) { + /** + * Asserts that the contents of a string is not equal + * to the contents of a file. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringNotEqualsFile + */ + function assertStringNotEqualsFile(string $expectedFile, string $actualString, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringNotEqualsFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringNotEqualsFileCanonicalizing')) { + /** + * Asserts that the contents of a string is not equal + * to the contents of a file (canonicalizing). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringNotEqualsFileCanonicalizing + */ + function assertStringNotEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringNotEqualsFileCanonicalizing(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringNotEqualsFileIgnoringCase')) { + /** + * Asserts that the contents of a string is not equal + * to the contents of a file (ignoring case). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringNotEqualsFileIgnoringCase + */ + function assertStringNotEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringNotEqualsFileIgnoringCase(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsReadable')) { + /** + * Asserts that a file/dir is readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsReadable + */ + function assertIsReadable(string $filename, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsReadable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotReadable')) { + /** + * Asserts that a file/dir exists and is not readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotReadable + */ + function assertIsNotReadable(string $filename, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotReadable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsWritable')) { + /** + * Asserts that a file/dir exists and is writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsWritable + */ + function assertIsWritable(string $filename, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsWritable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotWritable')) { + /** + * Asserts that a file/dir exists and is not writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotWritable + */ + function assertIsNotWritable(string $filename, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotWritable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertDirectoryExists')) { + /** + * Asserts that a directory exists. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryExists + */ + function assertDirectoryExists(string $directory, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertDirectoryExists(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertDirectoryDoesNotExist')) { + /** + * Asserts that a directory does not exist. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryDoesNotExist + */ + function assertDirectoryDoesNotExist(string $directory, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertDirectoryDoesNotExist(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertDirectoryIsReadable')) { + /** + * Asserts that a directory exists and is readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryIsReadable + */ + function assertDirectoryIsReadable(string $directory, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertDirectoryIsReadable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertDirectoryIsNotReadable')) { + /** + * Asserts that a directory exists and is not readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryIsNotReadable + */ + function assertDirectoryIsNotReadable(string $directory, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertDirectoryIsNotReadable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertDirectoryIsWritable')) { + /** + * Asserts that a directory exists and is writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryIsWritable + */ + function assertDirectoryIsWritable(string $directory, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertDirectoryIsWritable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertDirectoryIsNotWritable')) { + /** + * Asserts that a directory exists and is not writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryIsNotWritable + */ + function assertDirectoryIsNotWritable(string $directory, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertDirectoryIsNotWritable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileExists')) { + /** + * Asserts that a file exists. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileExists + */ + function assertFileExists(string $filename, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileExists(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileDoesNotExist')) { + /** + * Asserts that a file does not exist. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileDoesNotExist + */ + function assertFileDoesNotExist(string $filename, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileDoesNotExist(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileIsReadable')) { + /** + * Asserts that a file exists and is readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileIsReadable + */ + function assertFileIsReadable(string $file, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileIsReadable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileIsNotReadable')) { + /** + * Asserts that a file exists and is not readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileIsNotReadable + */ + function assertFileIsNotReadable(string $file, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileIsNotReadable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileIsWritable')) { + /** + * Asserts that a file exists and is writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileIsWritable + */ + function assertFileIsWritable(string $file, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileIsWritable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileIsNotWritable')) { + /** + * Asserts that a file exists and is not writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileIsNotWritable + */ + function assertFileIsNotWritable(string $file, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileIsNotWritable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertTrue')) { + /** + * Asserts that a condition is true. + * + * @throws ExpectationFailedException + * + * @phpstan-assert true $condition + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertTrue + */ + function assertTrue(mixed $condition, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertTrue(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotTrue')) { + /** + * Asserts that a condition is not true. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !true $condition + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotTrue + */ + function assertNotTrue(mixed $condition, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotTrue(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFalse')) { + /** + * Asserts that a condition is false. + * + * @throws ExpectationFailedException + * + * @phpstan-assert false $condition + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFalse + */ + function assertFalse(mixed $condition, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFalse(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotFalse')) { + /** + * Asserts that a condition is not false. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !false $condition + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotFalse + */ + function assertNotFalse(mixed $condition, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotFalse(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNull')) { + /** + * Asserts that a variable is null. + * + * @throws ExpectationFailedException + * + * @phpstan-assert null $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNull + */ + function assertNull(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNull(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotNull')) { + /** + * Asserts that a variable is not null. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !null $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotNull + */ + function assertNotNull(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotNull(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFinite')) { + /** + * Asserts that a variable is finite. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFinite + */ + function assertFinite(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFinite(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertInfinite')) { + /** + * Asserts that a variable is infinite. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertInfinite + */ + function assertInfinite(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertInfinite(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNan')) { + /** + * Asserts that a variable is nan. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNan + */ + function assertNan(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNan(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertObjectHasProperty')) { + /** + * Asserts that an object has a specified property. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertObjectHasProperty + */ + function assertObjectHasProperty(string $propertyName, object $object, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertObjectHasProperty(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertObjectNotHasProperty')) { + /** + * Asserts that an object does not have a specified property. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertObjectNotHasProperty + */ + function assertObjectNotHasProperty(string $propertyName, object $object, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertObjectNotHasProperty(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertSame')) { + /** + * Asserts that two variables have the same type and value. + * Used on objects, it asserts that two variables reference + * the same object. + * + * Comparison is performed using the === operator. + * + * @template ExpectedType + * + * @param ExpectedType $expected + * + * @throws ExpectationFailedException + * + * @phpstan-assert =ExpectedType $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertSame + */ + function assertSame(mixed $expected, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertSame(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotSame')) { + /** + * Asserts that two variables do not have the same type and value. + * Used on objects, it asserts that two variables do not reference + * the same object. + * + * Comparison is performed using the === operator. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotSame + */ + function assertNotSame(mixed $expected, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotSame(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertInstanceOf')) { + /** + * Asserts that a variable is of a given type. + * + * @template ExpectedType of object + * + * @param class-string $expected + * + * @throws Exception + * @throws ExpectationFailedException + * @throws UnknownClassOrInterfaceException + * + * @phpstan-assert =ExpectedType $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertInstanceOf + */ + function assertInstanceOf(string $expected, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertInstanceOf(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotInstanceOf')) { + /** + * Asserts that a variable is not of a given type. + * + * @template ExpectedType of object + * + * @param class-string $expected + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !ExpectedType $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotInstanceOf + */ + function assertNotInstanceOf(string $expected, mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotInstanceOf(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsArray')) { + /** + * Asserts that a variable is of type array. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert array $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsArray + */ + function assertIsArray(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsArray(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsBool')) { + /** + * Asserts that a variable is of type bool. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert bool $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsBool + */ + function assertIsBool(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsBool(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsFloat')) { + /** + * Asserts that a variable is of type float. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert float $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsFloat + */ + function assertIsFloat(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsFloat(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsInt')) { + /** + * Asserts that a variable is of type int. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert int $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsInt + */ + function assertIsInt(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsInt(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNumeric')) { + /** + * Asserts that a variable is of type numeric. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert numeric $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNumeric + */ + function assertIsNumeric(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNumeric(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsObject')) { + /** + * Asserts that a variable is of type object. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert object $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsObject + */ + function assertIsObject(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsObject(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsResource')) { + /** + * Asserts that a variable is of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert resource $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsResource + */ + function assertIsResource(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsClosedResource')) { + /** + * Asserts that a variable is of type resource and is closed. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert resource $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsClosedResource + */ + function assertIsClosedResource(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsClosedResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsString')) { + /** + * Asserts that a variable is of type string. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert string $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsString + */ + function assertIsString(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsScalar')) { + /** + * Asserts that a variable is of type scalar. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert scalar $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsScalar + */ + function assertIsScalar(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsScalar(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsCallable')) { + /** + * Asserts that a variable is of type callable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert callable $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsCallable + */ + function assertIsCallable(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsCallable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsIterable')) { + /** + * Asserts that a variable is of type iterable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert iterable $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsIterable + */ + function assertIsIterable(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsIterable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotArray')) { + /** + * Asserts that a variable is not of type array. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !array $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotArray + */ + function assertIsNotArray(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotArray(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotBool')) { + /** + * Asserts that a variable is not of type bool. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !bool $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotBool + */ + function assertIsNotBool(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotBool(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotFloat')) { + /** + * Asserts that a variable is not of type float. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !float $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotFloat + */ + function assertIsNotFloat(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotFloat(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotInt')) { + /** + * Asserts that a variable is not of type int. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !int $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotInt + */ + function assertIsNotInt(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotInt(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotNumeric')) { + /** + * Asserts that a variable is not of type numeric. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !numeric $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotNumeric + */ + function assertIsNotNumeric(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotNumeric(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotObject')) { + /** + * Asserts that a variable is not of type object. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !object $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotObject + */ + function assertIsNotObject(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotObject(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotResource')) { + /** + * Asserts that a variable is not of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !resource $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotResource + */ + function assertIsNotResource(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotClosedResource')) { + /** + * Asserts that a variable is not of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !resource $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotClosedResource + */ + function assertIsNotClosedResource(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotClosedResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotString')) { + /** + * Asserts that a variable is not of type string. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !string $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotString + */ + function assertIsNotString(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotScalar')) { + /** + * Asserts that a variable is not of type scalar. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !scalar $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotScalar + */ + function assertIsNotScalar(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotScalar(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotCallable')) { + /** + * Asserts that a variable is not of type callable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !callable $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotCallable + */ + function assertIsNotCallable(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotCallable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertIsNotIterable')) { + /** + * Asserts that a variable is not of type iterable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !iterable $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotIterable + */ + function assertIsNotIterable(mixed $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertIsNotIterable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertMatchesRegularExpression')) { + /** + * Asserts that a string matches a given regular expression. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertMatchesRegularExpression + */ + function assertMatchesRegularExpression(string $pattern, string $string, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertMatchesRegularExpression(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertDoesNotMatchRegularExpression')) { + /** + * Asserts that a string does not match a given regular expression. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDoesNotMatchRegularExpression + */ + function assertDoesNotMatchRegularExpression(string $pattern, string $string, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertDoesNotMatchRegularExpression(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertSameSize')) { + /** + * Assert that the size of two arrays (or `Countable` or `Traversable` objects) + * is the same. + * + * @param Countable|iterable $expected + * @param Countable|iterable $actual + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertSameSize + */ + function assertSameSize(Countable|iterable $expected, Countable|iterable $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertSameSize(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertNotSameSize')) { + /** + * Assert that the size of two arrays (or `Countable` or `Traversable` objects) + * is not the same. + * + * @param Countable|iterable $expected + * @param Countable|iterable $actual + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotSameSize + */ + function assertNotSameSize(Countable|iterable $expected, Countable|iterable $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertNotSameSize(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringContainsStringIgnoringLineEndings')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringContainsStringIgnoringLineEndings + */ + function assertStringContainsStringIgnoringLineEndings(string $needle, string $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringContainsStringIgnoringLineEndings(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringEqualsStringIgnoringLineEndings')) { + /** + * Asserts that two strings are equal except for line endings. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEqualsStringIgnoringLineEndings + */ + function assertStringEqualsStringIgnoringLineEndings(string $expected, string $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringEqualsStringIgnoringLineEndings(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileMatchesFormat')) { + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileMatchesFormat + */ + function assertFileMatchesFormat(string $format, string $actualFile, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileMatchesFormat(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertFileMatchesFormatFile')) { + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileMatchesFormatFile + */ + function assertFileMatchesFormatFile(string $formatFile, string $actualFile, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertFileMatchesFormatFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringMatchesFormat')) { + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringMatchesFormat + */ + function assertStringMatchesFormat(string $format, string $string, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringMatchesFormat(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringMatchesFormatFile')) { + /** + * Asserts that a string matches a given format file. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringMatchesFormatFile + */ + function assertStringMatchesFormatFile(string $formatFile, string $string, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringMatchesFormatFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringStartsWith')) { + /** + * Asserts that a string starts with a given prefix. + * + * @param non-empty-string $prefix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringStartsWith + */ + function assertStringStartsWith(string $prefix, string $string, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringStartsWith(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringStartsNotWith')) { + /** + * Asserts that a string starts not with a given prefix. + * + * @param non-empty-string $prefix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringStartsNotWith + */ + function assertStringStartsNotWith(string $prefix, string $string, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringStartsNotWith(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringContainsString')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringContainsString + */ + function assertStringContainsString(string $needle, string $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringContainsString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringContainsStringIgnoringCase')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringContainsStringIgnoringCase + */ + function assertStringContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringContainsStringIgnoringCase(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringNotContainsString')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringNotContainsString + */ + function assertStringNotContainsString(string $needle, string $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringNotContainsString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringNotContainsStringIgnoringCase')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringNotContainsStringIgnoringCase + */ + function assertStringNotContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringNotContainsStringIgnoringCase(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringEndsWith')) { + /** + * Asserts that a string ends with a given suffix. + * + * @param non-empty-string $suffix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEndsWith + */ + function assertStringEndsWith(string $suffix, string $string, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringEndsWith(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertStringEndsNotWith')) { + /** + * Asserts that a string ends not with a given suffix. + * + * @param non-empty-string $suffix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEndsNotWith + */ + function assertStringEndsNotWith(string $suffix, string $string, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertStringEndsNotWith(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertXmlFileEqualsXmlFile')) { + /** + * Asserts that two XML files are equal, ignoring comments. + * + * @throws Exception + * @throws ExpectationFailedException + * @throws XmlException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlFileEqualsXmlFile + */ + function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertXmlFileEqualsXmlFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertXmlFileNotEqualsXmlFile')) { + /** + * Asserts that two XML files are not equal, ignoring comments. + * + * @throws \PHPUnit\Util\Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlFileNotEqualsXmlFile + */ + function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertXmlFileNotEqualsXmlFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertXmlStringEqualsXmlFile')) { + /** + * Asserts that two XML documents are equal, ignoring comments. + * + * @throws ExpectationFailedException + * @throws XmlException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlStringEqualsXmlFile + */ + function assertXmlStringEqualsXmlFile(string $expectedFile, string $actualXml, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertXmlStringEqualsXmlFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertXmlStringNotEqualsXmlFile')) { + /** + * Asserts that two XML documents are not equal, ignoring comments. + * + * @throws ExpectationFailedException + * @throws XmlException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlStringNotEqualsXmlFile + */ + function assertXmlStringNotEqualsXmlFile(string $expectedFile, string $actualXml, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertXmlStringNotEqualsXmlFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertXmlStringEqualsXmlString')) { + /** + * Asserts that two XML documents are equal, ignoring comments. + * + * @throws ExpectationFailedException + * @throws XmlException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlStringEqualsXmlString + */ + function assertXmlStringEqualsXmlString(string $expectedXml, string $actualXml, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertXmlStringEqualsXmlString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertXmlStringNotEqualsXmlString')) { + /** + * Asserts that two XML documents are not equal, ignoring comments. + * + * @throws ExpectationFailedException + * @throws XmlException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlStringNotEqualsXmlString + */ + function assertXmlStringNotEqualsXmlString(string $expectedXml, string $actualXml, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertXmlStringNotEqualsXmlString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertThat')) { + /** + * Evaluates a PHPUnit\Framework\Constraint matcher object. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertThat + */ + function assertThat(mixed $value, Constraint $constraint, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertThat(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertJson')) { + /** + * Asserts that a string is a valid JSON string. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJson + */ + function assertJson(string $actual, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertJson(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertJsonStringEqualsJsonString')) { + /** + * Asserts that two given JSON encoded objects or arrays are equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonStringEqualsJsonString + */ + function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertJsonStringEqualsJsonString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertJsonStringNotEqualsJsonString')) { + /** + * Asserts that two given JSON encoded objects or arrays are not equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonStringNotEqualsJsonString + */ + function assertJsonStringNotEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertJsonStringNotEqualsJsonString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertJsonStringEqualsJsonFile')) { + /** + * Asserts that the generated JSON encoded object and the content of the given file are equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonStringEqualsJsonFile + */ + function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertJsonStringEqualsJsonFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertJsonStringNotEqualsJsonFile')) { + /** + * Asserts that the generated JSON encoded object and the content of the given file are not equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonStringNotEqualsJsonFile + */ + function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertJsonStringNotEqualsJsonFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertJsonFileEqualsJsonFile')) { + /** + * Asserts that two JSON files are equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonFileEqualsJsonFile + */ + function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertJsonFileEqualsJsonFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\assertJsonFileNotEqualsJsonFile')) { + /** + * Asserts that two JSON files are not equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonFileNotEqualsJsonFile + */ + function assertJsonFileNotEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void + { + \PHPUnit\Framework\Assert::assertJsonFileNotEqualsJsonFile(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\logicalAnd')) { + function logicalAnd(mixed ...$constraints): LogicalAnd + { + return \PHPUnit\Framework\Assert::logicalAnd(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\logicalOr')) { + function logicalOr(mixed ...$constraints): LogicalOr + { + return \PHPUnit\Framework\Assert::logicalOr(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\logicalNot')) { + function logicalNot(Constraint $constraint): LogicalNot + { + return \PHPUnit\Framework\Assert::logicalNot(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\logicalXor')) { + function logicalXor(mixed ...$constraints): LogicalXor + { + return \PHPUnit\Framework\Assert::logicalXor(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\anything')) { + function anything(): IsAnything + { + return \PHPUnit\Framework\Assert::anything(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isTrue')) { + function isTrue(): IsTrue + { + return \PHPUnit\Framework\Assert::isTrue(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isFalse')) { + function isFalse(): IsFalse + { + return \PHPUnit\Framework\Assert::isFalse(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isJson')) { + function isJson(): IsJson + { + return \PHPUnit\Framework\Assert::isJson(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isNull')) { + function isNull(): IsNull + { + return \PHPUnit\Framework\Assert::isNull(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isFinite')) { + function isFinite(): IsFinite + { + return \PHPUnit\Framework\Assert::isFinite(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isInfinite')) { + function isInfinite(): IsInfinite + { + return \PHPUnit\Framework\Assert::isInfinite(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isNan')) { + function isNan(): IsNan + { + return \PHPUnit\Framework\Assert::isNan(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsEqual')) { + function containsEqual(mixed $value): TraversableContainsEqual + { + return \PHPUnit\Framework\Assert::containsEqual(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsIdentical')) { + function containsIdentical(mixed $value): TraversableContainsIdentical + { + return \PHPUnit\Framework\Assert::containsIdentical(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyArray')) { + function containsOnlyArray(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyArray(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyBool')) { + function containsOnlyBool(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyBool(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyCallable')) { + function containsOnlyCallable(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyCallable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyFloat')) { + function containsOnlyFloat(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyFloat(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyInt')) { + function containsOnlyInt(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyInt(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyIterable')) { + function containsOnlyIterable(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyIterable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyNull')) { + function containsOnlyNull(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyNull(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyNumeric')) { + function containsOnlyNumeric(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyNumeric(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyObject')) { + function containsOnlyObject(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyObject(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyResource')) { + function containsOnlyResource(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyClosedResource')) { + function containsOnlyClosedResource(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyClosedResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyScalar')) { + function containsOnlyScalar(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyScalar(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyString')) { + function containsOnlyString(): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\containsOnlyInstancesOf')) { + function containsOnlyInstancesOf(string $className): TraversableContainsOnly + { + return \PHPUnit\Framework\Assert::containsOnlyInstancesOf(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\arrayHasKey')) { + function arrayHasKey(mixed $key): ArrayHasKey + { + return \PHPUnit\Framework\Assert::arrayHasKey(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isList')) { + function isList(): IsList + { + return \PHPUnit\Framework\Assert::isList(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\equalTo')) { + function equalTo(mixed $value): IsEqual + { + return \PHPUnit\Framework\Assert::equalTo(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\equalToCanonicalizing')) { + function equalToCanonicalizing(mixed $value): IsEqualCanonicalizing + { + return \PHPUnit\Framework\Assert::equalToCanonicalizing(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\equalToIgnoringCase')) { + function equalToIgnoringCase(mixed $value): IsEqualIgnoringCase + { + return \PHPUnit\Framework\Assert::equalToIgnoringCase(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\equalToWithDelta')) { + function equalToWithDelta(mixed $value, float $delta): IsEqualWithDelta + { + return \PHPUnit\Framework\Assert::equalToWithDelta(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isEmpty')) { + function isEmpty(): IsEmpty + { + return \PHPUnit\Framework\Assert::isEmpty(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isWritable')) { + function isWritable(): IsWritable + { + return \PHPUnit\Framework\Assert::isWritable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isReadable')) { + function isReadable(): IsReadable + { + return \PHPUnit\Framework\Assert::isReadable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\directoryExists')) { + function directoryExists(): DirectoryExists + { + return \PHPUnit\Framework\Assert::directoryExists(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\fileExists')) { + function fileExists(): FileExists + { + return \PHPUnit\Framework\Assert::fileExists(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\greaterThan')) { + function greaterThan(mixed $value): GreaterThan + { + return \PHPUnit\Framework\Assert::greaterThan(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\greaterThanOrEqual')) { + function greaterThanOrEqual(mixed $value): LogicalOr + { + return \PHPUnit\Framework\Assert::greaterThanOrEqual(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\identicalTo')) { + function identicalTo(mixed $value): IsIdentical + { + return \PHPUnit\Framework\Assert::identicalTo(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isInstanceOf')) { + function isInstanceOf(string $className): IsInstanceOf + { + return \PHPUnit\Framework\Assert::isInstanceOf(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isArray')) { + function isArray(): IsType + { + return \PHPUnit\Framework\Assert::isArray(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isBool')) { + function isBool(): IsType + { + return \PHPUnit\Framework\Assert::isBool(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isCallable')) { + function isCallable(): IsType + { + return \PHPUnit\Framework\Assert::isCallable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isFloat')) { + function isFloat(): IsType + { + return \PHPUnit\Framework\Assert::isFloat(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isInt')) { + function isInt(): IsType + { + return \PHPUnit\Framework\Assert::isInt(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isIterable')) { + function isIterable(): IsType + { + return \PHPUnit\Framework\Assert::isIterable(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isNumeric')) { + function isNumeric(): IsType + { + return \PHPUnit\Framework\Assert::isNumeric(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isObject')) { + function isObject(): IsType + { + return \PHPUnit\Framework\Assert::isObject(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isResource')) { + function isResource(): IsType + { + return \PHPUnit\Framework\Assert::isResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isClosedResource')) { + function isClosedResource(): IsType + { + return \PHPUnit\Framework\Assert::isClosedResource(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isScalar')) { + function isScalar(): IsType + { + return \PHPUnit\Framework\Assert::isScalar(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\isString')) { + function isString(): IsType + { + return \PHPUnit\Framework\Assert::isString(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\lessThan')) { + function lessThan(mixed $value): LessThan + { + return \PHPUnit\Framework\Assert::lessThan(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\lessThanOrEqual')) { + function lessThanOrEqual(mixed $value): LogicalOr + { + return \PHPUnit\Framework\Assert::lessThanOrEqual(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\matchesRegularExpression')) { + function matchesRegularExpression(string $pattern): RegularExpression + { + return \PHPUnit\Framework\Assert::matchesRegularExpression(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\matches')) { + function matches(string $string): StringMatchesFormatDescription + { + return \PHPUnit\Framework\Assert::matches(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\stringStartsWith')) { + function stringStartsWith(string $prefix): StringStartsWith + { + return \PHPUnit\Framework\Assert::stringStartsWith(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\stringContains')) { + function stringContains(string $string, bool $case = \true): StringContains + { + return \PHPUnit\Framework\Assert::stringContains(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\stringEndsWith')) { + function stringEndsWith(string $suffix): StringEndsWith + { + return \PHPUnit\Framework\Assert::stringEndsWith(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\stringEqualsStringIgnoringLineEndings')) { + function stringEqualsStringIgnoringLineEndings(string $string): StringEqualsStringIgnoringLineEndings + { + return \PHPUnit\Framework\Assert::stringEqualsStringIgnoringLineEndings(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\countOf')) { + function countOf(int $count): Count + { + return \PHPUnit\Framework\Assert::countOf(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\objectEquals')) { + function objectEquals(object $object, string $method = 'equals'): ObjectEquals + { + return \PHPUnit\Framework\Assert::objectEquals(...func_get_args()); + } +} +if (!function_exists('PHPUnit\Framework\callback')) { + /** + * @template CallbackInput of mixed + * + * @param callable(CallbackInput $callback): bool $callback + * + * @return Callback + */ + function callback(callable $callback): Callback + { + return \PHPUnit\Framework\Assert::callback($callback); + } +} +if (!function_exists('PHPUnit\Framework\any')) { + /** + * Returns a matcher that matches when the method is executed + * zero or more times. + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/6461 + */ + function any(): AnyInvokedCountMatcher + { + return new AnyInvokedCountMatcher(); + } +} +if (!function_exists('PHPUnit\Framework\never')) { + /** + * Returns a matcher that matches when the method is never executed. + */ + function never(): InvokedCountMatcher + { + return new InvokedCountMatcher(0); + } +} +if (!function_exists('PHPUnit\Framework\atLeast')) { + /** + * Returns a matcher that matches when the method is executed + * at least N times. + */ + function atLeast(int $requiredInvocations): InvokedAtLeastCountMatcher + { + if ($requiredInvocations < 1) { + EventFacade::emitter()->testTriggeredPhpunitDeprecation(null, 'Calling atLeast() with an argument that is not positive is deprecated.' . PHP_EOL . 'This will become an error in PHPUnit 14.'); + } + return new InvokedAtLeastCountMatcher($requiredInvocations); + } +} +if (!function_exists('PHPUnit\Framework\atLeastOnce')) { + /** + * Returns a matcher that matches when the method is executed at least once. + */ + function atLeastOnce(): InvokedAtLeastOnceMatcher + { + return new InvokedAtLeastOnceMatcher(); + } +} +if (!function_exists('PHPUnit\Framework\once')) { + /** + * Returns a matcher that matches when the method is executed exactly once. + */ + function once(): InvokedCountMatcher + { + return new InvokedCountMatcher(1); + } +} +if (!function_exists('PHPUnit\Framework\exactly')) { + /** + * Returns a matcher that matches when the method is executed + * exactly $count times. + */ + function exactly(int $count): InvokedCountMatcher + { + return new InvokedCountMatcher($count); + } +} +if (!function_exists('PHPUnit\Framework\atMost')) { + /** + * Returns a matcher that matches when the method is executed + * at most N times. + */ + function atMost(int $allowedInvocations): InvokedAtMostCountMatcher + { + return new InvokedAtMostCountMatcher($allowedInvocations); + } +} +if (!function_exists('PHPUnit\Framework\throwException')) { + function throwException(Throwable $exception): ExceptionStub + { + return new ExceptionStub($exception); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class After +{ + private int $priority; + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class AfterClass +{ + private int $priority; + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class AllowMockObjectsWithoutExpectations +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class BackupGlobals +{ + private bool $enabled; + public function __construct(bool $enabled) + { + $this->enabled = $enabled; + } + public function enabled(): bool + { + return $this->enabled; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class BackupStaticProperties +{ + private bool $enabled; + public function __construct(bool $enabled) + { + $this->enabled = $enabled; + } + public function enabled(): bool + { + return $this->enabled; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class Before +{ + private int $priority; + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class BeforeClass +{ + private int $priority; + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversClass +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversClassesThatExtendClass +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversClassesThatImplementInterface +{ + /** + * @var class-string + */ + private string $interfaceName; + /** + * @param class-string $interfaceName + */ + public function __construct(string $interfaceName) + { + $this->interfaceName = $interfaceName; + } + /** + * @return class-string + */ + public function interfaceName(): string + { + return $this->interfaceName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversFunction +{ + /** + * @var non-empty-string + */ + private string $functionName; + /** + * @param non-empty-string $functionName + */ + public function __construct(string $functionName) + { + $this->functionName = $functionName; + } + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversMethod +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversNamespace +{ + /** + * @var non-empty-string + */ + private string $namespace; + /** + * @param non-empty-string $namespace + */ + public function __construct(string $namespace) + { + $this->namespace = $namespace; + } + /** + * @return non-empty-string + */ + public function namespace(): string + { + return $this->namespace; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class CoversNothing +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversTrait +{ + /** + * @var trait-string + */ + private string $traitName; + /** + * @param trait-string $traitName + */ + public function __construct(string $traitName) + { + $this->traitName = $traitName; + } + /** + * @return trait-string + */ + public function traitName(): string + { + return $this->traitName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DataProvider +{ + /** + * @var non-empty-string + */ + private string $methodName; + private bool $validateArgumentCount; + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName, bool $validateArgumentCount = \true) + { + $this->methodName = $methodName; + $this->validateArgumentCount = $validateArgumentCount; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + public function validateArgumentCount(): bool + { + return $this->validateArgumentCount; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +use Closure; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DataProviderClosure +{ + private Closure $closure; + private bool $validateArgumentCount; + public function __construct(Closure $closure, bool $validateArgumentCount = \true) + { + $this->closure = $closure; + $this->validateArgumentCount = $validateArgumentCount; + } + public function closure(): Closure + { + return $this->closure; + } + public function validateArgumentCount(): bool + { + return $this->validateArgumentCount; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DataProviderExternal +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + private bool $validateArgumentCount; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName, bool $validateArgumentCount = \true) + { + $this->className = $className; + $this->methodName = $methodName; + $this->validateArgumentCount = $validateArgumentCount; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + public function validateArgumentCount(): bool + { + return $this->validateArgumentCount; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class Depends +{ + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName) + { + $this->methodName = $methodName; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsExternal +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsExternalUsingDeepClone +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsExternalUsingShallowClone +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsOnClass +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsOnClassUsingDeepClone +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsOnClassUsingShallowClone +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsUsingDeepClone +{ + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName) + { + $this->methodName = $methodName; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsUsingShallowClone +{ + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName) + { + $this->methodName = $methodName; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS)] +final readonly class DisableReturnValueGenerationForTestDoubles +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class DoesNotPerformAssertions +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class ExcludeGlobalVariableFromBackup +{ + /** + * @var non-empty-string + */ + private string $globalVariableName; + /** + * @param non-empty-string $globalVariableName + */ + public function __construct(string $globalVariableName) + { + $this->globalVariableName = $globalVariableName; + } + /** + * @return non-empty-string + */ + public function globalVariableName(): string + { + return $this->globalVariableName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class ExcludeStaticPropertyFromBackup +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $propertyName; + /** + * @param class-string $className + * @param non-empty-string $propertyName + */ + public function __construct(string $className, string $propertyName) + { + $this->className = $className; + $this->propertyName = $propertyName; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function propertyName(): string + { + return $this->propertyName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class Group +{ + /** + * @var non-empty-string + */ + private string $name; + /** + * @param non-empty-string $name + */ + public function __construct(string $name) + { + $this->name = $name; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class IgnoreDeprecations +{ + /** @var null|non-empty-string */ + private ?string $messagePattern; + /** + * @param null|non-empty-string $messagePattern + */ + public function __construct(null|string $messagePattern = null) + { + $this->messagePattern = $messagePattern; + } + /** + * @return null|non-empty-string + */ + public function messagePattern(): ?string + { + return $this->messagePattern; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class IgnorePhpunitDeprecations +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class IgnorePhpunitWarnings +{ + /** @var null|non-empty-string */ + private ?string $messagePattern; + /** + * @param null|non-empty-string $messagePattern + */ + public function __construct(null|string $messagePattern = null) + { + $this->messagePattern = $messagePattern; + } + /** + * @return null|non-empty-string + */ + public function messagePattern(): ?string + { + return $this->messagePattern; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS)] +final readonly class Large +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS)] +final readonly class Medium +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class PostCondition +{ + private int $priority; + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class PreCondition +{ + private int $priority; + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class PreserveGlobalState +{ + private bool $enabled; + public function __construct(bool $enabled) + { + $this->enabled = $enabled; + } + public function enabled(): bool + { + return $this->enabled; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresEnvironmentVariable +{ + private string $environmentVariableName; + private null|string $value; + public function __construct(string $environmentVariableName, null|string $value = null) + { + $this->environmentVariableName = $environmentVariableName; + $this->value = $value; + } + public function environmentVariableName(): string + { + return $this->environmentVariableName; + } + public function value(): null|string + { + return $this->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresFunction +{ + /** + * @var non-empty-string + */ + private string $functionName; + /** + * @param non-empty-string $functionName + */ + public function __construct(string $functionName) + { + $this->functionName = $functionName; + } + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresMethod +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class RequiresOperatingSystem +{ + /** + * @var non-empty-string + */ + private string $regularExpression; + /** + * @param non-empty-string $regularExpression + */ + public function __construct(string $regularExpression) + { + $this->regularExpression = $regularExpression; + } + /** + * @return non-empty-string + */ + public function regularExpression(): string + { + return $this->regularExpression; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class RequiresOperatingSystemFamily +{ + /** + * @var non-empty-string + */ + private string $operatingSystemFamily; + /** + * @param non-empty-string $operatingSystemFamily + */ + public function __construct(string $operatingSystemFamily) + { + $this->operatingSystemFamily = $operatingSystemFamily; + } + /** + * @return non-empty-string + */ + public function operatingSystemFamily(): string + { + return $this->operatingSystemFamily; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class RequiresPhp +{ + /** + * @var non-empty-string + */ + private string $versionRequirement; + /** + * @param non-empty-string $versionRequirement + */ + public function __construct(string $versionRequirement) + { + $this->versionRequirement = $versionRequirement; + } + /** + * @return non-empty-string + */ + public function versionRequirement(): string + { + return $this->versionRequirement; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresPhpExtension +{ + /** + * @var non-empty-string + */ + private string $extension; + /** + * @var null|non-empty-string + */ + private ?string $versionRequirement; + /** + * @param non-empty-string $extension + * @param null|non-empty-string $versionRequirement + */ + public function __construct(string $extension, ?string $versionRequirement = null) + { + $this->extension = $extension; + $this->versionRequirement = $versionRequirement; + } + /** + * @return non-empty-string + */ + public function extension(): string + { + return $this->extension; + } + /** + * @return null|non-empty-string + */ + public function versionRequirement(): ?string + { + return $this->versionRequirement; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class RequiresPhpunit +{ + /** + * @var non-empty-string + */ + private string $versionRequirement; + /** + * @param non-empty-string $versionRequirement + */ + public function __construct(string $versionRequirement) + { + $this->versionRequirement = $versionRequirement; + } + /** + * @return non-empty-string + */ + public function versionRequirement(): string + { + return $this->versionRequirement; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +use PHPUnit\Runner\Extension\Extension; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresPhpunitExtension +{ + /** + * @var class-string + */ + private string $extensionClass; + /** + * @param class-string $extensionClass + */ + public function __construct(string $extensionClass) + { + $this->extensionClass = $extensionClass; + } + /** + * @return class-string + */ + public function extensionClass(): string + { + return $this->extensionClass; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresSetting +{ + /** + * @var non-empty-string + */ + private string $setting; + /** + * @var non-empty-string + */ + private string $value; + /** + * @param non-empty-string $setting + * @param non-empty-string $value + */ + public function __construct(string $setting, string $value) + { + $this->setting = $setting; + $this->value = $value; + } + /** + * @return non-empty-string + */ + public function setting(): string + { + return $this->setting; + } + /** + * @return non-empty-string + */ + public function value(): string + { + return $this->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class RunInSeparateProcess +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS)] +final readonly class RunTestsInSeparateProcesses +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS)] +final readonly class Small +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class Test +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class TestDox +{ + /** + * @var non-empty-string + */ + private string $text; + /** + * @param non-empty-string $text + */ + public function __construct(string $text) + { + $this->text = $text; + } + /** + * @return non-empty-string + */ + public function text(): string + { + return $this->text; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class TestDoxFormatter +{ + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName) + { + $this->methodName = $methodName; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class TestDoxFormatterExternal +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class TestWith +{ + /** + * @var array + */ + private array $data; + /** + * @var ?non-empty-string + */ + private ?string $name; + /** + * @param array $data + * @param ?non-empty-string $name + */ + public function __construct(array $data, ?string $name = null) + { + $this->data = $data; + $this->name = $name; + } + /** + * @return array + */ + public function data(): array + { + return $this->data; + } + /** + * @return ?non-empty-string + */ + public function name(): ?string + { + return $this->name; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class TestWithJson +{ + /** + * @var non-empty-string + */ + private string $json; + /** + * @var ?non-empty-string + */ + private ?string $name; + /** + * @param non-empty-string $json + * @param ?non-empty-string $name + */ + public function __construct(string $json, ?string $name = null) + { + $this->json = $json; + $this->name = $name; + } + /** + * @return non-empty-string + */ + public function json(): string + { + return $this->json; + } + /** + * @return ?non-empty-string + */ + public function name(): ?string + { + return $this->name; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class Ticket +{ + /** + * @var non-empty-string + */ + private string $text; + /** + * @param non-empty-string $text + */ + public function __construct(string $text) + { + $this->text = $text; + } + /** + * @return non-empty-string + */ + public function text(): string + { + return $this->text; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesClass +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesClassesThatExtendClass +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesClassesThatImplementInterface +{ + /** + * @var class-string + */ + private string $interfaceName; + /** + * @param class-string $interfaceName + */ + public function __construct(string $interfaceName) + { + $this->interfaceName = $interfaceName; + } + /** + * @return class-string + */ + public function interfaceName(): string + { + return $this->interfaceName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesFunction +{ + /** + * @var non-empty-string + */ + private string $functionName; + /** + * @param non-empty-string $functionName + */ + public function __construct(string $functionName) + { + $this->functionName = $functionName; + } + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesMethod +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesNamespace +{ + /** + * @var non-empty-string + */ + private string $namespace; + /** + * @param non-empty-string $namespace + */ + public function __construct(string $namespace) + { + $this->namespace = $namespace; + } + /** + * @return non-empty-string + */ + public function namespace(): string + { + return $this->namespace; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesTrait +{ + /** + * @var trait-string + */ + private string $traitName; + /** + * @param trait-string $traitName + */ + public function __construct(string $traitName) + { + $this->traitName = $traitName; + } + /** + * @return trait-string + */ + public function traitName(): string + { + return $this->traitName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class WithEnvironmentVariable +{ + /** + * @var non-empty-string + */ + private string $environmentVariableName; + private null|string $value; + /** + * @param non-empty-string $environmentVariableName + */ + public function __construct(string $environmentVariableName, null|string $value = null) + { + $this->environmentVariableName = $environmentVariableName; + $this->value = $value; + } + /** + * @return non-empty-string + */ + public function environmentVariableName(): string + { + return $this->environmentVariableName; + } + public function value(): null|string + { + return $this->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class WithoutErrorHandler +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_key_exists; +use function array_values; +use function count; +use function is_array; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\Exporter; +use PHPUnitPHAR\SebastianBergmann\Comparator\ComparisonFailure; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class ArrayComparison extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * @var array + */ + protected readonly array $expected; + protected readonly bool $keysMatter; + protected readonly bool $orderMatters; + /** + * @param array $expected + */ + public function __construct(array $expected, bool $keysMatter, bool $orderMatters) + { + $this->expected = $expected; + $this->keysMatter = $keysMatter; + $this->orderMatters = $orderMatters; + } + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = \false): ?bool + { + if (!is_array($other)) { + return \false; + } + $success = $this->compare($this->expected, $other); + if ($returnResult) { + return $success; + } + if (!$success) { + $this->fail($other, $description, new ComparisonFailure($this->expected, $other, Exporter::export($this->expected), Exporter::export($other))); + } + // @codeCoverageIgnoreStart + return null; + // @codeCoverageIgnoreEnd + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + if ($this->keysMatter && $this->orderMatters) { + return 'two arrays are ' . $this->comparisonType(); + } + if (!$this->keysMatter && !$this->orderMatters) { + return 'two arrays are ' . $this->comparisonType() . ' while ignoring keys and order'; + } + if (!$this->keysMatter) { + return 'two arrays are ' . $this->comparisonType() . ' while ignoring keys'; + } + return 'two arrays are ' . $this->comparisonType() . ' while ignoring order'; + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return $this->toString(); + } + /** + * @return 'equal'|'identical' + */ + abstract protected function comparisonType(): string; + /** + * Compares two non-array values (or two arrays in modes where order at + * every level is significant) using the strictness defined by the + * concrete subclass. + */ + abstract protected function compareLeaf(mixed $expected, mixed $actual): bool; + /** + * Compares two values, recursing into arrays as needed. + * + * Whenever both $expected and $actual are arrays, the same comparison + * mode (controlled by $keysMatter and $orderMatters) is applied at every + * level of nesting. For all other value combinations, the leaf comparison + * provided by the concrete subclass is used. + */ + private function compare(mixed $expected, mixed $actual): bool + { + if (!is_array($expected) || !is_array($actual)) { + return $this->compareLeaf($expected, $actual); + } + if ($this->keysMatter && $this->orderMatters) { + return $this->compareLeaf($expected, $actual); + } + if (!$this->keysMatter && $this->orderMatters) { + return $this->compareLeaf(array_values($expected), array_values($actual)); + } + if ($this->keysMatter) { + return $this->compareKeyedIgnoringOrder($expected, $actual); + } + return $this->compareIgnoringKeysAndOrder($expected, $actual); + } + /** + * @param array $expected + * @param array $actual + */ + private function compareKeyedIgnoringOrder(array $expected, array $actual): bool + { + if (count($expected) !== count($actual)) { + return \false; + } + foreach ($expected as $key => $value) { + if (!array_key_exists($key, $actual)) { + return \false; + } + if (!$this->compare($value, $actual[$key])) { + return \false; + } + } + return \true; + } + /** + * @param array $expected + * @param array $actual + */ + private function compareIgnoringKeysAndOrder(array $expected, array $actual): bool + { + if (count($expected) !== count($actual)) { + return \false; + } + $remaining = array_values($actual); + foreach ($expected as $expectedValue) { + $matchedIndex = null; + foreach ($remaining as $index => $candidate) { + if ($this->compare($expectedValue, $candidate)) { + $matchedIndex = $index; + break; + } + } + if ($matchedIndex === null) { + return \false; + } + unset($remaining[$matchedIndex]); + } + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_key_exists; +use function is_array; +use ArrayAccess; +use PHPUnit\Util\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ArrayHasKey extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly mixed $key; + public function __construct(mixed $key) + { + $this->key = $key; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'has the key ' . Exporter::export($this->key); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if (is_array($other)) { + return array_key_exists($this->key, $other); + } + if ($other instanceof ArrayAccess) { + return $other->offsetExists($this->key); + } + return \false; + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return 'an array ' . $this->toString(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ArraysAreEqual extends \PHPUnit\Framework\Constraint\ArrayComparison +{ + protected function compareLeaf(mixed $expected, mixed $actual): bool + { + /** @phpstan-ignore equal.notAllowed */ + return $expected == $actual; + } + /** + * @return 'equal' + */ + protected function comparisonType(): string + { + return 'equal'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ArraysAreIdentical extends \PHPUnit\Framework\Constraint\ArrayComparison +{ + protected function compareLeaf(mixed $expected, mixed $actual): bool + { + return $expected === $actual; + } + /** + * @return 'identical' + */ + protected function comparisonType(): string + { + return 'identical'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_is_list; +use function is_array; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsList extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is a list'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if (!is_array($other)) { + return \false; + } + return array_is_list($other); + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return $this->valueToTypeStringFragment($other) . $this->toString(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsFalse extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is false'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $other === \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsTrue extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is true'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $other === \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use Closure; +use ReflectionFunction; +/** + * @template CallbackInput of mixed + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class Callback extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * @var callable(CallbackInput): bool + */ + private readonly mixed $callback; + /** + * @param callable(CallbackInput $input): bool $callback + */ + public function __construct(callable $callback) + { + $this->callback = $callback; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is accepted by specified callback'; + } + public function isVariadic(): bool + { + return (new ReflectionFunction(Closure::fromCallable($this->callback)))->isVariadic(); + } + /** + * Evaluates the constraint for parameter $value. Returns true if the + * constraint is met, false otherwise. + * + * @param CallbackInput $other + */ + protected function matches(mixed $other): bool + { + if ($this->isVariadic()) { + return ($this->callback)(...$other); + } + return ($this->callback)($other); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function count; +use function is_countable; +use function iterator_count; +use function sprintf; +use EmptyIterator; +use Generator; +use Iterator; +use IteratorAggregate; +use PHPUnit\Framework\Exception; +use PHPUnit\Framework\GeneratorNotSupportedException; +use PHPUnitPHAR\SebastianBergmann\RecursionContext\Context; +use Traversable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +class Count extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly int $expectedCount; + public function __construct(int $expected) + { + $this->expectedCount = $expected; + } + public function toString(): string + { + return sprintf('count matches %d', $this->expectedCount); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @throws Exception + */ + protected function matches(mixed $other): bool + { + return $this->expectedCount === $this->getCountOf($other); + } + /** + * @throws Exception + */ + protected function getCountOf(mixed $other): ?int + { + if (is_countable($other)) { + return count($other); + } + if ($other instanceof EmptyIterator) { + return 0; + } + if ($other instanceof Traversable) { + $context = new Context(); + while ($other instanceof IteratorAggregate) { + if ($context->contains($other) !== \false) { + throw new Exception('IteratorAggregate::getIterator() returned an object that was already seen'); + } + $context->add($other); + try { + $other = $other->getIterator(); + } catch (\Exception $e) { + throw new Exception($e->getMessage(), $e->getCode(), $e); + } + } + $iterator = $other; + if ($iterator instanceof Generator) { + throw new GeneratorNotSupportedException(); + } + if (!$iterator instanceof Iterator) { + return iterator_count($iterator); + } + $key = $iterator->key(); + $count = iterator_count($iterator); + // Manually rewind $iterator to previous key, since iterator_count + // moves pointer. + if ($key !== null) { + $iterator->rewind(); + while ($iterator->valid() && $key !== $iterator->key()) { + $iterator->next(); + } + } + return $count; + } + return null; + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + * + * @throws Exception + */ + protected function failureDescription(mixed $other): string + { + return sprintf('actual size %d matches expected size %d', (int) $this->getCountOf($other), $this->expectedCount); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Util\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class GreaterThan extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly mixed $value; + public function __construct(mixed $value) + { + $this->value = $value; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is greater than ' . Exporter::export($this->value); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $this->value < $other; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function count; +use function gettype; +use function sprintf; +use function str_starts_with; +use Countable; +use EmptyIterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsEmpty extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is empty'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if ($other instanceof EmptyIterator) { + return \true; + } + if ($other instanceof Countable) { + return count($other) === 0; + } + /** @phpstan-ignore empty.notAllowed */ + return empty($other); + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + $type = gettype($other); + return sprintf('%s %s %s', str_starts_with($type, 'a') || str_starts_with($type, 'o') ? 'an' : 'a', $type, $this->toString()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Util\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class LessThan extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly mixed $value; + public function __construct(mixed $value) + { + $this->value = $value; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is less than ' . Exporter::export($this->value); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $this->value > $other; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use Countable; +use PHPUnit\Framework\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class SameSize extends \PHPUnit\Framework\Constraint\Count +{ + /** + * @param Countable|iterable $expected + * + * @throws Exception + */ + public function __construct(Countable|iterable $expected) + { + parent::__construct((int) $this->getCountOf($expected)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function assert; +use function gettype; +use function is_int; +use function is_object; +use function sprintf; +use function str_replace; +use function strpos; +use function strtolower; +use function substr; +use Countable; +use PHPUnit\Framework\Assert; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\SelfDescribing; +use PHPUnit\Util\Exporter; +use ReflectionObject; +use PHPUnitPHAR\SebastianBergmann\Comparator\ComparisonFailure; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class Constraint implements Countable, SelfDescribing +{ + /** + * @template A + * + * @param A $actual + * + * @return A + */ + final public function __invoke(mixed $actual): mixed + { + Assert::assertThat($actual, $this); + return $actual; + } + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = \false): ?bool + { + $success = \false; + if ($this->matches($other)) { + $success = \true; + } + if ($returnResult) { + return $success; + } + if (!$success) { + $this->fail($other, $description); + } + return null; + } + /** + * Counts the number of constraint elements. + */ + public function count(): int + { + return 1; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * This method can be overridden to implement the evaluation algorithm. + */ + protected function matches(mixed $other): bool + { + return \false; + } + /** + * Throws an exception for the given compared value and test description. + * + * @throws ExpectationFailedException + */ + protected function fail(mixed $other, string $description, ?ComparisonFailure $comparisonFailure = null): never + { + $failureDescription = sprintf('Failed asserting that %s.', $this->failureDescription($other)); + $additionalFailureDescription = $this->additionalFailureDescription($other); + if ($additionalFailureDescription !== '') { + $failureDescription .= "\n" . $additionalFailureDescription; + } + if ($description !== '') { + $failureDescription = $description . "\n" . $failureDescription; + } + throw new ExpectationFailedException($failureDescription, $comparisonFailure); + } + /** + * Return additional failure description where needed. + * + * The function can be overridden to provide additional failure + * information like a diff + */ + protected function additionalFailureDescription(mixed $other): string + { + return ''; + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + * + * To provide additional failure information additionalFailureDescription + * can be used. + */ + protected function failureDescription(mixed $other): string + { + return Exporter::export($other) . ' ' . $this->toString(); + } + /** + * Returns a custom string representation of the constraint object when it + * appears in context of an $operator expression. + * + * The purpose of this method is to provide meaningful descriptive string + * in context of operators such as LogicalNot. Native PHPUnit constraints + * are supported out of the box by LogicalNot, but externally developed + * ones had no way to provide correct strings in this context. + * + * The method shall return empty string, when it does not handle + * customization by itself. + */ + protected function toStringInContext(\PHPUnit\Framework\Constraint\Operator $operator, mixed $role): string + { + return ''; + } + /** + * Returns the description of the failure when this constraint appears in + * context of an $operator expression. + * + * The purpose of this method is to provide meaningful failure description + * in context of operators such as LogicalNot. Native PHPUnit constraints + * are supported out of the box by LogicalNot, but externally developed + * ones had no way to provide correct messages in this context. + * + * The method shall return empty string, when it does not handle + * customization by itself. + */ + protected function failureDescriptionInContext(\PHPUnit\Framework\Constraint\Operator $operator, mixed $role, mixed $other): string + { + $string = $this->toStringInContext($operator, $role); + if ($string === '') { + return ''; + } + return Exporter::export($other) . ' ' . $string; + } + /** + * Reduces the sub-expression starting at $this by skipping degenerate + * sub-expression and returns first descendant constraint that starts + * a non-reducible sub-expression. + * + * Returns $this for terminal constraints and for operators that start + * non-reducible sub-expression, or the nearest descendant of $this that + * starts a non-reducible sub-expression. + * + * A constraint expression may be modelled as a tree with non-terminal + * nodes (operators) and terminal nodes. For example: + * + * LogicalOr (operator, non-terminal) + * + LogicalAnd (operator, non-terminal) + * | + IsType('int') (terminal) + * | + GreaterThan(10) (terminal) + * + LogicalNot (operator, non-terminal) + * + IsType('array') (terminal) + * + * A degenerate sub-expression is a part of the tree, that effectively does + * not contribute to the evaluation of the expression it appears in. An example + * of degenerate sub-expression is a BinaryOperator constructed with single + * operand or nested BinaryOperators, each with single operand. An + * expression involving a degenerate sub-expression is equivalent to a + * reduced expression with the degenerate sub-expression removed, for example + * + * LogicalAnd (operator) + * + LogicalOr (degenerate operator) + * | + LogicalAnd (degenerate operator) + * | + IsType('int') (terminal) + * + GreaterThan(10) (terminal) + * + * is equivalent to + * + * LogicalAnd (operator) + * + IsType('int') (terminal) + * + GreaterThan(10) (terminal) + * + * because the subexpression + * + * + LogicalOr + * + LogicalAnd + * + - + * + * is degenerate. Calling reduce() on the LogicalOr object above, as well + * as on LogicalAnd, shall return the IsType('int') instance. + * + * Other specific reductions can be implemented, for example cascade of + * LogicalNot operators + * + * + LogicalNot + * + LogicalNot + * +LogicalNot + * + IsTrue + * + * can be reduced to + * + * LogicalNot + * + IsTrue + */ + protected function reduce(): self + { + return $this; + } + /** + * @return non-empty-string + */ + protected function valueToTypeStringFragment(mixed $value): string + { + if (is_object($value)) { + $reflector = new ReflectionObject($value); + if ($reflector->isAnonymous()) { + $name = str_replace('class@anonymous', '', $reflector->getName()); + $length = strpos($name, '$'); + assert(is_int($length)); + $name = substr($name, 0, $length); + return 'an instance of anonymous class created at ' . $name . ' '; + } + return 'an instance of class ' . $reflector->getName() . ' '; + } + $type = strtolower(gettype($value)); + if ($type === 'double') { + $type = 'float'; + } + if ($type === 'resource (closed)') { + $type = 'closed resource'; + } + return match ($type) { + 'array', 'integer' => 'an ' . $type . ' ', + 'boolean', 'closed resource', 'float', 'resource', 'string' => 'a ' . $type . ' ', + 'null' => 'null ', + default => 'a value of ' . $type . ' ', + }; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_string; +use function sprintf; +use function str_contains; +use function trim; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\Exporter; +use PHPUnitPHAR\SebastianBergmann\Comparator\ComparisonFailure; +use PHPUnitPHAR\SebastianBergmann\Comparator\Factory as ComparatorFactory; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsEqual extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly mixed $value; + public function __construct(mixed $value) + { + $this->value = $value; + } + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = \false): bool + { + // If $this->value and $other are identical, they are also equal. + // This is the most common path and will allow us to skip + // initialization of all the comparators. + if ($this->value === $other) { + return \true; + } + $comparatorFactory = ComparatorFactory::getInstance(); + try { + $comparator = $comparatorFactory->getComparatorFor($this->value, $other); + $comparator->assertEquals($this->value, $other); + } catch (ComparisonFailure $f) { + if ($returnResult) { + return \false; + } + throw new ExpectationFailedException(trim($description . "\n" . $f->getMessage()), $f); + } + return \true; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + $delta = ''; + if (is_string($this->value)) { + if (str_contains($this->value, "\n")) { + return 'is equal to '; + } + return sprintf("is equal to '%s'", $this->value); + } + return sprintf('is equal to %s%s', Exporter::export($this->value), $delta); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_string; +use function sprintf; +use function str_contains; +use function trim; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\Exporter; +use PHPUnitPHAR\SebastianBergmann\Comparator\ComparisonFailure; +use PHPUnitPHAR\SebastianBergmann\Comparator\Factory as ComparatorFactory; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsEqualCanonicalizing extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly mixed $value; + public function __construct(mixed $value) + { + $this->value = $value; + } + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = \false): bool + { + // If $this->value and $other are identical, they are also equal. + // This is the most common path and will allow us to skip + // initialization of all the comparators. + if ($this->value === $other) { + return \true; + } + $comparatorFactory = ComparatorFactory::getInstance(); + try { + $comparator = $comparatorFactory->getComparatorFor($this->value, $other); + $comparator->assertEquals($this->value, $other, 0.0, \true); + } catch (ComparisonFailure $f) { + if ($returnResult) { + return \false; + } + throw new ExpectationFailedException(trim($description . "\n" . $f->getMessage()), $f); + } + return \true; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + if (is_string($this->value)) { + if (str_contains($this->value, "\n")) { + return 'is equal to '; + } + return sprintf("is equal to '%s'", $this->value); + } + return sprintf('is equal to %s', Exporter::export($this->value)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_string; +use function sprintf; +use function str_contains; +use function trim; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\Exporter; +use PHPUnitPHAR\SebastianBergmann\Comparator\ComparisonFailure; +use PHPUnitPHAR\SebastianBergmann\Comparator\Factory as ComparatorFactory; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsEqualIgnoringCase extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly mixed $value; + public function __construct(mixed $value) + { + $this->value = $value; + } + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = \false): bool + { + // If $this->value and $other are identical, they are also equal. + // This is the most common path and will allow us to skip + // initialization of all the comparators. + if ($this->value === $other) { + return \true; + } + $comparatorFactory = ComparatorFactory::getInstance(); + try { + $comparator = $comparatorFactory->getComparatorFor($this->value, $other); + $comparator->assertEquals($this->value, $other, 0.0, \false, \true); + } catch (ComparisonFailure $f) { + if ($returnResult) { + return \false; + } + throw new ExpectationFailedException(trim($description . "\n" . $f->getMessage()), $f); + } + return \true; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + if (is_string($this->value)) { + if (str_contains($this->value, "\n")) { + return 'is equal to '; + } + return sprintf("is equal to '%s'", $this->value); + } + return sprintf('is equal to %s', Exporter::export($this->value)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function sprintf; +use function trim; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\Exporter; +use PHPUnitPHAR\SebastianBergmann\Comparator\ComparisonFailure; +use PHPUnitPHAR\SebastianBergmann\Comparator\Factory as ComparatorFactory; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsEqualWithDelta extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly mixed $value; + private readonly float $delta; + public function __construct(mixed $value, float $delta) + { + $this->value = $value; + $this->delta = $delta; + } + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = \false): bool + { + // If $this->value and $other are identical, they are also equal. + // This is the most common path and will allow us to skip + // initialization of all the comparators. + if ($this->value === $other) { + return \true; + } + $comparatorFactory = ComparatorFactory::getInstance(); + try { + $comparator = $comparatorFactory->getComparatorFor($this->value, $other); + $comparator->assertEquals($this->value, $other, $this->delta); + } catch (ComparisonFailure $f) { + if ($returnResult) { + return \false; + } + throw new ExpectationFailedException(trim($description . "\n" . $f->getMessage()), $f); + } + return \true; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf('is equal to %s with delta <%F>', Exporter::export($this->value), $this->delta); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function sprintf; +use PHPUnit\Util\Filter; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Exception extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly string $className; + public function __construct(string $className) + { + $this->className = $className; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf('exception of type "%s"', $this->className); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $other instanceof $this->className; + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + * + * @throws \PHPUnit\Framework\Exception + */ + protected function failureDescription(mixed $other): string + { + if ($other === null) { + return sprintf('exception of type "%s" is thrown', $this->className); + } + $message = ''; + if ($other instanceof Throwable) { + $message = '. Message was: "' . $other->getMessage() . '" at' . "\n" . Filter::stackTraceFromThrowableAsString($other); + } + return sprintf('exception of type "%s" matches expected exception "%s"%s', $other::class, $this->className, $message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function sprintf; +use PHPUnit\Util\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExceptionCode extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly int|string $expectedCode; + public function __construct(int|string $expected) + { + $this->expectedCode = $expected; + } + public function toString(): string + { + return 'exception code is ' . $this->expectedCode; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return (string) $other === (string) $this->expectedCode; + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf('%s is equal to expected exception code %s', Exporter::export($other), Exporter::export($this->expectedCode)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function sprintf; +use function str_contains; +use PHPUnit\Util\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExceptionMessageIsOrContains extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly string $expectedMessage; + public function __construct(string $expectedMessage) + { + $this->expectedMessage = $expectedMessage; + } + public function toString(): string + { + if ($this->expectedMessage === '') { + return 'exception message is empty'; + } + return 'exception message contains ' . Exporter::export($this->expectedMessage); + } + protected function matches(mixed $other): bool + { + if ($this->expectedMessage === '') { + return $other === ''; + } + return str_contains((string) $other, $this->expectedMessage); + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + if ($this->expectedMessage === '') { + return sprintf("exception message is empty but is '%s'", $other); + } + return sprintf("exception message '%s' contains '%s'", $other, $this->expectedMessage); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function preg_match; +use function sprintf; +use Exception; +use PHPUnit\Util\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExceptionMessageMatchesRegularExpression extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly string $regularExpression; + public function __construct(string $regularExpression) + { + $this->regularExpression = $regularExpression; + } + public function toString(): string + { + return 'exception message matches ' . Exporter::export($this->regularExpression); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @throws \PHPUnit\Framework\Exception + * @throws Exception + */ + protected function matches(mixed $other): bool + { + $match = @preg_match($this->regularExpression, (string) $other); + if ($match === \false) { + throw new \PHPUnit\Framework\Exception(sprintf('Invalid expected exception message regular expression given: %s', $this->regularExpression)); + } + return $match === 1; + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf("exception message '%s' matches '%s'", $other, $this->regularExpression); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_dir; +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class DirectoryExists extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'directory exists'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_dir($other); + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf('directory "%s" exists', $other); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function file_exists; +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class FileExists extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'file exists'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return file_exists($other); + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf('file "%s" exists', $other); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_readable; +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsReadable extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is readable'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_readable($other); + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf('"%s" is readable', $other); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_writable; +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsWritable extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is writable'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_writable($other); + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf('"%s" is writable', $other); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsAnything extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws void + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = \false): ?bool + { + return $returnResult ? \true : null; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is anything'; + } + /** + * Counts the number of constraint elements. + */ + public function count(): int + { + return 0; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function explode; +use function gettype; +use function is_array; +use function is_object; +use function is_string; +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\Exporter; +use PHPUnitPHAR\SebastianBergmann\Comparator\ComparisonFailure; +use UnitEnum; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsIdentical extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly mixed $value; + public function __construct(mixed $value) + { + $this->value = $value; + } + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = \false): ?bool + { + $success = $this->value === $other; + if ($returnResult) { + return $success; + } + if (!$success) { + $f = null; + // if both values are strings, make sure a diff is generated + if (is_string($this->value) && is_string($other)) { + $f = new ComparisonFailure($this->value, $other, sprintf("'%s'", $this->value), sprintf("'%s'", $other)); + } + // if both values are array or enums, make sure a diff is generated + if (is_array($this->value) && is_array($other) || $this->value instanceof UnitEnum && $other instanceof UnitEnum) { + $f = new ComparisonFailure($this->value, $other, Exporter::export($this->value), Exporter::export($other)); + } + $this->fail($other, $description, $f); + } + return null; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + if (is_object($this->value)) { + return 'is identical to an object of class "' . $this->value::class . '"'; + } + return 'is identical to ' . Exporter::export($this->value); + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + if (is_object($this->value) && is_object($other)) { + return 'two variables reference the same object'; + } + if (explode(' ', gettype($this->value), 2)[0] === 'resource' && explode(' ', gettype($other), 2)[0] === 'resource') { + return 'two variables reference the same resource'; + } + if (is_string($this->value) && is_string($other)) { + return 'two strings are identical'; + } + if (is_array($this->value) && is_array($other)) { + return 'two arrays are identical'; + } + return parent::failureDescription($other); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function json_decode; +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\InvalidJsonException; +use PHPUnit\Util\Json; +use PHPUnitPHAR\SebastianBergmann\Comparator\ComparisonFailure; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class JsonMatches extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly string $value; + public function __construct(string $value) + { + $this->value = $value; + } + /** + * Returns a string representation of the object. + */ + public function toString(): string + { + return sprintf('matches JSON string "%s"', $this->value); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * This method can be overridden to implement the evaluation algorithm. + */ + protected function matches(mixed $other): bool + { + [$error, $recodedOther] = Json::canonicalize($other); + if ($error) { + return \false; + } + [$error, $recodedValue] = Json::canonicalize($this->value); + if ($error) { + return \false; + } + return $recodedOther === $recodedValue; + } + /** + * Throws an exception for the given compared value and test description. + * + * @throws ExpectationFailedException + * @throws InvalidJsonException + */ + protected function fail(mixed $other, string $description, ?ComparisonFailure $comparisonFailure = null): never + { + if ($comparisonFailure === null) { + [$error, $recodedOther] = Json::canonicalize($other); + if ($error) { + parent::fail($other, $description); + } + [$error, $recodedValue] = Json::canonicalize($this->value); + if ($error) { + parent::fail($other, $description); + } + $comparisonFailure = new ComparisonFailure(json_decode($this->value), json_decode($other), Json::prettify($recodedValue), Json::prettify($recodedOther), 'Failed asserting that two json values are equal.'); + } + parent::fail($other, $description, $comparisonFailure); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_finite; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsFinite extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is finite'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_finite($other); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_infinite; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsInfinite extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is infinite'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_infinite($other); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_nan; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsNan extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is nan'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_nan($other); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function assert; +use function count; +use function is_bool; +use function is_object; +use PHPUnit\Framework\ActualValueIsNotAnObjectException; +use PHPUnit\Framework\ComparisonMethodDoesNotAcceptParameterTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareBoolReturnTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareExactlyOneParameterException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareParameterTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotExistException; +use ReflectionNamedType; +use ReflectionObject; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ObjectEquals extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly object $expected; + private readonly string $method; + public function __construct(object $object, string $method = 'equals') + { + $this->expected = $object; + $this->method = $method; + } + public function toString(): string + { + return 'two objects are equal'; + } + /** + * @throws ActualValueIsNotAnObjectException + * @throws ComparisonMethodDoesNotAcceptParameterTypeException + * @throws ComparisonMethodDoesNotDeclareBoolReturnTypeException + * @throws ComparisonMethodDoesNotDeclareExactlyOneParameterException + * @throws ComparisonMethodDoesNotDeclareParameterTypeException + * @throws ComparisonMethodDoesNotExistException + */ + protected function matches(mixed $other): bool + { + if (!is_object($other)) { + throw new ActualValueIsNotAnObjectException(); + } + $object = new ReflectionObject($other); + if (!$object->hasMethod($this->method)) { + throw new ComparisonMethodDoesNotExistException($other::class, $this->method); + } + $method = $object->getMethod($this->method); + if (!$method->hasReturnType()) { + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException($other::class, $this->method); + } + $returnType = $method->getReturnType(); + if (!$returnType instanceof ReflectionNamedType) { + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException($other::class, $this->method); + } + if ($returnType->allowsNull()) { + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException($other::class, $this->method); + } + if ($returnType->getName() !== 'bool') { + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException($other::class, $this->method); + } + if ($method->getNumberOfParameters() !== 1 || $method->getNumberOfRequiredParameters() !== 1) { + throw new ComparisonMethodDoesNotDeclareExactlyOneParameterException($other::class, $this->method); + } + assert(count($method->getParameters()) > 0); + $parameter = $method->getParameters()[0]; + if (!$parameter->hasType()) { + throw new ComparisonMethodDoesNotDeclareParameterTypeException($other::class, $this->method); + } + $type = $parameter->getType(); + if (!$type instanceof ReflectionNamedType) { + throw new ComparisonMethodDoesNotDeclareParameterTypeException($other::class, $this->method); + } + $typeName = $type->getName(); + if ($typeName === 'self') { + $typeName = $other::class; + } + if (!$this->expected instanceof $typeName) { + throw new ComparisonMethodDoesNotAcceptParameterTypeException($other::class, $this->method, $this->expected::class); + } + /** @phpstan-ignore method.dynamicName */ + $result = $other->{$this->method}($this->expected); + assert(is_bool($result)); + return $result; + } + protected function failureDescription(mixed $other): string + { + return $this->toString(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function gettype; +use function is_object; +use function sprintf; +use ReflectionObject; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ObjectHasProperty extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly string $propertyName; + public function __construct(string $propertyName) + { + $this->propertyName = $propertyName; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf('has property "%s"', $this->propertyName); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @param mixed $other value or object to evaluate + */ + protected function matches(mixed $other): bool + { + if (!is_object($other)) { + return \false; + } + return (new ReflectionObject($other))->hasProperty($this->propertyName); + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + * + * @param mixed $other evaluated value or object + */ + protected function failureDescription(mixed $other): string + { + if (is_object($other)) { + return sprintf('object of class "%s" %s', $other::class, $this->toString()); + } + return sprintf('"%s" (%s) %s', $other, gettype($other), $this->toString()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_map; +use function count; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class BinaryOperator extends \PHPUnit\Framework\Constraint\Operator +{ + /** + * @var list + */ + private readonly array $constraints; + protected function __construct(mixed ...$constraints) + { + $this->constraints = array_map($this->checkConstraint(...), $constraints); + } + /** + * Returns the number of operands (constraints). + */ + final public function arity(): int + { + return count($this->constraints); + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + $reduced = $this->reduce(); + if ($reduced !== $this) { + return $reduced->toString(); + } + $text = ''; + foreach ($this->constraints as $key => $constraint) { + $constraint = $constraint->reduce(); + $text .= $this->constraintToString($constraint, $key); + } + return $text; + } + /** + * Counts the number of constraint elements. + */ + public function count(): int + { + $count = 0; + foreach ($this->constraints as $constraint) { + $count += count($constraint); + } + return $count; + } + /** + * @return list + */ + final protected function constraints(): array + { + return $this->constraints; + } + /** + * Returns true if the $constraint needs to be wrapped with braces. + */ + final protected function constraintNeedsParentheses(\PHPUnit\Framework\Constraint\Constraint $constraint): bool + { + return $this->arity() > 1 && parent::constraintNeedsParentheses($constraint); + } + /** + * Reduces the sub-expression starting at $this by skipping degenerate + * sub-expression and returns first descendant constraint that starts + * a non-reducible sub-expression. + * + * See Constraint::reduce() for more. + */ + protected function reduce(): \PHPUnit\Framework\Constraint\Constraint + { + if (count($this->constraints) === 1 && $this->constraints[0] instanceof \PHPUnit\Framework\Constraint\Operator) { + return $this->constraints[0]->reduce(); + } + return parent::reduce(); + } + /** + * Returns string representation of given operand in context of this operator. + */ + private function constraintToString(\PHPUnit\Framework\Constraint\Constraint $constraint, int $position): string + { + $prefix = ''; + if ($position > 0) { + $prefix = ' ' . $this->operator() . ' '; + } + if ($this->constraintNeedsParentheses($constraint)) { + return $prefix . '( ' . $constraint->toString() . ' )'; + } + $string = $constraint->toStringInContext($this, $position); + if ($string === '') { + $string = $constraint->toString(); + } + return $prefix . $string; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class LogicalAnd extends \PHPUnit\Framework\Constraint\BinaryOperator +{ + public static function fromConstraints(mixed ...$constraints): self + { + return new self(...$constraints); + } + /** + * Returns the name of this operator. + */ + public function operator(): string + { + return 'and'; + } + /** + * Returns this operator's precedence. + * + * @see https://www.php.net/manual/en/language.operators.precedence.php + */ + public function precedence(): int + { + return 22; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + foreach ($this->constraints() as $constraint) { + if (!$constraint->evaluate($other, '', \true)) { + return \false; + } + } + return [] !== $this->constraints(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_map; +use function assert; +use function count; +use function preg_match; +use function preg_quote; +use function preg_replace; +use PHPUnit\Framework\ExpectationFailedException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class LogicalNot extends \PHPUnit\Framework\Constraint\UnaryOperator +{ + /** + * @param non-empty-string $string + * + * @return non-empty-string + */ + public static function negate(string $string): string + { + $positives = ['contains ', 'exists', 'has ', 'is ', 'are ', 'matches ', 'starts with ', 'ends with ', 'reference ', 'not not ']; + $negatives = ['does not contain ', 'does not exist', 'does not have ', 'is not ', 'are not ', 'does not match ', 'starts not with ', 'ends not with ', 'don\'t reference ', 'not ']; + preg_match('/(\'[\w\W]*\')([\w\W]*)("[\w\W]*")/i', $string, $matches); + if (count($matches) === 0) { + preg_match('/(\'[\w\W]*\')([\w\W]*)(\'[\w\W]*\')/i', $string, $matches); + } + $positives = array_map(static fn(string $s) => '/\b' . preg_quote($s, '/') . '/', $positives); + if (count($matches) >= 3) { + $nonInput = $matches[2]; + $negatedString = preg_replace('/' . preg_quote($nonInput, '/') . '/', preg_replace($positives, $negatives, $nonInput), $string); + } else { + $negatedString = preg_replace($positives, $negatives, $string); + } + assert($negatedString !== null); + assert($negatedString !== ''); + return $negatedString; + } + /** + * Returns the name of this operator. + */ + public function operator(): string + { + return 'not'; + } + /** + * Returns this operator's precedence. + * + * @see https://www.php.net/manual/en/language.operators.precedence.php + */ + public function precedence(): int + { + return 5; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @throws ExpectationFailedException + */ + protected function matches(mixed $other): bool + { + return !$this->constraint()->evaluate($other, '', \true); + } + /** + * Applies additional transformation to strings returned by toString() or + * failureDescription(). + */ + protected function transformString(string $string): string + { + return self::negate($string); + } + /** + * Reduces the sub-expression starting at $this by skipping degenerate + * sub-expression and returns first descendant constraint that starts + * a non-reducible sub-expression. + * + * See Constraint::reduce() for more. + */ + protected function reduce(): \PHPUnit\Framework\Constraint\Constraint + { + $constraint = $this->constraint(); + if ($constraint instanceof self) { + return $constraint->constraint()->reduce(); + } + return parent::reduce(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_any; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class LogicalOr extends \PHPUnit\Framework\Constraint\BinaryOperator +{ + public static function fromConstraints(mixed ...$constraints): self + { + return new self(...$constraints); + } + /** + * Returns the name of this operator. + */ + public function operator(): string + { + return 'or'; + } + /** + * Returns this operator's precedence. + * + * @see https://www.php.net/manual/en/language.operators.precedence.php + */ + public function precedence(): int + { + return 24; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + public function matches(mixed $other): bool + { + return array_any($this->constraints(), static fn(\PHPUnit\Framework\Constraint\Constraint $constraint) => $constraint->evaluate($other, '', \true)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_reduce; +use function array_shift; +use function assert; +use function is_bool; +use PHPUnit\Framework\ExpectationFailedException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class LogicalXor extends \PHPUnit\Framework\Constraint\BinaryOperator +{ + public static function fromConstraints(mixed ...$constraints): self + { + return new self(...$constraints); + } + /** + * Returns the name of this operator. + */ + public function operator(): string + { + return 'xor'; + } + /** + * Returns this operator's precedence. + * + * @see https://www.php.net/manual/en/language.operators.precedence.php. + */ + public function precedence(): int + { + return 23; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @throws ExpectationFailedException + */ + public function matches(mixed $other): bool + { + $constraints = $this->constraints(); + $initial = array_shift($constraints); + if ($initial === null) { + return \false; + } + $result = array_reduce($constraints, static fn(?bool $matches, \PHPUnit\Framework\Constraint\Constraint $constraint): bool => $matches xor $constraint->evaluate($other, '', \true), $initial->evaluate($other, '', \true)); + assert(is_bool($result)); + return $result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class Operator extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns the name of this operator. + */ + abstract public function operator(): string; + /** + * Returns this operator's precedence. + * + * @see https://www.php.net/manual/en/language.operators.precedence.php + */ + abstract public function precedence(): int; + /** + * Returns the number of operands. + */ + abstract public function arity(): int; + /** + * Validates $constraint argument. + */ + protected function checkConstraint(mixed $constraint): \PHPUnit\Framework\Constraint\Constraint + { + if (!$constraint instanceof \PHPUnit\Framework\Constraint\Constraint) { + return new \PHPUnit\Framework\Constraint\IsEqual($constraint); + } + return $constraint; + } + /** + * Returns true if the $constraint needs to be wrapped with braces. + */ + protected function constraintNeedsParentheses(\PHPUnit\Framework\Constraint\Constraint $constraint): bool + { + return $constraint instanceof self && $constraint->arity() > 1 && $this->precedence() <= $constraint->precedence(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function count; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class UnaryOperator extends \PHPUnit\Framework\Constraint\Operator +{ + private readonly \PHPUnit\Framework\Constraint\Constraint $constraint; + public function __construct(mixed $constraint) + { + $this->constraint = $this->checkConstraint($constraint); + } + /** + * Returns the number of operands (constraints). + */ + public function arity(): int + { + return 1; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + $reduced = $this->reduce(); + if ($reduced !== $this) { + return $reduced->toString(); + } + $constraint = $this->constraint->reduce(); + if ($this->constraintNeedsParentheses($constraint)) { + return $this->operator() . '( ' . $constraint->toString() . ' )'; + } + $string = $constraint->toStringInContext($this, 0); + if ($string === '') { + return $this->transformString($constraint->toString()); + } + return $string; + } + /** + * Counts the number of constraint elements. + */ + public function count(): int + { + return count($this->constraint); + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + $reduced = $this->reduce(); + if ($reduced !== $this) { + return $reduced->failureDescription($other); + } + $constraint = $this->constraint->reduce(); + if ($this->constraintNeedsParentheses($constraint)) { + return $this->operator() . '( ' . $constraint->failureDescription($other) . ' )'; + } + $string = $constraint->failureDescriptionInContext($this, 0, $other); + if ($string === '') { + return $this->transformString($constraint->failureDescription($other)); + } + return $string; + } + /** + * Transforms string returned by the member constraint's toString() or + * failureDescription() such that it reflects constraint's participation in + * this expression. + * + * The method may be overwritten in a subclass to apply default + * transformation in case the operand constraint does not provide its own + * custom strings via toStringInContext() or failureDescriptionInContext(). + */ + protected function transformString(string $string): string + { + return $string; + } + /** + * Provides access to $this->constraint for subclasses. + */ + final protected function constraint(): \PHPUnit\Framework\Constraint\Constraint + { + return $this->constraint; + } + /** + * Returns true if the $constraint needs to be wrapped with parentheses. + */ + protected function constraintNeedsParentheses(\PHPUnit\Framework\Constraint\Constraint $constraint): bool + { + $constraint = $constraint->reduce(); + return $constraint instanceof self || parent::constraintNeedsParentheses($constraint); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use const JSON_ERROR_CTRL_CHAR; +use const JSON_ERROR_DEPTH; +use const JSON_ERROR_NONE; +use const JSON_ERROR_STATE_MISMATCH; +use const JSON_ERROR_SYNTAX; +use const JSON_ERROR_UTF8; +use function is_string; +use function json_decode; +use function json_last_error; +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsJson extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is valid JSON'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if (!is_string($other) || $other === '') { + return \false; + } + json_decode($other); + if (json_last_error() !== JSON_ERROR_NONE) { + return \false; + } + return \true; + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + if (!is_string($other)) { + return $this->valueToTypeStringFragment($other) . 'is valid JSON'; + } + if ($other === '') { + return 'an empty string is valid JSON'; + } + return sprintf('a string is valid JSON (%s)', $this->determineJsonError($other)); + } + private function determineJsonError(string $json): string + { + json_decode($json); + return match (json_last_error()) { + JSON_ERROR_NONE => '', + JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', + JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch', + JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', + JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', + JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded', + default => 'Unknown error', + }; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function preg_last_error_msg; +use function preg_match; +use function sprintf; +use PHPUnit\Framework\Exception as FrameworkException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class RegularExpression extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly string $pattern; + public function __construct(string $pattern) + { + $this->pattern = $pattern; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf('matches PCRE pattern "%s"', $this->pattern); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @throws FrameworkException + */ + protected function matches(mixed $other): bool + { + $matches = @preg_match($this->pattern, $other); + if ($matches === \false) { + throw new FrameworkException(sprintf('Regular expression cannot be matched: %s', preg_last_error_msg())); + } + return $matches > 0; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_string; +use function mb_detect_encoding; +use function mb_stripos; +use function mb_strtolower; +use function sprintf; +use function str_contains; +use function strlen; +use function strtr; +use PHPUnit\Util\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class StringContains extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly string $needle; + private readonly bool $ignoreCase; + private readonly bool $ignoreLineEndings; + public function __construct(string $needle, bool $ignoreCase = \false, bool $ignoreLineEndings = \false) + { + if ($ignoreLineEndings) { + $needle = $this->normalizeLineEndings($needle); + } + $this->needle = $needle; + $this->ignoreCase = $ignoreCase; + $this->ignoreLineEndings = $ignoreLineEndings; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + $needle = $this->needle; + if ($this->ignoreCase) { + $needle = mb_strtolower($this->needle, 'UTF-8'); + } + return sprintf('contains "%s" [%s](length: %s)', $needle, $this->detectedEncoding($needle), strlen($needle)); + } + public function failureDescription(mixed $other): string + { + $stringifiedHaystack = Exporter::export($other); + $haystackEncoding = $this->detectedEncoding($other); + $haystackLength = $this->haystackLength($other); + $haystackInformation = sprintf('%s [%s](length: %s) ', $stringifiedHaystack, $haystackEncoding, $haystackLength); + $needleInformation = $this->toString(); + return $haystackInformation . $needleInformation; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + $haystack = $other; + if ('' === $this->needle) { + return \true; + } + if (!is_string($haystack)) { + return \false; + } + if ($this->ignoreLineEndings) { + $haystack = $this->normalizeLineEndings($haystack); + } + if ($this->ignoreCase) { + /* + * We must use the multibyte-safe version, so we can accurately compare non-latin uppercase characters with + * their lowercase equivalents. + */ + return mb_stripos($haystack, $this->needle, 0, 'UTF-8') !== \false; + } + /* + * Use the non-multibyte safe functions to see if the string is contained in $other. + * + * This function is very fast, and we don't care about the character position in the string. + * + * Additionally, we want this method to be binary safe, so we can check if some binary data is in other binary + * data. + */ + return str_contains($haystack, $this->needle); + } + private function detectedEncoding(mixed $other): string + { + if ($this->ignoreCase) { + return 'Encoding ignored'; + } + if (!is_string($other)) { + return 'Encoding detection failed'; + } + $detectedEncoding = mb_detect_encoding($other, null, \true); + if ($detectedEncoding === \false) { + return 'Encoding detection failed'; + } + return $detectedEncoding; + } + private function haystackLength(mixed $haystack): int + { + if (!is_string($haystack)) { + return 0; + } + if ($this->ignoreLineEndings) { + $haystack = $this->normalizeLineEndings($haystack); + } + return strlen($haystack); + } + private function normalizeLineEndings(string $string): string + { + return strtr($string, ["\r\n" => "\n", "\r" => "\n"]); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function str_ends_with; +use PHPUnit\Framework\EmptyStringException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class StringEndsWith extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly string $suffix; + /** + * @throws EmptyStringException + */ + public function __construct(string $suffix) + { + if ($suffix === '') { + throw new EmptyStringException(); + } + $this->suffix = $suffix; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'ends with "' . $this->suffix . '"'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return str_ends_with((string) $other, $this->suffix); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function sprintf; +use function strtr; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class StringEqualsStringIgnoringLineEndings extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly string $string; + public function __construct(string $string) + { + $this->string = $this->normalizeLineEndings($string); + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf('is equal to "%s" ignoring line endings', $this->string); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $this->string === $this->normalizeLineEndings((string) $other); + } + private function normalizeLineEndings(string $string): string + { + return strtr($string, ["\r\n" => "\n", "\r" => "\n"]); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use const DIRECTORY_SEPARATOR; +use const PHP_EOL; +use function assert; +use function count; +use function explode; +use function implode; +use function preg_last_error_msg; +use function preg_match; +use function preg_quote; +use function preg_replace; +use function sprintf; +use function str_replace; +use function strlen; +use function strpos; +use function strtr; +use function substr; +use PHPUnit\Framework\Exception as FrameworkException; +use PHPUnitPHAR\SebastianBergmann\Diff\Differ; +use PHPUnitPHAR\SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class StringMatchesFormatDescription extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly string $formatDescription; + public function __construct(string $formatDescription) + { + $this->formatDescription = $formatDescription; + } + public function toString(): string + { + return 'matches format description:' . PHP_EOL . $this->formatDescription; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @throws FrameworkException + */ + protected function matches(mixed $other): bool + { + $other = $this->convertNewlines($other); + $matches = @preg_match($this->regularExpressionForFormatDescription($this->convertNewlines($this->formatDescription)), $other); + if ($matches === \false) { + throw new FrameworkException(sprintf('Format description cannot be matched: %s', preg_last_error_msg())); + } + return $matches > 0; + } + protected function failureDescription(mixed $other): string + { + return 'string matches format description'; + } + /** + * Returns a cleaned up diff. + * + * The expected string can contain placeholders like %s and %d. + * By using 'diff' such placeholders compared to the real output will + * always be different, although we don't want to show them as different. + * This method removes the expected differences by figuring out if a difference + * is allowed by the use of a placeholder. + * + * For %A and %a multiline placeholders that can match across multiple lines, + * we use anchor lookahead: find the next non-multiline expected line and search + * for it in the actual output to determine how many actual lines the placeholder + * consumed, keeping expected and actual in sync. + */ + protected function additionalFailureDescription(mixed $other): string + { + $expected = explode("\n", $this->formatDescription); + $expectedCount = count($expected); + $actual = explode("\n", $this->convertNewlines($other)); + $actualCount = count($actual); + $synced = []; + $expectedIndex = 0; + $actualIndex = 0; + while ($expectedIndex < $expectedCount && $actualIndex < $actualCount) { + if ($expected[$expectedIndex] === $actual[$actualIndex]) { + $synced[] = $actual[$actualIndex]; + $expectedIndex++; + $actualIndex++; + continue; + } + if ($this->isMultilineMatch($expected[$expectedIndex])) { + $anchorExpectedIndex = $this->findNextAnchor($expected, $expectedIndex + 1); + if ($anchorExpectedIndex !== null) { + $anchorActualIndex = $this->findAnchorInActual($expected[$anchorExpectedIndex], $actual, $actualIndex); + if ($anchorActualIndex !== null) { + for ($i = $actualIndex; $i < $anchorActualIndex; $i++) { + $synced[] = $actual[$i]; + } + $synced[] = $actual[$anchorActualIndex]; + $expectedIndex = $anchorExpectedIndex + 1; + $actualIndex = $anchorActualIndex + 1; + continue; + } + } else { + // No anchor after multiline placeholder(s): consume all remaining actual lines + for ($i = $actualIndex; $i < $actualCount; $i++) { + $synced[] = $actual[$i]; + } + $expectedIndex = $expectedCount; + $actualIndex = $actualCount; + continue; + } + } + // Single-line comparison + $regex = $this->regularExpressionForFormatDescription($expected[$expectedIndex]); + if (@preg_match($regex, $actual[$actualIndex]) > 0) { + $synced[] = $actual[$actualIndex]; + } else { + $synced[] = $expected[$expectedIndex]; + } + $expectedIndex++; + $actualIndex++; + } + while ($expectedIndex < $expectedCount) { + $synced[] = $expected[$expectedIndex]; + $expectedIndex++; + } + return $this->differ()->diff(implode("\n", $synced), implode("\n", $actual)); + } + private function regularExpressionForFormatDescription(string $string): string + { + $quoted = ''; + $startOffset = 0; + $length = strlen($string); + while ($startOffset < $length) { + $start = strpos($string, '%r', $startOffset); + if ($start !== \false) { + $end = strpos($string, '%r', $start + 2); + if ($end === \false) { + $end = $start = $length; + } + } else { + $start = $end = $length; + } + $quoted .= preg_quote(substr($string, $startOffset, $start - $startOffset), '/'); + if ($end > $start) { + $quoted .= '(' . substr($string, $start + 2, $end - $start - 2) . ')'; + } + $startOffset = $end + 2; + } + $string = strtr($quoted, ['%%' => '%', '%e' => preg_quote(DIRECTORY_SEPARATOR, '/'), '%s' => '[^\r\n]+', '%S' => '[^\r\n]*', '%a' => '.+?', '%A' => '.*?', '%w' => '\s*', '%i' => '[+-]?\d+', '%d' => '\d+', '%x' => '[0-9a-fA-F]+', '%f' => '[+-]?(?:\d+|(?=\.\d))(?:\.\d+)?(?:[Ee][+-]?\d+)?', '%c' => '.', '%0' => '\x00']); + return '/^' . $string . '$/s'; + } + private function isMultilineMatch(string $line): bool + { + return preg_match('/%[aA]/', str_replace('%%', '', $line)) > 0; + } + /** + * @param list $expected + */ + private function findNextAnchor(array $expected, int $startIdx): ?int + { + for ($i = $startIdx, $len = count($expected); $i < $len; $i++) { + if (!$this->isMultilineMatch($expected[$i])) { + return $i; + } + } + return null; + } + /** + * @param list $actual + */ + private function findAnchorInActual(string $anchorLine, array $actual, int $startIdx): ?int + { + $anchorRegex = $this->regularExpressionForFormatDescription($anchorLine); + for ($i = $startIdx, $len = count($actual); $i < $len; $i++) { + if ($anchorLine === $actual[$i] || @preg_match($anchorRegex, $actual[$i]) > 0) { + return $i; + } + } + return null; + } + private function convertNewlines(string $text): string + { + $result = preg_replace('/\r\n/', "\n", $text); + assert($result !== null); + return $result; + } + private function differ(): Differ + { + return new Differ(new UnifiedDiffOutputBuilder("--- Expected\n+++ Actual\n", \false, 3, \false)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function str_starts_with; +use PHPUnit\Framework\EmptyStringException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class StringStartsWith extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly string $prefix; + /** + * @throws EmptyStringException + */ + public function __construct(string $prefix) + { + if ($prefix === '') { + throw new EmptyStringException(); + } + $this->prefix = $prefix; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'starts with "' . $this->prefix . '"'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return str_starts_with((string) $other, $this->prefix); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_array; +use function sprintf; +use PHPUnit\Util\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class TraversableContains extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly mixed $value; + public function __construct(mixed $value) + { + $this->value = $value; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'contains ' . Exporter::export($this->value); + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf('%s %s', is_array($other) ? 'an array' : 'a traversable', $this->toString()); + } + protected function value(): mixed + { + return $this->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use SplObjectStorage; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TraversableContainsEqual extends \PHPUnit\Framework\Constraint\TraversableContains +{ + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if ($other instanceof SplObjectStorage) { + return $other->offsetExists($this->value()); + } + foreach ($other as $element) { + /** @phpstan-ignore equal.notAllowed */ + if ($this->value() == $element) { + return \true; + } + } + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use SplObjectStorage; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TraversableContainsIdentical extends \PHPUnit\Framework\Constraint\TraversableContains +{ + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if ($other instanceof SplObjectStorage) { + return $other->offsetExists($this->value()); + } + foreach ($other as $element) { + if ($this->value() === $element) { + return \true; + } + } + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\NativeType; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TraversableContainsOnly extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly \PHPUnit\Framework\Constraint\Constraint $constraint; + private readonly string $type; + public static function forNativeType(NativeType $type): self + { + return new self(new \PHPUnit\Framework\Constraint\IsType($type), $type->value); + } + /** + * @param class-string $type + */ + public static function forClassOrInterface(string $type): self + { + return new self(new \PHPUnit\Framework\Constraint\IsInstanceOf($type), $type); + } + private function __construct(\PHPUnit\Framework\Constraint\IsInstanceOf|\PHPUnit\Framework\Constraint\IsType $constraint, string $type) + { + $this->constraint = $constraint; + $this->type = $type; + } + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = \false): bool + { + $success = \true; + foreach ($other as $item) { + if (!$this->constraint->evaluate($item, '', \true)) { + $success = \false; + break; + } + } + if (!$success && !$returnResult) { + $this->fail($other, $description); + } + return $success; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'contains only values of type "' . $this->type . '"'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function class_exists; +use function interface_exists; +use function sprintf; +use PHPUnit\Framework\UnknownClassOrInterfaceException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsInstanceOf extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * @var class-string + */ + private readonly string $name; + /** + * @var 'class'|'interface' + */ + private readonly string $type; + /** + * @throws UnknownClassOrInterfaceException + */ + public function __construct(string $name) + { + if (class_exists($name)) { + $this->type = 'class'; + } elseif (interface_exists($name)) { + $this->type = 'interface'; + } else { + throw new UnknownClassOrInterfaceException($name); + } + $this->name = $name; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf('is an instance of %s %s', $this->type, $this->name); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $other instanceof $this->name; + } + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return $this->valueToTypeStringFragment($other) . $this->toString(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsNull extends \PHPUnit\Framework\Constraint\Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is null'; + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $other === null; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function gettype; +use function is_array; +use function is_bool; +use function is_callable; +use function is_float; +use function is_int; +use function is_iterable; +use function is_numeric; +use function is_object; +use function is_scalar; +use function is_string; +use function sprintf; +use PHPUnit\Framework\NativeType; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsType extends \PHPUnit\Framework\Constraint\Constraint +{ + private readonly NativeType $type; + public function __construct(NativeType $type) + { + $this->type = $type; + } + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf('is of type %s', $this->type->value); + } + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + switch ($this->type) { + case NativeType::Numeric: + return is_numeric($other); + case NativeType::Int: + return is_int($other); + case NativeType::Float: + return is_float($other); + case NativeType::String: + return is_string($other); + case NativeType::Bool: + return is_bool($other); + case NativeType::Null: + return null === $other; + case NativeType::Array: + return is_array($other); + case NativeType::Object: + return is_object($other); + case NativeType::Resource: + $type = gettype($other); + return $type === 'resource' || $type === 'resource (closed)'; + case NativeType::ClosedResource: + return gettype($other) === 'resource (closed)'; + case NativeType::Scalar: + return is_scalar($other); + case NativeType::Callable: + return is_callable($other); + case NativeType::Iterable: + return is_iterable($other); + default: + return \false; + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function assert; +use function class_exists; +use function count; +use function explode; +use PHPUnit\Framework\TestSize\TestSize; +use PHPUnit\Metadata\Api\Groups; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DataProviderTestSuite extends \PHPUnit\Framework\TestSuite +{ + /** + * @var list + */ + private array $dependencies = []; + /** + * @var ?non-empty-list + */ + private ?array $providedTests = null; + /** + * @param list $dependencies + */ + public function setDependencies(array $dependencies): void + { + $this->dependencies = $dependencies; + foreach ($this->tests() as $test) { + if (!$test instanceof \PHPUnit\Framework\TestCase) { + continue; + } + $test->setDependencies($dependencies); + } + } + /** + * @return non-empty-list + */ + public function provides(): array + { + if ($this->providedTests === null) { + $this->providedTests = [new \PHPUnit\Framework\ExecutionOrderDependency($this->name())]; + } + return $this->providedTests; + } + /** + * @return list + */ + public function requires(): array + { + // A DataProviderTestSuite does not have to traverse its child tests + // as these are inherited and cannot reference dataProvider rows directly + return $this->dependencies; + } + /** + * Returns the size of each test created using the data provider(s). + */ + public function size(): TestSize + { + assert(count(explode('::', $this->name())) === 2); + [$className, $methodName] = explode('::', $this->name()); + assert(class_exists($className)); + assert($methodName !== ''); + return (new Groups())->size($className, $methodName); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +class AssertionFailedError extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\SelfDescribing +{ + /** + * Wrapper for getMessage() which is declared as final. + */ + public function toString(): string + { + return $this->getMessage(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class EmptyStringException extends \PHPUnit\Framework\InvalidArgumentException +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ErrorLogNotWritableException extends \PHPUnit\Framework\Exception +{ + public function __construct() + { + parent::__construct('Could not create writable file for error_log()'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function array_keys; +use function get_object_vars; +use function is_int; +use function sprintf; +use RuntimeException; +use Throwable; +/** + * Base class for all PHPUnit Framework exceptions. + * + * Ensures that exceptions thrown during a test run do not leave stray + * references behind. + * + * Every Exception contains a stack trace. Each stack frame contains the 'args' + * of the called function. The function arguments can contain references to + * instantiated objects. The references prevent the objects from being + * destructed (until test results are eventually printed), so memory cannot be + * freed up. + * + * With enabled process isolation, test results are serialized in the child + * process and unserialized in the parent process. The stack trace of Exceptions + * may contain objects that cannot be serialized or unserialized (e.g., PDO + * connections). Unserializing user-space objects from the child process into + * the parent would break the intended encapsulation of process isolation. + * + * @see http://fabien.potencier.org/article/9/php-serialization-stack-traces-and-exceptions + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +class Exception extends RuntimeException implements \PHPUnit\Exception +{ + /** + * @var list + */ + protected array $serializableTrace; + public function __construct(string $message = '', int|string $code = 0, ?Throwable $previous = null) + { + /** + * @see https://github.com/sebastianbergmann/phpunit/issues/5965 + */ + if (!is_int($code)) { + $message .= sprintf(' (exception code: %s)', $code); + $code = 0; + } + parent::__construct($message, $code, $previous); + $this->serializableTrace = $this->getTrace(); + foreach (array_keys($this->serializableTrace) as $key) { + unset($this->serializableTrace[$key]['args']); + } + } + public function __serialize(): array + { + return get_object_vars($this); + } + /** + * Returns the serializable trace (without 'args'). + * + * @return list + */ + public function getSerializableTrace(): array + { + return $this->serializableTrace; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use Exception; +use PHPUnitPHAR\SebastianBergmann\Comparator\ComparisonFailure; +/** + * Exception for expectations which failed their check. + * + * The exception contains the error message and optionally a + * SebastianBergmann\Comparator\ComparisonFailure which is used to + * generate diff output of the failed expectations. + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ExpectationFailedException extends \PHPUnit\Framework\AssertionFailedError +{ + protected ?ComparisonFailure $comparisonFailure = null; + public function __construct(string $message, ?ComparisonFailure $comparisonFailure = null, ?Exception $previous = null) + { + $this->comparisonFailure = $comparisonFailure; + parent::__construct($message, 0, $previous); + } + public function getComparisonFailure(): ?ComparisonFailure + { + return $this->comparisonFailure; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class GeneratorNotSupportedException extends \PHPUnit\Framework\InvalidArgumentException +{ + public static function fromParameterName(string $parameterName): self + { + return new self(sprintf('Passing an argument of type Generator for the %s parameter is not supported', $parameterName)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface IncompleteTest extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class IncompleteTestError extends \PHPUnit\Framework\AssertionFailedError implements \PHPUnit\Framework\IncompleteTest +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract class InvalidArgumentException extends \PHPUnit\Framework\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidDataProviderException extends \PHPUnit\Framework\Exception +{ + private ?string $providerLabel = null; + public static function forException(Throwable $e, string $providerLabel): self + { + $exception = new self($e->getMessage(), $e->getCode(), $e); + $exception->providerLabel = $providerLabel; + return $exception; + } + public function getProviderLabel(): ?string + { + return $this->providerLabel; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidDependencyException extends \PHPUnit\Framework\AssertionFailedError implements \PHPUnit\Framework\SkippedTest +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoChildTestSuiteException extends \PHPUnit\Framework\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ActualValueIsNotAnObjectException extends \PHPUnit\Framework\Exception +{ + public function __construct() + { + parent::__construct('Actual value is not an object'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotAcceptParameterTypeException extends \PHPUnit\Framework\Exception +{ + public function __construct(string $className, string $methodName, string $type) + { + parent::__construct(sprintf('%s is not an accepted argument type for comparison method %s::%s().', $type, $className, $methodName)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotDeclareBoolReturnTypeException extends \PHPUnit\Framework\Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct(sprintf('Comparison method %s::%s() does not declare bool return type.', $className, $methodName)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotDeclareExactlyOneParameterException extends \PHPUnit\Framework\Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct(sprintf('Comparison method %s::%s() does not declare exactly one parameter.', $className, $methodName)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotDeclareParameterTypeException extends \PHPUnit\Framework\Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct(sprintf('Parameter of comparison method %s::%s() does not have a declared type.', $className, $methodName)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotExistException extends \PHPUnit\Framework\Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct(sprintf('Comparison method %s::%s() does not exist.', $className, $methodName)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class PhptAssertionFailedError extends \PHPUnit\Framework\AssertionFailedError +{ + private readonly string $syntheticFile; + private readonly int $syntheticLine; + /** + * @var list + */ + private readonly array $syntheticTrace; + private readonly string $diff; + /** + * @param list $trace + */ + public function __construct(string $message, int $code, string $file, int $line, array $trace, string $diff) + { + parent::__construct($message, $code); + $this->syntheticFile = $file; + $this->syntheticLine = $line; + $this->syntheticTrace = $trace; + $this->diff = $diff; + } + public function syntheticFile(): string + { + return $this->syntheticFile; + } + public function syntheticLine(): int + { + return $this->syntheticLine; + } + /** + * @return list + */ + public function syntheticTrace(): array + { + return $this->syntheticTrace; + } + public function diff(): string + { + return $this->diff; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ProcessIsolationException extends \PHPUnit\Framework\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface SkippedTest extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SkippedTestSuiteError extends \PHPUnit\Framework\AssertionFailedError implements \PHPUnit\Framework\SkippedTest +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SkippedWithMessageException extends \PHPUnit\Framework\AssertionFailedError implements \PHPUnit\Framework\SkippedTest +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownClassOrInterfaceException extends \PHPUnit\Framework\InvalidArgumentException +{ + public function __construct(string $name) + { + parent::__construct(sprintf('Class or interface "%s" does not exist', $name)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownNativeTypeException extends \PHPUnit\Framework\InvalidArgumentException +{ + public function __construct(string $type) + { + parent::__construct(sprintf('Native type "%s" is not known', $type)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function array_filter; +use function array_map; +use function array_values; +use function assert; +use function count; +use function explode; +use function in_array; +use function str_contains; +use PHPUnit\Metadata\DependsOnClass; +use PHPUnit\Metadata\DependsOnMethod; +use Stringable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExecutionOrderDependency implements Stringable +{ + private string $className = ''; + private string $methodName = ''; + private readonly bool $shallowClone; + private readonly bool $deepClone; + public static function invalid(): self + { + return new self('', '', \false, \false); + } + public static function forClass(DependsOnClass $metadata): self + { + return new self($metadata->className(), 'class', $metadata->deepClone(), $metadata->shallowClone()); + } + public static function forMethod(DependsOnMethod $metadata): self + { + return new self($metadata->className(), $metadata->methodName(), $metadata->deepClone(), $metadata->shallowClone()); + } + /** + * @param list $dependencies + * + * @return list + */ + public static function filterInvalid(array $dependencies): array + { + return array_values(array_filter($dependencies, static fn(self $d) => $d->isValid())); + } + /** + * @param list $existing + * @param list $additional + * + * @return list + */ + public static function mergeUnique(array $existing, array $additional): array + { + $existingTargets = array_map(static fn(\PHPUnit\Framework\ExecutionOrderDependency $dependency) => $dependency->getTarget(), $existing); + foreach ($additional as $dependency) { + $additionalTarget = $dependency->getTarget(); + if (in_array($additionalTarget, $existingTargets, \true)) { + continue; + } + $existingTargets[] = $additionalTarget; + $existing[] = $dependency; + } + return $existing; + } + /** + * @param list $left + * @param list $right + * + * @return list + */ + public static function diff(array $left, array $right): array + { + if ($right === []) { + return $left; + } + if ($left === []) { + return []; + } + $diff = []; + $rightTargets = array_map(static fn(\PHPUnit\Framework\ExecutionOrderDependency $dependency) => $dependency->getTarget(), $right); + foreach ($left as $dependency) { + if (in_array($dependency->getTarget(), $rightTargets, \true)) { + continue; + } + $diff[] = $dependency; + } + return $diff; + } + public function __construct(string $classOrCallableName, ?string $methodName = null, bool $deepClone = \false, bool $shallowClone = \false) + { + $this->deepClone = $deepClone; + $this->shallowClone = $shallowClone; + if ($classOrCallableName === '') { + return; + } + if (str_contains($classOrCallableName, '::')) { + assert(count(explode('::', $classOrCallableName)) === 2); + [$this->className, $this->methodName] = explode('::', $classOrCallableName); + } else { + $this->className = $classOrCallableName; + $this->methodName = $methodName !== null && $methodName !== '' ? $methodName : 'class'; + } + } + public function __toString(): string + { + return $this->getTarget(); + } + /** + * @phpstan-assert-if-true non-empty-string $this->getTarget() + */ + public function isValid(): bool + { + // Invalid dependencies can be declared and are skipped by the runner + return $this->className !== '' && $this->methodName !== ''; + } + public function shallowClone(): bool + { + return $this->shallowClone; + } + public function deepClone(): bool + { + return $this->deepClone; + } + public function targetIsClass(): bool + { + return $this->methodName === 'class'; + } + public function getTarget(): string + { + return $this->isValid() ? $this->className . '::' . $this->methodName : ''; + } + public function getTargetClassName(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnitPHAR\SebastianBergmann\Type\Type; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ConfigurableMethod +{ + /** + * @var non-empty-string + */ + private string $name; + /** + * @var array + */ + private array $defaultParameterValues; + /** + * @var non-negative-int + */ + private int $numberOfParameters; + private Type $returnType; + /** + * @param non-empty-string $name + * @param array $defaultParameterValues + * @param non-negative-int $numberOfParameters + */ + public function __construct(string $name, array $defaultParameterValues, int $numberOfParameters, Type $returnType) + { + $this->name = $name; + $this->defaultParameterValues = $defaultParameterValues; + $this->numberOfParameters = $numberOfParameters; + $this->returnType = $returnType; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + /** + * @return array + */ + public function defaultParameterValues(): array + { + return $this->defaultParameterValues; + } + /** + * @return non-negative-int + */ + public function numberOfParameters(): int + { + return $this->numberOfParameters; + } + public function mayReturn(mixed $value): bool + { + return $this->returnType->isAssignable(Type::fromValue($value, \false)); + } + public function returnTypeDeclaration(): string + { + return $this->returnType->asString(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class BadMethodCallException extends \BadMethodCallException implements \PHPUnit\Framework\MockObject\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CannotUseOnlyMethodsException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct(string $type, string $methodName) + { + parent::__construct(sprintf('Trying to configure method "%s" with onlyMethods(), but it does not exist in class "%s"', $methodName, $type)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends \PHPUnit\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function get_debug_type; +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class IncompatibleReturnValueException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct(\PHPUnit\Framework\MockObject\ConfigurableMethod $method, mixed $value) + { + parent::__construct(sprintf('Method %s may not return value of type %s, its declared return type is "%s"', $method->name(), get_debug_type($value), $method->returnTypeDeclaration())); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MatchBuilderNotFoundException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct(string $id) + { + parent::__construct(sprintf('No builder found for match builder identification <%s>', $id)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MatcherAlreadyRegisteredException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct(string $id) + { + parent::__construct(sprintf('Matcher with id <%s> is already registered', $id)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodCannotBeConfiguredException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct(string $method) + { + parent::__construct(sprintf('Trying to configure method "%s" which cannot be configured because it does not exist, has not been specified, is final, or is static', $method)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodNameAlreadyConfiguredException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct() + { + parent::__construct('Method name is already configured'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodNameNotConfiguredException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct() + { + parent::__construct('Method name is not configured'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodParametersAlreadyConfiguredException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct() + { + parent::__construct('Method parameters already configured'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class NeverReturningMethodException extends RuntimeException implements \PHPUnit\Framework\MockObject\Exception +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + parent::__construct(sprintf('Method %s::%s() is declared to never return', $className, $methodName)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoMoreParameterSetsConfiguredException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct(\PHPUnit\Framework\MockObject\Invocation $invocation, int $numberOfConfiguredParameterSets) + { + parent::__construct(sprintf('Not enough parameter sets configured, only %d parameter sets given for %s::%s()', $numberOfConfiguredParameterSets, $invocation->className(), $invocation->methodName())); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoMoreReturnValuesConfiguredException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct(\PHPUnit\Framework\MockObject\Invocation $invocation, int $numberOfConfiguredReturnValues) + { + parent::__construct(sprintf('Only %d return values have been configured for %s::%s()', $numberOfConfiguredReturnValues, $invocation->className(), $invocation->methodName())); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReturnValueNotConfiguredException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct(\PHPUnit\Framework\MockObject\Invocation $invocation) + { + parent::__construct(sprintf('No return value is configured for %s::%s() and return value generation is disabled', $invocation->className(), $invocation->methodName())); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class RuntimeException extends \RuntimeException implements \PHPUnit\Framework\MockObject\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestDoubleSealedException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Exception +{ + public function __construct() + { + parent::__construct('This test double has been sealed and cannot be configured further'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function class_exists; +use PHPUnit\Framework\MockObject\ConfigurableMethod; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DoubledClass +{ + private string $classCode; + /** + * @var class-string + */ + private string $mockName; + /** + * @var list + */ + private array $configurableMethods; + /** + * @param class-string $mockName + * @param list $configurableMethods + */ + public function __construct(string $classCode, string $mockName, array $configurableMethods) + { + $this->classCode = $classCode; + $this->mockName = $mockName; + $this->configurableMethods = $configurableMethods; + } + /** + * @return class-string + */ + public function generate(): string + { + if (!class_exists($this->mockName, \false)) { + eval($this->classCode); + } + return $this->mockName; + } + public function classCode(): string + { + return $this->classCode; + } + /** + * @return list + */ + public function configurableMethods(): array + { + return $this->configurableMethods; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function array_key_exists; +use function assert; +use function count; +use function explode; +use function implode; +use function is_object; +use function is_string; +use function preg_match; +use function preg_replace; +use function str_contains; +use function strlen; +use function strpos; +use function substr; +use function substr_count; +use function trim; +use function var_export; +use ReflectionMethod; +use ReflectionParameter; +use PHPUnitPHAR\SebastianBergmann\Type\ReflectionMapper; +use PHPUnitPHAR\SebastianBergmann\Type\Type; +use PHPUnitPHAR\SebastianBergmann\Type\UnknownType; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DoubledMethod +{ + use \PHPUnit\Framework\MockObject\Generator\TemplateLoader; + /** + * @var class-string + */ + private readonly string $className; + /** + * @var non-empty-string + */ + private readonly string $methodName; + private readonly string $modifier; + private readonly string $argumentsForDeclaration; + private readonly string $argumentsForCall; + private readonly Type $returnType; + private readonly string $reference; + private readonly bool $static; + private readonly ?string $deprecation; + /** + * @var array + */ + private readonly array $defaultParameterValues; + /** + * @var non-negative-int + */ + private readonly int $numberOfParameters; + /** + * @throws ReflectionException + * @throws RuntimeException + */ + public static function fromReflection(ReflectionMethod $method): self + { + if ($method->isPrivate()) { + $modifier = 'private'; + } elseif ($method->isProtected()) { + $modifier = 'protected'; + } else { + $modifier = 'public'; + } + if ($method->isStatic()) { + $modifier .= ' static'; + } + if ($method->returnsReference()) { + $reference = '&'; + } else { + $reference = ''; + } + $docComment = $method->getDocComment(); + if (is_string($docComment) && preg_match('#\*[ \t]*+@deprecated[ \t]*+(.*?)\r?+\n[ \t]*+\*(?:[ \t]*+@|/$)#s', $docComment, $deprecation) > 0) { + $deprecation = trim(preg_replace('#[ \t]*\r?\n[ \t]*+\*[ \t]*+#', ' ', $deprecation[1])); + } else { + $deprecation = null; + } + return new self($method->getDeclaringClass()->getName(), $method->getName(), $modifier, self::methodParametersForDeclaration($method), self::methodParametersForCall($method), self::methodParametersDefaultValues($method), count($method->getParameters()), (new ReflectionMapper())->fromReturnType($method), $reference, $method->isStatic(), $deprecation); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function fromName(string $className, string $methodName): self + { + return new self($className, $methodName, 'public', '', '', [], 0, new UnknownType(), '', \false, null); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + * @param array $defaultParameterValues + * @param non-negative-int $numberOfParameters + */ + private function __construct(string $className, string $methodName, string $modifier, string $argumentsForDeclaration, string $argumentsForCall, array $defaultParameterValues, int $numberOfParameters, Type $returnType, string $reference, bool $static, ?string $deprecation) + { + $this->className = $className; + $this->methodName = $methodName; + $this->modifier = $modifier; + $this->argumentsForDeclaration = $argumentsForDeclaration; + $this->argumentsForCall = $argumentsForCall; + $this->defaultParameterValues = $defaultParameterValues; + $this->numberOfParameters = $numberOfParameters; + $this->returnType = $returnType; + $this->reference = $reference; + $this->static = $static; + $this->deprecation = $deprecation; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + /** + * @throws RuntimeException + */ + public function generateCode(): string + { + if ($this->static) { + $templateFile = 'doubled_static_method.tpl'; + } else { + $templateFile = 'doubled_method.tpl'; + } + $deprecation = $this->deprecation; + $returnResult = ''; + if (!$this->returnType->isNever() && !$this->returnType->isVoid()) { + $returnResult = <<<'EOT' + + + return $__phpunit_result; +EOT; + } + if (null !== $this->deprecation) { + $deprecation = "The {$this->className}::{$this->methodName} method is deprecated ({$this->deprecation})."; + $deprecationTemplate = $this->loadTemplate('deprecation.tpl'); + $deprecationTemplate->setVar(['deprecation' => var_export($deprecation, \true)]); + $deprecation = $deprecationTemplate->render(); + } + $template = $this->loadTemplate($templateFile); + $argumentsCount = 0; + if (str_contains($this->argumentsForCall, '...')) { + $argumentsCount = null; + } elseif ($this->argumentsForCall !== '') { + $argumentsCount = substr_count($this->argumentsForCall, ',') + 1; + } + $returnDeclaration = ''; + $returnTypeAsString = $this->returnType->asString(); + if ($returnTypeAsString !== '') { + $returnDeclaration = ': ' . $returnTypeAsString; + } + $template->setVar(['arguments_decl' => $this->argumentsForDeclaration, 'arguments_call' => $this->argumentsForCall, 'return_declaration' => $returnDeclaration, 'return_type' => $this->returnType->asString(), 'arguments_count' => (string) $argumentsCount, 'class_name' => $this->className, 'method_name' => $this->methodName, 'modifier' => $this->modifier, 'reference' => $this->reference, 'deprecation' => $deprecation, 'return_result' => $returnResult]); + return $template->render(); + } + public function returnType(): Type + { + return $this->returnType; + } + /** + * @return array + */ + public function defaultParameterValues(): array + { + return $this->defaultParameterValues; + } + /** + * @return non-negative-int + */ + public function numberOfParameters(): int + { + return $this->numberOfParameters; + } + /** + * Returns the parameters of a function or method. + * + * @throws RuntimeException + */ + private static function methodParametersForDeclaration(ReflectionMethod $method): string + { + $parameters = []; + $types = (new ReflectionMapper())->fromParameterTypes($method); + foreach ($method->getParameters() as $i => $parameter) { + $name = '$' . $parameter->getName(); + /* Note: PHP extensions may use empty names for reference arguments + * or "..." for methods taking a variable number of arguments. + */ + // @codeCoverageIgnoreStart + if ($name === '$' || $name === '$...') { + $name = '$arg' . $i; + } + // @codeCoverageIgnoreEnd + $default = ''; + $reference = ''; + $typeDeclaration = ''; + assert(array_key_exists($i, $types)); + if (!$types[$i]->type()->isUnknown()) { + $typeDeclaration = $types[$i]->type()->asString() . ' '; + } + if ($parameter->isPassedByReference()) { + $reference = '&'; + } + if ($parameter->isVariadic()) { + $name = '...' . $name; + } elseif ($parameter->isDefaultValueAvailable()) { + $default = ' = ' . self::exportDefaultValue($parameter); + } elseif ($parameter->isOptional()) { + $default = ' = null'; + } + $parameters[] = $typeDeclaration . $reference . $name . $default; + } + return implode(', ', $parameters); + } + /** + * Returns the parameters of a function or method. + * + * @throws ReflectionException + */ + private static function methodParametersForCall(ReflectionMethod $method): string + { + $parameters = []; + foreach ($method->getParameters() as $i => $parameter) { + $name = '$' . $parameter->getName(); + /* Note: PHP extensions may use empty names for reference arguments + * or "..." for methods taking a variable number of arguments. + */ + // @codeCoverageIgnoreStart + if ($name === '$' || $name === '$...') { + $name = '$arg' . $i; + } + // @codeCoverageIgnoreEnd + if ($parameter->isVariadic()) { + continue; + } + if ($parameter->isPassedByReference()) { + $parameters[] = '&' . $name; + } else { + $parameters[] = $name; + } + } + return implode(', ', $parameters); + } + /** + * @throws ReflectionException + */ + private static function exportDefaultValue(ReflectionParameter $parameter): string + { + try { + $defaultValue = $parameter->getDefaultValue(); + if (!is_object($defaultValue)) { + return var_export($defaultValue, \true); + } + $parameterAsString = $parameter->__toString(); + return explode(' = ', substr(substr($parameterAsString, strpos($parameterAsString, ' ') + strlen(' ')), 0, -2))[1]; + // @codeCoverageIgnoreStart + } catch (\ReflectionException $e) { + throw new \PHPUnit\Framework\MockObject\Generator\ReflectionException($e->getMessage(), $e->getCode(), $e); + } + // @codeCoverageIgnoreEnd + } + /** + * @return array + */ + private static function methodParametersDefaultValues(ReflectionMethod $method): array + { + $result = []; + foreach ($method->getParameters() as $i => $parameter) { + if (!$parameter->isDefaultValueAvailable()) { + continue; + } + $result[$i] = $parameter->getDefaultValue(); + } + return $result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function array_key_exists; +use function array_values; +use function strtolower; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DoubledMethodSet +{ + /** + * @var array + */ + private array $methods = []; + public function addMethods(\PHPUnit\Framework\MockObject\Generator\DoubledMethod ...$methods): void + { + foreach ($methods as $method) { + $this->methods[strtolower($method->methodName())] = $method; + } + } + /** + * @return list + */ + public function asArray(): array + { + return array_values($this->methods); + } + public function hasMethod(string $methodName): bool + { + return array_key_exists(strtolower($methodName), $this->methods); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ClassIsAnonymousException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ + public function __construct(string $className) + { + parent::__construct(sprintf('Class "%s" is an anonymous class and cannot be doubled', $className)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ClassIsEnumerationException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ + public function __construct(string $className) + { + parent::__construct(sprintf('Class "%s" is an enumeration and cannot be doubled', $className)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ClassIsFinalException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ + public function __construct(string $className) + { + parent::__construct(sprintf('Class "%s" is declared "final" and cannot be doubled', $className)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function array_diff_assoc; +use function array_unique; +use function implode; +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DuplicateMethodException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ + /** + * @param list $methods + */ + public function __construct(array $methods) + { + parent::__construct(sprintf('Cannot double using a method list that contains duplicates: "%s" (duplicate: "%s")', implode(', ', $methods), implode(', ', array_unique(array_diff_assoc($methods, array_unique($methods)))))); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use PHPUnit\Framework\MockObject\Exception as BaseException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends BaseException +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidClassNameException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ + public function __construct(string $className) + { + parent::__construct(sprintf('Cannot use "%s" as the name of a test double class because it is not a valid PHP class name', $className)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidMethodNameException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ + public function __construct(string $method) + { + parent::__construct(sprintf('Cannot double method with invalid name "%s"', $method)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodNamedMethodException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ + public function __construct() + { + parent::__construct('Doubling interfaces (or classes) that have a method named "method" is not supported.'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NameAlreadyInUseException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ + /** + * @param class-string|trait-string $name + */ + public function __construct(string $name) + { + parent::__construct(sprintf('The name "%s" is already in use', $name)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReflectionException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class RuntimeException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownInterfaceException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ + public function __construct(string $interfaceName) + { + parent::__construct(sprintf('Interface "%s" does not exist', $interfaceName)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownTypeException extends \PHPUnit\Framework\Exception implements \PHPUnit\Framework\MockObject\Generator\Exception +{ + public function __construct(string $type) + { + parent::__construct(sprintf('Class or interface "%s" does not exist', $type)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use const PHP_EOL; +use const PHP_VERSION; +use function array_merge; +use function array_pop; +use function array_unique; +use function assert; +use function class_exists; +use function count; +use function explode; +use function implode; +use function in_array; +use function interface_exists; +use function is_array; +use function md5; +use function mt_rand; +use function preg_match; +use function serialize; +use function sort; +use function sprintf; +use function substr; +use function trait_exists; +use function version_compare; +use Exception; +use Iterator; +use IteratorAggregate; +use PHPUnit\Framework\MockObject\ConfigurableMethod; +use PHPUnit\Framework\MockObject\DoubledCloneMethod; +use PHPUnit\Framework\MockObject\Method; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\MockObjectApi; +use PHPUnit\Framework\MockObject\MockObjectInternal; +use PHPUnit\Framework\MockObject\ProxiedCloneMethod; +use PHPUnit\Framework\MockObject\Stub; +use PHPUnit\Framework\MockObject\StubApi; +use PHPUnit\Framework\MockObject\StubInternal; +use PHPUnit\Framework\MockObject\TestDoubleState; +use PropertyHookType; +use ReflectionClass; +use ReflectionMethod; +use ReflectionObject; +use PHPUnitPHAR\SebastianBergmann\Type\ReflectionMapper; +use PHPUnitPHAR\SebastianBergmann\Type\Type; +use Throwable; +use Traversable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Generator +{ + use \PHPUnit\Framework\MockObject\Generator\TemplateLoader; + /** + * @var null|non-empty-array + */ + private static ?array $excludedMethodNames = null; + /** + * @var array + */ + private static array $cache = []; + /** + * Returns a test double for the specified class. + * + * @param class-string $type + * @param ?list $methods + * @param array $arguments + * + * @throws ClassIsAnonymousException + * @throws ClassIsEnumerationException + * @throws ClassIsFinalException + * @throws DuplicateMethodException + * @throws InvalidClassNameException + * @throws InvalidMethodNameException + * @throws NameAlreadyInUseException + * @throws ReflectionException + * @throws RuntimeException + * @throws UnknownTypeException + */ + public function testDouble(string $type, bool $mockObject, ?array $methods = [], array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = \true, bool $callOriginalClone = \true, bool $returnValueGeneration = \true): MockObject|Stub + { + if ($type === Traversable::class) { + $type = Iterator::class; + } + $this->ensureKnownType($type); + $this->ensureValidMethods($methods); + $this->ensureValidNameForTestDoubleClass($mockClassName); + $this->ensureNameForTestDoubleClassIsAvailable($mockClassName); + $mock = $this->generate($type, $mockObject, $methods, $mockClassName, $callOriginalClone); + $object = $this->instantiate($mock, $type, $callOriginalConstructor, $arguments, $returnValueGeneration, $mockObject); + assert($object instanceof $type); + if ($mockObject) { + assert($object instanceof MockObject); + } else { + assert($object instanceof Stub); + } + return $object; + } + /** + * @param list $interfaces + * + * @throws RuntimeException + * @throws UnknownInterfaceException + */ + public function testDoubleForInterfaceIntersection(array $interfaces, bool $mockObject, bool $returnValueGeneration = \true): MockObject|Stub + { + if (count($interfaces) < 2) { + throw new \PHPUnit\Framework\MockObject\Generator\RuntimeException('At least two interfaces must be specified'); + } + foreach ($interfaces as $interface) { + if (!interface_exists($interface)) { + throw new \PHPUnit\Framework\MockObject\Generator\UnknownInterfaceException($interface); + } + } + sort($interfaces); + $methods = []; + foreach ($interfaces as $interface) { + $methods = array_merge($methods, $this->namesOfMethodsIn($interface)); + } + if (count(array_unique($methods)) < count($methods)) { + throw new \PHPUnit\Framework\MockObject\Generator\RuntimeException('Interfaces must not declare the same method'); + } + $unqualifiedNames = []; + foreach ($interfaces as $interface) { + $parts = explode('\\', $interface); + $unqualifiedNames[] = array_pop($parts); + } + sort($unqualifiedNames); + do { + $intersectionName = sprintf('Intersection_%s_%s', implode('_', $unqualifiedNames), substr(md5((string) mt_rand()), 0, 8)); + } while (interface_exists($intersectionName, \false)); + $template = $this->loadTemplate('intersection.tpl'); + $template->setVar(['intersection' => $intersectionName, 'interfaces' => implode(', ', $interfaces)]); + eval($template->render()); + assert(interface_exists($intersectionName)); + return $this->testDouble($intersectionName, $mockObject, returnValueGeneration: $returnValueGeneration); + } + /** + * @param class-string $type + * @param ?list $methods + * + * @throws ClassIsAnonymousException + * @throws ClassIsEnumerationException + * @throws ClassIsFinalException + * @throws ReflectionException + * @throws RuntimeException + * + * @todo This method is only public because it is used to test generated code in PHPT tests + * + * @see https://github.com/sebastianbergmann/phpunit/issues/5476 + */ + public function generate(string $type, bool $mockObject, ?array $methods = null, string $mockClassName = '', bool $callOriginalClone = \true): \PHPUnit\Framework\MockObject\Generator\DoubledClass + { + if ($mockClassName !== '') { + return $this->generateCodeForTestDoubleClass($type, $mockObject, $methods, $mockClassName, $callOriginalClone); + } + $key = md5($type . ($mockObject ? 'MockObject' : 'TestStub') . serialize($methods) . serialize($callOriginalClone)); + if (!isset(self::$cache[$key])) { + self::$cache[$key] = $this->generateCodeForTestDoubleClass($type, $mockObject, $methods, $mockClassName, $callOriginalClone); + } + return self::$cache[$key]; + } + /** + * @param class-string $className + * + * @throws ReflectionException + * + * @return list + */ + private function mockClassMethods(string $className): array + { + $class = $this->reflectClass($className); + $methods = []; + foreach ($class->getMethods() as $method) { + if (($method->isPublic() || $method->isAbstract()) && $this->canMethodBeDoubled($method)) { + $methods[] = \PHPUnit\Framework\MockObject\Generator\DoubledMethod::fromReflection($method); + } + } + return $methods; + } + /** + * @param class-string $interfaceName + * + * @throws ReflectionException + * + * @return list + */ + private function userDefinedInterfaceMethods(string $interfaceName): array + { + $interface = $this->reflectClass($interfaceName); + $methods = []; + foreach ($interface->getMethods() as $method) { + if (!$method->isUserDefined()) { + continue; + } + $methods[] = $method; + } + return $methods; + } + /** + * @param array $arguments + * + * @throws ReflectionException + * @throws RuntimeException + */ + private function instantiate(\PHPUnit\Framework\MockObject\Generator\DoubledClass $mockClass, string $type, bool $callOriginalConstructor, array $arguments, bool $returnValueGeneration, bool $isMockObject): object + { + $className = $mockClass->generate(); + try { + $object = (new ReflectionClass($className))->newInstanceWithoutConstructor(); + // @codeCoverageIgnoreStart + } catch (\ReflectionException $e) { + throw new \PHPUnit\Framework\MockObject\Generator\ReflectionException($e->getMessage(), $e->getCode(), $e); + // @codeCoverageIgnoreEnd + } + $reflector = new ReflectionObject($object); + /** + * @noinspection PhpUnhandledExceptionInspection + */ + $reflector->getProperty('__phpunit_state')->setValue($object, new TestDoubleState($mockClass->configurableMethods(), $type, $returnValueGeneration, $isMockObject)); + if ($callOriginalConstructor && $reflector->getConstructor() !== null) { + try { + $reflector->getConstructor()->invokeArgs($object, $arguments); + // @codeCoverageIgnoreStart + } catch (\ReflectionException $e) { + throw new \PHPUnit\Framework\MockObject\Generator\ReflectionException($e->getMessage(), $e->getCode(), $e); + // @codeCoverageIgnoreEnd + } + } + return $object; + } + /** + * @param class-string $type + * @param ?list $explicitMethods + * + * @throws ClassIsAnonymousException + * @throws ClassIsEnumerationException + * @throws ClassIsFinalException + * @throws MethodNamedMethodException + * @throws ReflectionException + * @throws RuntimeException + */ + private function generateCodeForTestDoubleClass(string $type, bool $mockObject, ?array $explicitMethods, string $mockClassName, bool $callOriginalClone): \PHPUnit\Framework\MockObject\Generator\DoubledClass + { + $classTemplate = $this->loadTemplate('test_double_class.tpl'); + $additionalInterfaces = []; + $doubledCloneMethod = \false; + $proxiedCloneMethod = \false; + $isClass = \false; + $isReadonly = \false; + $isInterface = \false; + $mockMethods = new \PHPUnit\Framework\MockObject\Generator\DoubledMethodSet(); + $testDoubleClassPrefix = $mockObject ? 'MockObject_' : 'TestStub_'; + $_mockClassName = $this->generateClassName($type, $mockClassName, $testDoubleClassPrefix); + if (class_exists($_mockClassName['fullClassName'])) { + $isClass = \true; + } elseif (interface_exists($_mockClassName['fullClassName'])) { + $isInterface = \true; + } + $class = $this->reflectClass($_mockClassName['fullClassName']); + if ($class->isAnonymous()) { + throw new \PHPUnit\Framework\MockObject\Generator\ClassIsAnonymousException($_mockClassName['fullClassName']); + } + if ($class->isEnum()) { + throw new \PHPUnit\Framework\MockObject\Generator\ClassIsEnumerationException($_mockClassName['fullClassName']); + } + if ($class->isFinal()) { + throw new \PHPUnit\Framework\MockObject\Generator\ClassIsFinalException($_mockClassName['fullClassName']); + } + if ($class->isReadOnly()) { + $isReadonly = \true; + } + // @see https://github.com/sebastianbergmann/phpunit/issues/2995 + if ($isInterface && $class->implementsInterface(Throwable::class)) { + $actualClassName = Exception::class; + $additionalInterfaces[] = $class->getName(); + $isInterface = \false; + $class = $this->reflectClass($actualClassName); + foreach ($this->userDefinedInterfaceMethods($_mockClassName['fullClassName']) as $method) { + $methodName = $method->getName(); + if ($class->hasMethod($methodName)) { + $classMethod = $class->getMethod($methodName); + if (!$this->canMethodBeDoubled($classMethod)) { + continue; + } + } + $mockMethods->addMethods(\PHPUnit\Framework\MockObject\Generator\DoubledMethod::fromReflection($method)); + } + $_mockClassName = $this->generateClassName($actualClassName, $_mockClassName['className'], $testDoubleClassPrefix); + } + // @see https://github.com/sebastianbergmann/phpunit-mock-objects/issues/103 + if ($isInterface && $class->implementsInterface(Traversable::class) && !$class->implementsInterface(Iterator::class) && !$class->implementsInterface(IteratorAggregate::class)) { + $additionalInterfaces[] = Iterator::class; + $mockMethods->addMethods(...$this->mockClassMethods(Iterator::class)); + } + if ($class->hasMethod('__clone')) { + $cloneMethod = $class->getMethod('__clone'); + if (!$cloneMethod->isFinal()) { + if ($callOriginalClone && !$isInterface) { + $proxiedCloneMethod = \true; + } else { + $doubledCloneMethod = \true; + } + } + } else { + $doubledCloneMethod = \true; + } + if ($isClass && $explicitMethods === []) { + $mockMethods->addMethods(...$this->mockClassMethods($_mockClassName['fullClassName'])); + } + if ($isInterface && ($explicitMethods === [] || $explicitMethods === null)) { + $mockMethods->addMethods(...$this->interfaceMethods($_mockClassName['fullClassName'])); + } + if (is_array($explicitMethods)) { + foreach ($explicitMethods as $methodName) { + if ($class->hasMethod($methodName)) { + $method = $class->getMethod($methodName); + if ($this->canMethodBeDoubled($method)) { + $mockMethods->addMethods(\PHPUnit\Framework\MockObject\Generator\DoubledMethod::fromReflection($method)); + } + } else { + $mockMethods->addMethods(\PHPUnit\Framework\MockObject\Generator\DoubledMethod::fromName($_mockClassName['fullClassName'], $methodName)); + } + } + } + $propertiesWithHooks = $this->properties($class); + $configurableMethods = $this->configurableMethods($mockMethods, $propertiesWithHooks); + $mockedMethods = ''; + foreach ($mockMethods->asArray() as $mockMethod) { + $mockedMethods .= $mockMethod->generateCode(); + } + /** @var trait-string[] $traits */ + $traits = [StubApi::class]; + if ($mockObject) { + $traits[] = MockObjectApi::class; + } + if ($mockMethods->hasMethod('method') || $class->hasMethod('method')) { + throw new \PHPUnit\Framework\MockObject\Generator\MethodNamedMethodException(); + } + $traits[] = Method::class; + if ($doubledCloneMethod) { + $traits[] = DoubledCloneMethod::class; + } elseif ($proxiedCloneMethod) { + $traits[] = ProxiedCloneMethod::class; + } + $useStatements = ''; + foreach ($traits as $trait) { + $useStatements .= sprintf(' use %s;' . PHP_EOL, $trait); + } + unset($traits); + $classTemplate->setVar(['class_declaration' => $this->generateTestDoubleClassDeclaration($mockObject, $_mockClassName, $isInterface, $additionalInterfaces, $isReadonly), 'use_statements' => $useStatements, 'mock_class_name' => $_mockClassName['className'], 'methods' => $mockedMethods, 'property_hooks' => (new \PHPUnit\Framework\MockObject\Generator\HookedPropertyGenerator())->generate($_mockClassName['className'], $propertiesWithHooks)]); + return new \PHPUnit\Framework\MockObject\Generator\DoubledClass($classTemplate->render(), $_mockClassName['className'], $configurableMethods); + } + /** + * @param class-string $type + * + * @return array{className: class-string, originalClassName: class-string, fullClassName: class-string, namespaceName: string} + */ + private function generateClassName(string $type, string $className, string $prefix): array + { + if ($type[0] === '\\') { + $type = substr($type, 1); + } + $classNameParts = explode('\\', $type); + if (count($classNameParts) > 1) { + $type = array_pop($classNameParts); + $namespaceName = implode('\\', $classNameParts); + $fullClassName = $namespaceName . '\\' . $type; + } else { + $namespaceName = ''; + $fullClassName = $type; + } + if ($className === '') { + do { + $className = $prefix . $type . '_' . substr(md5((string) mt_rand()), 0, 8); + } while (class_exists($className, \false)); + } + return ['className' => $className, 'originalClassName' => $type, 'fullClassName' => $fullClassName, 'namespaceName' => $namespaceName]; + } + /** + * @param array{className: non-empty-string, originalClassName: non-empty-string, fullClassName: non-empty-string, namespaceName: string} $mockClassName + * @param list $additionalInterfaces + */ + private function generateTestDoubleClassDeclaration(bool $mockObject, array $mockClassName, bool $isInterface, array $additionalInterfaces, bool $isReadonly): string + { + if ($mockObject) { + $additionalInterfaces[] = MockObjectInternal::class; + } else { + $additionalInterfaces[] = StubInternal::class; + } + if ($isReadonly) { + $buffer = 'readonly class '; + } else { + $buffer = 'class '; + } + $interfaces = implode(', ', $additionalInterfaces); + if ($isInterface) { + $buffer .= sprintf('%s implements %s', $mockClassName['className'], $interfaces); + if (!in_array($mockClassName['originalClassName'], $additionalInterfaces, \true)) { + $buffer .= ', '; + if ($mockClassName['namespaceName'] !== '') { + $buffer .= $mockClassName['namespaceName'] . '\\'; + } + $buffer .= $mockClassName['originalClassName']; + } + } else { + $buffer .= sprintf('%s extends %s%s implements %s', $mockClassName['className'], $mockClassName['namespaceName'] !== '' ? $mockClassName['namespaceName'] . '\\' : '', $mockClassName['originalClassName'], $interfaces); + } + return $buffer; + } + private function canMethodBeDoubled(ReflectionMethod $method): bool + { + if ($method->isConstructor()) { + return \false; + } + if ($method->isDestructor()) { + return \false; + } + if ($method->isFinal()) { + return \false; + } + if ($method->isPrivate()) { + return \false; + } + return !$this->isMethodNameExcluded($method->getName()); + } + private function isMethodNameExcluded(string $name): bool + { + if (self::$excludedMethodNames === null) { + self::$excludedMethodNames = ['__CLASS__' => \true, '__DIR__' => \true, '__FILE__' => \true, '__FUNCTION__' => \true, '__LINE__' => \true, '__METHOD__' => \true, '__NAMESPACE__' => \true, '__TRAIT__' => \true, '__clone' => \true, '__halt_compiler' => \true]; + if (version_compare(PHP_VERSION, '8.5', '>=')) { + self::$excludedMethodNames['__sleep'] = \true; + self::$excludedMethodNames['__wakeup'] = \true; + } + } + return isset(self::$excludedMethodNames[$name]); + } + /** + * @throws UnknownTypeException + */ + private function ensureKnownType(string $type): void + { + if (!class_exists($type) && !interface_exists($type)) { + throw new \PHPUnit\Framework\MockObject\Generator\UnknownTypeException($type); + } + } + /** + * @param ?list $methods + * + * @throws DuplicateMethodException + * @throws InvalidMethodNameException + */ + private function ensureValidMethods(?array $methods): void + { + if ($methods === null) { + return; + } + foreach ($methods as $method) { + if (!preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', (string) $method)) { + throw new \PHPUnit\Framework\MockObject\Generator\InvalidMethodNameException((string) $method); + } + } + if ($methods !== array_unique($methods)) { + throw new \PHPUnit\Framework\MockObject\Generator\DuplicateMethodException($methods); + } + } + /** + * @throws InvalidClassNameException + */ + private function ensureValidNameForTestDoubleClass(string $className): void + { + if ($className === '') { + return; + } + if (!preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', $className)) { + throw new \PHPUnit\Framework\MockObject\Generator\InvalidClassNameException($className); + } + } + /** + * @throws NameAlreadyInUseException + * @throws ReflectionException + */ + private function ensureNameForTestDoubleClassIsAvailable(string $className): void + { + if ($className === '') { + return; + } + if (class_exists($className, \false) || interface_exists($className, \false) || trait_exists($className, \false)) { + throw new \PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException($className); + } + } + /** + * @template T of object + * + * @param class-string $className + * + * @throws ReflectionException + * + * @return ReflectionClass + * + * @phpstan-ignore throws.unusedType + */ + private function reflectClass(string $className): ReflectionClass + { + try { + $class = new ReflectionClass($className); + // @codeCoverageIgnoreStart + /** @phpstan-ignore catch.neverThrown */ + } catch (\ReflectionException $e) { + throw new \PHPUnit\Framework\MockObject\Generator\ReflectionException($e->getMessage(), $e->getCode(), $e); + } + // @codeCoverageIgnoreEnd + return $class; + } + /** + * @param class-string $classOrInterfaceName + * + * @throws ReflectionException + * + * @return list + */ + private function namesOfMethodsIn(string $classOrInterfaceName): array + { + $class = $this->reflectClass($classOrInterfaceName); + $methods = []; + foreach ($class->getMethods() as $method) { + if ($method->isPublic() || $method->isAbstract()) { + $methods[] = $method->getName(); + } + } + return $methods; + } + /** + * @param class-string $interfaceName + * + * @throws ReflectionException + * + * @return list + */ + private function interfaceMethods(string $interfaceName): array + { + $class = $this->reflectClass($interfaceName); + $methods = []; + foreach ($class->getMethods() as $method) { + $methods[] = \PHPUnit\Framework\MockObject\Generator\DoubledMethod::fromReflection($method); + } + return $methods; + } + /** + * @param list $propertiesWithHooks + * + * @return list + */ + private function configurableMethods(\PHPUnit\Framework\MockObject\Generator\DoubledMethodSet $methods, array $propertiesWithHooks): array + { + $configurable = []; + foreach ($methods->asArray() as $method) { + $configurable[] = new ConfigurableMethod($method->methodName(), $method->defaultParameterValues(), $method->numberOfParameters(), $method->returnType()); + } + foreach ($propertiesWithHooks as $property) { + if ($property->shouldGenerateGetHook()) { + $configurable[] = new ConfigurableMethod(sprintf('$%s::get', $property->name()), [], 0, $property->type()); + } + if ($property->shouldGenerateSetHook()) { + $configurable[] = new ConfigurableMethod(sprintf('$%s::set', $property->name()), [], 1, Type::fromName('void', \false)); + } + } + return $configurable; + } + /** + * @param ReflectionClass $class + * + * @return list + */ + private function properties(ReflectionClass $class): array + { + $mapper = new ReflectionMapper(); + $properties = []; + foreach ($class->getProperties() as $property) { + if (!$property->isPublic()) { + continue; + } + if ($property->isFinal()) { + continue; + } + if (!$property->hasHooks()) { + continue; + } + $hasGetHook = \false; + $hasSetHook = \false; + $setHookMethodParameterType = null; + if ($property->hasHook(PropertyHookType::Get) && !$property->getHook(PropertyHookType::Get)->isFinal()) { + $hasGetHook = \true; + } + if ($property->hasHook(PropertyHookType::Set) && !$property->getHook(PropertyHookType::Set)->isFinal()) { + $hasSetHook = \true; + $setHookMethodParameterType = $mapper->fromParameterTypes($property->getHook(PropertyHookType::Set))[0]->type(); + } + if (!$hasGetHook && !$hasSetHook) { + continue; + } + $properties[] = new \PHPUnit\Framework\MockObject\Generator\HookedProperty($property->getName(), $mapper->fromPropertyType($property), $hasGetHook, $hasSetHook, $property->isVirtual(), $setHookMethodParameterType); + } + return $properties; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use PHPUnitPHAR\SebastianBergmann\Type\Type; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class HookedProperty +{ + /** + * @var non-empty-string + */ + private string $name; + private Type $type; + private bool $getHook; + private bool $setHook; + private bool $virtual; + private ?Type $setterType; + /** + * @param non-empty-string $name + */ + public function __construct(string $name, Type $type, bool $getHook, bool $setHook, bool $virtual, ?Type $setterType) + { + $this->name = $name; + $this->type = $type; + $this->getHook = $getHook; + $this->setHook = $setHook; + $this->virtual = $virtual; + $this->setterType = $setterType; + } + public function name(): string + { + return $this->name; + } + public function type(): Type + { + return $this->type; + } + public function hasGetHook(): bool + { + return $this->getHook; + } + public function hasSetHook(): bool + { + return $this->setHook; + } + public function shouldGenerateGetHook(): bool + { + return $this->getHook || !$this->virtual && $this->setHook; + } + public function shouldGenerateSetHook(): bool + { + return $this->setHook || !$this->virtual && $this->getHook; + } + public function hasSetterType(): bool + { + return $this->setterType !== null; + } + /** + * @throws RuntimeException + */ + public function setterType(): Type + { + if ($this->setterType === null) { + throw new \PHPUnit\Framework\MockObject\Generator\RuntimeException(); + } + return $this->setterType; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class HookedPropertyGenerator +{ + /** + * @param class-string $className + * @param list $properties + */ + public function generate(string $className, array $properties): string + { + $code = ''; + foreach ($properties as $property) { + $code .= sprintf(<<<'EOT' + + public %s $%s { +EOT +, $property->type()->asString(), $property->name()); + if ($property->shouldGenerateGetHook()) { + $code .= sprintf(<<<'EOT' + + get { + return $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + '%s', '$%s::get', [], '%s', $this + ) + ); + } + +EOT +, $className, $property->name(), $property->type()->asString()); + } + if ($property->shouldGenerateSetHook()) { + $code .= sprintf(<<<'EOT' + + set (%s $value) { + $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + '%s', '$%s::set', [$value], 'void', $this + ) + ); + } + +EOT +, ($property->hasSetterType() ? $property->setterType() : $property->type())->asString(), $className, $property->name()); + } + $code .= <<<'EOT' + } + +EOT; + } + return $code; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use PHPUnitPHAR\SebastianBergmann\Template\Template; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait TemplateLoader +{ + /** + * @var array + */ + private static array $templates = []; + private function loadTemplate(string $template): Template + { + $filename = __DIR__ . '/templates/' . $template; + if (!isset(self::$templates[$filename])) { + self::$templates[$filename] = new Template($filename); + } + return self::$templates[$filename]; + } +} + + @trigger_error({deprecation}, E_USER_DEPRECATED); + + {modifier} function {reference}{method_name}({arguments_decl}){return_declaration} + {{deprecation} + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [{arguments_call}]; + $__phpunit_count = func_num_args(); + + if ({arguments_count} !== null && $__phpunit_count > {arguments_count}) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = {arguments_count}; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + '{class_name}', '{method_name}', $__phpunit_arguments, '{return_type}', $this + ) + );{return_result} + } + + {modifier} function {reference}{method_name}({arguments_decl}){return_declaration} + { + throw new \PHPUnit\Framework\MockObject\BadMethodCallException('Static method "{method_name}" cannot be invoked on mock object'); + } +declare(strict_types=1); + +interface {intersection} extends {interfaces} +{ +} +declare(strict_types=1); + +{class_declaration} +{ +{use_statements}{property_hooks}{methods}} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function assert; +use PHPUnit\Framework\InvalidArgumentException; +use PHPUnit\Framework\MockObject\Generator\ClassIsAnonymousException; +use PHPUnit\Framework\MockObject\Generator\ClassIsEnumerationException; +use PHPUnit\Framework\MockObject\Generator\ClassIsFinalException; +use PHPUnit\Framework\MockObject\Generator\DuplicateMethodException; +use PHPUnit\Framework\MockObject\Generator\InvalidClassNameException; +use PHPUnit\Framework\MockObject\Generator\InvalidMethodNameException; +use PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException; +use PHPUnit\Framework\MockObject\Generator\ReflectionException; +use PHPUnit\Framework\MockObject\Generator\RuntimeException; +use PHPUnit\Framework\MockObject\Generator\UnknownTypeException; +use PHPUnit\Framework\TestCase; +/** + * @template MockedType + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class MockBuilder extends \PHPUnit\Framework\MockObject\TestDoubleBuilder +{ + private readonly TestCase $testCase; + /** + * @var ?class-string + */ + private ?string $mockClassName = null; + /** + * @param class-string|trait-string $type + */ + public function __construct(TestCase $testCase, string $type) + { + parent::__construct($type); + $this->testCase = $testCase; + } + /** + * Creates a mock object using a fluent interface. + * + * @throws ClassIsAnonymousException + * @throws ClassIsEnumerationException + * @throws ClassIsFinalException + * @throws DuplicateMethodException + * @throws InvalidArgumentException + * @throws InvalidClassNameException + * @throws InvalidMethodNameException + * @throws NameAlreadyInUseException + * @throws ReflectionException + * @throws RuntimeException + * @throws UnknownTypeException + * + * @return MockedType&MockObject + */ + public function getMock(): \PHPUnit\Framework\MockObject\MockObject + { + $object = $this->getTestDouble($this->mockClassName, \true); + assert($object instanceof $this->type); + assert($object instanceof \PHPUnit\Framework\MockObject\MockObject); + $this->testCase->registerMockObject($this->type, $object); + return $object; + } + /** + * Specifies the name for the mock class. + * + * @param class-string $name + * + * @return $this + */ + public function setMockClassName(string $name): self + { + $this->mockClassName = $name; + return $this; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function array_flip; +use function array_key_exists; +use function array_map; +use function array_merge; +use function array_pop; +use function assert; +use function count; +use function is_string; +use function range; +use function strtolower; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\InvalidArgumentException; +use PHPUnit\Framework\MockObject\Runtime\PropertyHook; +use PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls; +use PHPUnit\Framework\MockObject\Stub\Exception; +use PHPUnit\Framework\MockObject\Stub\ReturnArgument; +use PHPUnit\Framework\MockObject\Stub\ReturnCallback; +use PHPUnit\Framework\MockObject\Stub\ReturnReference; +use PHPUnit\Framework\MockObject\Stub\ReturnSelf; +use PHPUnit\Framework\MockObject\Stub\ReturnStub; +use PHPUnit\Framework\MockObject\Stub\ReturnValueMap; +use PHPUnit\Framework\MockObject\Stub\Stub; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract class AbstractInvocationImplementation implements \PHPUnit\Framework\MockObject\InvocationStubber +{ + protected readonly \PHPUnit\Framework\MockObject\InvocationHandler $invocationHandler; + protected readonly \PHPUnit\Framework\MockObject\Matcher $matcher; + /** + * @var list + */ + protected readonly array $configurableMethods; + /** + * @var ?array + */ + protected ?array $configurableMethodNames = null; + protected bool $createdWithoutExplicitExpects = \false; + final public function __construct(\PHPUnit\Framework\MockObject\InvocationHandler $handler, \PHPUnit\Framework\MockObject\Matcher $matcher, \PHPUnit\Framework\MockObject\ConfigurableMethod ...$configurableMethods) + { + $this->invocationHandler = $handler; + $this->matcher = $matcher; + $this->configurableMethods = $configurableMethods; + } + /** + * @param Constraint|non-empty-string|PropertyHook $constraint + * + * @throws InvalidArgumentException + * @throws MethodCannotBeConfiguredException + * @throws MethodNameAlreadyConfiguredException + * + * @return $this + */ + final public function method(Constraint|PropertyHook|string $constraint): \PHPUnit\Framework\MockObject\InvocationStubber + { + if ($this->matcher->hasMethodNameRule()) { + throw new \PHPUnit\Framework\MockObject\MethodNameAlreadyConfiguredException(); + } + if ($constraint instanceof PropertyHook) { + $constraint = $constraint->asString(); + } + if (is_string($constraint)) { + $this->configurableMethodNames ??= array_flip(array_map(static fn(\PHPUnit\Framework\MockObject\ConfigurableMethod $configurable) => strtolower($configurable->name()), $this->configurableMethods)); + if (!array_key_exists(strtolower($constraint), $this->configurableMethodNames)) { + throw new \PHPUnit\Framework\MockObject\MethodCannotBeConfiguredException($constraint); + } + } + $this->matcher->setMethodNameRule(new \PHPUnit\Framework\MockObject\Rule\MethodName($constraint)); + return $this; + } + /** + * @return $this + */ + final public function will(Stub $stub): \PHPUnit\Framework\MockObject\InvocationStubber + { + $this->matcher->setStub($stub); + return $this; + } + /** + * @throws IncompatibleReturnValueException + */ + final public function willReturn(mixed $value, mixed ...$nextValues): \PHPUnit\Framework\MockObject\InvocationStubber + { + if (count($nextValues) === 0) { + $this->ensureTypeOfReturnValues([$value]); + $stub = $value instanceof Stub ? $value : new ReturnStub($value); + return $this->will($stub); + } + $values = array_merge([$value], $nextValues); + $this->ensureTypeOfReturnValues($values); + $stub = new ConsecutiveCalls($values); + return $this->will($stub); + } + final public function willReturnReference(mixed &$reference): \PHPUnit\Framework\MockObject\InvocationStubber + { + $stub = new ReturnReference($reference); + return $this->will($stub); + } + final public function willReturnMap(array $valueMap): \PHPUnit\Framework\MockObject\InvocationStubber + { + $method = $this->configuredMethod(); + assert($method instanceof \PHPUnit\Framework\MockObject\ConfigurableMethod); + $numberOfParameters = $method->numberOfParameters(); + $defaultValues = $method->defaultParameterValues(); + $hasDefaultValues = $defaultValues !== []; + $_valueMap = []; + foreach ($valueMap as $mapping) { + $numberOfConfiguredParameters = count($mapping) - 1; + if ($numberOfConfiguredParameters === $numberOfParameters || !$hasDefaultValues) { + $_valueMap[] = $mapping; + continue; + } + $_mapping = []; + $returnValue = array_pop($mapping); + foreach (range(0, $numberOfParameters - 1) as $i) { + if (array_key_exists($i, $mapping)) { + $_mapping[] = $mapping[$i]; + continue; + } + if (array_key_exists($i, $defaultValues)) { + $_mapping[] = $defaultValues[$i]; + } + } + $_mapping[] = $returnValue; + $_valueMap[] = $_mapping; + } + $stub = new ReturnValueMap($_valueMap); + return $this->will($stub); + } + final public function willReturnArgument(int $argumentIndex): \PHPUnit\Framework\MockObject\InvocationStubber + { + $stub = new ReturnArgument($argumentIndex); + return $this->will($stub); + } + final public function willReturnCallback(callable $callback): \PHPUnit\Framework\MockObject\InvocationStubber + { + $stub = new ReturnCallback($callback); + return $this->will($stub); + } + final public function willReturnSelf(): \PHPUnit\Framework\MockObject\InvocationStubber + { + $stub = new ReturnSelf(); + return $this->will($stub); + } + final public function willReturnOnConsecutiveCalls(mixed ...$values): \PHPUnit\Framework\MockObject\InvocationStubber + { + $stub = new ConsecutiveCalls($values); + return $this->will($stub); + } + final public function willThrowException(Throwable $exception): \PHPUnit\Framework\MockObject\InvocationStubber + { + $stub = new Exception($exception); + return $this->will($stub); + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function markAsCreatedWithoutExplicitExpects(): static + { + $this->createdWithoutExplicitExpects = \true; + return $this; + } + final public function seal(): void + { + $this->invocationHandler->seal($this->invocationHandler->isMockObject()); + } + /** + * @throws MethodNameNotConfiguredException + * @throws MethodParametersAlreadyConfiguredException + */ + final protected function ensureParametersCanBeConfigured(): void + { + if (!$this->matcher->hasMethodNameRule()) { + throw new \PHPUnit\Framework\MockObject\MethodNameNotConfiguredException(); + } + if ($this->matcher->hasParametersRule()) { + throw new \PHPUnit\Framework\MockObject\MethodParametersAlreadyConfiguredException(); + } + } + private function configuredMethod(): ?\PHPUnit\Framework\MockObject\ConfigurableMethod + { + $configuredMethod = null; + foreach ($this->configurableMethods as $configurableMethod) { + if ($this->matcher->methodNameRule()->matchesName($configurableMethod->name())) { + if ($configuredMethod !== null) { + return null; + } + $configuredMethod = $configurableMethod; + } + } + return $configuredMethod; + } + /** + * @param array $values + * + * @throws IncompatibleReturnValueException + */ + private function ensureTypeOfReturnValues(array $values): void + { + $configuredMethod = $this->configuredMethod(); + if ($configuredMethod === null) { + return; + } + foreach ($values as $value) { + if (!$configuredMethod->mayReturn($value)) { + throw new \PHPUnit\Framework\MockObject\IncompatibleReturnValueException($configuredMethod, $value); + } + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait DoubledCloneMethod +{ + public function __clone(): void + { + $this->__phpunit_state = clone $this->__phpunit_state; + $this->__phpunit_state()->cloneInvocationHandler(); + } + abstract public function __phpunit_state(): \PHPUnit\Framework\MockObject\TestDoubleState; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount; +use PHPUnit\Framework\MockObject\Runtime\PropertyHook; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait Method +{ + abstract public function __phpunit_getInvocationHandler(): \PHPUnit\Framework\MockObject\InvocationHandler; + public function method(Constraint|PropertyHook|string $constraint): \PHPUnit\Framework\MockObject\InvocationStubber + { + return $this->__phpunit_getInvocationHandler()->expects(new AnyInvokedCount())->method($constraint)->markAsCreatedWithoutExplicitExpects(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\MockObject\Rule\InvocationOrder; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait MockObjectApi +{ + public function __phpunit_hasInvocationCountRule(): bool + { + return $this->__phpunit_getInvocationHandler()->hasInvocationCountRule(); + } + public function __phpunit_hasParametersRule(): bool + { + return $this->__phpunit_getInvocationHandler()->hasParametersRule(); + } + public function __phpunit_verify(bool $unsetInvocationMocker = \true): void + { + $this->__phpunit_getInvocationHandler()->verify(); + if ($unsetInvocationMocker) { + $this->__phpunit_unsetInvocationMocker(); + } + } + abstract public function __phpunit_state(): \PHPUnit\Framework\MockObject\TestDoubleState; + abstract public function __phpunit_getInvocationHandler(): \PHPUnit\Framework\MockObject\InvocationHandler; + abstract public function __phpunit_unsetInvocationMocker(): void; + public function expects(InvocationOrder $matcher): \PHPUnit\Framework\MockObject\InvocationMocker + { + return $this->__phpunit_getInvocationHandler()->expects($matcher); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait ProxiedCloneMethod +{ + public function __clone(): void + { + $this->__phpunit_state = clone $this->__phpunit_state; + $this->__phpunit_state()->cloneInvocationHandler(); + parent::__clone(); + } + abstract public function __phpunit_state(): \PHPUnit\Framework\MockObject\TestDoubleState; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait StubApi +{ + private readonly \PHPUnit\Framework\MockObject\TestDoubleState $__phpunit_state; + public function __phpunit_state(): \PHPUnit\Framework\MockObject\TestDoubleState + { + return $this->__phpunit_state ?? new \PHPUnit\Framework\MockObject\TestDoubleState([], static::class, \true, \false); + } + public function __phpunit_getInvocationHandler(): \PHPUnit\Framework\MockObject\InvocationHandler + { + return $this->__phpunit_state()->invocationHandler(); + } + public function __phpunit_unsetInvocationMocker(): void + { + $this->__phpunit_state()->unsetInvocationHandler(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestDoubleState +{ + /** + * @var list + */ + private readonly array $configurableMethods; + /** + * @var class-string + */ + private readonly string $className; + private readonly bool $generateReturnValues; + private readonly bool $isMockObject; + private ?\PHPUnit\Framework\MockObject\InvocationHandler $invocationHandler = null; + /** + * @param list $configurableMethods + * @param class-string $className + */ + public function __construct(array $configurableMethods, string $className, bool $generateReturnValues, bool $isMockObject = \false) + { + $this->configurableMethods = $configurableMethods; + $this->className = $className; + $this->generateReturnValues = $generateReturnValues; + $this->isMockObject = $isMockObject; + } + public function invocationHandler(): \PHPUnit\Framework\MockObject\InvocationHandler + { + if ($this->invocationHandler !== null) { + return $this->invocationHandler; + } + $this->invocationHandler = new \PHPUnit\Framework\MockObject\InvocationHandler($this->configurableMethods, $this->className, $this->generateReturnValues, $this->isMockObject); + return $this->invocationHandler; + } + public function cloneInvocationHandler(): void + { + if ($this->invocationHandler === null) { + return; + } + $this->invocationHandler = clone $this->invocationHandler; + } + public function unsetInvocationHandler(): void + { + $this->invocationHandler = null; + } + /** + * @return list + */ + public function configurableMethods(): array + { + return $this->configurableMethods; + } + public function generateReturnValues(): bool + { + return $this->generateReturnValues; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +interface InvocationMocker extends \PHPUnit\Framework\MockObject\InvocationStubber +{ + /** + * @return $this + */ + public function with(mixed ...$arguments): self; + /** + * @return $this + */ + public function withParameterSetsInOrder(mixed ...$arguments): self; + /** + * @return $this + */ + public function withParameterSetsInAnyOrder(mixed ...$arguments): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function withAnyParameters(): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @param non-empty-string $id + * + * @return $this + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/6537 + */ + public function id(string $id): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @param non-empty-string $id + * + * @return $this + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/6537 + */ + public function after(string $id): self; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\MockObject\Runtime\PropertyHook; +use PHPUnit\Framework\MockObject\Stub\Stub; +use Throwable; +interface InvocationStubber +{ + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @param Constraint|non-empty-string|PropertyHook $constraint + * + * @return $this + */ + public function method(Constraint|PropertyHook|string $constraint): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function will(Stub $stub): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturn(mixed $value, mixed ...$nextValues): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturnReference(mixed &$reference): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @param array> $valueMap + * + * @return $this + */ + public function willReturnMap(array $valueMap): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturnArgument(int $argumentIndex): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturnCallback(callable $callback): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturnSelf(): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturnOnConsecutiveCalls(mixed ...$values): self; + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willThrowException(Throwable $exception): self; + public function seal(): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\MockObject\Rule\InvocationOrder; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface MockObject extends \PHPUnit\Framework\MockObject\Stub +{ + public function expects(InvocationOrder $invocationRule): \PHPUnit\Framework\MockObject\InvocationMocker; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface MockObjectInternal extends \PHPUnit\Framework\MockObject\MockObject, \PHPUnit\Framework\MockObject\StubInternal +{ + public function __phpunit_hasInvocationCountRule(): bool; + public function __phpunit_hasParametersRule(): bool; + public function __phpunit_verify(bool $unsetInvocationMocker = \true): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\MockObject\Runtime\PropertyHook; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Stub +{ + public function method(Constraint|PropertyHook|string $constraint): \PHPUnit\Framework\MockObject\InvocationStubber; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface StubInternal extends \PHPUnit\Framework\MockObject\Stub +{ + public function __phpunit_state(): \PHPUnit\Framework\MockObject\TestDoubleState; + public function __phpunit_getInvocationHandler(): \PHPUnit\Framework\MockObject\InvocationHandler; + public function __phpunit_unsetInvocationMocker(): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function array_map; +use function implode; +use function sprintf; +use function str_starts_with; +use function strtolower; +use function substr; +use PHPUnit\Framework\SelfDescribing; +use PHPUnit\Util\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Invocation implements SelfDescribing +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @var array + */ + private array $parameters; + private string $returnType; + private bool $isReturnTypeNullable; + private \PHPUnit\Framework\MockObject\MockObjectInternal|\PHPUnit\Framework\MockObject\StubInternal $object; + /** + * @param class-string $className + * @param non-empty-string $methodName + * @param array $parameters + */ + public function __construct(string $className, string $methodName, array $parameters, string $returnType, \PHPUnit\Framework\MockObject\MockObjectInternal|\PHPUnit\Framework\MockObject\StubInternal $object) + { + $this->className = $className; + $this->methodName = $methodName; + $this->parameters = $parameters; + $this->object = $object; + if (strtolower($methodName) === '__tostring') { + $returnType = 'string'; + } + if (str_starts_with($returnType, '?')) { + $returnType = substr($returnType, 1); + $this->isReturnTypeNullable = \true; + } else { + $this->isReturnTypeNullable = \false; + } + $this->returnType = $returnType; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + /** + * @return array + */ + public function parameters(): array + { + return $this->parameters; + } + /** + * @throws Exception + */ + public function generateReturnValue(): mixed + { + if ($this->returnType === 'never') { + throw new \PHPUnit\Framework\MockObject\NeverReturningMethodException($this->className, $this->methodName); + } + if ($this->isReturnTypeNullable) { + return null; + } + return (new \PHPUnit\Framework\MockObject\ReturnValueGenerator())->generate($this->className, $this->methodName, $this->object, $this->returnType); + } + public function toString(): string + { + return sprintf('%s::%s(%s)%s', $this->className, $this->methodName, implode(', ', array_map(Exporter::shortenedExport(...), $this->parameters)), $this->returnType !== '' ? sprintf(': %s', $this->returnType) : ''); + } + public function object(): \PHPUnit\Framework\MockObject\MockObjectInternal|\PHPUnit\Framework\MockObject\StubInternal + { + return $this->object; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function array_any; +use function array_unique; +use function array_values; +use function in_array; +use function strtolower; +use Exception; +use PHPUnit\Framework\AssertionFailedError; +use PHPUnit\Framework\MockObject\Rule\InvocationOrder; +use PHPUnit\Framework\MockObject\Rule\InvokedCount; +use PHPUnit\Framework\MockObject\Rule\MethodName; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvocationHandler +{ + /** + * @var list + */ + private array $matchers = []; + /** + * @var array + */ + private array $matcherMap = []; + /** + * @var list + */ + private readonly array $configurableMethods; + /** + * @var class-string + */ + private readonly string $className; + private readonly bool $returnValueGeneration; + private readonly bool $isMockObject; + private bool $sealed = \false; + private ?AssertionFailedError $assertionFailure = null; + /** + * @param list $configurableMethods + * @param class-string $className + */ + public function __construct(array $configurableMethods, string $className, bool $returnValueGeneration, bool $isMockObject = \false) + { + $this->configurableMethods = $configurableMethods; + $this->className = $className; + $this->returnValueGeneration = $returnValueGeneration; + $this->isMockObject = $isMockObject; + } + public function isMockObject(): bool + { + return $this->isMockObject; + } + public function hasInvocationCountRule(): bool + { + return array_any($this->matchers, static fn(\PHPUnit\Framework\MockObject\Matcher $matcher) => $matcher->hasInvocationCountRule()); + } + public function hasParametersRule(): bool + { + return array_any($this->matchers, static fn(\PHPUnit\Framework\MockObject\Matcher $matcher) => $matcher->hasParametersRule()); + } + /** + * Looks up the match builder with identification $id and returns it. + * + * @param non-empty-string $id + */ + public function lookupMatcher(string $id): ?\PHPUnit\Framework\MockObject\Matcher + { + return $this->matcherMap[$id] ?? null; + } + /** + * Registers a matcher with the identification $id. The matcher can later be + * looked up using lookupMatcher() to figure out if it has been invoked. + * + * @param non-empty-string $id + * + * @throws MatcherAlreadyRegisteredException + */ + public function registerMatcher(string $id, \PHPUnit\Framework\MockObject\Matcher $matcher): void + { + if (isset($this->matcherMap[$id])) { + throw new \PHPUnit\Framework\MockObject\MatcherAlreadyRegisteredException($id); + } + $this->matcherMap[$id] = $matcher; + } + /** + * @throws TestDoubleSealedException + */ + public function expects(InvocationOrder $rule): \PHPUnit\Framework\MockObject\InvocationMocker|\PHPUnit\Framework\MockObject\InvocationStubber + { + if ($this->sealed) { + throw new \PHPUnit\Framework\MockObject\TestDoubleSealedException(); + } + $matcher = new \PHPUnit\Framework\MockObject\Matcher($rule, $this->className); + $this->addMatcher($matcher); + if ($this->isMockObject) { + return new \PHPUnit\Framework\MockObject\InvocationMockerImplementation($this, $matcher, ...$this->configurableMethods); + } + return new \PHPUnit\Framework\MockObject\InvocationStubberImplementation($this, $matcher, ...$this->configurableMethods); + } + /** + * @throws \PHPUnit\Framework\MockObject\Exception + * @throws Exception + */ + public function invoke(\PHPUnit\Framework\MockObject\Invocation $invocation): mixed + { + $exception = null; + $hasReturnValue = \false; + $returnValue = null; + foreach ($this->matchers as $match) { + try { + if ($match->matches($invocation)) { + $value = $match->invoked($invocation); + if (!$hasReturnValue) { + $returnValue = $value; + $hasReturnValue = \true; + } + } + } catch (Exception $e) { + $exception = $e; + if ($this->assertionFailure === null && $e instanceof AssertionFailedError) { + $this->assertionFailure = $e; + } + } + } + if ($exception !== null) { + throw $exception; + } + if ($hasReturnValue) { + return $returnValue; + } + if (!$this->returnValueGeneration) { + if (strtolower($invocation->methodName()) === '__tostring') { + return ''; + } + throw new \PHPUnit\Framework\MockObject\ReturnValueNotConfiguredException($invocation); + } + return $invocation->generateReturnValue(); + } + /** + * @throws Throwable + */ + public function verify(): void + { + foreach ($this->matchers as $matcher) { + $matcher->verify(); + } + if ($this->assertionFailure !== null) { + throw $this->assertionFailure; + } + } + public function seal(bool $isMockObject): void + { + if ($this->sealed) { + return; + } + $this->sealed = \true; + if (!$isMockObject) { + return; + } + $configuredMethods = $this->configuredMethodNames(); + foreach ($this->configurableMethods as $method) { + if (!in_array($method->name(), $configuredMethods, \true)) { + $matcher = new \PHPUnit\Framework\MockObject\Matcher(new InvokedCount(0), $this->className); + $matcher->setMethodNameRule(new MethodName($method->name())); + $this->addMatcher($matcher); + } + } + } + public function isSealed(): bool + { + return $this->sealed; + } + private function addMatcher(\PHPUnit\Framework\MockObject\Matcher $matcher): void + { + $this->matchers[] = $matcher; + } + /** + * Returns the list of method names that have been configured with expectations. + * Only considers exact string matches for method names. + * Methods with any() expectation are considered configured. + * + * @return list + */ + private function configuredMethodNames(): array + { + $names = []; + foreach ($this->matchers as $matcher) { + if (!$matcher->hasMethodNameRule()) { + continue; + } + foreach ($this->configurableMethods as $method) { + if ($matcher->methodNameRule()->matchesName($method->name())) { + $names[] = $method->name(); + } + } + } + return array_values(array_unique($names)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvocationMockerImplementation extends \PHPUnit\Framework\MockObject\AbstractInvocationImplementation implements \PHPUnit\Framework\MockObject\InvocationMocker +{ + /** + * @throws Exception + * @throws MethodNameNotConfiguredException + * @throws MethodParametersAlreadyConfiguredException + * + * @return $this + */ + public function with(mixed ...$arguments): \PHPUnit\Framework\MockObject\InvocationMocker + { + $this->ensureParametersCanBeConfigured(); + $this->emitDeprecationWhenCreatedWithoutExplicitExpects(); + $this->matcher->setParametersRule(new \PHPUnit\Framework\MockObject\Rule\Parameters($arguments)); + return $this; + } + public function withParameterSetsInOrder(mixed ...$arguments): \PHPUnit\Framework\MockObject\InvocationMocker + { + $this->ensureParametersCanBeConfigured(); + $this->emitDeprecationWhenCreatedWithoutExplicitExpects(); + $this->matcher->setParametersRule(new \PHPUnit\Framework\MockObject\Rule\OrderedParameterSets($arguments)); + return $this; + } + public function withParameterSetsInAnyOrder(mixed ...$arguments): \PHPUnit\Framework\MockObject\InvocationMocker + { + $this->ensureParametersCanBeConfigured(); + $this->emitDeprecationWhenCreatedWithoutExplicitExpects(); + $this->matcher->setParametersRule(new \PHPUnit\Framework\MockObject\Rule\UnorderedParameterSets($arguments)); + return $this; + } + /** + * @throws MethodNameNotConfiguredException + * @throws MethodParametersAlreadyConfiguredException + * + * @return $this + */ + public function withAnyParameters(): \PHPUnit\Framework\MockObject\InvocationMocker + { + $this->ensureParametersCanBeConfigured(); + $this->emitDeprecationWhenCreatedWithoutExplicitExpects(); + $this->matcher->setParametersRule(new \PHPUnit\Framework\MockObject\Rule\AnyParameters()); + return $this; + } + /** + * @param non-empty-string $id + * + * @throws MatcherAlreadyRegisteredException + * + * @return $this + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/6537 + */ + public function id(string $id): \PHPUnit\Framework\MockObject\InvocationMocker + { + $this->invocationHandler->registerMatcher($id, $this->matcher); + return $this; + } + /** + * @param non-empty-string $id + * + * @return $this + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/6537 + */ + public function after(string $id): \PHPUnit\Framework\MockObject\InvocationMocker + { + $this->matcher->setAfterMatchBuilderId($id); + return $this; + } + private function emitDeprecationWhenCreatedWithoutExplicitExpects(): void + { + if (!$this->createdWithoutExplicitExpects) { + return; + } + EventFacade::emitter()->testTriggeredPhpunitDeprecation(null, 'Using with*() without expects() is deprecated and will no longer be possible in PHPUnit 14.'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvocationStubberImplementation extends \PHPUnit\Framework\MockObject\AbstractInvocationImplementation implements \PHPUnit\Framework\MockObject\InvocationStubber +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount; +use PHPUnit\Framework\MockObject\Rule\AnyParameters; +use PHPUnit\Framework\MockObject\Rule\InvocationOrder; +use PHPUnit\Framework\MockObject\Rule\InvokedAtMostCount; +use PHPUnit\Framework\MockObject\Rule\InvokedCount; +use PHPUnit\Framework\MockObject\Rule\MethodName; +use PHPUnit\Framework\MockObject\Rule\ParametersRule; +use PHPUnit\Framework\MockObject\Stub\Stub; +use PHPUnit\Util\ThrowableToStringMapper; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Matcher +{ + private readonly InvocationOrder $invocationRule; + /** + * @var class-string + */ + private readonly string $className; + /** + * @var ?non-empty-string + */ + private ?string $afterMatchBuilderId = null; + private ?MethodName $methodNameRule = null; + private ?ParametersRule $parametersRule = null; + private ?Stub $stub = null; + /** + * @param class-string $className + */ + public function __construct(InvocationOrder $rule, string $className) + { + $this->invocationRule = $rule; + $this->className = $className; + } + public function hasInvocationCountRule(): bool + { + return !$this->invocationRule instanceof AnyInvokedCount; + } + /** + * @phpstan-assert-if-true !null $this->methodNameRule + */ + public function hasMethodNameRule(): bool + { + return $this->methodNameRule !== null; + } + /** + * @throws MethodNameNotConfiguredException + */ + public function methodNameRule(): MethodName + { + if (!$this->hasMethodNameRule()) { + throw new \PHPUnit\Framework\MockObject\MethodNameNotConfiguredException(); + } + return $this->methodNameRule; + } + public function setMethodNameRule(MethodName $rule): void + { + $this->methodNameRule = $rule; + } + /** + * @phpstan-assert-if-true !null $this->parametersRule + */ + public function hasParametersRule(): bool + { + return $this->parametersRule !== null; + } + public function setParametersRule(ParametersRule $rule): void + { + $this->parametersRule = $rule; + } + public function setStub(Stub $stub): void + { + $this->stub = $stub; + } + /** + * @param non-empty-string $id + */ + public function setAfterMatchBuilderId(string $id): void + { + $this->afterMatchBuilderId = $id; + } + /** + * @throws Exception + * @throws ExpectationFailedException + * @throws MatchBuilderNotFoundException + * @throws MethodNameNotConfiguredException + * @throws RuntimeException + */ + public function invoked(\PHPUnit\Framework\MockObject\Invocation $invocation): mixed + { + if ($this->methodNameRule === null) { + throw new \PHPUnit\Framework\MockObject\MethodNameNotConfiguredException(); + } + if ($this->afterMatchBuilderId !== null) { + $matcher = $invocation->object()->__phpunit_getInvocationHandler()->lookupMatcher($this->afterMatchBuilderId); + if ($matcher === null) { + throw new \PHPUnit\Framework\MockObject\MatchBuilderNotFoundException($this->afterMatchBuilderId); + } + } + $this->invocationRule->invoked($invocation); + try { + $this->parametersRule?->apply($invocation); + } catch (ExpectationFailedException $e) { + throw new ExpectationFailedException(sprintf("Expectation for %s failed.\n%s", $this->methodNameRule->failureDescription($this->className), $e->getMessage()), $e->getComparisonFailure()); + } + if ($this->stub !== null) { + return $this->stub->invoke($invocation); + } + return $invocation->generateReturnValue(); + } + /** + * @throws ExpectationFailedException + * @throws MatchBuilderNotFoundException + * @throws MethodNameNotConfiguredException + * @throws RuntimeException + */ + public function matches(\PHPUnit\Framework\MockObject\Invocation $invocation): bool + { + if ($this->afterMatchBuilderId !== null) { + $matcher = $invocation->object()->__phpunit_getInvocationHandler()->lookupMatcher($this->afterMatchBuilderId); + if ($matcher === null) { + throw new \PHPUnit\Framework\MockObject\MatchBuilderNotFoundException($this->afterMatchBuilderId); + } + if (!$matcher->invocationRule->hasBeenInvoked()) { + return \false; + } + } + if ($this->methodNameRule === null) { + throw new \PHPUnit\Framework\MockObject\MethodNameNotConfiguredException(); + } + if (!$this->invocationRule->matches($invocation)) { + return \false; + } + try { + if (!$this->methodNameRule->matches($invocation)) { + return \false; + } + } catch (ExpectationFailedException $e) { + throw new ExpectationFailedException(sprintf("Expectation for %s failed.\n%s", $this->methodNameRule->failureDescription($this->className), $e->getMessage()), $e->getComparisonFailure()); + } + return \true; + } + /** + * @throws ExpectationFailedException + * @throws MethodNameNotConfiguredException + */ + public function verify(): void + { + if ($this->methodNameRule === null) { + throw new \PHPUnit\Framework\MockObject\MethodNameNotConfiguredException(); + } + try { + $this->invocationRule->verify(); + } catch (ExpectationFailedException) { + $actual = $this->invocationRule->numberOfInvocations(); + if ($actual === 0) { + $invoked = 'never invoked'; + } elseif ($actual === 1) { + $invoked = 'invoked once'; + } else { + $invoked = sprintf('invoked %d times', $actual); + } + throw new ExpectationFailedException(sprintf('%s was expected to be %s but was %s.', $this->methodNameRule->failureDescription($this->className), $this->invocationRule->toString(), $invoked)); + } + if ($this->parametersRule === null) { + $this->parametersRule = new AnyParameters(); + } + $invocationIsAny = $this->invocationRule instanceof AnyInvokedCount; + $invocationIsNever = $this->invocationRule instanceof InvokedCount && $this->invocationRule->isNever(); + $invocationIsAtMost = $this->invocationRule instanceof InvokedAtMostCount; + if (!$invocationIsAny && !$invocationIsNever && !$invocationIsAtMost) { + try { + $this->parametersRule->verify(); + } catch (ExpectationFailedException $e) { + throw new ExpectationFailedException(sprintf("Expectation for %s failed.\n%s", $this->methodNameRule->failureDescription($this->className), ThrowableToStringMapper::map($e))); + } + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +use function strtolower; +use PHPUnit\Framework\Constraint\Constraint; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodNameConstraint extends Constraint +{ + private string $methodName; + public function __construct(string $methodName) + { + $this->methodName = $methodName; + } + public function methodName(): string + { + return $this->methodName; + } + public function toString(): string + { + return sprintf('is "%s"', $this->methodName); + } + protected function matches(mixed $other): bool + { + return strtolower($this->methodName) === strtolower((string) $other); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Runtime; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PropertyGetHook extends \PHPUnit\Framework\MockObject\Runtime\PropertyHook +{ + /** + * @return non-empty-string + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function asString(): string + { + return sprintf('$%s::get', $this->propertyName()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Runtime; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class PropertyHook +{ + /** + * @var non-empty-string + */ + private string $propertyName; + /** + * @param non-empty-string $propertyName + */ + public static function get(string $propertyName): \PHPUnit\Framework\MockObject\Runtime\PropertyGetHook + { + return new \PHPUnit\Framework\MockObject\Runtime\PropertyGetHook($propertyName); + } + /** + * @param non-empty-string $propertyName + */ + public static function set(string $propertyName): \PHPUnit\Framework\MockObject\Runtime\PropertySetHook + { + return new \PHPUnit\Framework\MockObject\Runtime\PropertySetHook($propertyName); + } + /** + * @param non-empty-string $propertyName + */ + protected function __construct(string $propertyName) + { + $this->propertyName = $propertyName; + } + /** + * @return non-empty-string + */ + public function propertyName(): string + { + return $this->propertyName; + } + /** + * @return non-empty-string + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + abstract public function asString(): string; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Runtime; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PropertySetHook extends \PHPUnit\Framework\MockObject\Runtime\PropertyHook +{ + /** + * @return non-empty-string + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function asString(): string + { + return sprintf('$%s::set', $this->propertyName()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function array_all; +use function array_map; +use function explode; +use function in_array; +use function interface_exists; +use function sprintf; +use function str_contains; +use function str_ends_with; +use function str_starts_with; +use function substr; +use PHPUnit\Framework\MockObject\Generator\Generator; +use ReflectionClass; +use ReflectionObject; +use stdClass; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReturnValueGenerator +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @throws Exception + */ + public function generate(string $className, string $methodName, \PHPUnit\Framework\MockObject\StubInternal $testStub, string $returnType): mixed + { + $intersection = \false; + $union = \false; + if (str_contains($returnType, '|')) { + $types = explode('|', $returnType); + $union = \true; + foreach ($types as $key => $type) { + if (str_starts_with($type, '(') && str_ends_with($type, ')')) { + $types[$key] = substr($type, 1, -1); + } + } + } elseif (str_contains($returnType, '&')) { + $types = explode('&', $returnType); + $intersection = \true; + } else { + $types = [$returnType]; + } + if (!$intersection) { + $lowerTypes = array_map(strtolower(...), $types); + if (in_array('', $lowerTypes, \true) || in_array('null', $lowerTypes, \true) || in_array('mixed', $lowerTypes, \true) || in_array('void', $lowerTypes, \true)) { + return null; + } + if (in_array('true', $lowerTypes, \true)) { + return \true; + } + if (in_array('false', $lowerTypes, \true) || in_array('bool', $lowerTypes, \true)) { + return \false; + } + if (in_array('float', $lowerTypes, \true)) { + return 0.0; + } + if (in_array('int', $lowerTypes, \true)) { + return 0; + } + if (in_array('string', $lowerTypes, \true)) { + return ''; + } + if (in_array('array', $lowerTypes, \true)) { + return []; + } + if (in_array('static', $lowerTypes, \true)) { + return $this->newInstanceOf($testStub, $className, $methodName); + } + if (in_array('object', $lowerTypes, \true)) { + return new stdClass(); + } + if (in_array('callable', $lowerTypes, \true) || in_array('closure', $lowerTypes, \true)) { + return static function (): void { + }; + } + if (in_array('traversable', $lowerTypes, \true) || in_array('generator', $lowerTypes, \true) || in_array('iterable', $lowerTypes, \true)) { + $generator = static function (): \Generator { + yield from []; + }; + return $generator(); + } + if (!$union) { + return $this->testDoubleFor($returnType, $className, $methodName); + } + } + if ($union) { + foreach ($types as $type) { + if (str_contains($type, '&')) { + $_types = explode('&', $type); + if ($this->onlyInterfaces($_types)) { + return $this->testDoubleForIntersectionOfInterfaces($_types, $className, $methodName); + } + } + } + } + if ($intersection && $this->onlyInterfaces($types)) { + return $this->testDoubleForIntersectionOfInterfaces($types, $className, $methodName); + } + $reason = ''; + if ($union) { + $reason = ' because the declared return type is a union'; + } elseif ($intersection) { + $reason = ' because the declared return type is an intersection'; + } + throw new \PHPUnit\Framework\MockObject\RuntimeException(sprintf('Return value for %s::%s() cannot be generated%s, please configure a return value for this method', $className, $methodName, $reason)); + } + /** + * @param non-empty-list $types + */ + private function onlyInterfaces(array $types): bool + { + return array_all($types, static fn(string $type) => interface_exists($type)); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @throws RuntimeException + */ + private function newInstanceOf(\PHPUnit\Framework\MockObject\StubInternal $testStub, string $className, string $methodName): \PHPUnit\Framework\MockObject\Stub + { + try { + $object = (new ReflectionClass($testStub::class))->newInstanceWithoutConstructor(); + $reflector = new ReflectionObject($object); + $reflector->getProperty('__phpunit_state')->setValue($object, new \PHPUnit\Framework\MockObject\TestDoubleState($testStub->__phpunit_state()->configurableMethods(), $className, $testStub->__phpunit_state()->generateReturnValues())); + return $object; + // @codeCoverageIgnoreStart + } catch (Throwable $t) { + throw new \PHPUnit\Framework\MockObject\RuntimeException(sprintf('Return value for %s::%s() cannot be generated: %s', $className, $methodName, $t->getMessage())); + // @codeCoverageIgnoreEnd + } + } + /** + * @param class-string $type + * @param class-string $className + * @param non-empty-string $methodName + * + * @throws RuntimeException + */ + private function testDoubleFor(string $type, string $className, string $methodName): \PHPUnit\Framework\MockObject\Stub + { + try { + return (new Generator())->testDouble($type, \false, [], [], '', \false); + // @codeCoverageIgnoreStart + } catch (Throwable $t) { + throw new \PHPUnit\Framework\MockObject\RuntimeException(sprintf('Return value for %s::%s() cannot be generated: %s', $className, $methodName, $t->getMessage())); + // @codeCoverageIgnoreEnd + } + } + /** + * @param non-empty-list $types + * @param class-string $className + * @param non-empty-string $methodName + * + * @throws RuntimeException + */ + private function testDoubleForIntersectionOfInterfaces(array $types, string $className, string $methodName): \PHPUnit\Framework\MockObject\Stub + { + try { + return (new Generator())->testDoubleForInterfaceIntersection($types, \false); + // @codeCoverageIgnoreStart + } catch (Throwable $t) { + throw new \PHPUnit\Framework\MockObject\RuntimeException(sprintf('Return value for %s::%s() cannot be generated: %s', $className, $methodName, $t->getMessage())); + // @codeCoverageIgnoreEnd + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class AnyInvokedCount extends \PHPUnit\Framework\MockObject\Rule\InvocationOrder +{ + public function toString(): string + { + return 'invoked zero or more times'; + } + public function verify(): void + { + } + public function matches(BaseInvocation $invocation): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class AnyParameters implements \PHPUnit\Framework\MockObject\Rule\ParametersRule +{ + /** + * @throws void + */ + public function apply(BaseInvocation $invocation): void + { + } + public function verify(): void + { + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function count; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +use PHPUnit\Framework\SelfDescribing; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract class InvocationOrder implements SelfDescribing +{ + /** + * @var list + */ + private array $invocations = []; + public function numberOfInvocations(): int + { + return count($this->invocations); + } + public function hasBeenInvoked(): bool + { + return count($this->invocations) > 0; + } + final public function invoked(BaseInvocation $invocation): void + { + $this->invocations[] = $invocation; + $this->invokedDo($invocation); + } + abstract public function matches(BaseInvocation $invocation): bool; + abstract public function verify(): void; + protected function invokedDo(BaseInvocation $invocation): void + { + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvokedAtLeastCount extends \PHPUnit\Framework\MockObject\Rule\InvocationOrder +{ + private readonly int $requiredInvocations; + public function __construct(int $requiredInvocations) + { + $this->requiredInvocations = $requiredInvocations; + } + public function toString(): string + { + return sprintf('invoked at least %d time%s', $this->requiredInvocations, $this->requiredInvocations !== 1 ? 's' : ''); + } + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + $actualInvocations = $this->numberOfInvocations(); + if ($actualInvocations < $this->requiredInvocations) { + throw new ExpectationFailedException(sprintf('Expected invocation at least %d time%s but it occurred %d time%s.', $this->requiredInvocations, $this->requiredInvocations !== 1 ? 's' : '', $actualInvocations, $actualInvocations !== 1 ? 's' : '')); + } + } + public function matches(BaseInvocation $invocation): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvokedAtLeastOnce extends \PHPUnit\Framework\MockObject\Rule\InvocationOrder +{ + public function toString(): string + { + return 'invoked at least once'; + } + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + $count = $this->numberOfInvocations(); + if ($count < 1) { + throw new ExpectationFailedException('Expected invocation at least once but it never occurred.'); + } + } + public function matches(BaseInvocation $invocation): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvokedAtMostCount extends \PHPUnit\Framework\MockObject\Rule\InvocationOrder +{ + private readonly int $allowedInvocations; + public function __construct(int $allowedInvocations) + { + $this->allowedInvocations = $allowedInvocations; + } + public function toString(): string + { + if ($this->allowedInvocations === 1) { + return 'invoked at most once'; + } + return sprintf('invoked at most %d times', $this->allowedInvocations); + } + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + $actualInvocations = $this->numberOfInvocations(); + if ($actualInvocations > $this->allowedInvocations) { + throw new ExpectationFailedException(sprintf('Expected invocation at most %d time%s but it occurred %d time%s.', $this->allowedInvocations, $this->allowedInvocations !== 1 ? 's' : '', $actualInvocations, $actualInvocations !== 1 ? 's' : '')); + } + } + public function matches(BaseInvocation $invocation): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvokedCount extends \PHPUnit\Framework\MockObject\Rule\InvocationOrder +{ + private readonly int $expectedCount; + public function __construct(int $expectedCount) + { + $this->expectedCount = $expectedCount; + } + public function isNever(): bool + { + return $this->expectedCount === 0; + } + public function toString(): string + { + if ($this->expectedCount === 1) { + return 'invoked once'; + } + return sprintf('invoked %d times', $this->expectedCount); + } + public function matches(BaseInvocation $invocation): bool + { + return \true; + } + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + $actualCount = $this->numberOfInvocations(); + if ($actualCount !== $this->expectedCount) { + throw new ExpectationFailedException(sprintf('Method was expected to be called %d time%s, actually called %d time%s.', $this->expectedCount, $this->expectedCount !== 1 ? 's' : '', $actualCount, $actualCount !== 1 ? 's' : '')); + } + } + /** + * @throws ExpectationFailedException + */ + protected function invokedDo(BaseInvocation $invocation): void + { + $count = $this->numberOfInvocations(); + if ($count > $this->expectedCount) { + $message = $invocation->toString() . ' '; + $message .= match ($this->expectedCount) { + 0 => 'was not expected to be called', + 1 => 'was not expected to be called more than once', + default => sprintf('was not expected to be called more than %d times', $this->expectedCount), + }; + $message .= sprintf(', actually called %d time%s.', $count, $count !== 1 ? 's' : ''); + throw new ExpectationFailedException($message); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function is_string; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\InvalidArgumentException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +use PHPUnit\Framework\MockObject\MethodNameConstraint; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MethodName +{ + private Constraint $constraint; + /** + * @throws InvalidArgumentException + */ + public function __construct(Constraint|string $constraint) + { + if (is_string($constraint)) { + $constraint = new MethodNameConstraint($constraint); + } + $this->constraint = $constraint; + } + public function toString(): string + { + return 'method name ' . $this->constraint->toString(); + } + /** + * @param class-string $className + */ + public function failureDescription(string $className): string + { + if ($this->constraint instanceof MethodNameConstraint) { + return $className . '::' . $this->constraint->methodName() . '()'; + } + return $this->toString(); + } + /** + * @throws ExpectationFailedException + */ + public function matches(BaseInvocation $invocation): bool + { + return $this->matchesName($invocation->methodName()); + } + /** + * @throws ExpectationFailedException + */ + public function matchesName(string $methodName): bool + { + return (bool) $this->constraint->evaluate($methodName, '', \true); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function array_shift; +use function count; +use function is_array; +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +use PHPUnit\Framework\MockObject\NoMoreParameterSetsConfiguredException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class OrderedParameterSets implements \PHPUnit\Framework\MockObject\Rule\ParametersRule +{ + /** + * @var list + */ + private array $stack = []; + /** + * @var list + */ + private array $applied = []; + private int $numberOfConfiguredParameterSets; + /** + * @param list $stack + */ + public function __construct(array $stack) + { + foreach ($stack as $parameters) { + $this->stack[] = new \PHPUnit\Framework\MockObject\Rule\Parameters(is_array($parameters) ? $parameters : [$parameters]); + } + $this->numberOfConfiguredParameterSets = count($stack); + } + public function apply(BaseInvocation $invocation): void + { + if ($this->stack === []) { + throw new NoMoreParameterSetsConfiguredException($invocation, $this->numberOfConfiguredParameterSets); + } + $parameters = array_shift($this->stack); + $this->applied[] = $parameters; + $parameters->apply($invocation); + } + /** + * Checks if the invocation $invocation matches the current rules. If it + * does the rule will get the invoked() method called which should check + * if an expectation is met. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + if (count($this->applied) !== $this->numberOfConfiguredParameterSets && count($this->stack) > 0) { + throw new ExpectationFailedException(sprintf('Too many parameter sets given, %d out of %d expected parameter set%s %s been called.', count($this->applied), $this->numberOfConfiguredParameterSets, $this->numberOfConfiguredParameterSets !== 1 ? 's' : '', count($this->applied) !== 1 ? 'have' : 'has')); + } + foreach ($this->applied as $parameters) { + $parameters->verify(); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function assert; +use function count; +use function sprintf; +use Exception; +use PHPUnit\Framework\Constraint\Callback; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\Constraint\IsAnything; +use PHPUnit\Framework\Constraint\IsEqual; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +use PHPUnit\Util\Test; +use ReflectionException; +use ReflectionMethod; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Parameters implements \PHPUnit\Framework\MockObject\Rule\ParametersRule +{ + /** + * @var list + */ + private array $parameters = []; + private ?BaseInvocation $invocation = null; + private null|bool|ExpectationFailedException $parameterVerificationResult; + private bool $useAssertionCount = \true; + /** + * @param array $parameters + * + * @throws \PHPUnit\Framework\Exception + */ + public function __construct(array $parameters) + { + foreach ($parameters as $parameter) { + if (!$parameter instanceof Constraint) { + $parameter = new IsEqual($parameter); + } + $this->parameters[] = $parameter; + } + } + /** + * @throws Exception + */ + public function apply(BaseInvocation $invocation): void + { + $this->invocation = $invocation; + $this->parameterVerificationResult = null; + try { + $this->parameterVerificationResult = $this->doVerify(); + } catch (ExpectationFailedException $e) { + $this->parameterVerificationResult = $e; + throw $this->parameterVerificationResult; + } + } + /** + * Checks if the invocation $invocation matches the current rules. If it + * does the rule will get the invoked() method called which should check + * if an expectation is met. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + $this->doVerify(); + } + public function useAssertionCount(bool $useAssertionCount): void + { + $this->useAssertionCount = $useAssertionCount; + } + /** + * @throws ExpectationFailedException + */ + private function doVerify(): bool + { + if (isset($this->parameterVerificationResult)) { + return $this->guardAgainstDuplicateEvaluationOfParameterConstraints(); + } + if ($this->invocation === null) { + throw new ExpectationFailedException('Doubled method does not exist.'); + } + if (count($this->invocation->parameters()) < count($this->parameters)) { + $message = 'Parameter count for invocation %s is too low.'; + // The user called `->with($this->anything())`, but may have meant + // `->withAnyParameters()`. + // + // @see https://github.com/sebastianbergmann/phpunit-mock-objects/issues/199 + if (count($this->parameters) === 1 && $this->parameters[0]::class === IsAnything::class) { + $message .= "\nTo allow 0 or more parameters with any value, omit ->with() or use ->withAnyParameters() instead."; + } + $this->incrementAssertionCount(); + throw new ExpectationFailedException(sprintf($message, $this->invocation->toString())); + } + $parameters = $this->parameters($this->invocation); + foreach ($this->parameters as $i => $parameter) { + if ($parameter instanceof Callback && $parameter->isVariadic()) { + $other = $this->invocation->parameters(); + } else { + $other = $this->invocation->parameters()[$i]; + } + $this->incrementAssertionCount(); + $parameter->evaluate($other, sprintf('Parameter %s for invocation %s does not match expected value.', $parameters[$i] ?? (string) $i, $this->invocation->toString())); + } + return \true; + } + /** + * @throws ExpectationFailedException + */ + private function guardAgainstDuplicateEvaluationOfParameterConstraints(): bool + { + if ($this->parameterVerificationResult instanceof ExpectationFailedException) { + throw $this->parameterVerificationResult; + } + return (bool) $this->parameterVerificationResult; + } + private function incrementAssertionCount(): void + { + if ($this->useAssertionCount === \false) { + return; + } + Test::currentTestCase()->addToAssertionCount(1); + } + /** + * @return array + */ + private function parameters(BaseInvocation $invocation): array + { + $parameters = []; + try { + $reflector = new ReflectionMethod($invocation->className(), $invocation->methodName()); + foreach ($reflector->getParameters() as $parameter) { + assert($parameter->getPosition() >= 0); + $parameters[$parameter->getPosition()] = '$' . $parameter->getName(); + } + } catch (ReflectionException) { + } + return $parameters; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ParametersRule +{ + /** + * @throws ExpectationFailedException if the invocation violates the rule + */ + public function apply(BaseInvocation $invocation): void; + public function verify(): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function array_search; +use function array_shift; +use function count; +use function implode; +use function is_array; +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +use PHPUnit\Framework\MockObject\NoMoreParameterSetsConfiguredException; +final class UnorderedParameterSets implements \PHPUnit\Framework\MockObject\Rule\ParametersRule +{ + /** + * @var list + */ + private array $stack = []; + /** + * @var list + */ + private array $unapplied = []; + /** + * @var list + */ + private array $applied = []; + private int $numberOfConfiguredParameterSets; + /** + * @param list $stack + */ + public function __construct(array $stack) + { + foreach ($stack as $parameters) { + $this->stack[] = new \PHPUnit\Framework\MockObject\Rule\Parameters(is_array($parameters) ? $parameters : [$parameters]); + } + $this->unapplied = $this->stack; + $this->numberOfConfiguredParameterSets = count($stack); + } + public function apply(BaseInvocation $invocation): void + { + if ($this->unapplied === []) { + throw new NoMoreParameterSetsConfiguredException($invocation, $this->numberOfConfiguredParameterSets); + } + $checkedParameters = 0; + $unappliedParameters = count($this->unapplied); + while ($checkedParameters < $unappliedParameters) { + $checkedParameters++; + $parameters = array_shift($this->unapplied); + try { + $parameters->useAssertionCount(\false); + $parameters->apply($invocation); + $this->applied[] = $parameters; + $parameters->useAssertionCount(\true); + $parameters->apply($invocation); + break; + } catch (ExpectationFailedException $e) { + $this->unapplied[] = $parameters; + } + } + } + /** + * Checks if the invocation $invocation matches the current rules. If it + * does the rule will get the invoked() method called which should check + * if an expectation is met. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + if (count($this->applied) !== $this->numberOfConfiguredParameterSets && count($this->unapplied) > 0) { + $unappliedIndexes = []; + foreach ($this->unapplied as $parameters) { + $unappliedIndexes[] = array_search($parameters, $this->stack, \true); + } + throw new ExpectationFailedException(sprintf('%d out of %d expected parameter set%s %s called, index%s [' . implode(', ', $unappliedIndexes) . '] %s not called.', count($this->applied), $this->numberOfConfiguredParameterSets, $this->numberOfConfiguredParameterSets !== 1 ? 's' : '', count($this->applied) !== 1 ? 'were' : 'was', count($unappliedIndexes) !== 1 ? 'es' : '', count($unappliedIndexes) !== 1 ? 'were' : 'was')); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use function array_shift; +use function count; +use PHPUnit\Framework\MockObject\Invocation; +use PHPUnit\Framework\MockObject\NoMoreReturnValuesConfiguredException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ConsecutiveCalls implements \PHPUnit\Framework\MockObject\Stub\Stub +{ + /** + * @var array + */ + private array $stack; + private int $numberOfConfiguredReturnValues; + /** + * @param array $stack + */ + public function __construct(array $stack) + { + $this->stack = $stack; + $this->numberOfConfiguredReturnValues = count($stack); + } + /** + * @throws NoMoreReturnValuesConfiguredException + */ + public function invoke(Invocation $invocation): mixed + { + if ($this->stack === []) { + throw new NoMoreReturnValuesConfiguredException($invocation, $this->numberOfConfiguredReturnValues); + } + $value = array_shift($this->stack); + if ($value instanceof \PHPUnit\Framework\MockObject\Stub\Stub) { + $value = $value->invoke($invocation); + } + return $value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Exception implements \PHPUnit\Framework\MockObject\Stub\Stub +{ + private Throwable $exception; + public function __construct(Throwable $exception) + { + $this->exception = $exception; + } + /** + * @throws Throwable + */ + public function invoke(Invocation $invocation): never + { + throw $this->exception; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ReturnArgument implements \PHPUnit\Framework\MockObject\Stub\Stub +{ + private int $argumentIndex; + public function __construct(int $argumentIndex) + { + $this->argumentIndex = $argumentIndex; + } + public function invoke(Invocation $invocation): mixed + { + return $invocation->parameters()[$this->argumentIndex] ?? null; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use function call_user_func_array; +use PHPUnit\Framework\MockObject\Invocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReturnCallback implements \PHPUnit\Framework\MockObject\Stub\Stub +{ + /** + * @var callable + */ + private $callback; + public function __construct(callable $callback) + { + $this->callback = $callback; + } + public function invoke(Invocation $invocation): mixed + { + return call_user_func_array($this->callback, $invocation->parameters()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReturnReference implements \PHPUnit\Framework\MockObject\Stub\Stub +{ + private mixed $reference; + public function __construct(mixed &$reference) + { + $this->reference =& $reference; + } + public function invoke(Invocation $invocation): mixed + { + return $this->reference; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; +use PHPUnit\Framework\MockObject\RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReturnSelf implements \PHPUnit\Framework\MockObject\Stub\Stub +{ + /** + * @throws RuntimeException + */ + public function invoke(Invocation $invocation): object + { + return $invocation->object(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ReturnStub implements \PHPUnit\Framework\MockObject\Stub\Stub +{ + private mixed $value; + public function __construct(mixed $value) + { + $this->value = $value; + } + public function invoke(Invocation $invocation): mixed + { + return $this->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use function array_pop; +use function count; +use function is_array; +use PHPUnit\Framework\MockObject\Invocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ReturnValueMap implements \PHPUnit\Framework\MockObject\Stub\Stub +{ + /** + * @var array + */ + private array $valueMap; + /** + * @param array $valueMap + */ + public function __construct(array $valueMap) + { + $this->valueMap = $valueMap; + } + public function invoke(Invocation $invocation): mixed + { + $parameterCount = count($invocation->parameters()); + foreach ($this->valueMap as $map) { + if (!is_array($map) || $parameterCount !== count($map) - 1) { + continue; + } + $return = array_pop($map); + if ($invocation->parameters() === $map) { + return $return; + } + } + return null; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Stub +{ + /** + * Fakes the processing of the invocation $invocation by returning a + * specific value. + */ + public function invoke(Invocation $invocation): mixed; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function array_merge; +use PHPUnit\Framework\MockObject\Generator\Generator; +use PHPUnit\Framework\MockObject\Generator\ReflectionException; +use ReflectionClass; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class TestDoubleBuilder +{ + /** + * @var class-string|trait-string + */ + protected readonly string $type; + /** + * @var list + */ + protected array $methods = []; + protected bool $emptyMethodsArray = \false; + /** + * @var array + */ + protected array $constructorArgs = []; + protected bool $originalConstructor = \true; + protected bool $originalClone = \true; + protected bool $returnValueGeneration = \true; + /** + * @param class-string|trait-string $type + */ + public function __construct(string $type) + { + $this->type = $type; + } + /** + * Specifies the subset of methods to mock, requiring each to exist in the class. + * + * @param list $methods + * + * @throws CannotUseOnlyMethodsException + * @throws ReflectionException + * + * @return $this + */ + public function onlyMethods(array $methods): static + { + if ($methods === []) { + $this->emptyMethodsArray = \true; + return $this; + } + try { + $reflector = new ReflectionClass($this->type); + // @codeCoverageIgnoreStart + } catch (\ReflectionException $e) { + throw new ReflectionException($e->getMessage(), $e->getCode(), $e); + // @codeCoverageIgnoreEnd + } + foreach ($methods as $method) { + if (!$reflector->hasMethod($method)) { + throw new \PHPUnit\Framework\MockObject\CannotUseOnlyMethodsException($this->type, $method); + } + } + $this->methods = array_merge($this->methods, $methods); + return $this; + } + /** + * Specifies the arguments for the constructor. + * + * @param array $arguments + * + * @return $this + */ + public function setConstructorArgs(array $arguments): static + { + $this->constructorArgs = $arguments; + return $this; + } + /** + * Disables the invocation of the original constructor. + * + * @return $this + */ + public function disableOriginalConstructor(): static + { + $this->originalConstructor = \false; + return $this; + } + /** + * Enables the invocation of the original constructor. + * + * @return $this + */ + public function enableOriginalConstructor(): static + { + $this->originalConstructor = \true; + return $this; + } + /** + * Disables the invocation of the original clone constructor. + * + * @return $this + */ + public function disableOriginalClone(): static + { + $this->originalClone = \false; + return $this; + } + /** + * Enables the invocation of the original clone constructor. + * + * @return $this + */ + public function enableOriginalClone(): static + { + $this->originalClone = \true; + return $this; + } + /** + * @return $this + */ + public function enableAutoReturnValueGeneration(): static + { + $this->returnValueGeneration = \true; + return $this; + } + /** + * @return $this + */ + public function disableAutoReturnValueGeneration(): static + { + $this->returnValueGeneration = \false; + return $this; + } + protected function getTestDouble(?string $testDoubleClassName, bool $mockObject): \PHPUnit\Framework\MockObject\MockObject|\PHPUnit\Framework\MockObject\Stub + { + return (new Generator())->testDouble($this->type, $mockObject, !$this->emptyMethodsArray ? $this->methods : null, $this->constructorArgs, $testDoubleClassName ?? '', $this->originalConstructor, $this->originalClone, $this->returnValueGeneration); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function assert; +use PHPUnit\Framework\MockObject\Generator\ClassIsAnonymousException; +use PHPUnit\Framework\MockObject\Generator\ClassIsEnumerationException; +use PHPUnit\Framework\MockObject\Generator\ClassIsFinalException; +use PHPUnit\Framework\MockObject\Generator\DuplicateMethodException; +use PHPUnit\Framework\MockObject\Generator\InvalidClassNameException; +use PHPUnit\Framework\MockObject\Generator\InvalidMethodNameException; +use PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException; +use PHPUnit\Framework\MockObject\Generator\ReflectionException; +use PHPUnit\Framework\MockObject\Generator\RuntimeException; +use PHPUnit\Framework\MockObject\Generator\UnknownTypeException; +/** + * @template StubbedType + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TestStubBuilder extends \PHPUnit\Framework\MockObject\TestDoubleBuilder +{ + /** + * @var ?class-string + */ + private ?string $stubClassName = null; + /** + * Creates a test stub using a fluent interface. + * + * @throws ClassIsAnonymousException + * @throws ClassIsEnumerationException + * @throws ClassIsFinalException + * @throws DuplicateMethodException + * @throws InvalidClassNameException + * @throws InvalidMethodNameException + * @throws NameAlreadyInUseException + * @throws ReflectionException + * @throws RuntimeException + * @throws UnknownTypeException + * + * @return Stub&StubbedType + */ + public function getStub(): \PHPUnit\Framework\MockObject\Stub + { + $object = $this->getTestDouble($this->stubClassName, \false); + assert($object instanceof $this->type); + assert($object instanceof \PHPUnit\Framework\MockObject\Stub); + assert(!$object instanceof \PHPUnit\Framework\MockObject\MockObject); + return $object; + } + /** + * Specifies the name for the mock class. + * + * @param class-string $name + * + * @return $this + */ + public function setStubClassName(string $name): self + { + $this->stubClassName = $name; + return $this; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +enum NativeType : string +{ + case Array = 'array'; + case Bool = 'bool'; + case Callable = 'callable'; + case ClosedResource = 'resource (closed)'; + case Float = 'float'; + case Int = 'int'; + case Iterable = 'iterable'; + case Null = 'null'; + case Numeric = 'numeric'; + case Object = 'object'; + case Resource = 'resource'; + case Scalar = 'scalar'; + case String = 'string'; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Reorderable +{ + public function sortId(): string; + /** + * @return list + */ + public function provides(): array; + /** + * @return list + */ + public function requires(): array; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface SelfDescribing +{ + /** + * Returns a string representation of the object. + */ + public function toString(): string; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use Countable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Test extends Countable +{ + public function run(): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function array_merge; +use function assert; +use PHPUnit\Metadata\Api\DataProvider; +use PHPUnit\Metadata\Api\Groups; +use PHPUnit\Metadata\Api\ProvidedData; +use PHPUnit\Metadata\Api\Requirements; +use PHPUnit\Metadata\BackupGlobals; +use PHPUnit\Metadata\BackupStaticProperties; +use PHPUnit\Metadata\ExcludeGlobalVariableFromBackup; +use PHPUnit\Metadata\ExcludeStaticPropertyFromBackup; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Metadata\PreserveGlobalState; +use PHPUnit\Runner\ErrorHandler; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use ReflectionClass; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestBuilder +{ + /** + * @param ReflectionClass $theClass + * @param non-empty-string $methodName + * @param list $groups + * + * @throws InvalidDataProviderException + */ + public function build(ReflectionClass $theClass, string $methodName, array $groups = []): \PHPUnit\Framework\Test + { + $className = $theClass->getName(); + $data = null; + if ($this->requirementsSatisfied($className, $methodName)) { + try { + ErrorHandler::instance()->enterTestCaseContext($className, $methodName); + $data = (new DataProvider())->providedData($className, $methodName); + } finally { + ErrorHandler::instance()->leaveTestCaseContext(); + } + } + if ($data !== null) { + return $this->buildDataProviderTestSuite($methodName, $className, $data, $this->shouldTestMethodBeRunInSeparateProcess($className, $methodName), $this->shouldGlobalStateBePreserved($className, $methodName), $this->backupSettings($className, $methodName), $groups); + } + $test = new $className($methodName); + $this->configureTestCase($test, $this->shouldTestMethodBeRunInSeparateProcess($className, $methodName), $this->shouldGlobalStateBePreserved($className, $methodName), $this->backupSettings($className, $methodName)); + return $test; + } + /** + * @param non-empty-string $methodName + * @param class-string $className + * @param array $data + * @param array{backupGlobals: ?true, backupGlobalsExcludeList: list, backupStaticProperties: ?true, backupStaticPropertiesExcludeList: array>} $backupSettings + * @param list $groups + */ + private function buildDataProviderTestSuite(string $methodName, string $className, array $data, bool $runTestInSeparateProcess, ?bool $preserveGlobalState, array $backupSettings, array $groups): \PHPUnit\Framework\DataProviderTestSuite + { + $dataProviderTestSuite = \PHPUnit\Framework\DataProviderTestSuite::empty($className . '::' . $methodName); + $groups = array_merge($groups, (new Groups())->groups($className, $methodName)); + foreach ($data as $_dataName => $_data) { + $_test = new $className($methodName); + $_test->setData($_dataName, $_data->value()); + $this->configureTestCase($_test, $runTestInSeparateProcess, $preserveGlobalState, $backupSettings); + $dataProviderTestSuite->addTest($_test, $groups); + } + return $dataProviderTestSuite; + } + /** + * @param array{backupGlobals: ?true, backupGlobalsExcludeList: list, backupStaticProperties: ?true, backupStaticPropertiesExcludeList: array>} $backupSettings + */ + private function configureTestCase(\PHPUnit\Framework\TestCase $test, bool $runTestInSeparateProcess, ?bool $preserveGlobalState, array $backupSettings): void + { + if ($runTestInSeparateProcess) { + $test->setRunTestInSeparateProcess(\true); + } + if ($preserveGlobalState !== null) { + $test->setPreserveGlobalState($preserveGlobalState); + } + if ($backupSettings['backupGlobals'] !== null) { + $test->setBackupGlobals($backupSettings['backupGlobals']); + } else { + $test->setBackupGlobals(ConfigurationRegistry::get()->backupGlobals()); + } + $test->setBackupGlobalsExcludeList($backupSettings['backupGlobalsExcludeList']); + if ($backupSettings['backupStaticProperties'] !== null) { + $test->setBackupStaticProperties($backupSettings['backupStaticProperties']); + } else { + $test->setBackupStaticProperties(ConfigurationRegistry::get()->backupStaticProperties()); + } + $test->setBackupStaticPropertiesExcludeList($backupSettings['backupStaticPropertiesExcludeList']); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @return array{backupGlobals: ?true, backupGlobalsExcludeList: list, backupStaticProperties: ?true, backupStaticPropertiesExcludeList: array>} + */ + private function backupSettings(string $className, string $methodName): array + { + $metadataForClass = MetadataRegistry::parser()->forClass($className); + $metadataForMethod = MetadataRegistry::parser()->forMethod($className, $methodName); + $metadataForClassAndMethod = MetadataRegistry::parser()->forClassAndMethod($className, $methodName); + $backupGlobals = null; + $backupGlobalsExcludeList = []; + if ($metadataForMethod->isBackupGlobals()->isNotEmpty()) { + $metadata = $metadataForMethod->isBackupGlobals()->asArray()[0]; + assert($metadata instanceof BackupGlobals); + if ($metadata->enabled()) { + $backupGlobals = \true; + } + } elseif ($metadataForClass->isBackupGlobals()->isNotEmpty()) { + $metadata = $metadataForClass->isBackupGlobals()->asArray()[0]; + assert($metadata instanceof BackupGlobals); + if ($metadata->enabled()) { + $backupGlobals = \true; + } + } + foreach ($metadataForClassAndMethod->isExcludeGlobalVariableFromBackup() as $metadata) { + assert($metadata instanceof ExcludeGlobalVariableFromBackup); + $backupGlobalsExcludeList[] = $metadata->globalVariableName(); + } + $backupStaticProperties = null; + $backupStaticPropertiesExcludeList = []; + if ($metadataForMethod->isBackupStaticProperties()->isNotEmpty()) { + $metadata = $metadataForMethod->isBackupStaticProperties()->asArray()[0]; + assert($metadata instanceof BackupStaticProperties); + if ($metadata->enabled()) { + $backupStaticProperties = \true; + } + } elseif ($metadataForClass->isBackupStaticProperties()->isNotEmpty()) { + $metadata = $metadataForClass->isBackupStaticProperties()->asArray()[0]; + assert($metadata instanceof BackupStaticProperties); + if ($metadata->enabled()) { + $backupStaticProperties = \true; + } + } + foreach ($metadataForClassAndMethod->isExcludeStaticPropertyFromBackup() as $metadata) { + assert($metadata instanceof ExcludeStaticPropertyFromBackup); + if (!isset($backupStaticPropertiesExcludeList[$metadata->className()])) { + $backupStaticPropertiesExcludeList[$metadata->className()] = []; + } + $backupStaticPropertiesExcludeList[$metadata->className()][] = $metadata->propertyName(); + } + return ['backupGlobals' => $backupGlobals, 'backupGlobalsExcludeList' => $backupGlobalsExcludeList, 'backupStaticProperties' => $backupStaticProperties, 'backupStaticPropertiesExcludeList' => $backupStaticPropertiesExcludeList]; + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + private function shouldGlobalStateBePreserved(string $className, string $methodName): ?bool + { + $metadataForMethod = MetadataRegistry::parser()->forMethod($className, $methodName); + if ($metadataForMethod->isPreserveGlobalState()->isNotEmpty()) { + $metadata = $metadataForMethod->isPreserveGlobalState()->asArray()[0]; + assert($metadata instanceof PreserveGlobalState); + return $metadata->enabled(); + } + $metadataForClass = MetadataRegistry::parser()->forClass($className); + if ($metadataForClass->isPreserveGlobalState()->isNotEmpty()) { + $metadata = $metadataForClass->isPreserveGlobalState()->asArray()[0]; + assert($metadata instanceof PreserveGlobalState); + return $metadata->enabled(); + } + return null; + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + private function shouldTestMethodBeRunInSeparateProcess(string $className, string $methodName): bool + { + if (MetadataRegistry::parser()->forClass($className)->isRunTestsInSeparateProcesses()->isNotEmpty()) { + return \true; + } + if (MetadataRegistry::parser()->forMethod($className, $methodName)->isRunInSeparateProcess()->isNotEmpty()) { + return \true; + } + return \false; + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + private function requirementsSatisfied(string $className, string $methodName): bool + { + return (new Requirements())->requirementsNotSatisfiedFor($className, $methodName) === []; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function array_any; +use function array_keys; +use function array_merge; +use function array_reverse; +use function array_values; +use function assert; +use function chdir; +use function class_exists; +use function clearstatcache; +use function count; +use function defined; +use function error_clear_last; +use function explode; +use function fclose; +use function getcwd; +use function implode; +use function in_array; +use function ini_get; +use function ini_set; +use function is_array; +use function is_callable; +use function is_int; +use function is_object; +use function is_string; +use function is_writable; +use function libxml_clear_errors; +use function method_exists; +use function ob_end_clean; +use function ob_get_clean; +use function ob_get_contents; +use function ob_get_level; +use function ob_start; +use function preg_match; +use function preg_replace; +use function putenv; +use function restore_error_handler; +use function restore_exception_handler; +use function set_error_handler; +use function set_exception_handler; +use function sprintf; +use function str_contains; +use function str_starts_with; +use function stream_get_contents; +use function stream_get_meta_data; +use function tmpfile; +use function trim; +use AssertionError; +use PHPUnitPHAR\DeepCopy\DeepCopy; +use PHPUnit\Event; +use PHPUnit\Event\NoPreviousThrowableException; +use PHPUnit\Framework\Constraint\Exception as ExceptionConstraint; +use PHPUnit\Framework\Constraint\ExceptionCode; +use PHPUnit\Framework\Constraint\ExceptionMessageIsOrContains; +use PHPUnit\Framework\Constraint\ExceptionMessageMatchesRegularExpression; +use PHPUnit\Framework\MockObject\Exception as MockObjectException; +use PHPUnit\Framework\MockObject\Generator\Generator as MockGenerator; +use PHPUnit\Framework\MockObject\MockBuilder; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\MockObjectInternal; +use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount as AnyInvokedCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastCount as InvokedAtLeastCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastOnce as InvokedAtLeastOnceMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtMostCount as InvokedAtMostCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedCount; +use PHPUnit\Framework\MockObject\Rule\InvokedCount as InvokedCountMatcher; +use PHPUnit\Framework\MockObject\Stub; +use PHPUnit\Framework\MockObject\Stub\Exception as ExceptionStub; +use PHPUnit\Framework\MockObject\TestStubBuilder; +use PHPUnit\Framework\TestSize\TestSize; +use PHPUnit\Framework\TestStatus\TestStatus; +use PHPUnit\Metadata\Api\Groups; +use PHPUnit\Metadata\Api\HookMethods; +use PHPUnit\Metadata\Api\Requirements; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Metadata\WithEnvironmentVariable; +use PHPUnit\Runner\BackedUpEnvironmentVariable; +use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollector; +use PHPUnit\Runner\HookMethodCollection; +use PHPUnit\Runner\ShutdownHandler; +use PHPUnit\TestRunner\TestResult\PassedTests; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use PHPUnit\Util\Exporter; +use PHPUnit\Util\Sanitizer; +use PHPUnit\Util\Test as TestUtil; +use ReflectionClass; +use ReflectionException; +use ReflectionMethod; +use ReflectionObject; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException; +use PHPUnitPHAR\SebastianBergmann\Comparator\Comparator; +use PHPUnitPHAR\SebastianBergmann\Comparator\Factory as ComparatorFactory; +use PHPUnitPHAR\SebastianBergmann\Diff\Differ; +use PHPUnitPHAR\SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder; +use PHPUnitPHAR\SebastianBergmann\GlobalState\ExcludeList as GlobalStateExcludeList; +use PHPUnitPHAR\SebastianBergmann\GlobalState\Restorer; +use PHPUnitPHAR\SebastianBergmann\GlobalState\Snapshot; +use PHPUnitPHAR\SebastianBergmann\Invoker\TimeoutException; +use PHPUnitPHAR\SebastianBergmann\ObjectEnumerator\Enumerator; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class TestCase extends \PHPUnit\Framework\Assert implements \PHPUnit\Framework\Reorderable, \PHPUnit\Framework\SelfDescribing, \PHPUnit\Framework\Test +{ + private ?bool $backupGlobals = null; + /** + * @var list + */ + private array $backupGlobalsExcludeList = []; + private ?bool $backupStaticProperties = null; + /** + * @var array> + */ + private array $backupStaticPropertiesExcludeList = []; + private ?Snapshot $snapshot = null; + /** + * @var list + */ + private ?array $backupGlobalErrorHandlers = null; + /** + * @var list + */ + private ?array $backupGlobalExceptionHandlers = null; + private ?bool $runTestInSeparateProcess = null; + private bool $preserveGlobalState = \false; + private bool $inIsolation = \false; + private ?string $expectedException = null; + private ?string $expectedExceptionMessage = null; + private ?string $expectedExceptionMessageRegExp = null; + private null|int|string $expectedExceptionCode = null; + /** + * @var list + */ + private array $backupEnvironmentVariables = []; + /** + * @var list + */ + private array $providedTests = []; + /** + * @var array + */ + private array $data = []; + private int|string $dataName = ''; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @var list + */ + private array $groups = []; + /** + * @var list + */ + private array $dependencies = []; + /** + * @var array> + */ + private array $dependencyInput = []; + /** + * @var list + */ + private array $mockObjects = []; + private TestStatus $status; + /** + * @var non-negative-int + */ + private int $numberOfAssertionsPerformed = 0; + private mixed $testResult = null; + private string $output = ''; + private ?string $outputExpectedRegex = null; + private ?string $outputExpectedString = null; + private bool $outputBufferingActive = \false; + private int $outputBufferingLevel; + private bool $outputRetrievedForAssertion = \false; + private bool $doesNotPerformAssertions = \false; + private bool $expectErrorLog = \false; + /** + * @var list + */ + private array $customComparators = []; + private ?Event\Code\TestMethod $testValueObjectForEvents = null; + private bool $wasPrepared = \false; + /** + * @var array + */ + private array $failureTypes = []; + /** + * @var list + */ + private array $expectedUserDeprecationMessage = []; + /** + * @var list + */ + private array $expectedUserDeprecationMessageRegularExpression = []; + /** + * @var false|resource + */ + private mixed $errorLogCapture = \false; + private false|string $previousErrorLogTarget = \false; + /** + * @param non-empty-string $name + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function __construct(string $name) + { + $this->methodName = $name; + $this->status = TestStatus::unknown(); + if (is_callable($this->sortId(), \true)) { + $this->providedTests = [new \PHPUnit\Framework\ExecutionOrderDependency($this->sortId())]; + } + } + /** + * This method is called before the first test of this test class is run. + * + * @codeCoverageIgnore + */ + public static function setUpBeforeClass(): void + { + } + /** + * This method is called after the last test of this test class is run. + * + * @codeCoverageIgnore + */ + public static function tearDownAfterClass(): void + { + } + /** + * This method is called before each test. + * + * @codeCoverageIgnore + */ + protected function setUp(): void + { + } + /** + * Performs assertions shared by all tests of a test case. + * + * This method is called between setUp() and test. + * + * @codeCoverageIgnore + */ + protected function assertPreConditions(): void + { + } + /** + * Performs assertions shared by all tests of a test case. + * + * This method is called between test and tearDown(). + * + * @codeCoverageIgnore + */ + protected function assertPostConditions(): void + { + } + /** + * This method is called after each test. + * + * @codeCoverageIgnore + */ + protected function tearDown(): void + { + } + /** + * Returns a string representation of the test case. + * + * @throws Exception + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function toString(): string + { + $buffer = sprintf('%s::%s', (new ReflectionClass($this))->getName(), $this->methodName); + return $buffer . $this->dataSetAsStringWithData(); + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function count(): int + { + return 1; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function status(): TestStatus + { + return $this->status; + } + /** + * @throws \PHPUnit\Runner\Exception + * @throws \PHPUnit\Util\Exception + * @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException + * @throws \SebastianBergmann\Template\InvalidArgumentException + * @throws Exception + * @throws NoPreviousThrowableException + * @throws ProcessIsolationException + * @throws UnintentionallyCoveredCodeException + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function run(): void + { + if (!$this->handleDependencies()) { + return; + } + if (!$this->shouldRunInSeparateProcess() || $this->requirementsNotSatisfied()) { + try { + ShutdownHandler::setMessage(sprintf('Fatal error: Premature end of PHP process when running %s.', $this->toString())); + (new \PHPUnit\Framework\TestRunner())->run($this); + } finally { + ShutdownHandler::resetMessage(); + } + return; + } + (new \PHPUnit\Framework\SeparateProcessTestRunner())->run($this, $this->preserveGlobalState, $this->requiresXdebug()); + } + /** + * @return list + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function groups(): array + { + return $this->groups; + } + /** + * @param list $groups + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setGroups(array $groups): void + { + $this->groups = $groups; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function nameWithDataSet(): string + { + return $this->methodName . $this->dataSetAsString(); + } + /** + * @return non-empty-string + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function name(): string + { + return $this->methodName; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function size(): TestSize + { + return (new Groups())->size(static::class, $this->methodName); + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + * + * @phpstan-assert-if-true non-empty-string $this->output() + */ + final public function hasUnexpectedOutput(): bool + { + if ($this->output === '') { + return \false; + } + if ($this->expectsOutput()) { + return \false; + } + return \true; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function output(): string + { + if (!$this->outputBufferingActive) { + return $this->output; + } + return (string) ob_get_contents(); + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function doesNotPerformAssertions(): bool + { + return $this->doesNotPerformAssertions; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function expectsOutput(): bool + { + return $this->hasExpectationOnOutput() || $this->outputRetrievedForAssertion; + } + /** + * @throws Throwable + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function runBare(): void + { + $emitter = Event\Facade::emitter(); + error_clear_last(); + clearstatcache(); + $emitter->testPreparationStarted($this->valueObjectForEvents()); + $this->snapshotGlobalState(); + $this->snapshotGlobalErrorExceptionHandlers(); + $this->handleEnvironmentVariables(); + $this->startOutputBuffering(); + $hookMethods = (new HookMethods())->hookMethods(static::class); + $hasMetRequirements = \false; + $this->numberOfAssertionsPerformed = 0; + $currentWorkingDirectory = getcwd(); + try { + $this->checkRequirements(); + $hasMetRequirements = \true; + if ($this->inIsolation) { + // @codeCoverageIgnoreStart + $this->invokeBeforeClassHookMethods($hookMethods, $emitter); + // @codeCoverageIgnoreEnd + } + if (method_exists(static::class, $this->methodName) && MetadataRegistry::parser()->forClassAndMethod(static::class, $this->methodName)->isDoesNotPerformAssertions()->isNotEmpty()) { + $this->doesNotPerformAssertions = \true; + } + $this->invokeBeforeTestHookMethods($hookMethods, $emitter); + $this->invokePreConditionHookMethods($hookMethods, $emitter); + $emitter->testPrepared($this->valueObjectForEvents()); + $this->wasPrepared = \true; + $this->testResult = $this->runTest(); + $this->verifyDeprecationExpectations(); + $this->verifyMockObjects(); + $this->invokePostConditionHookMethods($hookMethods, $emitter); + $this->status = TestStatus::success(); + } catch (\PHPUnit\Framework\IncompleteTest $e) { + $this->status = TestStatus::incomplete($e->getMessage()); + $emitter->testMarkedAsIncomplete($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($e)); + } catch (\PHPUnit\Framework\SkippedTest $e) { + $this->status = TestStatus::skipped($e->getMessage()); + $emitter->testSkipped($this->valueObjectForEvents(), $e->getMessage()); + } catch (AssertionError|\PHPUnit\Framework\AssertionFailedError $e) { + $this->handleExceptionFromInvokedCountMockObjectRule($e); + if (!$this->wasPrepared) { + $this->wasPrepared = \true; + $emitter->testPreparationFailed($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($e)); + } + $this->status = TestStatus::failure($e->getMessage()); + $emitter->testFailed($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($e), Event\Code\ComparisonFailureBuilder::from($e)); + } catch (TimeoutException $e) { + } catch (Throwable $_e) { + if ($this->isRegisteredFailure($_e)) { + $this->status = TestStatus::failure($_e->getMessage()); + $emitter->testFailed($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($_e), null); + } else { + $e = $this->transformException($_e); + $this->status = TestStatus::error($e->getMessage()); + if (!$this->wasPrepared) { + if ($e instanceof \PHPUnit\Framework\AssertionFailedError) { + $emitter->testPreparationFailed($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($e)); + } else { + $emitter->testPreparationErrored($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($e)); + } + } + $emitter->testErrored($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($e)); + } + } + $outputBufferingStopped = \false; + if (!isset($e) && $this->hasExpectationOnOutput() && $this->stopOutputBuffering()) { + $outputBufferingStopped = \true; + try { + $this->performAssertionsOnOutput(); + } catch (\PHPUnit\Framework\ExpectationFailedException $e) { + } + } + try { + $this->mockObjects = []; + /** @phpstan-ignore catch.neverThrown */ + } catch (Throwable $e) { + Event\Facade::emitter()->testErrored($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($e)); + } + // Tear down the fixture. An exception raised in tearDown() will be + // caught and passed on when no exception was raised before. + try { + if ($hasMetRequirements) { + $this->invokeAfterTestHookMethods($hookMethods, $emitter); + if ($this->inIsolation) { + // @codeCoverageIgnoreStart + $this->invokeAfterClassHookMethods($hookMethods, $emitter); + // @codeCoverageIgnoreEnd + } + } + } catch (AssertionError|\PHPUnit\Framework\AssertionFailedError $e) { + $this->status = TestStatus::failure($e->getMessage()); + $emitter->testFailed($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($e), Event\Code\ComparisonFailureBuilder::from($e)); + } catch (Throwable $exceptionRaisedDuringTearDown) { + if (!isset($e) || $e instanceof \PHPUnit\Framework\SkippedWithMessageException) { + $this->status = TestStatus::error($exceptionRaisedDuringTearDown->getMessage()); + $e = $exceptionRaisedDuringTearDown; + $emitter->testErrored($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($exceptionRaisedDuringTearDown)); + } + } + if (!isset($e) && !isset($_e)) { + $emitter->testPassed($this->valueObjectForEvents()); + if (!$this->usesDataProvider()) { + PassedTests::instance()->testMethodPassed($this->valueObjectForEvents(), $this->testResult); + } + } + if (!$outputBufferingStopped) { + $this->stopOutputBuffering(); + } + clearstatcache(); + if ($currentWorkingDirectory !== \false && $currentWorkingDirectory !== getcwd()) { + chdir($currentWorkingDirectory); + } + $this->restoreEnvironmentVariables(); + $this->restoreGlobalErrorExceptionHandlers(); + $this->restoreGlobalState(); + $this->unregisterCustomComparators(); + libxml_clear_errors(); + $this->testValueObjectForEvents = null; + if (isset($e)) { + $this->onNotSuccessfulTest($e); + } + } + /** + * @param list $dependencies + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setDependencies(array $dependencies): void + { + $this->dependencies = $dependencies; + } + /** + * @param array> $dependencyInput + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ + final public function setDependencyInput(array $dependencyInput): void + { + $this->dependencyInput = $dependencyInput; + } + /** + * @return array> + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function dependencyInput(): array + { + return $this->dependencyInput; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function hasDependencyInput(): bool + { + return $this->dependencyInput !== []; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setBackupGlobals(bool $backupGlobals): void + { + $this->backupGlobals = $backupGlobals; + } + /** + * @param list $backupGlobalsExcludeList + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setBackupGlobalsExcludeList(array $backupGlobalsExcludeList): void + { + $this->backupGlobalsExcludeList = $backupGlobalsExcludeList; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setBackupStaticProperties(bool $backupStaticProperties): void + { + $this->backupStaticProperties = $backupStaticProperties; + } + /** + * @param array> $backupStaticPropertiesExcludeList + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setBackupStaticPropertiesExcludeList(array $backupStaticPropertiesExcludeList): void + { + $this->backupStaticPropertiesExcludeList = $backupStaticPropertiesExcludeList; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setRunTestInSeparateProcess(bool $runTestInSeparateProcess): void + { + if ($this->runTestInSeparateProcess === null) { + $this->runTestInSeparateProcess = $runTestInSeparateProcess; + } + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setPreserveGlobalState(bool $preserveGlobalState): void + { + $this->preserveGlobalState = $preserveGlobalState; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ + final public function setInIsolation(bool $inIsolation): void + { + $this->inIsolation = $inIsolation; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ + final public function result(): mixed + { + return $this->testResult; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setResult(mixed $result): void + { + $this->testResult = $result; + } + /** + * @template RealInstanceType of object + * + * @param class-string $type + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function registerMockObject(string $type, MockObject $mockObject): void + { + assert($mockObject instanceof MockObjectInternal); + $this->mockObjects[] = ['type' => $type, 'mockObject' => $mockObject]; + } + /** + * @param non-negative-int $count + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function addToAssertionCount(int $count): void + { + assert($count >= 0); + $this->numberOfAssertionsPerformed += $count; + } + /** + * @return non-negative-int + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function numberOfAssertionsPerformed(): int + { + return $this->numberOfAssertionsPerformed; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function usesDataProvider(): bool + { + return $this->data !== []; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function dataName(): int|string + { + return $this->dataName; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function dataSetAsString(): string + { + if ($this->data !== []) { + if (is_int($this->dataName)) { + return sprintf(' with data set #%s', $this->dataName); + } + return sprintf(' with data set "%s"', Sanitizer::sanitizeBidirectionalControlCharacters($this->dataName)); + } + return ''; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function dataSetAsStringWithData(): string + { + if ($this->data === []) { + return ''; + } + return sprintf('%s with data (%s)', $this->dataSetAsFilterString(), Exporter::shortenedRecursiveExport($this->data)); + } + /** + * @return array + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function providedData(): array + { + return $this->data; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function sortId(): string + { + $id = $this->methodName; + if (!str_contains($id, '::')) { + $id = static::class . '::' . $id; + } + if ($this->usesDataProvider()) { + $id .= $this->dataSetAsString(); + } + return $id; + } + /** + * @return list + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function provides(): array + { + return $this->providedTests; + } + /** + * @return list + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function requires(): array + { + return $this->dependencies; + } + /** + * @param array $data + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setData(int|string $dataName, array $data): void + { + $this->dataName = $dataName; + $this->data = $data; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function valueObjectForEvents(): Event\Code\TestMethod + { + if ($this->testValueObjectForEvents !== null) { + return $this->testValueObjectForEvents; + } + $this->testValueObjectForEvents = Event\Code\TestMethodBuilder::fromTestCase($this); + return $this->testValueObjectForEvents; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function wasPrepared(): bool + { + return $this->wasPrepared; + } + /** + * Returns a matcher that matches when the method is executed + * zero or more times. + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/6461 + */ + final protected function any(): AnyInvokedCountMatcher + { + Event\Facade::emitter()->testTriggeredPhpunitDeprecation($this->testValueObjectForEvents, 'The any() invoked count expectation is deprecated and will be removed in PHPUnit 14. ' . 'Use a test stub instead or configure a real invocation count expectation.'); + return new AnyInvokedCountMatcher(); + } + /** + * Returns a matcher that matches when the method is never executed. + */ + final protected function never(): InvokedCountMatcher + { + return new InvokedCountMatcher(0); + } + /** + * Returns a matcher that matches when the method is executed + * at least N times. + */ + final protected function atLeast(int $requiredInvocations): InvokedAtLeastCountMatcher + { + if ($requiredInvocations < 1) { + Event\Facade::emitter()->testTriggeredPhpunitDeprecation($this->valueObjectForEvents(), 'Calling atLeast() with an argument that is not positive is deprecated.' . PHP_EOL . 'This will become an error in PHPUnit 14.'); + } + return new InvokedAtLeastCountMatcher($requiredInvocations); + } + /** + * Returns a matcher that matches when the method is executed at least once. + */ + final protected function atLeastOnce(): InvokedAtLeastOnceMatcher + { + return new InvokedAtLeastOnceMatcher(); + } + /** + * Returns a matcher that matches when the method is executed exactly once. + */ + final protected function once(): InvokedCountMatcher + { + return new InvokedCountMatcher(1); + } + /** + * Returns a matcher that matches when the method is executed + * exactly $count times. + */ + final protected function exactly(int $count): InvokedCountMatcher + { + return new InvokedCountMatcher($count); + } + /** + * Returns a matcher that matches when the method is executed + * at most N times. + */ + final protected function atMost(int $allowedInvocations): InvokedAtMostCountMatcher + { + return new InvokedAtMostCountMatcher($allowedInvocations); + } + final protected function throwException(Throwable $exception): ExceptionStub + { + return new ExceptionStub($exception); + } + final protected function getActualOutputForAssertion(): string + { + $this->outputRetrievedForAssertion = \true; + return $this->output(); + } + final protected function expectOutputRegex(string $expectedRegex): void + { + $this->outputExpectedRegex = $expectedRegex; + } + final protected function expectOutputString(string $expectedString): void + { + $this->outputExpectedString = $expectedString; + } + final protected function expectErrorLog(): void + { + $this->expectErrorLog = \true; + } + /** + * @param class-string $exception + */ + final protected function expectException(string $exception): void + { + $this->expectedException = $exception; + } + final protected function expectExceptionCode(int|string $code): void + { + $this->expectedExceptionCode = $code; + } + final protected function expectExceptionMessage(string $message): void + { + $this->expectedExceptionMessage = $message; + } + final protected function expectExceptionMessageMatches(string $regularExpression): void + { + $this->expectedExceptionMessageRegExp = $regularExpression; + } + /** + * Sets up an expectation for an exception to be raised by the code under test. + * Information for expected exception class, expected exception message, and + * expected exception code are retrieved from a given Exception object. + */ + final protected function expectExceptionObject(Throwable $exception): void + { + $this->expectException($exception::class); + $this->expectExceptionMessage($exception->getMessage()); + $this->expectExceptionCode($exception->getCode()); + } + final protected function expectNotToPerformAssertions(): void + { + $this->doesNotPerformAssertions = \true; + } + /** + * @param non-empty-string $expectedUserDeprecationMessage + */ + final protected function expectUserDeprecationMessage(string $expectedUserDeprecationMessage): void + { + $this->expectedUserDeprecationMessage[] = $expectedUserDeprecationMessage; + } + /** + * @param non-empty-string $expectedUserDeprecationMessageRegularExpression + */ + final protected function expectUserDeprecationMessageMatches(string $expectedUserDeprecationMessageRegularExpression): void + { + $this->expectedUserDeprecationMessageRegularExpression[] = $expectedUserDeprecationMessageRegularExpression; + } + /** + * Returns a builder object to create mock objects using a fluent interface. + * + * @template RealInstanceType of object + * + * @param class-string $className + * + * @return MockBuilder + */ + final protected function getMockBuilder(string $className): MockBuilder + { + return new MockBuilder($this, $className); + } + final protected function registerComparator(Comparator $comparator): void + { + ComparatorFactory::getInstance()->register($comparator); + Event\Facade::emitter()->testRegisteredComparator($comparator::class); + $this->customComparators[] = $comparator; + } + /** + * @param class-string $classOrInterface + */ + final protected function registerFailureType(string $classOrInterface): void + { + $this->failureTypes[$classOrInterface] = \true; + } + /** + * Creates a mock object for the specified interface or class. + * + * @template RealInstanceType of object + * + * @param class-string $type + * + * @throws InvalidArgumentException + * @throws MockObjectException + * @throws NoPreviousThrowableException + * + * @return MockObject&RealInstanceType + */ + final protected function createMock(string $type): MockObject + { + $mock = (new MockGenerator())->testDouble($type, \true, callOriginalConstructor: \false, callOriginalClone: \false, returnValueGeneration: self::generateReturnValuesForTestDoubles()); + assert($mock instanceof $type); + assert($mock instanceof MockObject); + $this->registerMockObject($type, $mock); + Event\Facade::emitter()->testCreatedMockObject($type); + return $mock; + } + /** + * @param list $interfaces + * + * @throws MockObjectException + */ + final protected function createMockForIntersectionOfInterfaces(array $interfaces): MockObject + { + $mock = (new MockGenerator())->testDoubleForInterfaceIntersection($interfaces, \true, returnValueGeneration: self::generateReturnValuesForTestDoubles()); + assert($mock instanceof MockObject); + $this->registerMockObject(implode('|', $interfaces), $mock); + Event\Facade::emitter()->testCreatedMockObjectForIntersectionOfInterfaces($interfaces); + return $mock; + } + /** + * Creates (and configures) a mock object for the specified interface or class. + * + * @template RealInstanceType of object + * + * @param class-string $type + * @param array $configuration + * + * @throws InvalidArgumentException + * @throws MockObjectException + * @throws NoPreviousThrowableException + * + * @return MockObject&RealInstanceType + */ + final protected function createConfiguredMock(string $type, array $configuration): MockObject + { + $o = $this->createMock($type); + foreach ($configuration as $method => $return) { + $o->method($method)->willReturn($return); + } + return $o; + } + /** + * Creates a partial mock object for the specified interface or class. + * + * @param class-string $type + * @param list $methods + * + * @template RealInstanceType of object + * + * @throws InvalidArgumentException + * @throws MockObjectException + * + * @return MockObject&RealInstanceType + */ + final protected function createPartialMock(string $type, array $methods): MockObject + { + $mockBuilder = $this->getMockBuilder($type)->disableOriginalConstructor()->disableOriginalClone()->onlyMethods($methods); + if (!self::generateReturnValuesForTestDoubles()) { + $mockBuilder->disableAutoReturnValueGeneration(); + } + $partialMock = $mockBuilder->getMock(); + Event\Facade::emitter()->testCreatedPartialMockObject($type, ...$methods); + return $partialMock; + } + /** + * @param non-empty-string $additionalInformation + */ + final protected function provideAdditionalInformation(string $additionalInformation): void + { + Event\Facade::emitter()->testProvidedAdditionalInformation($this->valueObjectForEvents(), $additionalInformation); + } + protected function transformException(Throwable $t): Throwable + { + return $t; + } + /** + * This method is called when a test method did not execute successfully. + * + * @throws Throwable + */ + protected function onNotSuccessfulTest(Throwable $t): never + { + throw $t; + } + /** + * @param array $testArguments + */ + protected function invokeTestMethod(string $methodName, array $testArguments): mixed + { + /** @phpstan-ignore method.dynamicName */ + return $this->{$methodName}(...$testArguments); + } + /** + * Returns the data set as a string compatible with the --filter CLI option. + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + private function dataSetAsFilterString(): string + { + if ($this->data !== []) { + if (is_int($this->dataName)) { + return sprintf('#%d', $this->dataName); + } + return sprintf('@%s', Sanitizer::sanitizeBidirectionalControlCharacters($this->dataName)); + } + return ''; + } + /** + * @throws AssertionFailedError + * @throws Exception + * @throws ExpectationFailedException + * @throws Throwable + */ + private function runTest(): mixed + { + $testArguments = array_merge($this->data, array_values($this->dependencyInput)); + $this->startErrorLogCapture(); + try { + $testResult = $this->invokeTestMethod($this->methodName, $testArguments); + $this->verifyErrorLogExpectation(); + } catch (Throwable $exception) { + $this->handleErrorLogError(); + if (!$this->shouldExceptionExpectationsBeVerified($exception)) { + throw $exception; + } + $this->verifyExceptionExpectations($exception); + return null; + } finally { + $this->stopErrorLogCapture(); + } + $this->emitEventForCustomTestMethodInvocation(); + $this->expectedExceptionWasNotRaised(); + return $testResult; + } + private function stripDateFromErrorLog(string $log): string + { + // https://github.com/php/php-src/blob/c696087e323263e941774ebbf902ac249774ec9f/main/main.c#L905 + $result = preg_replace('/\[\d+-\w+-\d+ \d+:\d+:\d+ [^\r\n[\]]+?\] /', '', $log); + assert($result !== null); + return $result; + } + /** + * @throws ExpectationFailedException + */ + private function verifyDeprecationExpectations(): void + { + foreach ($this->expectedUserDeprecationMessage as $deprecationExpectation) { + $this->numberOfAssertionsPerformed++; + if (!in_array($deprecationExpectation, DeprecationCollector::deprecations(), \true)) { + throw new \PHPUnit\Framework\ExpectationFailedException(sprintf('Expected deprecation with message "%s" was not triggered', $deprecationExpectation)); + } + } + foreach ($this->expectedUserDeprecationMessageRegularExpression as $deprecationExpectation) { + $this->numberOfAssertionsPerformed++; + $expectedDeprecationTriggered = array_any(DeprecationCollector::deprecations(), static fn(string $deprecation) => @preg_match($deprecationExpectation, $deprecation) > 0); + if (!$expectedDeprecationTriggered) { + throw new \PHPUnit\Framework\ExpectationFailedException(sprintf('Expected deprecation with message matching regular expression "%s" was not triggered', $deprecationExpectation)); + } + } + } + /** + * @throws Throwable + */ + private function verifyMockObjects(): void + { + $allowsMockObjectsWithoutExpectations = $this->allowsMockObjectsWithoutExpectations(); + $isPhpunitTestSuite = str_starts_with($this::class, 'PHPUnit\\'); + $requireSealedMockObjects = ConfigurationRegistry::get()->requireSealedMockObjects(); + foreach ($this->mockObjects as $mockObject) { + $mockedType = $mockObject['type']; + $mockObject = $mockObject['mockObject']; + if ($requireSealedMockObjects && !$mockObject->__phpunit_getInvocationHandler()->isSealed()) { + Event\Facade::emitter()->testConsideredRisky($this->valueObjectForEvents(), sprintf('Mock object for %s has not been sealed', $mockedType)); + } + if (!$mockObject->__phpunit_hasInvocationCountRule()) { + if (!$mockObject->__phpunit_hasParametersRule() && !$allowsMockObjectsWithoutExpectations && !$isPhpunitTestSuite) { + Event\Facade::emitter()->testTriggeredPhpunitNotice($this->testValueObjectForEvents, sprintf('No expectations were configured for the mock object for %s. ' . 'Consider refactoring your test code to use a test stub instead. ' . 'The #[AllowMockObjectsWithoutExpectations] attribute can be used to opt out of this check.', $mockedType)); + } + continue; + } + $this->numberOfAssertionsPerformed++; + $mockObject->__phpunit_verify($this->shouldInvocationMockerBeReset($mockObject)); + } + } + /** + * @throws SkippedTest + */ + private function checkRequirements(): void + { + if ($this->methodName === '' || !method_exists($this, $this->methodName)) { + return; + } + $missingRequirements = (new Requirements())->requirementsNotSatisfiedFor(static::class, $this->methodName); + if ($missingRequirements !== []) { + $this->markTestSkipped(implode(PHP_EOL, $missingRequirements)); + } + } + private function handleDependencies(): bool + { + if ([] === $this->dependencies || $this->inIsolation) { + return \true; + } + $passedTests = PassedTests::instance(); + foreach ($this->dependencies as $dependency) { + if (!$dependency->isValid()) { + $this->markErrorForInvalidDependency(); + return \false; + } + if ($dependency->targetIsClass()) { + $dependencyClassName = $dependency->getTargetClassName(); + if (!class_exists($dependencyClassName)) { + $this->markErrorForInvalidDependency($dependency); + return \false; + } + if (!$passedTests->hasTestClassPassed($dependencyClassName)) { + $this->markSkippedForMissingDependency($dependency); + return \false; + } + continue; + } + $dependencyTarget = $dependency->getTarget(); + if (!$passedTests->hasTestMethodPassed($dependencyTarget)) { + if (!$this->isCallableTestMethod($dependencyTarget)) { + $this->markErrorForInvalidDependency($dependency); + } else { + $this->markSkippedForMissingDependency($dependency); + } + return \false; + } + if ($passedTests->isGreaterThan($dependencyTarget, $this->size())) { + Event\Facade::emitter()->testConsideredRisky($this->valueObjectForEvents(), 'This test depends on a test that is larger than itself'); + return \true; + } + if (!$passedTests->hasReturnValue($dependencyTarget)) { + return \true; + } + $returnValue = $passedTests->returnValue($dependencyTarget); + if ($dependency->deepClone()) { + $deepCopy = new DeepCopy(); + $deepCopy->skipUncloneable(\false); + $this->dependencyInput[$dependencyTarget] = $deepCopy->copy($returnValue); + } elseif ($dependency->shallowClone()) { + $this->dependencyInput[$dependencyTarget] = clone $returnValue; + } else { + $this->dependencyInput[$dependencyTarget] = $returnValue; + } + } + $this->testValueObjectForEvents = null; + return \true; + } + /** + * @throws Exception + * @throws NoPreviousThrowableException + */ + private function markErrorForInvalidDependency(?\PHPUnit\Framework\ExecutionOrderDependency $dependency = null): void + { + $message = 'This test has an invalid dependency'; + if ($dependency !== null) { + $message = sprintf('This test depends on "%s" which does not exist', $dependency->targetIsClass() ? $dependency->getTargetClassName() : $dependency->getTarget()); + } + $exception = new \PHPUnit\Framework\InvalidDependencyException($message); + Event\Facade::emitter()->testErrored($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($exception)); + $this->status = TestStatus::error($message); + } + private function markSkippedForMissingDependency(\PHPUnit\Framework\ExecutionOrderDependency $dependency): void + { + $message = sprintf('This test depends on "%s" to pass', $dependency->getTarget()); + Event\Facade::emitter()->testSkipped($this->valueObjectForEvents(), $message); + $this->status = TestStatus::skipped($message); + } + private function startOutputBuffering(): void + { + ob_start(); + $this->outputBufferingActive = \true; + $this->outputBufferingLevel = ob_get_level(); + } + private function stopOutputBuffering(): bool + { + $bufferingLevel = ob_get_level(); + if ($bufferingLevel !== $this->outputBufferingLevel) { + if ($bufferingLevel > $this->outputBufferingLevel) { + $message = 'Test code or tested code did not close its own output buffers'; + } else { + $message = 'Test code or tested code closed output buffers other than its own'; + } + while (ob_get_level() >= $this->outputBufferingLevel) { + ob_end_clean(); + } + Event\Facade::emitter()->testConsideredRisky($this->valueObjectForEvents(), $message); + return \false; + } + $this->output = ob_get_clean(); + $this->outputBufferingActive = \false; + $this->outputBufferingLevel = ob_get_level(); + return \true; + } + private function snapshotGlobalErrorExceptionHandlers(): void + { + $this->backupGlobalErrorHandlers = $this->activeErrorHandlers(); + $this->backupGlobalExceptionHandlers = $this->activeExceptionHandlers(); + } + private function restoreGlobalErrorExceptionHandlers(): void + { + $activeErrorHandlers = $this->activeErrorHandlers(); + $activeExceptionHandlers = $this->activeExceptionHandlers(); + $message = null; + if ($activeErrorHandlers !== $this->backupGlobalErrorHandlers) { + if (count($activeErrorHandlers) > count($this->backupGlobalErrorHandlers)) { + if (!$this->inIsolation) { + $message = 'Test code or tested code did not remove its own error handlers'; + } + } else { + $message = 'Test code or tested code removed error handlers other than its own'; + } + foreach ($activeErrorHandlers as $handler) { + restore_error_handler(); + } + foreach ($this->backupGlobalErrorHandlers as $handler) { + set_error_handler($handler); + } + } + if ($message !== null) { + Event\Facade::emitter()->testConsideredRisky($this->valueObjectForEvents(), $message); + } + $message = null; + if ($activeExceptionHandlers !== $this->backupGlobalExceptionHandlers) { + if (count($activeExceptionHandlers) > count($this->backupGlobalExceptionHandlers)) { + if (!$this->inIsolation) { + $message = 'Test code or tested code did not remove its own exception handlers'; + } + } else { + $message = 'Test code or tested code removed exception handlers other than its own'; + } + foreach ($activeExceptionHandlers as $handler) { + restore_exception_handler(); + } + foreach ($this->backupGlobalExceptionHandlers as $handler) { + set_exception_handler($handler); + } + } + $this->backupGlobalErrorHandlers = null; + $this->backupGlobalExceptionHandlers = null; + if ($message !== null) { + Event\Facade::emitter()->testConsideredRisky($this->valueObjectForEvents(), $message); + } + } + /** + * @return list + */ + private function activeErrorHandlers(): array + { + $activeErrorHandlers = []; + while (\true) { + $previousHandler = set_error_handler(static fn() => \false); + restore_error_handler(); + if ($previousHandler === null) { + break; + } + $activeErrorHandlers[] = $previousHandler; + restore_error_handler(); + } + $activeErrorHandlers = array_reverse($activeErrorHandlers); + $invalidErrorHandlerStack = \false; + foreach ($activeErrorHandlers as $handler) { + if (!is_callable($handler)) { + $invalidErrorHandlerStack = \true; + continue; + } + set_error_handler($handler); + } + if ($invalidErrorHandlerStack) { + $message = 'At least one error handler is not callable outside the scope it was registered in'; + Event\Facade::emitter()->testConsideredRisky($this->valueObjectForEvents(), $message); + } + return $activeErrorHandlers; + } + /** + * @return list + */ + private function activeExceptionHandlers(): array + { + $res = []; + while (\true) { + $previousHandler = set_exception_handler(static fn() => null); + restore_exception_handler(); + if ($previousHandler === null) { + break; + } + $res[] = $previousHandler; + restore_exception_handler(); + } + $res = array_reverse($res); + foreach ($res as $handler) { + set_exception_handler($handler); + } + return $res; + } + private function snapshotGlobalState(): void + { + if ($this->runTestInSeparateProcess || $this->inIsolation || !$this->backupGlobals && !$this->backupStaticProperties) { + return; + } + $snapshot = $this->createGlobalStateSnapshot($this->backupGlobals === \true); + $this->snapshot = $snapshot; + } + private function restoreGlobalState(): void + { + if (!$this->snapshot instanceof Snapshot) { + return; + } + if (ConfigurationRegistry::get()->beStrictAboutChangesToGlobalState()) { + $this->compareGlobalStateSnapshots($this->snapshot, $this->createGlobalStateSnapshot($this->backupGlobals === \true)); + } + $restorer = new Restorer(); + if ($this->backupGlobals) { + $restorer->restoreGlobalVariables($this->snapshot); + } + if ($this->backupStaticProperties) { + $restorer->restoreStaticProperties($this->snapshot); + } + $this->snapshot = null; + } + private function createGlobalStateSnapshot(bool $backupGlobals): Snapshot + { + $excludeList = new GlobalStateExcludeList(); + foreach ($this->backupGlobalsExcludeList as $globalVariable) { + $excludeList->addGlobalVariable($globalVariable); + } + if (!defined('PHPUNIT_TESTSUITE')) { + $excludeList->addClassNamePrefix('PHPUnit'); + $excludeList->addClassNamePrefix('PHPUnitPHAR\SebastianBergmann\CodeCoverage'); + $excludeList->addClassNamePrefix('PHPUnitPHAR\SebastianBergmann\FileIterator'); + $excludeList->addClassNamePrefix('PHPUnitPHAR\SebastianBergmann\Invoker'); + $excludeList->addClassNamePrefix('PHPUnitPHAR\SebastianBergmann\Template'); + $excludeList->addClassNamePrefix('PHPUnitPHAR\SebastianBergmann\Timer'); + foreach (array_keys($GLOBALS) as $key) { + if (str_starts_with($key, '__phpunit_')) { + $excludeList->addGlobalVariable($key); + } + } + $excludeList->addStaticProperty(ComparatorFactory::class, 'instance'); + foreach ($this->backupStaticPropertiesExcludeList as $class => $properties) { + foreach ($properties as $property) { + $excludeList->addStaticProperty($class, $property); + } + } + } + try { + return new Snapshot($excludeList, $backupGlobals, (bool) $this->backupStaticProperties, \false, \false, \false, \false, \false, \false, \false); + } catch (Throwable $t) { + Event\Facade::emitter()->testPreparationFailed($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($t)); + Event\Facade::emitter()->testErrored($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($t)); + throw $t; + } + } + private function compareGlobalStateSnapshots(Snapshot $before, Snapshot $after): void + { + $backupGlobals = $this->backupGlobals === null || $this->backupGlobals; + if ($backupGlobals) { + $this->compareGlobalStateSnapshotPart($before->globalVariables(), $after->globalVariables(), "--- Global variables before the test\n+++ Global variables after the test\n"); + $this->compareGlobalStateSnapshotPart($before->superGlobalVariables(), $after->superGlobalVariables(), "--- Super-global variables before the test\n+++ Super-global variables after the test\n"); + } + if ($this->backupStaticProperties) { + $this->compareGlobalStateSnapshotPart($before->staticProperties(), $after->staticProperties(), "--- Static properties before the test\n+++ Static properties after the test\n"); + } + } + /** + * @param array $before + * @param array $after + */ + private function compareGlobalStateSnapshotPart(array $before, array $after, string $header): void + { + if ($before === $after) { + return; + } + $differ = new Differ(new UnifiedDiffOutputBuilder($header, \false, 3, \false)); + Event\Facade::emitter()->testConsideredRisky($this->valueObjectForEvents(), 'This test modified global state but was not expected to do so' . PHP_EOL . trim($differ->diff(Exporter::export($before), Exporter::export($after)))); + } + private function handleEnvironmentVariables(): void + { + $withEnvironmentVariables = MetadataRegistry::parser()->forClassAndMethod(static::class, $this->methodName)->isWithEnvironmentVariable(); + $environmentVariables = []; + foreach ($withEnvironmentVariables as $metadata) { + assert($metadata instanceof WithEnvironmentVariable); + $environmentVariables[$metadata->environmentVariableName()] = $metadata->value(); + } + foreach ($environmentVariables as $environmentVariableName => $environmentVariableValue) { + $this->backupEnvironmentVariables = [...$this->backupEnvironmentVariables, ...BackedUpEnvironmentVariable::create($environmentVariableName)]; + if ($environmentVariableValue === null) { + unset($_ENV[$environmentVariableName]); + putenv($environmentVariableName); + } else { + $_ENV[$environmentVariableName] = $environmentVariableValue; + putenv("{$environmentVariableName}={$environmentVariableValue}"); + } + } + } + private function restoreEnvironmentVariables(): void + { + foreach ($this->backupEnvironmentVariables as $backupEnvironmentVariable) { + $backupEnvironmentVariable->restore(); + } + $this->backupEnvironmentVariables = []; + } + private function shouldInvocationMockerBeReset(MockObject $mock): bool + { + $enumerator = new Enumerator(); + if (in_array($mock, $enumerator->enumerate($this->dependencyInput), \true)) { + return \false; + } + if (!is_array($this->testResult) && !is_object($this->testResult)) { + return \true; + } + return !in_array($mock, $enumerator->enumerate($this->testResult), \true); + } + private function unregisterCustomComparators(): void + { + $factory = ComparatorFactory::getInstance(); + foreach ($this->customComparators as $comparator) { + $factory->unregister($comparator); + } + $this->customComparators = []; + } + /** + * @throws Exception + */ + private function shouldExceptionExpectationsBeVerified(Throwable $throwable): bool + { + $result = \false; + if ($this->expectedException !== null || $this->expectedExceptionCode !== null || $this->expectedExceptionMessage !== null || $this->expectedExceptionMessageRegExp !== null) { + $result = \true; + } + if ($throwable instanceof \PHPUnit\Framework\Exception) { + $result = \false; + } + if (is_string($this->expectedException)) { + try { + $reflector = new ReflectionClass($this->expectedException); + // @codeCoverageIgnoreStart + } catch (ReflectionException $e) { + throw new \PHPUnit\Framework\Exception($e->getMessage(), $e->getCode(), $e); + } + // @codeCoverageIgnoreEnd + if ($this->expectedException === 'PHPUnit\Framework\Exception' || $this->expectedException === '\PHPUnit\Framework\Exception' || $reflector->isSubclassOf(\PHPUnit\Framework\Exception::class)) { + $result = \true; + } + } + return $result; + } + private function shouldRunInSeparateProcess(): bool + { + if ($this->inIsolation) { + return \false; + } + if ($this->runTestInSeparateProcess) { + return \true; + } + return ConfigurationRegistry::get()->processIsolation(); + } + private function isCallableTestMethod(string $dependency): bool + { + [$className, $methodName] = explode('::', $dependency); + if (!class_exists($className)) { + return \false; + } + $class = new ReflectionClass($className); + if (!$class->isSubclassOf(__CLASS__)) { + return \false; + } + if (!$class->hasMethod($methodName)) { + return \false; + } + return TestUtil::isTestMethod($class->getMethod($methodName)); + } + /** + * @throws Exception + * @throws ExpectationFailedException + * @throws NoPreviousThrowableException + */ + private function performAssertionsOnOutput(): void + { + try { + if ($this->outputExpectedRegex !== null) { + $this->assertMatchesRegularExpression($this->outputExpectedRegex, $this->output); + } elseif ($this->outputExpectedString !== null) { + $this->assertSame($this->outputExpectedString, $this->output); + } + } catch (\PHPUnit\Framework\ExpectationFailedException $e) { + $this->status = TestStatus::failure($e->getMessage()); + Event\Facade::emitter()->testFailed($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($e), Event\Code\ComparisonFailureBuilder::from($e)); + throw $e; + } + } + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + * + * @codeCoverageIgnore + */ + private function invokeBeforeClassHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods($hookMethods['beforeClass'], $emitter, 'beforeFirstTestMethodCalled', 'beforeFirstTestMethodErrored', 'beforeFirstTestMethodFailed', 'beforeFirstTestMethodFinished', \false); + } + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + */ + private function invokeBeforeTestHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods($hookMethods['before'], $emitter, 'beforeTestMethodCalled', 'beforeTestMethodErrored', 'beforeTestMethodFailed', 'beforeTestMethodFinished'); + } + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + */ + private function invokePreConditionHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods($hookMethods['preCondition'], $emitter, 'preConditionCalled', 'preConditionErrored', 'preConditionFailed', 'preConditionFinished'); + } + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + */ + private function invokePostConditionHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods($hookMethods['postCondition'], $emitter, 'postConditionCalled', 'postConditionErrored', 'postConditionFailed', 'postConditionFinished'); + } + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + */ + private function invokeAfterTestHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods($hookMethods['after'], $emitter, 'afterTestMethodCalled', 'afterTestMethodErrored', 'afterTestMethodFailed', 'afterTestMethodFinished'); + } + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + * + * @codeCoverageIgnore + */ + private function invokeAfterClassHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods($hookMethods['afterClass'], $emitter, 'afterLastTestMethodCalled', 'afterLastTestMethodErrored', 'afterLastTestMethodFailed', 'afterLastTestMethodFinished', \false); + } + /** + * @param 'afterLastTestMethodCalled'|'afterTestMethodCalled'|'beforeFirstTestMethodCalled'|'beforeTestMethodCalled'|'postConditionCalled'|'preConditionCalled' $calledMethod + * @param 'afterLastTestMethodErrored'|'afterTestMethodErrored'|'beforeFirstTestMethodErrored'|'beforeTestMethodErrored'|'postConditionErrored'|'preConditionErrored' $erroredMethod + * @param 'afterLastTestMethodFailed'|'afterTestMethodFailed'|'beforeFirstTestMethodFailed'|'beforeTestMethodFailed'|'postConditionFailed'|'preConditionFailed' $failedMethod + * @param 'afterLastTestMethodFinished'|'afterTestMethodFinished'|'beforeFirstTestMethodFinished'|'beforeTestMethodFinished'|'postConditionFinished'|'preConditionFinished' $finishedMethod + * + * @throws Throwable + */ + private function invokeHookMethods(HookMethodCollection $hookMethods, Event\Emitter $emitter, string $calledMethod, string $erroredMethod, string $failedMethod, string $finishedMethod, bool $forTestCase = \true): void + { + if ($forTestCase) { + $test = $this->valueObjectForEvents(); + } else { + $test = static::class; + } + $methodsInvoked = []; + foreach ($hookMethods->methodNamesSortedByPriority() as $methodName) { + if ($this->methodDoesNotExistOrIsDeclaredInTestCase($methodName)) { + continue; + } + $methodInvoked = new Event\Code\ClassMethod(static::class, $methodName); + try { + /** @phpstan-ignore method.dynamicName */ + $this->{$methodName}(); + } catch (Throwable $t) { + } + /** @phpstan-ignore method.dynamicName */ + $emitter->{$calledMethod}($test, $methodInvoked); + $methodsInvoked[] = $methodInvoked; + if (isset($t) && !$t instanceof \PHPUnit\Framework\SkippedTest) { + if ($t instanceof \PHPUnit\Framework\AssertionFailedError) { + $method = $failedMethod; + } else { + $method = $erroredMethod; + } + /** @phpstan-ignore method.dynamicName */ + $emitter->{$method}($test, $methodInvoked, Event\Code\ThrowableBuilder::from($t)); + break; + } + } + if ($methodsInvoked !== []) { + /** @phpstan-ignore method.dynamicName */ + $emitter->{$finishedMethod}($test, ...$methodsInvoked); + } + if (isset($t)) { + throw $t; + } + } + /** + * @param non-empty-string $methodName + */ + private function methodDoesNotExistOrIsDeclaredInTestCase(string $methodName): bool + { + $reflector = new ReflectionObject($this); + return !$reflector->hasMethod($methodName) || $reflector->getMethod($methodName)->getDeclaringClass()->getName() === self::class; + } + /** + * @throws ExpectationFailedException + */ + private function verifyExceptionExpectations(\Exception|Throwable $exception): void + { + if ($this->expectedException !== null) { + $this->assertThat($exception, new ExceptionConstraint($this->expectedException)); + } + if ($this->expectedExceptionMessage !== null) { + $this->assertThat($exception->getMessage(), new ExceptionMessageIsOrContains($this->expectedExceptionMessage)); + } + if ($this->expectedExceptionMessageRegExp !== null) { + $this->assertThat($exception->getMessage(), new ExceptionMessageMatchesRegularExpression($this->expectedExceptionMessageRegExp)); + } + if ($this->expectedExceptionCode !== null) { + $this->assertThat($exception->getCode(), new ExceptionCode($this->expectedExceptionCode)); + } + } + /** + * @throws AssertionFailedError + */ + private function expectedExceptionWasNotRaised(): void + { + if ($this->expectedException !== null) { + $this->assertThat(null, new ExceptionConstraint($this->expectedException)); + } elseif ($this->expectedExceptionMessage !== null) { + $this->numberOfAssertionsPerformed++; + throw new \PHPUnit\Framework\AssertionFailedError(sprintf('Failed asserting that exception with message "%s" is thrown', $this->expectedExceptionMessage)); + } elseif ($this->expectedExceptionMessageRegExp !== null) { + $this->numberOfAssertionsPerformed++; + throw new \PHPUnit\Framework\AssertionFailedError(sprintf('Failed asserting that exception with message matching "%s" is thrown', $this->expectedExceptionMessageRegExp)); + } elseif ($this->expectedExceptionCode !== null) { + $this->numberOfAssertionsPerformed++; + throw new \PHPUnit\Framework\AssertionFailedError(sprintf('Failed asserting that exception with code "%s" is thrown', $this->expectedExceptionCode)); + } + } + private function isRegisteredFailure(Throwable $t): bool + { + return array_any(array_keys($this->failureTypes), static fn(string $failureType) => $t instanceof $failureType); + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + private function hasExpectationOnOutput(): bool + { + return is_string($this->outputExpectedString) || is_string($this->outputExpectedRegex); + } + private function requirementsNotSatisfied(): bool + { + return (new Requirements())->requirementsNotSatisfiedFor(static::class, $this->methodName) !== []; + } + private function requiresXdebug(): bool + { + return (new Requirements())->requiresXdebug(static::class, $this->methodName); + } + /** + * @see https://github.com/sebastianbergmann/phpunit/issues/6095 + */ + private function handleExceptionFromInvokedCountMockObjectRule(Throwable $t): void + { + if (!$t instanceof \PHPUnit\Framework\ExpectationFailedException) { + return; + } + $trace = $t->getTrace(); + if (isset($trace[0]['class']) && $trace[0]['class'] === InvokedCount::class) { + $this->numberOfAssertionsPerformed++; + } + } + private function startErrorLogCapture(): void + { + if (ini_get('display_errors') === '0') { + ShutdownHandler::setMessage('Fatal error: Premature end of PHPUnit\'s PHP process. Use display_errors=On to see the error message.'); + } + $errorLogCapture = tmpfile(); + if ($errorLogCapture === \false) { + return; + } + $capturePath = stream_get_meta_data($errorLogCapture)['uri']; + if (!@is_writable($capturePath)) { + return; + } + $this->errorLogCapture = $errorLogCapture; + $this->previousErrorLogTarget = ini_set('error_log', $capturePath); + } + /** + * @throws ErrorLogNotWritableException + */ + private function verifyErrorLogExpectation(): void + { + if ($this->errorLogCapture === \false) { + if ($this->expectErrorLog) { + throw new \PHPUnit\Framework\ErrorLogNotWritableException(); + } + return; + } + $errorLogOutput = stream_get_contents($this->errorLogCapture); + if ($this->expectErrorLog) { + $this->assertNotEmpty($errorLogOutput, 'error_log() was not called'); + return; + } + if ($errorLogOutput === \false) { + return; + } + print $this->stripDateFromErrorLog($errorLogOutput); + } + private function handleErrorLogError(): void + { + if ($this->errorLogCapture === \false) { + return; + } + if ($this->expectErrorLog) { + return; + } + $errorLogOutput = stream_get_contents($this->errorLogCapture); + if ($errorLogOutput !== \false) { + print $this->stripDateFromErrorLog($errorLogOutput); + } + } + private function stopErrorLogCapture(): void + { + if ($this->errorLogCapture === \false) { + return; + } + ShutdownHandler::resetMessage(); + fclose($this->errorLogCapture); + $this->errorLogCapture = \false; + if ($this->previousErrorLogTarget === \false) { + return; + } + ini_set('error_log', $this->previousErrorLogTarget); + $this->previousErrorLogTarget = \false; + } + private function allowsMockObjectsWithoutExpectations(): bool + { + return MetadataRegistry::parser()->forClassAndMethod(static::class, $this->methodName)->isAllowMockObjectsWithoutExpectations()->isNotEmpty(); + } + private function emitEventForCustomTestMethodInvocation(): void + { + $reflector = new ReflectionMethod($this, 'invokeTestMethod'); + if (self::class === $reflector->getDeclaringClass()->getName()) { + return; + } + Event\Facade::emitter()->testUsedCustomMethodInvocation($this->valueObjectForEvents(), new Event\Code\ClassMethod($reflector->getDeclaringClass()->getName(), 'invokeTestMethod')); + } + /** + * Returns a builder object to create test stubs using a fluent interface. + * + * @template RealInstanceType of object + * + * @param class-string $className + * + * @return TestStubBuilder + */ + final protected static function getStubBuilder(string $className): TestStubBuilder + { + return new TestStubBuilder($className); + } + /** + * Creates a test stub for the specified interface or class. + * + * @template RealInstanceType of object + * + * @param class-string $type + * + * @throws InvalidArgumentException + * @throws MockObjectException + * @throws NoPreviousThrowableException + * + * @return RealInstanceType&Stub + */ + final protected static function createStub(string $type): Stub + { + $stub = (new MockGenerator())->testDouble($type, \false, callOriginalConstructor: \false, callOriginalClone: \false, returnValueGeneration: self::generateReturnValuesForTestDoubles()); + Event\Facade::emitter()->testCreatedStub($type); + assert($stub instanceof $type); + assert($stub instanceof Stub); + return $stub; + } + /** + * @param list $interfaces + * + * @throws MockObjectException + */ + final protected static function createStubForIntersectionOfInterfaces(array $interfaces): Stub + { + $stub = (new MockGenerator())->testDoubleForInterfaceIntersection($interfaces, \false, returnValueGeneration: self::generateReturnValuesForTestDoubles()); + Event\Facade::emitter()->testCreatedStubForIntersectionOfInterfaces($interfaces); + return $stub; + } + /** + * Creates (and configures) a test stub for the specified interface or class. + * + * @template RealInstanceType of object + * + * @param class-string $type + * @param array $configuration + * + * @throws InvalidArgumentException + * @throws MockObjectException + * @throws NoPreviousThrowableException + * + * @return RealInstanceType&Stub + */ + final protected static function createConfiguredStub(string $type, array $configuration): Stub + { + $o = self::createStub($type); + foreach ($configuration as $method => $return) { + $o->method($method)->willReturn($return); + } + return $o; + } + private static function generateReturnValuesForTestDoubles(): bool + { + return MetadataRegistry::parser()->forClass(static::class)->isDisableReturnValueGenerationForTestDoubles()->isEmpty(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function assert; +use function hash_equals; +use function strlen; +use function substr; +use function trim; +use function unserialize; +use PHPUnit\Event\Code\TestMethodBuilder; +use PHPUnit\Event\Code\ThrowableBuilder; +use PHPUnit\Event\Emitter; +use PHPUnit\Event\Facade; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\TestRunner\TestResult\PassedTests; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessResultProcessor +{ + private Facade $eventFacade; + private Emitter $emitter; + private PassedTests $passedTests; + private CodeCoverage $codeCoverage; + public function __construct(Facade $eventFacade, Emitter $emitter, PassedTests $passedTests, CodeCoverage $codeCoverage) + { + $this->eventFacade = $eventFacade; + $this->emitter = $emitter; + $this->passedTests = $passedTests; + $this->codeCoverage = $codeCoverage; + } + /** + * @param ?non-empty-string $processResultNonce + */ + public function process(\PHPUnit\Framework\Test $test, string $serializedProcessResult, string $stderr, ?string $processResultNonce = null): void + { + if ($stderr !== '') { + $exception = new \PHPUnit\Framework\Exception(trim($stderr)); + assert($test instanceof \PHPUnit\Framework\TestCase); + $this->emitter->testErrored(TestMethodBuilder::fromTestCase($test), ThrowableBuilder::from($exception)); + return; + } + if ($processResultNonce !== null && $serializedProcessResult !== '') { + $nonceLength = strlen($processResultNonce); + if (strlen($serializedProcessResult) < $nonceLength || !hash_equals($processResultNonce, substr($serializedProcessResult, 0, $nonceLength))) { + $this->emitter->childProcessErrored(); + $exception = new \PHPUnit\Framework\AssertionFailedError('Test was run in child process and the result file was tampered with or written by an unexpected process'); + assert($test instanceof \PHPUnit\Framework\TestCase); + $this->emitter->testErrored(TestMethodBuilder::fromTestCase($test), ThrowableBuilder::from($exception)); + $this->emitter->testFinished(TestMethodBuilder::fromTestCase($test), 0); + return; + } + $serializedProcessResult = substr($serializedProcessResult, $nonceLength); + } + $childResult = @unserialize($serializedProcessResult); + if ($childResult === \false) { + $this->emitter->childProcessErrored(); + $exception = new \PHPUnit\Framework\AssertionFailedError('Test was run in child process and ended unexpectedly'); + assert($test instanceof \PHPUnit\Framework\TestCase); + $this->emitter->testErrored(TestMethodBuilder::fromTestCase($test), ThrowableBuilder::from($exception)); + $this->emitter->testFinished(TestMethodBuilder::fromTestCase($test), 0); + return; + } + $this->eventFacade->forward($childResult->events); + $this->passedTests->import($childResult->passedTests); + assert($test instanceof \PHPUnit\Framework\TestCase); + $test->setResult($childResult->testResult); + $test->addToAssertionCount($childResult->numAssertions); + if (!$this->codeCoverage->isActive()) { + return; + } + // @codeCoverageIgnoreStart + if (!$childResult->codeCoverage instanceof \PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage) { + return; + } + CodeCoverage::instance()->codeCoverage()->merge($childResult->codeCoverage); + // @codeCoverageIgnoreEnd + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function assert; +use function bin2hex; +use function defined; +use function get_include_path; +use function hrtime; +use function random_bytes; +use function serialize; +use function sprintf; +use function sys_get_temp_dir; +use function tempnam; +use function unlink; +use function var_export; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Event\NoPreviousThrowableException; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use PHPUnit\TextUI\Configuration\SourceMapper; +use PHPUnit\Util\GlobalState; +use PHPUnit\Util\PHP\Job; +use PHPUnit\Util\PHP\JobRunnerRegistry; +use ReflectionClass; +use PHPUnitPHAR\SebastianBergmann\Template\InvalidArgumentException; +use PHPUnitPHAR\SebastianBergmann\Template\Template; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SeparateProcessTestRunner +{ + private static ?string $sourceMapFile = null; + /** + * @throws \PHPUnit\Runner\Exception + * @throws \PHPUnit\Util\Exception + * @throws Exception + * @throws InvalidArgumentException + * @throws NoPreviousThrowableException + * @throws ProcessIsolationException + */ + public function run(\PHPUnit\Framework\TestCase $test, bool $preserveGlobalState, bool $requiresXdebug): void + { + $class = new ReflectionClass($test); + $bootstrap = ''; + $constants = ''; + $globals = ''; + $includedFiles = ''; + $iniSettings = ''; + if (ConfigurationRegistry::get()->hasBootstrap()) { + $bootstrap = ConfigurationRegistry::get()->bootstrap(); + } + if ($preserveGlobalState) { + $constants = GlobalState::getConstantsAsString(); + $globalStateResult = GlobalState::exportGlobals(); + $globals = $globalStateResult->globalsString(); + $includedFiles = GlobalState::getIncludedFilesAsString(); + $iniSettings = GlobalState::getIniSettingsAsString(); + foreach ($globalStateResult->skippedGlobals() as $skipped) { + EventFacade::emitter()->testTriggeredPhpunitWarning($test->valueObjectForEvents(), sprintf('Global variable %s was not preserved because it %s', $skipped['name'], $skipped['reason'])); + } + } + $coverage = CodeCoverage::instance()->isActive() ? 'true' : 'false'; + if (defined('PHPUNIT_COMPOSER_INSTALL')) { + $composerAutoload = var_export(PHPUNIT_COMPOSER_INSTALL, \true); + } else { + $composerAutoload = '\'\''; + } + if (defined('__PHPUNIT_PHAR__')) { + $phar = var_export(__PHPUNIT_PHAR__, \true); + } else { + $phar = '\'\''; + } + $data = var_export(serialize($test->providedData()), \true); + $dataName = var_export($test->dataName(), \true); + $dependencyInput = var_export(serialize($test->dependencyInput()), \true); + $includePath = var_export(get_include_path(), \true); + // must do these fixes because TestCaseMethod.tpl has unserialize('{data}') in it, and we can't break BC + // the lines above used to use addcslashes() rather than var_export(), which breaks null byte escape sequences + $data = "'." . $data . ".'"; + $dataName = "'.(" . $dataName . ").'"; + $dependencyInput = "'." . $dependencyInput . ".'"; + $includePath = "'." . $includePath . ".'"; + $offset = hrtime(); + $serializedConfiguration = $this->saveConfigurationForChildProcess(); + $processResultFile = $this->pathForCachedSourceMap(); + $processResultNonce = bin2hex(random_bytes(16)); + $sourceMapFile = $this->sourceMapFileForChildProcess(); + $file = $class->getFileName(); + assert($file !== \false); + $var = ['bootstrap' => $bootstrap, 'composerAutoload' => $composerAutoload, 'phar' => $phar, 'filename' => $file, 'className' => $class->getName(), 'methodName' => $test->name(), 'collectCodeCoverageInformation' => $coverage, 'data' => $data, 'dataName' => $dataName, 'dependencyInput' => $dependencyInput, 'constants' => $constants, 'globals' => $globals, 'include_path' => $includePath, 'included_files' => $includedFiles, 'iniSettings' => $iniSettings, 'name' => $test->name(), 'offsetSeconds' => (string) $offset[0], 'offsetNanoseconds' => (string) $offset[1], 'serializedConfiguration' => $serializedConfiguration, 'processResultFile' => $processResultFile, 'processResultNonce' => $processResultNonce, 'sourceMapFile' => $sourceMapFile]; + $template = new Template(__DIR__ . '/templates/method.tpl'); + $template->setVar($var); + $code = $template->render(); + assert($code !== ''); + JobRunnerRegistry::runTestJob(new Job($code, requiresXdebug: $requiresXdebug), $processResultFile, $test, $processResultNonce); + @unlink($serializedConfiguration); + } + private function sourceMapFileForChildProcess(): string + { + if (self::$sourceMapFile !== null) { + return self::$sourceMapFile; + } + if (!ConfigurationRegistry::get()->source()->notEmpty()) { + self::$sourceMapFile = ''; + return self::$sourceMapFile; + } + $path = $this->pathForCachedSourceMap(); + if ($path === \false) { + // @codeCoverageIgnoreStart + self::$sourceMapFile = ''; + return self::$sourceMapFile; + // @codeCoverageIgnoreEnd + } + if (!SourceMapper::saveTo($path, ConfigurationRegistry::get()->source())) { + // @codeCoverageIgnoreStart + self::$sourceMapFile = ''; + return self::$sourceMapFile; + // @codeCoverageIgnoreEnd + } + self::$sourceMapFile = $path; + return self::$sourceMapFile; + } + /** + * @throws ProcessIsolationException + */ + private function saveConfigurationForChildProcess(): string + { + $path = $this->pathForCachedSourceMap(); + if ($path === \false) { + // @codeCoverageIgnoreStart + throw new \PHPUnit\Framework\ProcessIsolationException(); + // @codeCoverageIgnoreEnd + } + if (!ConfigurationRegistry::saveTo($path)) { + // @codeCoverageIgnoreStart + throw new \PHPUnit\Framework\ProcessIsolationException(); + // @codeCoverageIgnoreEnd + } + return $path; + } + private function pathForCachedSourceMap(): false|string + { + return tempnam(sys_get_temp_dir(), 'phpunit_'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function array_diff_assoc; +use function array_intersect; +use function array_unique; +use function assert; +use function extension_loaded; +use function sprintf; +use function xdebug_is_debugger_active; +use AssertionError; +use PHPUnit\Event\Facade; +use PHPUnit\Metadata\Api\CodeCoverage as CodeCoverageMetadataApi; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\Runner\ErrorHandler; +use PHPUnit\Runner\Exception; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception as CodeCoverageException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\InvalidArgumentException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\TargetCollection; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException; +use PHPUnitPHAR\SebastianBergmann\Invoker\Invoker; +use PHPUnitPHAR\SebastianBergmann\Invoker\TimeoutException; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestRunner +{ + private ?bool $timeLimitCanBeEnforced = null; + private readonly Configuration $configuration; + public function __construct() + { + $this->configuration = ConfigurationRegistry::get(); + } + /** + * @throws Exception + * @throws InvalidArgumentException + * @throws UnintentionallyCoveredCodeException + */ + public function run(\PHPUnit\Framework\TestCase $test): void + { + \PHPUnit\Framework\Assert::resetCount(); + $codeCoverageMetadataApi = new CodeCoverageMetadataApi(); + $coversTargets = $codeCoverageMetadataApi->coversTargets($test::class, $test->name()); + $usesTargets = $codeCoverageMetadataApi->usesTargets($test::class, $test->name()); + $shouldCodeCoverageBeCollected = $codeCoverageMetadataApi->shouldCodeCoverageBeCollectedFor($test); + $this->performSanityChecks($test, $coversTargets, $usesTargets, $shouldCodeCoverageBeCollected); + $error = \false; + $failure = \false; + $incomplete = \false; + $risky = \false; + $skipped = \false; + if ($this->shouldErrorHandlerBeUsed($test)) { + ErrorHandler::instance()->enable($test); + } + $collectCodeCoverage = CodeCoverage::instance()->isActive() && $shouldCodeCoverageBeCollected; + if ($collectCodeCoverage) { + CodeCoverage::instance()->start($test); + } + try { + if ($this->canTimeLimitBeEnforced() && $this->shouldTimeLimitBeEnforced($test)) { + $risky = $this->runTestWithTimeout($test); + } else { + $test->runBare(); + } + } catch (\PHPUnit\Framework\AssertionFailedError $e) { + $failure = \true; + if ($e instanceof \PHPUnit\Framework\IncompleteTestError) { + $incomplete = \true; + } elseif ($e instanceof \PHPUnit\Framework\SkippedTest) { + $skipped = \true; + } + } catch (AssertionError $e) { + $test->addToAssertionCount(1); + $failure = \true; + $frame = $e->getTrace()[0]; + assert(isset($frame['file'])); + assert(isset($frame['line'])); + $e = new \PHPUnit\Framework\AssertionFailedError(sprintf('%s in %s:%s', $e->getMessage(), $frame['file'], $frame['line'])); + } catch (Throwable $e) { + $error = \true; + } + $test->addToAssertionCount(\PHPUnit\Framework\Assert::getCount()); + if ($this->configuration->reportUselessTests() && !$test->doesNotPerformAssertions() && $test->numberOfAssertionsPerformed() === 0) { + $risky = \true; + } + if (!$error && !$failure && !$incomplete && !$skipped && !$risky && $this->configuration->requireCoverageMetadata() && !$this->hasCoverageMetadata($test::class, $test->name())) { + Facade::emitter()->testConsideredRisky($test->valueObjectForEvents(), 'This test does not define a code coverage target but is expected to do so'); + $risky = \true; + } + if ($collectCodeCoverage) { + $append = !$risky && !$incomplete && !$skipped; + if (!$append) { + $coversTargets = \false; + $usesTargets = null; + } + try { + CodeCoverage::instance()->stop($append, $coversTargets, $usesTargets); + } catch (UnintentionallyCoveredCodeException $cce) { + Facade::emitter()->testConsideredRisky($test->valueObjectForEvents(), 'This test executed code that is not listed as code to be covered or used:' . PHP_EOL . $cce->getMessage()); + } catch (CodeCoverageException $cce) { + $error = \true; + $e = $e ?? $cce; + } + } + ErrorHandler::instance()->disable(); + if (!$error && !$incomplete && !$skipped && $this->configuration->reportUselessTests() && !$test->doesNotPerformAssertions() && $test->numberOfAssertionsPerformed() === 0) { + Facade::emitter()->testConsideredRisky($test->valueObjectForEvents(), 'This test did not perform any assertions'); + } + if ($test->doesNotPerformAssertions() && $test->numberOfAssertionsPerformed() > 0) { + Facade::emitter()->testConsideredRisky($test->valueObjectForEvents(), sprintf('This test is not expected to perform assertions but performed %d assertion%s', $test->numberOfAssertionsPerformed(), $test->numberOfAssertionsPerformed() > 1 ? 's' : '')); + } + if ($test->hasUnexpectedOutput()) { + Facade::emitter()->testPrintedUnexpectedOutput($test->output()); + } + if ($this->configuration->disallowTestOutput() && $test->hasUnexpectedOutput()) { + Facade::emitter()->testConsideredRisky($test->valueObjectForEvents(), sprintf('Test code or tested code printed unexpected output: %s', $test->output())); + } + if ($test->wasPrepared()) { + Facade::emitter()->testFinished($test->valueObjectForEvents(), $test->numberOfAssertionsPerformed()); + } + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + private function hasCoverageMetadata(string $className, string $methodName): bool + { + foreach (MetadataRegistry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isCoversNamespace()) { + return \true; + } + if ($metadata->isCoversTrait()) { + return \true; + } + if ($metadata->isCoversClass()) { + return \true; + } + if ($metadata->isCoversClassesThatExtendClass()) { + return \true; + } + if ($metadata->isCoversClassesThatImplementInterface()) { + return \true; + } + if ($metadata->isCoversMethod()) { + return \true; + } + if ($metadata->isCoversFunction()) { + return \true; + } + if ($metadata->isCoversNothing()) { + return \true; + } + } + return \false; + } + private function canTimeLimitBeEnforced(): bool + { + if ($this->timeLimitCanBeEnforced !== null) { + return $this->timeLimitCanBeEnforced; + } + $this->timeLimitCanBeEnforced = (new Invoker())->canInvokeWithTimeout(); + return $this->timeLimitCanBeEnforced; + } + private function shouldTimeLimitBeEnforced(\PHPUnit\Framework\TestCase $test): bool + { + if (!$this->configuration->enforceTimeLimit()) { + return \false; + } + if (!($this->configuration->defaultTimeLimit() > 0 || $test->size()->isKnown())) { + return \false; + } + if (extension_loaded('xdebug') && xdebug_is_debugger_active()) { + return \false; + } + return \true; + } + /** + * @throws Throwable + */ + private function runTestWithTimeout(\PHPUnit\Framework\TestCase $test): bool + { + $_timeout = $this->configuration->defaultTimeLimit(); + $testSize = $test->size(); + if ($testSize->isSmall()) { + $_timeout = $this->configuration->timeoutForSmallTests(); + } elseif ($testSize->isMedium()) { + $_timeout = $this->configuration->timeoutForMediumTests(); + } elseif ($testSize->isLarge()) { + $_timeout = $this->configuration->timeoutForLargeTests(); + } + try { + (new Invoker())->invoke($test->runBare(...), [], $_timeout); + } catch (TimeoutException) { + Facade::emitter()->testConsideredRisky($test->valueObjectForEvents(), sprintf('This test was aborted after %d second%s', $_timeout, $_timeout !== 1 ? 's' : '')); + return \true; + } + return \false; + } + private function shouldErrorHandlerBeUsed(\PHPUnit\Framework\TestCase $test): bool + { + if (MetadataRegistry::parser()->forMethod($test::class, $test->name())->isWithoutErrorHandler()->isNotEmpty()) { + return \false; + } + return \true; + } + private function performSanityChecks(\PHPUnit\Framework\TestCase $test, TargetCollection $coversTargets, TargetCollection $usesTargets, bool $shouldCodeCoverageBeCollected): void + { + if (!$shouldCodeCoverageBeCollected) { + if ($coversTargets->isNotEmpty() || $usesTargets->isNotEmpty()) { + Facade::emitter()->testTriggeredPhpunitWarning($test->valueObjectForEvents(), '#[Covers*] and #[Uses*] attributes do not have an effect when the #[CoversNothing] attribute is used'); + } + } + $coversAsString = []; + $usesAsString = []; + foreach ($coversTargets as $coversTarget) { + $coversAsString[] = $coversTarget->description(); + } + foreach ($usesTargets as $usesTarget) { + $usesAsString[] = $usesTarget->description(); + } + $coversDuplicates = array_unique(array_diff_assoc($coversAsString, array_unique($coversAsString))); + $usesDuplicates = array_unique(array_diff_assoc($usesAsString, array_unique($usesAsString))); + $coversAndUses = array_intersect($coversAsString, $usesAsString); + foreach ($coversDuplicates as $target) { + Facade::emitter()->testTriggeredPhpunitWarning($test->valueObjectForEvents(), sprintf('%s is targeted multiple times by the same "Covers" attribute', $target)); + } + foreach ($usesDuplicates as $target) { + Facade::emitter()->testTriggeredPhpunitWarning($test->valueObjectForEvents(), sprintf('%s is targeted multiple times by the same "Uses" attribute', $target)); + } + foreach ($coversAndUses as $target) { + Facade::emitter()->testTriggeredPhpunitWarning($test->valueObjectForEvents(), sprintf('%s is targeted by both "Covers" and "Uses" attributes', $target)); + } + } +} +initForIsolation( + PHPUnit\Event\Telemetry\HRTime::fromSecondsAndNanoseconds( + {offsetSeconds}, + {offsetNanoseconds} + ), + ); + + require_once '{filename}'; + + $configuration = ConfigurationRegistry::get(); + + if ({collectCodeCoverageInformation}) { + CodeCoverage::instance()->init($configuration, CodeCoverageFilterRegistry::instance(), true); + } + + $deprecationTriggers = [ + 'functions' => [], + 'methods' => [], + ]; + + foreach ($configuration->source()->deprecationTriggers()['functions'] as $function) { + $deprecationTriggers['functions'][] = $function; + } + + foreach ($configuration->source()->deprecationTriggers()['methods'] as $method) { + [$className, $methodName] = explode('::', $method); + + $deprecationTriggers['methods'][] = [ + 'className' => $className, + 'methodName' => $methodName, + ]; + } + + ErrorHandler::instance()->useDeprecationTriggers($deprecationTriggers); + + foreach (array_reverse($configuration->source()->issueTriggerResolvers()) as $className) { + ErrorHandler::instance()->addIssueTriggerResolver(new $className); + } + + $test = new {className}('{methodName}'); + + $test->setData('{dataName}', unserialize('{data}')); + $test->setDependencyInput(unserialize('{dependencyInput}')); + $test->setInIsolation(true); + + ob_end_clean(); + + $test->run(); + + $output = ''; + + if (!$test->expectsOutput()) { + $output = $test->output(); + } + + ini_set('xdebug.scream', '0'); + + // Not every STDOUT target stream is rewindable + $hasRewound = @rewind(STDOUT); + + if ($hasRewound && $stdout = @stream_get_contents(STDOUT)) { + $output = $stdout . $output; + $streamMetaData = stream_get_meta_data(STDOUT); + + if (!empty($streamMetaData['stream_type']) && 'STDIO' === $streamMetaData['stream_type']) { + @ftruncate(STDOUT, 0); + @rewind(STDOUT); + } + } + + file_put_contents( + '{processResultFile}', + '{processResultNonce}' . serialize( + (object)[ + 'testResult' => $test->result(), + 'codeCoverage' => {collectCodeCoverageInformation} ? CodeCoverage::instance()->codeCoverage() : null, + 'numAssertions' => $test->numberOfAssertionsPerformed(), + 'output' => $output, + 'events' => $dispatcher->flush(), + 'passedTests' => PassedTests::instance() + ] + ) + ); +} + +function __phpunit_error_handler($errno, $errstr, $errfile, $errline) +{ + return true; +} + +set_error_handler('__phpunit_error_handler'); + +{constants} +{included_files} +{globals} + +restore_error_handler(); + +ConfigurationRegistry::loadFrom('{serializedConfiguration}'); + +if ('{sourceMapFile}' !== '') { + SourceMapper::loadFrom('{sourceMapFile}', ConfigurationRegistry::get()->source()); +} + +(new PhpHandler)->handle(ConfigurationRegistry::get()->php()); + +if ('{bootstrap}' !== '') { + require_once '{bootstrap}'; +} + +$__phpunit_includeTestSuites = ConfigurationRegistry::get()->includeTestSuites(); +$__phpunit_excludeTestSuites = ConfigurationRegistry::get()->excludeTestSuites(); + +foreach (ConfigurationRegistry::get()->bootstrapForTestSuite() as $__phpunit_testSuiteName => $__phpunit_bootstrapForTestSuite) { + if ($__phpunit_includeTestSuites !== [] && !in_array($__phpunit_testSuiteName, $__phpunit_includeTestSuites, true)) { + continue; + } + + if ($__phpunit_excludeTestSuites !== [] && in_array($__phpunit_testSuiteName, $__phpunit_excludeTestSuites, true)) { + continue; + } + + require_once $__phpunit_bootstrapForTestSuite; +} + +__phpunit_run_isolated_test(); + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +abstract readonly class Known extends \PHPUnit\Framework\TestSize\TestSize +{ + public function isKnown(): true + { + return \true; + } + abstract public function isGreaterThan(self $other): bool; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Large extends \PHPUnit\Framework\TestSize\Known +{ + public function isLarge(): true + { + return \true; + } + public function isGreaterThan(\PHPUnit\Framework\TestSize\TestSize $other): bool + { + return !$other->isLarge(); + } + public function asString(): string + { + return 'large'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Medium extends \PHPUnit\Framework\TestSize\Known +{ + public function isMedium(): true + { + return \true; + } + public function isGreaterThan(\PHPUnit\Framework\TestSize\TestSize $other): bool + { + return $other->isSmall(); + } + public function asString(): string + { + return 'medium'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Small extends \PHPUnit\Framework\TestSize\Known +{ + public function isSmall(): true + { + return \true; + } + public function isGreaterThan(\PHPUnit\Framework\TestSize\TestSize $other): bool + { + return \false; + } + public function asString(): string + { + return 'small'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +abstract readonly class TestSize +{ + public static function unknown(): self + { + return new \PHPUnit\Framework\TestSize\Unknown(); + } + public static function small(): self + { + return new \PHPUnit\Framework\TestSize\Small(); + } + public static function medium(): self + { + return new \PHPUnit\Framework\TestSize\Medium(); + } + public static function large(): self + { + return new \PHPUnit\Framework\TestSize\Large(); + } + /** + * @phpstan-assert-if-true Known $this + */ + public function isKnown(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Unknown $this + */ + public function isUnknown(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Small $this + */ + public function isSmall(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Medium $this + */ + public function isMedium(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Large $this + */ + public function isLarge(): bool + { + return \false; + } + abstract public function asString(): string; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Unknown extends \PHPUnit\Framework\TestSize\TestSize +{ + public function isUnknown(): true + { + return \true; + } + public function asString(): string + { + return 'unknown'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Deprecation extends \PHPUnit\Framework\TestStatus\Known +{ + public function isDeprecation(): true + { + return \true; + } + public function asInt(): int + { + return 4; + } + public function asString(): string + { + return 'deprecation'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Error extends \PHPUnit\Framework\TestStatus\Known +{ + public function isError(): true + { + return \true; + } + public function asInt(): int + { + return 8; + } + public function asString(): string + { + return 'error'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Failure extends \PHPUnit\Framework\TestStatus\Known +{ + public function isFailure(): true + { + return \true; + } + public function asInt(): int + { + return 7; + } + public function asString(): string + { + return 'failure'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Incomplete extends \PHPUnit\Framework\TestStatus\Known +{ + public function isIncomplete(): true + { + return \true; + } + public function asInt(): int + { + return 2; + } + public function asString(): string + { + return 'incomplete'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Known extends \PHPUnit\Framework\TestStatus\TestStatus +{ + public function isKnown(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Notice extends \PHPUnit\Framework\TestStatus\Known +{ + public function isNotice(): true + { + return \true; + } + public function asInt(): int + { + return 3; + } + public function asString(): string + { + return 'notice'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Risky extends \PHPUnit\Framework\TestStatus\Known +{ + public function isRisky(): true + { + return \true; + } + public function asInt(): int + { + return 5; + } + public function asString(): string + { + return 'risky'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Skipped extends \PHPUnit\Framework\TestStatus\Known +{ + public function isSkipped(): true + { + return \true; + } + public function asInt(): int + { + return 1; + } + public function asString(): string + { + return 'skipped'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Success extends \PHPUnit\Framework\TestStatus\Known +{ + public function isSuccess(): true + { + return \true; + } + public function asInt(): int + { + return 0; + } + public function asString(): string + { + return 'success'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class TestStatus +{ + private string $message; + public static function from(int $status): self + { + return match ($status) { + 0 => self::success(), + 1 => self::skipped(), + 2 => self::incomplete(), + 3 => self::notice(), + 4 => self::deprecation(), + 5 => self::risky(), + 6 => self::warning(), + 7 => self::failure(), + 8 => self::error(), + default => self::unknown(), + }; + } + public static function unknown(): self + { + return new \PHPUnit\Framework\TestStatus\Unknown(); + } + public static function success(): self + { + return new \PHPUnit\Framework\TestStatus\Success(); + } + public static function skipped(string $message = ''): self + { + return new \PHPUnit\Framework\TestStatus\Skipped($message); + } + public static function incomplete(string $message = ''): self + { + return new \PHPUnit\Framework\TestStatus\Incomplete($message); + } + public static function notice(string $message = ''): self + { + return new \PHPUnit\Framework\TestStatus\Notice($message); + } + public static function deprecation(string $message = ''): self + { + return new \PHPUnit\Framework\TestStatus\Deprecation($message); + } + public static function failure(string $message = ''): self + { + return new \PHPUnit\Framework\TestStatus\Failure($message); + } + public static function error(string $message = ''): self + { + return new \PHPUnit\Framework\TestStatus\Error($message); + } + public static function warning(string $message = ''): self + { + return new \PHPUnit\Framework\TestStatus\Warning($message); + } + public static function risky(string $message = ''): self + { + return new \PHPUnit\Framework\TestStatus\Risky($message); + } + private function __construct(string $message = '') + { + $this->message = $message; + } + /** + * @phpstan-assert-if-true Known $this + */ + public function isKnown(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Unknown $this + */ + public function isUnknown(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Success $this + */ + public function isSuccess(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Skipped $this + */ + public function isSkipped(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Incomplete $this + */ + public function isIncomplete(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Notice $this + */ + public function isNotice(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Deprecation $this + */ + public function isDeprecation(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Failure $this + */ + public function isFailure(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Error $this + */ + public function isError(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Warning $this + */ + public function isWarning(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Risky $this + */ + public function isRisky(): bool + { + return \false; + } + public function message(): string + { + return $this->message; + } + public function isMoreImportantThan(self $other): bool + { + return $this->asInt() > $other->asInt(); + } + abstract public function asInt(): int; + abstract public function asString(): string; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Unknown extends \PHPUnit\Framework\TestStatus\TestStatus +{ + public function isUnknown(): true + { + return \true; + } + public function asInt(): int + { + return -1; + } + public function asString(): string + { + return 'unknown'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Warning extends \PHPUnit\Framework\TestStatus\Known +{ + public function isWarning(): true + { + return \true; + } + public function asInt(): int + { + return 6; + } + public function asString(): string + { + return 'warning'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function array_all; +use function array_merge; +use function array_pop; +use function array_reverse; +use function assert; +use function call_user_func; +use function class_exists; +use function count; +use function implode; +use function is_callable; +use function is_file; +use function is_subclass_of; +use function sprintf; +use function str_ends_with; +use function str_starts_with; +use function trim; +use Iterator; +use IteratorAggregate; +use PHPUnit\Event; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\NoPreviousThrowableException; +use PHPUnit\Metadata\Api\Dependencies; +use PHPUnit\Metadata\Api\Groups; +use PHPUnit\Metadata\Api\HookMethods; +use PHPUnit\Metadata\Api\Requirements; +use PHPUnit\Metadata\MetadataCollection; +use PHPUnit\Runner\Exception as RunnerException; +use PHPUnit\Runner\Filter\Factory; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use PHPUnit\Runner\TestSuiteLoader; +use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade; +use PHPUnit\Util\Filter; +use PHPUnit\Util\Reflection; +use PHPUnit\Util\Test as TestUtil; +use ReflectionClass; +use ReflectionMethod; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\InvalidArgumentException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException; +use Throwable; +/** + * @template-implements IteratorAggregate + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +class TestSuite implements IteratorAggregate, \PHPUnit\Framework\Reorderable, \PHPUnit\Framework\Test +{ + /** + * @var non-empty-string + */ + private string $name; + /** + * @var array> + */ + private array $groups = []; + /** + * @var ?list + */ + private ?array $requiredTests = null; + /** + * @var list + */ + private array $tests = []; + /** + * @var ?list + */ + private ?array $providedTests = null; + private ?Factory $iteratorFilter = null; + private bool $wasRun = \false; + /** + * @param non-empty-string $name + */ + public static function empty(string $name): static + { + return new static($name); + } + /** + * @param ReflectionClass $class + * @param list $groups + */ + public static function fromClassReflector(ReflectionClass $class, array $groups = []): static + { + $testSuite = new static($class->getName()); + foreach (Reflection::publicMethodsDeclaredDirectlyInTestClass($class) as $method) { + if (!TestUtil::isTestMethod($method)) { + continue; + } + if ((new HookMethods())->isHookMethod($method)) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Method %s::%s() cannot be used both as a hook method and as a test method', $class->getName(), $method->getName())); + continue; + } + $testSuite->addTestMethod($class, $method, $groups); + } + if ($testSuite->isEmpty()) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('No tests found in class "%s".', $class->getName())); + } + return $testSuite; + } + /** + * @param non-empty-string $name + */ + final private function __construct(string $name) + { + $this->name = $name; + } + /** + * Adds a test to the suite. + * + * @param list $groups + */ + public function addTest(\PHPUnit\Framework\Test $test, array $groups = []): void + { + if ($test instanceof self) { + $this->tests[] = $test; + $this->clearCaches(); + return; + } + assert($test instanceof \PHPUnit\Framework\TestCase || $test instanceof PhptTestCase); + $this->tests[] = $test; + $this->clearCaches(); + if ($this->containsOnlyVirtualGroups($groups)) { + $groups[] = 'default'; + } + if ($test instanceof \PHPUnit\Framework\TestCase) { + $id = $test->valueObjectForEvents()->id(); + $test->setGroups($groups); + } else { + $id = $test->valueObjectForEvents()->id(); + } + foreach ($groups as $group) { + if (!isset($this->groups[$group])) { + $this->groups[$group] = [$id]; + } else { + $this->groups[$group][] = $id; + } + } + } + /** + * Adds the tests from the given class to the suite. + * + * @param ReflectionClass $testClass + * @param list $groups + * + * @throws Exception + */ + public function addTestSuite(ReflectionClass $testClass, array $groups = []): void + { + if ($testClass->isAbstract()) { + throw new \PHPUnit\Framework\Exception(sprintf('Class %s is abstract', $testClass->getName())); + } + if (!$testClass->isSubclassOf(\PHPUnit\Framework\TestCase::class)) { + throw new \PHPUnit\Framework\Exception(sprintf('Class %s is not a subclass of %s', $testClass->getName(), \PHPUnit\Framework\TestCase::class)); + } + $this->addTest(self::fromClassReflector($testClass, $groups), $groups); + } + /** + * Wraps both addTest() and addTestSuite + * as well as the separate import statements for the user's convenience. + * + * If the named file cannot be read or there are no new tests that can be + * added, a PHPUnit\Framework\WarningTestCase will be created instead, + * leaving the current test run untouched. + * + * @param list $groups + * + * @throws Exception + */ + public function addTestFile(string $filename, array $groups = []): void + { + try { + if (str_ends_with($filename, '.phpt') && is_file($filename)) { + $this->addTest(new PhptTestCase($filename)); + } else { + $this->addTestSuite((new TestSuiteLoader())->load($filename), $groups); + } + } catch (RunnerException $e) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning($e->getMessage()); + } + } + /** + * Wrapper for addTestFile() that adds multiple test files. + * + * @param iterable $fileNames + * + * @throws Exception + */ + public function addTestFiles(iterable $fileNames): void + { + foreach ($fileNames as $filename) { + $this->addTestFile((string) $filename); + } + } + /** + * Counts the number of test cases that will be run by this test. + */ + public function count(): int + { + $numTests = 0; + foreach ($this as $test) { + $numTests += count($test); + } + return $numTests; + } + public function isEmpty(): bool + { + foreach ($this as $test) { + if (count($test) !== 0) { + return \false; + } + } + return \true; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + /** + * @return array> + */ + public function groups(): array + { + return $this->groups; + } + /** + * @return list + */ + public function collect(): array + { + $tests = []; + foreach ($this as $test) { + if ($test instanceof self) { + $tests = array_merge($tests, $test->collect()); + continue; + } + assert($test instanceof \PHPUnit\Framework\TestCase || $test instanceof PhptTestCase); + $tests[] = $test; + } + return $tests; + } + /** + * @throws Event\RuntimeException + * @throws Exception + * @throws InvalidArgumentException + * @throws NoPreviousThrowableException + * @throws UnintentionallyCoveredCodeException + */ + public function run(): void + { + if ($this->wasRun) { + // @codeCoverageIgnoreStart + throw new \PHPUnit\Framework\Exception('The tests aggregated by this TestSuite were already run'); + // @codeCoverageIgnoreEnd + } + $this->wasRun = \true; + if ($this->isEmpty()) { + return; + } + $emitter = Event\Facade::emitter(); + $testSuiteValueObjectForEvents = Event\TestSuite\TestSuiteBuilder::from($this); + $emitter->testSuiteStarted($testSuiteValueObjectForEvents); + if (!$this->invokeMethodsBeforeFirstTest($emitter, $testSuiteValueObjectForEvents)) { + return; + } + /** @var list $tests */ + $tests = []; + foreach ($this as $test) { + $tests[] = $test; + } + $tests = array_reverse($tests); + $this->tests = []; + $this->groups = []; + while (($test = array_pop($tests)) !== null) { + if (TestResultFacade::shouldStop()) { + $emitter->testRunnerExecutionAborted(); + break; + } + $test->run(); + } + $this->invokeMethodsAfterLastTest($emitter); + $emitter->testSuiteFinished($testSuiteValueObjectForEvents); + } + /** + * Returns the tests as an enumeration. + * + * @return list + */ + public function tests(): array + { + return $this->tests; + } + /** + * Set tests of the test suite. + * + * @param list $tests + */ + public function setTests(array $tests): void + { + $this->tests = $tests; + } + /** + * Mark the test suite as skipped. + * + * @throws SkippedTestSuiteError + */ + public function markTestSuiteSkipped(string $message = ''): never + { + throw new \PHPUnit\Framework\SkippedTestSuiteError($message); + } + /** + * @return Iterator + */ + public function getIterator(): Iterator + { + $iterator = new \PHPUnit\Framework\TestSuiteIterator($this); + if ($this->iteratorFilter !== null) { + $iterator = $this->iteratorFilter->factory($iterator, $this); + } + return $iterator; + } + public function injectFilter(Factory $filter): void + { + $this->iteratorFilter = $filter; + foreach ($this as $test) { + if ($test instanceof self) { + $test->injectFilter($filter); + } + } + } + /** + * @return list + */ + public function provides(): array + { + if ($this->providedTests === null) { + $this->providedTests = []; + if (is_callable($this->sortId(), \true)) { + $this->providedTests[] = new \PHPUnit\Framework\ExecutionOrderDependency($this->sortId()); + } + foreach ($this->tests as $test) { + if (!$test instanceof \PHPUnit\Framework\Reorderable) { + // @codeCoverageIgnoreStart + continue; + // @codeCoverageIgnoreEnd + } + $this->providedTests = \PHPUnit\Framework\ExecutionOrderDependency::mergeUnique($this->providedTests, $test->provides()); + } + } + return $this->providedTests; + } + /** + * @return list + */ + public function requires(): array + { + if ($this->requiredTests === null) { + $this->requiredTests = []; + foreach ($this->tests as $test) { + if (!$test instanceof \PHPUnit\Framework\Reorderable) { + // @codeCoverageIgnoreStart + continue; + // @codeCoverageIgnoreEnd + } + $this->requiredTests = \PHPUnit\Framework\ExecutionOrderDependency::mergeUnique(\PHPUnit\Framework\ExecutionOrderDependency::filterInvalid($this->requiredTests), $test->requires()); + } + $this->requiredTests = \PHPUnit\Framework\ExecutionOrderDependency::diff($this->requiredTests, $this->provides()); + } + return $this->requiredTests; + } + public function sortId(): string + { + return $this->name() . '::class'; + } + /** + * @phpstan-assert-if-true class-string $this->name + */ + public function isForTestClass(): bool + { + return class_exists($this->name, \false) && is_subclass_of($this->name, \PHPUnit\Framework\TestCase::class); + } + /** + * @param ReflectionClass $class + * @param list $groups + * + * @throws Exception + */ + protected function addTestMethod(ReflectionClass $class, ReflectionMethod $method, array $groups): void + { + $className = $class->getName(); + $methodName = $method->getName(); + try { + $test = (new \PHPUnit\Framework\TestBuilder())->build($class, $methodName, $groups); + } catch (\PHPUnit\Framework\InvalidDataProviderException $e) { + if ($e->getProviderLabel() === null) { + $message = sprintf("The data provider specified for %s::%s is invalid\n%s", $className, $methodName, $this->exceptionToString($e)); + } else { + $message = sprintf("The data provider %s specified for %s::%s is invalid\n%s", $e->getProviderLabel(), $className, $methodName, $this->exceptionToString($e)); + } + Event\Facade::emitter()->testTriggeredPhpunitError(new TestMethod($className, $methodName, $method->getFileName(), $method->getStartLine(), Event\Code\TestDoxBuilder::fromClassNameAndMethodName($className, $methodName), MetadataCollection::fromArray([]), Event\TestData\TestDataCollection::fromArray([])), $message); + return; + } + if ($test instanceof \PHPUnit\Framework\TestCase || $test instanceof \PHPUnit\Framework\DataProviderTestSuite) { + $test->setDependencies(Dependencies::dependencies($class->getName(), $methodName)); + } + $this->addTest($test, array_merge($groups, (new Groups())->groups($class->getName(), $methodName))); + } + private function clearCaches(): void + { + $this->providedTests = null; + $this->requiredTests = null; + } + /** + * @param list $groups + */ + private function containsOnlyVirtualGroups(array $groups): bool + { + return array_all($groups, static fn(string $group) => str_starts_with($group, '__phpunit_')); + } + private function methodDoesNotExistOrIsDeclaredInTestCase(string $methodName): bool + { + $reflector = new ReflectionClass($this->name); + return !$reflector->hasMethod($methodName) || $reflector->getMethod($methodName)->getDeclaringClass()->getName() === \PHPUnit\Framework\TestCase::class; + } + /** + * @throws Exception + */ + private function exceptionToString(\PHPUnit\Framework\InvalidDataProviderException $e): string + { + $message = $e->getMessage(); + if (trim($message) === '') { + $message = ''; + } + return sprintf("%s\n%s", $message, Filter::stackTraceFromThrowableAsString($e)); + } + /** + * @throws Exception + * @throws NoPreviousThrowableException + */ + private function invokeMethodsBeforeFirstTest(Event\Emitter $emitter, Event\TestSuite\TestSuite $testSuiteValueObjectForEvents): bool + { + if (!$this->isForTestClass()) { + return \true; + } + $methods = (new HookMethods())->hookMethods($this->name)['beforeClass']->methodNamesSortedByPriority(); + $calledMethods = []; + $emitCalledEvent = \true; + $result = \true; + foreach ($methods as $method) { + if ($this->methodDoesNotExistOrIsDeclaredInTestCase($method)) { + continue; + } + $calledMethod = new Event\Code\ClassMethod($this->name, $method); + try { + $missingRequirements = (new Requirements())->requirementsNotSatisfiedFor($this->name, $method); + if ($missingRequirements !== []) { + $emitCalledEvent = \false; + $this->markTestSuiteSkipped(implode(PHP_EOL, $missingRequirements)); + } + call_user_func([$this->name, $method]); + } catch (Throwable $t) { + } + if ($emitCalledEvent) { + $emitter->beforeFirstTestMethodCalled($this->name, $calledMethod); + $calledMethods[] = $calledMethod; + } + if (isset($t) && $t instanceof \PHPUnit\Framework\SkippedTest) { + $emitter->testSuiteSkipped($testSuiteValueObjectForEvents, $t->getMessage()); + return \false; + } + if (isset($t)) { + if ($t instanceof \PHPUnit\Framework\AssertionFailedError) { + $emitter->beforeFirstTestMethodFailed($this->name, $calledMethod, Event\Code\ThrowableBuilder::from($t)); + } else { + $emitter->beforeFirstTestMethodErrored($this->name, $calledMethod, Event\Code\ThrowableBuilder::from($t)); + } + $result = \false; + } + } + if ($calledMethods !== []) { + $emitter->beforeFirstTestMethodFinished($this->name, ...$calledMethods); + } + if (!$result) { + $emitter->testSuiteFinished($testSuiteValueObjectForEvents); + } + return $result; + } + private function invokeMethodsAfterLastTest(Event\Emitter $emitter): void + { + if (!$this->isForTestClass()) { + return; + } + $methods = (new HookMethods())->hookMethods($this->name)['afterClass']->methodNamesSortedByPriority(); + $calledMethods = []; + foreach ($methods as $method) { + if ($this->methodDoesNotExistOrIsDeclaredInTestCase($method)) { + continue; + } + $calledMethod = new Event\Code\ClassMethod($this->name, $method); + try { + call_user_func([$this->name, $method]); + } catch (Throwable $t) { + } + $emitter->afterLastTestMethodCalled($this->name, $calledMethod); + $calledMethods[] = $calledMethod; + if (isset($t)) { + if ($t instanceof \PHPUnit\Framework\AssertionFailedError) { + $emitter->afterLastTestMethodFailed($this->name, $calledMethod, Event\Code\ThrowableBuilder::from($t)); + } else { + $emitter->afterLastTestMethodErrored($this->name, $calledMethod, Event\Code\ThrowableBuilder::from($t)); + } + } + } + if ($calledMethods !== []) { + $emitter->afterLastTestMethodFinished($this->name, ...$calledMethods); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function assert; +use RecursiveIterator; +/** + * @template-implements RecursiveIterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestSuiteIterator implements RecursiveIterator +{ + /** + * @var list + */ + private readonly array $tests; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\Framework\TestSuite $testSuite) + { + $this->tests = $testSuite->tests(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->tests[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\Framework\Test + { + return $this->tests[$this->position]; + } + public function next(): void + { + $this->position++; + } + /** + * @throws NoChildTestSuiteException + */ + public function getChildren(): self + { + if (!$this->hasChildren()) { + throw new \PHPUnit\Framework\NoChildTestSuiteException('The current item is not a TestSuite instance and therefore does not have any children.'); + } + $current = $this->current(); + assert($current instanceof \PHPUnit\Framework\TestSuite); + return new self($current); + } + public function hasChildren(): bool + { + return $this->valid() && $this->current() instanceof \PHPUnit\Framework\TestSuite; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging; + +use const FILE_APPEND; +use const LOCK_EX; +use const PHP_EOL; +use const PHP_OS_FAMILY; +use function file_put_contents; +use function implode; +use function preg_split; +use function str_repeat; +use function strlen; +use PHPUnit\Event\Event; +use PHPUnit\Event\Tracer\Tracer; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class EventLogger implements Tracer +{ + private string $path; + private bool $includeTelemetryInfo; + public function __construct(string $path, bool $includeTelemetryInfo) + { + $this->path = $path; + $this->includeTelemetryInfo = $includeTelemetryInfo; + } + public function trace(Event $event): void + { + $telemetryInfo = $this->telemetryInfo($event); + $indentation = PHP_EOL . str_repeat(' ', strlen($telemetryInfo)); + $flags = FILE_APPEND; + if (!(PHP_OS_FAMILY === 'Windows' || PHP_OS_FAMILY === 'Darwin') || $this->path !== 'php://stdout') { + $flags |= LOCK_EX; + } + $lines = preg_split('/\r\n|\r|\n/', $event->asString()); + if ($lines === \false) { + $lines = []; + } + file_put_contents($this->path, $telemetryInfo . implode($indentation, $lines) . PHP_EOL, $flags); + } + private function telemetryInfo(Event $event): string + { + if (!$this->includeTelemetryInfo) { + return ''; + } + return $event->telemetryInfo()->asString() . ' '; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use const PHP_EOL; +use function assert; +use function basename; +use function is_int; +use function sprintf; +use function str_replace; +use function trim; +use DOMDocument; +use DOMElement; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Facade; +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Telemetry\HRTime; +use PHPUnit\Event\Telemetry\Info; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\PreparationStarted; +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PrintedUnexpectedOutput; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\TextUI\Output\Printer; +use PHPUnit\Util\Xml; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class JunitXmlLogger +{ + private readonly Printer $printer; + private DOMDocument $document; + private DOMElement $root; + /** + * @var array + */ + private array $testSuites = []; + /** + * @var array + */ + private array $testSuiteTests = [0]; + /** + * @var array + */ + private array $testSuiteAssertions = [0]; + /** + * @var array + */ + private array $testSuiteErrors = [0]; + /** + * @var array + */ + private array $testSuiteFailures = [0]; + /** + * @var array + */ + private array $testSuiteSkipped = [0]; + /** + * @var array + */ + private array $testSuiteTimes = [0.0]; + private int $testSuiteLevel = 0; + private ?DOMElement $currentTestCase = null; + private ?HRTime $time = null; + private bool $prepared = \false; + private bool $preparationFailed = \false; + private ?string $unexpectedOutput = null; + public function __construct(Printer $printer, Facade $facade) + { + $this->printer = $printer; + $this->registerSubscribers($facade); + $this->createDocument(); + } + public function flush(): void + { + $xml = $this->document->saveXML(); + if ($xml === \false) { + $xml = ''; + } + $this->printer->print($xml); + $this->printer->flush(); + } + public function testSuiteStarted(Started $event): void + { + $testSuite = $this->document->createElement('testsuite'); + $testSuite->setAttribute('name', $event->testSuite()->name()); + if ($event->testSuite()->isForTestClass()) { + $testSuite->setAttribute('file', $event->testSuite()->file()); + } + if ($this->testSuiteLevel > 0) { + $this->testSuites[$this->testSuiteLevel]->appendChild($testSuite); + } else { + $this->root->appendChild($testSuite); + } + $this->testSuiteLevel++; + $this->testSuites[$this->testSuiteLevel] = $testSuite; + $this->testSuiteTests[$this->testSuiteLevel] = 0; + $this->testSuiteAssertions[$this->testSuiteLevel] = 0; + $this->testSuiteErrors[$this->testSuiteLevel] = 0; + $this->testSuiteFailures[$this->testSuiteLevel] = 0; + $this->testSuiteSkipped[$this->testSuiteLevel] = 0; + $this->testSuiteTimes[$this->testSuiteLevel] = 0.0; + } + public function testSuiteSkipped(TestSuiteSkipped $event): void + { + assert(isset($this->testSuiteSkipped[$this->testSuiteLevel])); + assert(isset($this->testSuiteTests[$this->testSuiteLevel])); + $this->testSuiteSkipped[$this->testSuiteLevel] += $event->testSuite()->count(); + $this->testSuiteTests[$this->testSuiteLevel] += $event->testSuite()->count(); + $this->testSuiteFinished(); + } + public function testSuiteFinished(): void + { + $this->testSuites[$this->testSuiteLevel]->setAttribute('tests', (string) $this->testSuiteTests[$this->testSuiteLevel]); + $this->testSuites[$this->testSuiteLevel]->setAttribute('assertions', (string) $this->testSuiteAssertions[$this->testSuiteLevel]); + $this->testSuites[$this->testSuiteLevel]->setAttribute('errors', (string) $this->testSuiteErrors[$this->testSuiteLevel]); + $this->testSuites[$this->testSuiteLevel]->setAttribute('failures', (string) $this->testSuiteFailures[$this->testSuiteLevel]); + $this->testSuites[$this->testSuiteLevel]->setAttribute('skipped', (string) $this->testSuiteSkipped[$this->testSuiteLevel]); + $this->testSuites[$this->testSuiteLevel]->setAttribute('time', sprintf('%F', $this->testSuiteTimes[$this->testSuiteLevel])); + if ($this->testSuiteLevel > 1) { + $this->testSuiteTests[$this->testSuiteLevel - 1] += $this->testSuiteTests[$this->testSuiteLevel]; + $this->testSuiteAssertions[$this->testSuiteLevel - 1] += $this->testSuiteAssertions[$this->testSuiteLevel]; + $this->testSuiteErrors[$this->testSuiteLevel - 1] += $this->testSuiteErrors[$this->testSuiteLevel]; + $this->testSuiteFailures[$this->testSuiteLevel - 1] += $this->testSuiteFailures[$this->testSuiteLevel]; + $this->testSuiteSkipped[$this->testSuiteLevel - 1] += $this->testSuiteSkipped[$this->testSuiteLevel]; + $this->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel]; + } + $this->testSuiteLevel--; + } + /** + * @throws InvalidArgumentException + */ + public function testPreparationStarted(PreparationStarted $event): void + { + $this->createTestCase($event); + $this->preparationFailed = \false; + } + public function testPreparationErrored(): void + { + $this->preparationFailed = \true; + } + public function testPreparationFailed(): void + { + $this->preparationFailed = \true; + } + public function testPrepared(): void + { + $this->prepared = \true; + } + public function testPrintedUnexpectedOutput(PrintedUnexpectedOutput $event): void + { + $this->unexpectedOutput = $event->output(); + } + /** + * @throws InvalidArgumentException + */ + public function testFinished(Finished $event): void + { + if (!$this->prepared || $this->preparationFailed) { + return; + } + $this->handleFinish($event->telemetryInfo(), $event->numberOfAssertionsPerformed()); + } + /** + * @throws InvalidArgumentException + */ + public function testMarkedIncomplete(MarkedIncomplete $event): void + { + $this->handleIncompleteOrSkipped($event); + } + /** + * @throws InvalidArgumentException + */ + public function testSkipped(Skipped $event): void + { + $this->handleIncompleteOrSkipped($event); + } + /** + * @throws InvalidArgumentException + */ + public function testErrored(Errored $event): void + { + $this->handleFault($event, 'error'); + $this->testSuiteErrors[$this->testSuiteLevel]++; + } + /** + * @throws InvalidArgumentException + */ + public function testFailed(Failed $event): void + { + $this->handleFault($event, 'failure'); + $this->testSuiteFailures[$this->testSuiteLevel]++; + } + /** + * @throws InvalidArgumentException + */ + private function handleFinish(Info $telemetryInfo, int $numberOfAssertionsPerformed): void + { + assert($this->currentTestCase !== null); + assert($this->time !== null); + $time = $telemetryInfo->time()->duration($this->time)->asFloat(); + $this->testSuiteAssertions[$this->testSuiteLevel] += $numberOfAssertionsPerformed; + $this->currentTestCase->setAttribute('assertions', (string) $numberOfAssertionsPerformed); + $this->currentTestCase->setAttribute('time', sprintf('%F', $time)); + if ($this->unexpectedOutput !== null) { + $systemOut = $this->document->createElement('system-out', Xml::prepareString($this->unexpectedOutput)); + $this->currentTestCase->appendChild($systemOut); + } + $this->testSuites[$this->testSuiteLevel]->appendChild($this->currentTestCase); + $this->testSuiteTests[$this->testSuiteLevel]++; + $this->testSuiteTimes[$this->testSuiteLevel] += $time; + $this->currentTestCase = null; + $this->time = null; + $this->preparationFailed = \false; + $this->prepared = \false; + $this->unexpectedOutput = null; + } + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers(new \PHPUnit\Logging\JUnit\TestSuiteStartedSubscriber($this), new \PHPUnit\Logging\JUnit\TestSuiteSkippedSubscriber($this), new \PHPUnit\Logging\JUnit\TestSuiteFinishedSubscriber($this), new \PHPUnit\Logging\JUnit\TestPreparationStartedSubscriber($this), new \PHPUnit\Logging\JUnit\TestPreparationErroredSubscriber($this), new \PHPUnit\Logging\JUnit\TestPreparationFailedSubscriber($this), new \PHPUnit\Logging\JUnit\TestPreparedSubscriber($this), new \PHPUnit\Logging\JUnit\TestPrintedUnexpectedOutputSubscriber($this), new \PHPUnit\Logging\JUnit\TestFinishedSubscriber($this), new \PHPUnit\Logging\JUnit\TestErroredSubscriber($this), new \PHPUnit\Logging\JUnit\TestFailedSubscriber($this), new \PHPUnit\Logging\JUnit\TestMarkedIncompleteSubscriber($this), new \PHPUnit\Logging\JUnit\TestSkippedSubscriber($this), new \PHPUnit\Logging\JUnit\TestRunnerExecutionFinishedSubscriber($this)); + } + private function createDocument(): void + { + $this->document = new DOMDocument('1.0', 'UTF-8'); + $this->document->formatOutput = \true; + $this->root = $this->document->createElement('testsuites'); + $this->document->appendChild($this->root); + } + /** + * @throws InvalidArgumentException + */ + private function handleFault(Errored|Failed $event, string $type): void + { + if (!$this->prepared) { + $this->createTestCase($event); + } + assert($this->currentTestCase !== null); + $buffer = $this->testAsString($event->test()); + $throwable = $event->throwable(); + $buffer .= trim($throwable->description() . PHP_EOL . $throwable->stackTrace()); + $fault = $this->document->createElement($type, Xml::prepareString($buffer)); + $fault->setAttribute('type', $throwable->className()); + $this->currentTestCase->appendChild($fault); + if (!$this->prepared) { + $this->handleFinish($event->telemetryInfo(), 0); + } + } + /** + * @throws InvalidArgumentException + */ + private function handleIncompleteOrSkipped(MarkedIncomplete|Skipped $event): void + { + if (!$this->prepared) { + $this->createTestCase($event); + } + assert($this->currentTestCase !== null); + $skipped = $this->document->createElement('skipped'); + $this->currentTestCase->appendChild($skipped); + $this->testSuiteSkipped[$this->testSuiteLevel]++; + if (!$this->prepared) { + $this->handleFinish($event->telemetryInfo(), 0); + } + } + /** + * @throws InvalidArgumentException + */ + private function testAsString(Test $test): string + { + if ($test->isPhpt()) { + return basename($test->file()); + } + assert($test instanceof TestMethod); + return sprintf('%s::%s%s', $test->className(), $this->name($test), PHP_EOL); + } + /** + * @throws InvalidArgumentException + */ + private function name(Test $test): string + { + if ($test->isPhpt()) { + return basename($test->file()); + } + assert($test instanceof TestMethod); + if (!$test->testData()->hasDataFromDataProvider()) { + return $test->methodName(); + } + $dataSetName = $test->testData()->dataFromDataProvider()->dataSetName(); + if (is_int($dataSetName)) { + return sprintf('%s with data set #%d', $test->methodName(), $dataSetName); + } + return sprintf('%s with data set "%s"', $test->methodName(), $dataSetName); + } + /** + * @throws InvalidArgumentException + * + * @phpstan-assert !null $this->currentTestCase + */ + private function createTestCase(Errored|Failed|MarkedIncomplete|PreparationStarted|Prepared|Skipped $event): void + { + $testCase = $this->document->createElement('testcase'); + $test = $event->test(); + $testCase->setAttribute('name', $this->name($test)); + $testCase->setAttribute('file', $test->file()); + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + $testCase->setAttribute('line', (string) $test->line()); + $testCase->setAttribute('class', $test->className()); + $testCase->setAttribute('classname', str_replace('\\', '.', $test->className())); + } + $this->currentTestCase = $testCase; + $this->time = $event->telemetryInfo()->time(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private \PHPUnit\Logging\JUnit\JunitXmlLogger $logger; + public function __construct(\PHPUnit\Logging\JUnit\JunitXmlLogger $logger) + { + $this->logger = $logger; + } + protected function logger(): \PHPUnit\Logging\JUnit\JunitXmlLogger + { + return $this->logger; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements ErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Errored $event): void + { + $this->logger()->testErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements FailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Failed $event): void + { + $this->logger()->testFailed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements FinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->logger()->testFinished($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements MarkedIncompleteSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(MarkedIncomplete $event): void + { + $this->logger()->testMarkedIncomplete($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationErrored; +use PHPUnit\Event\Test\PreparationErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationErroredSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements PreparationErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationErrored $event): void + { + $this->logger()->testPreparationErrored(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationFailed; +use PHPUnit\Event\Test\PreparationFailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationFailedSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements PreparationFailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationFailed $event): void + { + $this->logger()->testPreparationFailed(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationStarted; +use PHPUnit\Event\Test\PreparationStartedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationStartedSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements PreparationStartedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationStarted $event): void + { + $this->logger()->testPreparationStarted($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements PreparedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Prepared $event): void + { + $this->logger()->testPrepared(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\Test\PrintedUnexpectedOutput; +use PHPUnit\Event\Test\PrintedUnexpectedOutputSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPrintedUnexpectedOutputSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements PrintedUnexpectedOutputSubscriber +{ + public function notify(PrintedUnexpectedOutput $event): void + { + $this->logger()->testPrintedUnexpectedOutput($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerExecutionFinishedSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements ExecutionFinishedSubscriber +{ + public function notify(ExecutionFinished $event): void + { + $this->logger()->flush(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements SkippedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->logger()->testSkipped($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\TestSuite\Finished; +use PHPUnit\Event\TestSuite\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFinishedSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->logger()->testSuiteFinished(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\TestSuite\Skipped; +use PHPUnit\Event\TestSuite\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteSkippedSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements SkippedSubscriber +{ + public function notify(Skipped $event): void + { + $this->logger()->testSuiteSkipped($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\Event\TestSuite\StartedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteStartedSubscriber extends \PHPUnit\Logging\JUnit\Subscriber implements StartedSubscriber +{ + public function notify(Started $event): void + { + $this->logger()->testSuiteStarted($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use RuntimeException; +final class CannotOpenUriForWritingException extends RuntimeException implements \PHPUnit\Logging\OpenTestReporting\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +interface Exception extends \PHPUnit\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use const PHP_VERSION; +use const ZEND_THREAD_SAFE; +use function array_pop; +use function assert; +use function count; +use function error_get_last; +use function str_replace; +use DateTimeImmutable; +use DateTimeZone; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\AfterLastTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\PreparationErrored; +use PHPUnit\Event\Test\PreparationFailed; +use PHPUnit\Event\Test\Prepared as TestStarted; +use PHPUnit\Event\Test\PrintedUnexpectedOutput; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; +use PHPUnit\Event\TestSuite\TestSuiteForTestClass; +use PHPUnit\Metadata\Group; +use PHPUnitPHAR\SebastianBergmann\Environment\Host; +use PHPUnitPHAR\SebastianBergmann\GitState\Builder as GitStateBuilder; +use PHPUnitPHAR\SebastianBergmann\GitState\State as GitState; +use XMLWriter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class OtrXmlLogger +{ + private readonly XMLWriter $writer; + /** + * @var non-negative-int + */ + private int $idSequence = 0; + /** + * @var ?positive-int + */ + private ?int $parentId = null; + /** + * @var list + */ + private array $parentIdStack = []; + /** + * @var ?positive-int + */ + private ?int $testId = null; + private ?Throwable $parentErrored = null; + private ?Throwable $parentFailed = null; + private bool $testWasPrepared = \false; + private bool $alreadyFinished = \false; + private ?\PHPUnit\Logging\OpenTestReporting\Status $pendingStatus = null; + private ?string $pendingReason = null; + private ?Throwable $pendingThrowable = null; + private ?bool $pendingAssertionError = null; + private bool $includeGitInformation; + /** + * @param non-empty-string $uri + * + * @throws CannotOpenUriForWritingException + */ + public function __construct(Facade $facade, string $uri, bool $includeGitInformation) + { + $this->writer = new XMLWriter(); + if (@$this->writer->openUri($uri) === \false) { + throw new \PHPUnit\Logging\OpenTestReporting\CannotOpenUriForWritingException(str_replace('XMLWriter::openUri(): ', '', error_get_last()['message'])); + } + $this->writer->setIndent(\true); + $this->registerSubscribers($facade); + $this->includeGitInformation = $includeGitInformation; + } + public function testRunnerStarted(): void + { + $host = new Host(); + $gitInformation = $this->gitInformation(); + $this->writer->startDocument(); + $this->writer->startElement('e:events'); + $this->writer->writeAttribute('xmlns', 'https://schemas.opentest4j.org/reporting/core/0.2.0'); + $this->writer->writeAttribute('xmlns:e', 'https://schemas.opentest4j.org/reporting/events/0.2.0'); + if ($gitInformation !== \false) { + $this->writer->writeAttribute('xmlns:git', 'https://schemas.opentest4j.org/reporting/git/0.2.0'); + } + $this->writer->writeAttribute('xmlns:php', 'https://schema.phpunit.de/otr/php/0.1.0'); + $this->writer->writeAttribute('xmlns:phpunit', 'https://schema.phpunit.de/otr/phpunit/0.1.0'); + $this->writer->startElement('infrastructure'); + $this->writer->writeElement('hostName', $host->name()); + $this->writer->writeElement('userName', $host->user()); + $this->writer->writeElement('operatingSystem', $host->operatingSystem()); + $this->writer->writeElement('php:phpVersion', PHP_VERSION); + $this->writer->writeElement('php:threadModel', ZEND_THREAD_SAFE ? 'ZTS' : 'NTS'); + if ($gitInformation !== \false) { + $this->writer->startElement('git:repository'); + $this->writer->writeAttribute('originUrl', $gitInformation->originUrl()); + $this->writer->endElement(); + $this->writer->writeElement('git:branch', $gitInformation->branch()); + $this->writer->writeElement('git:commit', $gitInformation->commit()); + $this->writer->startElement('git:status'); + $this->writer->writeAttribute('clean', $gitInformation->isClean() ? 'true' : 'false'); + $this->writer->writeCdata($gitInformation->status()); + $this->writer->endElement(); + } + $this->writer->endElement(); + $this->writer->flush(); + } + public function testRunnerFinished(): void + { + $this->writer->endDocument(); + $this->writer->flush(); + } + public function testSuiteStarted(TestSuiteStarted $event): void + { + $id = $this->nextId(); + $this->writer->startElement('e:started'); + $this->writer->writeAttribute('id', (string) $id); + if ($this->parentId !== null) { + $this->writer->writeAttribute('parentId', (string) $this->parentId); + } + $testSuite = $event->testSuite(); + $this->writer->writeAttribute('name', $testSuite->name()); + $this->writer->writeAttribute('time', $this->timestamp()); + if ($testSuite->isForTestClass()) { + assert($testSuite instanceof TestSuiteForTestClass); + $this->writer->startElement('sources'); + $this->writer->startElement('fileSource'); + $this->writer->writeAttribute('path', $testSuite->file()); + $this->writer->startElement('filePosition'); + $this->writer->writeAttribute('line', (string) $testSuite->line()); + $this->writer->endElement(); + $this->writer->endElement(); + $this->writer->startElement('phpunit:classSource'); + $this->writer->writeAttribute('className', $testSuite->className()); + $this->writer->endElement(); + $this->writer->endElement(); + } + $this->writer->endElement(); + $this->writer->flush(); + $this->parentId = $id; + $this->parentIdStack[] = $id; + } + public function testSuiteSkipped(TestSuiteSkipped $event): void + { + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->parentId); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', 'SKIPPED'); + $this->writer->writeElement('reason', $event->message()); + $this->writer->endElement(); + $this->writer->endElement(); + $this->writer->flush(); + $this->reduceTestSuiteLevel(); + } + public function testSuiteFinished(): void + { + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->parentId); + $this->writer->writeAttribute('time', $this->timestamp()); + if ($this->parentErrored !== null) { + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', 'ERRORED'); + $this->writer->writeElement('reason', $this->parentErrored->message()); + $this->writeThrowable($this->parentErrored, \false); + $this->writer->endElement(); + } elseif ($this->parentFailed !== null) { + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', 'FAILED'); + $this->writer->writeElement('reason', $this->parentFailed->message()); + $this->writeThrowable($this->parentFailed, \true); + $this->writer->endElement(); + } + $this->writer->endElement(); + $this->writer->flush(); + $this->parentErrored = null; + $this->parentFailed = null; + $this->reduceTestSuiteLevel(); + } + public function testPrepared(PreparationErrored|PreparationFailed|TestStarted $event): void + { + $this->testId = $this->nextId(); + $this->writeTestStarted($event->test(), $this->testId, $this->parentId); + if ($event instanceof TestStarted) { + $this->testWasPrepared = \true; + } + } + public function testPrintedUnexpectedOutput(PrintedUnexpectedOutput $event): void + { + $this->writer->startElement('e:reported'); + $this->writer->writeAttribute('id', (string) $this->testId); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->startElement('attachments'); + $this->writer->startElement('output'); + $this->writer->writeAttribute('source', 'stdout'); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->writeCdata($event->output()); + $this->writer->endElement(); + $this->writer->endElement(); + $this->writer->endElement(); + $this->writer->flush(); + } + public function testDeprecationTriggered(DeprecationTriggered $event): void + { + $trigger = $event->trigger(); + $this->writeIssue('deprecation', $event->message(), $event->file(), $event->line(), $event->wasSuppressed(), $event->ignoredByBaseline(), $event->ignoredByTest(), $this->triggerAsString($trigger), $trigger->callerAsString(), $trigger->calleeAsString()); + } + public function testPhpDeprecationTriggered(PhpDeprecationTriggered $event): void + { + $trigger = $event->trigger(); + $this->writeIssue('php-deprecation', $event->message(), $event->file(), $event->line(), $event->wasSuppressed(), $event->ignoredByBaseline(), $event->ignoredByTest(), $this->triggerAsString($trigger), $trigger->callerAsString(), $trigger->calleeAsString()); + } + public function testPhpunitDeprecationTriggered(PhpunitDeprecationTriggered $event): void + { + $this->writeIssue('phpunit-deprecation', $event->message()); + } + public function testErrorTriggered(ErrorTriggered $event): void + { + $this->writeIssue('error', $event->message(), $event->file(), $event->line(), $event->wasSuppressed()); + } + public function testPhpunitErrorTriggered(PhpunitErrorTriggered $event): void + { + $this->writeIssue('phpunit-error', $event->message()); + } + public function testNoticeTriggered(NoticeTriggered $event): void + { + $this->writeIssue('notice', $event->message(), $event->file(), $event->line(), $event->wasSuppressed(), $event->ignoredByBaseline()); + } + public function testPhpNoticeTriggered(PhpNoticeTriggered $event): void + { + $this->writeIssue('php-notice', $event->message(), $event->file(), $event->line(), $event->wasSuppressed(), $event->ignoredByBaseline()); + } + public function testPhpunitNoticeTriggered(PhpunitNoticeTriggered $event): void + { + $this->writeIssue('phpunit-notice', $event->message()); + } + public function testWarningTriggered(WarningTriggered $event): void + { + $this->writeIssue('warning', $event->message(), $event->file(), $event->line(), $event->wasSuppressed(), $event->ignoredByBaseline()); + } + public function testPhpWarningTriggered(PhpWarningTriggered $event): void + { + $this->writeIssue('php-warning', $event->message(), $event->file(), $event->line(), $event->wasSuppressed(), $event->ignoredByBaseline()); + } + public function testPhpunitWarningTriggered(PhpunitWarningTriggered $event): void + { + $this->writeIssue('phpunit-warning', $event->message(), null, null, null, null, $event->ignoredByTest()); + } + public function testConsideredRisky(ConsideredRisky $event): void + { + $this->writeIssue('risky', $event->message()); + } + public function testFinished(): void + { + if (!$this->alreadyFinished) { + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->testId); + $this->writer->writeAttribute('time', $this->timestamp()); + $status = \PHPUnit\Logging\OpenTestReporting\Status::Successful; + if ($this->pendingStatus !== null) { + $status = $this->pendingStatus; + } + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', $status->value); + if ($this->pendingReason !== null) { + $this->writer->writeElement('reason', $this->pendingReason); + } + if ($this->pendingThrowable !== null) { + assert($this->pendingAssertionError !== null); + $this->writeThrowable($this->pendingThrowable, $this->pendingAssertionError); + } + $this->writer->endElement(); + $this->writer->endElement(); + $this->writer->flush(); + } + $this->alreadyFinished = \false; + $this->testWasPrepared = \false; + $this->testId = null; + $this->pendingStatus = null; + $this->pendingReason = null; + $this->pendingThrowable = null; + $this->pendingAssertionError = null; + } + public function testFailed(Failed $event): void + { + if ($this->testWasPrepared) { + $this->pendingStatus = \PHPUnit\Logging\OpenTestReporting\Status::Failed; + $this->pendingReason = $event->throwable()->message(); + $this->pendingThrowable = $event->throwable(); + $this->pendingAssertionError = \true; + return; + } + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->testId); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', \PHPUnit\Logging\OpenTestReporting\Status::Failed->value); + $this->writer->writeElement('reason', $event->throwable()->message()); + $this->writeThrowable($event->throwable(), \true); + $this->writer->endElement(); + $this->writer->endElement(); + $this->writer->flush(); + $this->alreadyFinished = \true; + } + public function testErrored(Errored $event): void + { + if ($this->testWasPrepared) { + $this->pendingStatus = \PHPUnit\Logging\OpenTestReporting\Status::Errored; + $this->pendingReason = $event->throwable()->message(); + $this->pendingThrowable = $event->throwable(); + $this->pendingAssertionError = \false; + return; + } + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->testId); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', \PHPUnit\Logging\OpenTestReporting\Status::Errored->value); + $this->writer->writeElement('reason', $event->throwable()->message()); + $this->writeThrowable($event->throwable(), \false); + $this->writer->endElement(); + $this->writer->endElement(); + $this->writer->flush(); + $this->alreadyFinished = \true; + } + public function testSkipped(Skipped $event): void + { + if ($this->testId === null) { + $this->testId = $this->nextId(); + $this->writeTestStarted($event->test(), $this->testId, $this->parentId); + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->testId); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', \PHPUnit\Logging\OpenTestReporting\Status::Skipped->value); + $this->writer->writeElement('reason', $event->message()); + $this->writer->endElement(); + $this->writer->endElement(); + $this->writer->flush(); + $this->testId = null; + return; + } + $this->pendingStatus = \PHPUnit\Logging\OpenTestReporting\Status::Skipped; + $this->pendingReason = $event->message(); + } + public function markTestIncomplete(MarkedIncomplete $event): void + { + $this->pendingStatus = \PHPUnit\Logging\OpenTestReporting\Status::Aborted; + $this->pendingReason = $event->throwable()->message(); + $this->pendingThrowable = $event->throwable(); + $this->pendingAssertionError = \false; + } + public function parentErrored(AfterLastTestMethodErrored|BeforeFirstTestMethodErrored $event): void + { + $this->parentErrored = $event->throwable(); + } + public function parentFailed(AfterLastTestMethodFailed|BeforeFirstTestMethodFailed $event): void + { + $this->parentFailed = $event->throwable(); + } + private function writeIssue(string $type, string $message, ?string $file = null, ?int $line = null, ?bool $suppressed = null, ?bool $ignoredByBaseline = null, ?bool $ignoredByTest = null, ?string $trigger = null, ?string $caller = null, ?string $callee = null): void + { + $this->writer->startElement('e:reported'); + $this->writer->writeAttribute('id', (string) $this->testId); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->startElement('attachments'); + $this->writer->startElement('phpunit:issue'); + $this->writer->writeAttribute('type', $type); + $this->writer->writeAttribute('message', $message); + if ($file !== null) { + $this->writer->writeAttribute('file', $file); + } + if ($line !== null) { + $this->writer->writeAttribute('line', (string) $line); + } + if ($suppressed !== null) { + $this->writer->writeAttribute('suppressed', $suppressed ? 'true' : 'false'); + } + if ($ignoredByBaseline !== null) { + $this->writer->writeAttribute('ignoredByBaseline', $ignoredByBaseline ? 'true' : 'false'); + } + if ($ignoredByTest !== null) { + $this->writer->writeAttribute('ignoredByTest', $ignoredByTest ? 'true' : 'false'); + } + if ($trigger !== null) { + $this->writer->writeAttribute('trigger', $trigger); + } + if ($caller !== null) { + $this->writer->writeAttribute('caller', $caller); + } + if ($callee !== null) { + $this->writer->writeAttribute('callee', $callee); + } + $this->writer->endElement(); + $this->writer->endElement(); + $this->writer->endElement(); + $this->writer->flush(); + } + private function triggerAsString(IssueTrigger $trigger): string + { + if ($trigger->isSelf()) { + return 'self'; + } + if ($trigger->isDirect()) { + return 'direct'; + } + if ($trigger->isIndirect()) { + return 'indirect'; + } + return 'unknown'; + } + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers(new \PHPUnit\Logging\OpenTestReporting\TestRunnerStartedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestSuiteStartedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestSuiteSkippedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\BeforeFirstTestMethodErroredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\BeforeFirstTestMethodFailedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\AfterLastTestMethodErroredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\AfterLastTestMethodFailedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestPreparationErroredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestPreparationFailedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestPreparedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestPrintedUnexpectedOutputSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestDeprecationTriggeredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestPhpDeprecationTriggeredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestPhpunitDeprecationTriggeredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestErrorTriggeredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestPhpunitErrorTriggeredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestNoticeTriggeredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestPhpNoticeTriggeredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestPhpunitNoticeTriggeredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestWarningTriggeredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestPhpWarningTriggeredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestPhpunitWarningTriggeredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestConsideredRiskySubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestAbortedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestErroredSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestFailedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestSkippedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestFinishedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestSuiteFinishedSubscriber($this), new \PHPUnit\Logging\OpenTestReporting\TestRunnerFinishedSubscriber($this)); + } + /** + * @param positive-int $id + * @param ?positive-int $parentId + */ + private function writeTestStarted(Test $test, int $id, ?int $parentId): void + { + $this->writer->startElement('e:started'); + $this->writer->writeAttribute('id', (string) $id); + if ($parentId !== null) { + $this->writer->writeAttribute('parentId', (string) $parentId); + } + $this->writer->writeAttribute('name', $test->name()); + $this->writer->writeAttribute('time', $this->timestamp()); + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + $tags = []; + foreach ($test->metadata()->isGroup() as $group) { + assert($group instanceof Group); + $tags[] = $group->groupName(); + } + if ($tags !== []) { + $this->writer->startElement('metadata'); + $this->writer->startElement('tags'); + foreach ($tags as $tag) { + $this->writer->writeElement('tag', $tag); + } + $this->writer->endElement(); + $this->writer->endElement(); + } + } + $this->writer->startElement('sources'); + $this->writer->startElement('fileSource'); + $this->writer->writeAttribute('path', $test->file()); + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + $this->writer->startElement('filePosition'); + $this->writer->writeAttribute('line', (string) $test->line()); + $this->writer->endElement(); + } + $this->writer->endElement(); + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + $this->writer->startElement('phpunit:methodSource'); + $this->writer->writeAttribute('className', $test->className()); + $this->writer->writeAttribute('methodName', $test->methodName()); + $this->writer->endElement(); + } + $this->writer->endElement(); + $this->writer->endElement(); + $this->writer->flush(); + } + private function writeThrowable(Throwable $throwable, bool $assertionError): void + { + $this->writer->startElement('phpunit:throwable'); + $this->writer->writeAttribute('type', $throwable->className()); + $this->writer->writeAttribute('assertionError', $assertionError ? 'true' : 'false'); + $this->writer->writeCdata($throwable->asString()); + $this->writer->endElement(); + } + /** + * @return non-empty-string + */ + private function timestamp(): string + { + return (new DateTimeImmutable('now', new DateTimeZone('UTC')))->format('Y-m-d\TH:i:s.u\Z'); + } + /** + * @return positive-int + */ + private function nextId(): int + { + return ++$this->idSequence; + } + private function reduceTestSuiteLevel(): void + { + array_pop($this->parentIdStack); + if ($this->parentIdStack !== []) { + $this->parentId = $this->parentIdStack[count($this->parentIdStack) - 1]; + return; + } + $this->parentId = null; + } + private function gitInformation(): false|GitState + { + if (!$this->includeGitInformation) { + return \false; + } + return (new GitStateBuilder())->build(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This enumeration is not covered by the backward compatibility promise for PHPUnit + */ +enum Status : string +{ + case Aborted = 'ABORTED'; + case Errored = 'ERRORED'; + case Failed = 'FAILED'; + case Skipped = 'SKIPPED'; + case Successful = 'SUCCESSFUL'; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\AfterLastTestMethodErroredSubscriber as AfterLastTestMethodErroredSubscriberInterface; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodErroredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements AfterLastTestMethodErroredSubscriberInterface +{ + /** + * @throws InvalidArgumentException + */ + public function notify(AfterLastTestMethodErrored $event): void + { + $this->logger()->parentErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\AfterLastTestMethodFailed; +use PHPUnit\Event\Test\AfterLastTestMethodFailedSubscriber as AfterLastTestMethodFailedSubscriberInterface; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodFailedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements AfterLastTestMethodFailedSubscriberInterface +{ + /** + * @throws InvalidArgumentException + */ + public function notify(AfterLastTestMethodFailed $event): void + { + $this->logger()->parentFailed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodErroredSubscriber as BeforeFirstTestMethodErroredSubscriberInterface; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodErroredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements BeforeFirstTestMethodErroredSubscriberInterface +{ + /** + * @throws InvalidArgumentException + */ + public function notify(BeforeFirstTestMethodErrored $event): void + { + $this->logger()->parentErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailedSubscriber as BeforeFirstTestMethodFailedSubscriberInterface; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodFailedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements BeforeFirstTestMethodFailedSubscriberInterface +{ + /** + * @throws InvalidArgumentException + */ + public function notify(BeforeFirstTestMethodFailed $event): void + { + $this->logger()->parentFailed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private \PHPUnit\Logging\OpenTestReporting\OtrXmlLogger $logger; + public function __construct(\PHPUnit\Logging\OpenTestReporting\OtrXmlLogger $logger) + { + $this->logger = $logger; + } + protected function logger(): \PHPUnit\Logging\OpenTestReporting\OtrXmlLogger + { + return $this->logger; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestAbortedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements MarkedIncompleteSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(MarkedIncomplete $event): void + { + $this->logger()->markTestIncomplete($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\ConsideredRiskySubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestConsideredRiskySubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements ConsideredRiskySubscriber +{ + public function notify(ConsideredRisky $event): void + { + $this->logger()->testConsideredRisky($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestDeprecationTriggeredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements DeprecationTriggeredSubscriber +{ + public function notify(DeprecationTriggered $event): void + { + $this->logger()->testDeprecationTriggered($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\ErrorTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErrorTriggeredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements ErrorTriggeredSubscriber +{ + public function notify(ErrorTriggered $event): void + { + $this->logger()->testErrorTriggered($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements ErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Errored $event): void + { + $this->logger()->testErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements FailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Failed $event): void + { + $this->logger()->testFailed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements FinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->logger()->testFinished(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\NoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestNoticeTriggeredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements NoticeTriggeredSubscriber +{ + public function notify(NoticeTriggered $event): void + { + $this->logger()->testNoticeTriggered($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPhpDeprecationTriggeredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements PhpDeprecationTriggeredSubscriber +{ + public function notify(PhpDeprecationTriggered $event): void + { + $this->logger()->testPhpDeprecationTriggered($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPhpNoticeTriggeredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements PhpNoticeTriggeredSubscriber +{ + public function notify(PhpNoticeTriggered $event): void + { + $this->logger()->testPhpNoticeTriggered($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPhpWarningTriggeredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements PhpWarningTriggeredSubscriber +{ + public function notify(PhpWarningTriggered $event): void + { + $this->logger()->testPhpWarningTriggered($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPhpunitDeprecationTriggeredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements PhpunitDeprecationTriggeredSubscriber +{ + public function notify(PhpunitDeprecationTriggered $event): void + { + $this->logger()->testPhpunitDeprecationTriggered($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPhpunitErrorTriggeredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements PhpunitErrorTriggeredSubscriber +{ + public function notify(PhpunitErrorTriggered $event): void + { + $this->logger()->testPhpunitErrorTriggered($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPhpunitNoticeTriggeredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements PhpunitNoticeTriggeredSubscriber +{ + public function notify(PhpunitNoticeTriggered $event): void + { + $this->logger()->testPhpunitNoticeTriggered($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPhpunitWarningTriggeredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements PhpunitWarningTriggeredSubscriber +{ + public function notify(PhpunitWarningTriggered $event): void + { + $this->logger()->testPhpunitWarningTriggered($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationErrored; +use PHPUnit\Event\Test\PreparationErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationErroredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements PreparationErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationErrored $event): void + { + $this->logger()->testPrepared($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationFailed; +use PHPUnit\Event\Test\PreparationFailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationFailedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements PreparationFailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationFailed $event): void + { + $this->logger()->testPrepared($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements PreparedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Prepared $event): void + { + $this->logger()->testPrepared($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\PrintedUnexpectedOutput; +use PHPUnit\Event\Test\PrintedUnexpectedOutputSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPrintedUnexpectedOutputSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements PrintedUnexpectedOutputSubscriber +{ + public function notify(PrintedUnexpectedOutput $event): void + { + $this->logger()->testPrintedUnexpectedOutput($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerFinishedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements ExecutionFinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(ExecutionFinished $event): void + { + $this->logger()->testRunnerFinished(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Application\Started; +use PHPUnit\Event\Application\StartedSubscriber; +use PHPUnit\Event\InvalidArgumentException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerStartedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements StartedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Started $event): void + { + $this->logger()->testRunnerStarted(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements SkippedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->logger()->testSkipped($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestSuite\Finished; +use PHPUnit\Event\TestSuite\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFinishedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements FinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->logger()->testSuiteFinished(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestSuite\Skipped; +use PHPUnit\Event\TestSuite\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteSkippedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements SkippedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->logger()->testSuiteSkipped($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\Event\TestSuite\StartedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteStartedSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements StartedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Started $event): void + { + $this->logger()->testSuiteStarted($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\Test\WarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestWarningTriggeredSubscriber extends \PHPUnit\Logging\OpenTestReporting\Subscriber implements WarningTriggeredSubscriber +{ + public function notify(WarningTriggered $event): void + { + $this->logger()->testWarningTriggered($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private \PHPUnit\Logging\TeamCity\TeamCityLogger $logger; + public function __construct(\PHPUnit\Logging\TeamCity\TeamCityLogger $logger) + { + $this->logger = $logger; + } + protected function logger(): \PHPUnit\Logging\TeamCity\TeamCityLogger + { + return $this->logger; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\ConsideredRiskySubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestConsideredRiskySubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements ConsideredRiskySubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(ConsideredRisky $event): void + { + $this->logger()->testConsideredRisky($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements ErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Errored $event): void + { + $this->logger()->testErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements FailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Failed $event): void + { + $this->logger()->testFailed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements FinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->logger()->testFinished($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements MarkedIncompleteSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(MarkedIncomplete $event): void + { + $this->logger()->testMarkedIncomplete($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationErrored; +use PHPUnit\Event\Test\PreparationErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationErroredSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements PreparationErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationErrored $event): void + { + $this->logger()->testPreparationErrored(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationFailed; +use PHPUnit\Event\Test\PreparationFailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationFailedSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements PreparationFailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationFailed $event): void + { + $this->logger()->testPreparationFailed(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationStarted; +use PHPUnit\Event\Test\PreparationStartedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationStartedSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements PreparationStartedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationStarted $event): void + { + $this->logger()->testPreparationStarted($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->logger()->testPrepared(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerExecutionFinishedSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements ExecutionFinishedSubscriber +{ + public function notify(ExecutionFinished $event): void + { + $this->logger()->flush(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements SkippedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->logger()->testSkipped($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteBeforeFirstTestMethodErroredSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements BeforeFirstTestMethodErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(BeforeFirstTestMethodErrored $event): void + { + $this->logger()->beforeFirstTestMethodErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteBeforeFirstTestMethodFailedSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements BeforeFirstTestMethodFailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(BeforeFirstTestMethodFailed $event): void + { + $this->logger()->beforeFirstTestMethodFailed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\TestSuite\Finished; +use PHPUnit\Event\TestSuite\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFinishedSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->logger()->testSuiteFinished($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestSuite\Skipped; +use PHPUnit\Event\TestSuite\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteSkippedSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements SkippedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->logger()->testSuiteSkipped($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\Event\TestSuite\StartedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteStartedSubscriber extends \PHPUnit\Logging\TeamCity\Subscriber implements StartedSubscriber +{ + public function notify(Started $event): void + { + $this->logger()->testSuiteStarted($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use function assert; +use function getmypid; +use function ini_get; +use function is_a; +use function round; +use function sprintf; +use function str_replace; +use function stripos; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Facade; +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Telemetry\HRTime; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\PreparationStarted; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; +use PHPUnit\Event\TestSuite\TestSuiteForTestClass; +use PHPUnit\Event\TestSuite\TestSuiteForTestMethodWithDataProvider; +use PHPUnit\Framework\Exception as FrameworkException; +use PHPUnit\TextUI\Output\Printer; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TeamCityLogger +{ + private readonly Printer $printer; + private bool $isSummaryTestCountPrinted = \false; + private ?HRTime $time = null; + private ?int $flowId = null; + private bool $testStartedEmitted = \false; + private bool $prepared = \false; + private bool $preparationFailed = \false; + public function __construct(Printer $printer, Facade $facade) + { + $this->printer = $printer; + $this->registerSubscribers($facade); + $this->setFlowId(); + } + public function testSuiteStarted(TestSuiteStarted $event): void + { + $testSuite = $event->testSuite(); + if (!$this->isSummaryTestCountPrinted) { + $this->isSummaryTestCountPrinted = \true; + $this->writeMessage('testCount', ['count' => $testSuite->count()]); + } + $parameters = ['name' => $testSuite->name()]; + if ($testSuite->isForTestClass()) { + assert($testSuite instanceof TestSuiteForTestClass); + $parameters['locationHint'] = sprintf('php_qn://%s::\%s', $testSuite->file(), $testSuite->name()); + } elseif ($testSuite->isForTestMethodWithDataProvider()) { + assert($testSuite instanceof TestSuiteForTestMethodWithDataProvider); + $parameters['locationHint'] = sprintf('php_qn://%s::\%s', $testSuite->file(), $testSuite->name()); + $parameters['name'] = $testSuite->methodName(); + } + $this->writeMessage('testSuiteStarted', $parameters); + } + public function testSuiteFinished(TestSuiteFinished $event): void + { + $testSuite = $event->testSuite(); + $parameters = ['name' => $testSuite->name()]; + if ($testSuite->isForTestMethodWithDataProvider()) { + assert($testSuite instanceof TestSuiteForTestMethodWithDataProvider); + $parameters['name'] = $testSuite->methodName(); + } + $this->writeMessage('testSuiteFinished', $parameters); + } + public function testPreparationStarted(PreparationStarted $event): void + { + $test = $event->test(); + $parameters = ['name' => $test->name()]; + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + $parameters['locationHint'] = sprintf('php_qn://%s::\%s::%s', $test->file(), $test->className(), $test->name()); + } + $this->writeMessage('testStarted', $parameters); + $this->time = $event->telemetryInfo()->time(); + $this->testStartedEmitted = \true; + $this->prepared = \false; + $this->preparationFailed = \false; + } + public function testPreparationErrored(): void + { + $this->preparationFailed = \true; + } + public function testPreparationFailed(): void + { + $this->preparationFailed = \true; + } + public function testPrepared(): void + { + $this->prepared = \true; + } + /** + * @throws InvalidArgumentException + */ + public function testMarkedIncomplete(MarkedIncomplete $event): void + { + if ($this->time === null) { + // @codeCoverageIgnoreStart + $this->time = $event->telemetryInfo()->time(); + // @codeCoverageIgnoreEnd + } + $this->writeMessage('testIgnored', ['name' => $event->test()->name(), 'message' => $event->throwable()->message(), 'details' => $this->details($event->throwable()), 'duration' => $this->duration($event)]); + $this->writeTestFinishedIfPreparationDidNotComplete($event); + } + /** + * @throws InvalidArgumentException + */ + public function testSkipped(Skipped $event): void + { + if ($this->time === null) { + $this->time = $event->telemetryInfo()->time(); + } + $parameters = ['name' => $event->test()->name(), 'message' => $event->message()]; + $parameters['duration'] = $this->duration($event); + $this->writeMessage('testIgnored', $parameters); + $this->writeTestFinishedIfPreparationDidNotComplete($event); + } + /** + * @throws InvalidArgumentException + */ + public function testSuiteSkipped(TestSuiteSkipped $event): void + { + if ($this->time === null) { + $this->time = $event->telemetryInfo()->time(); + } + $parameters = ['name' => $event->testSuite()->name(), 'message' => $event->message()]; + $parameters['duration'] = $this->duration($event); + $this->writeMessage('testIgnored', $parameters); + $this->writeMessage('testSuiteFinished', $parameters); + } + /** + * @throws InvalidArgumentException + */ + public function beforeFirstTestMethodErrored(BeforeFirstTestMethodErrored $event): void + { + $this->writeBeforeFirstTestMethodHookFailure($event, $event->testClassName(), $event->throwable()); + } + /** + * @throws InvalidArgumentException + */ + public function beforeFirstTestMethodFailed(BeforeFirstTestMethodFailed $event): void + { + $this->writeBeforeFirstTestMethodHookFailure($event, $event->testClassName(), $event->throwable()); + } + /** + * @throws InvalidArgumentException + */ + public function testErrored(Errored $event): void + { + if ($this->time === null) { + $this->time = $event->telemetryInfo()->time(); + } + $this->writeMessage('testFailed', ['name' => $event->test()->name(), 'message' => $this->message($event->throwable()), 'details' => $this->details($event->throwable()), 'duration' => $this->duration($event)]); + $this->writeTestFinishedIfPreparationDidNotComplete($event); + } + /** + * @throws InvalidArgumentException + */ + public function testFailed(Failed $event): void + { + if ($this->time === null) { + // @codeCoverageIgnoreStart + $this->time = $event->telemetryInfo()->time(); + // @codeCoverageIgnoreEnd + } + $parameters = ['name' => $event->test()->name(), 'message' => $this->message($event->throwable()), 'details' => $this->details($event->throwable()), 'duration' => $this->duration($event)]; + if ($event->hasComparisonFailure()) { + $parameters['type'] = 'comparisonFailure'; + $parameters['actual'] = $event->comparisonFailure()->actual(); + $parameters['expected'] = $event->comparisonFailure()->expected(); + } + $this->writeMessage('testFailed', $parameters); + $this->writeTestFinishedIfPreparationDidNotComplete($event); + } + /** + * @throws InvalidArgumentException + */ + public function testConsideredRisky(ConsideredRisky $event): void + { + if ($this->time === null) { + // @codeCoverageIgnoreStart + $this->time = $event->telemetryInfo()->time(); + // @codeCoverageIgnoreEnd + } + $this->writeMessage('testFailed', ['name' => $event->test()->name(), 'message' => $event->message(), 'details' => '', 'duration' => $this->duration($event)]); + } + /** + * @throws InvalidArgumentException + */ + public function testFinished(Finished $event): void + { + if (!$this->testStartedEmitted) { + return; + } + $this->writeMessage('testFinished', ['name' => $event->test()->name(), 'duration' => $this->duration($event)]); + $this->time = null; + $this->testStartedEmitted = \false; + $this->prepared = \false; + $this->preparationFailed = \false; + } + public function flush(): void + { + $this->printer->flush(); + } + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers(new \PHPUnit\Logging\TeamCity\TestSuiteStartedSubscriber($this), new \PHPUnit\Logging\TeamCity\TestSuiteFinishedSubscriber($this), new \PHPUnit\Logging\TeamCity\TestPreparationStartedSubscriber($this), new \PHPUnit\Logging\TeamCity\TestPreparationErroredSubscriber($this), new \PHPUnit\Logging\TeamCity\TestPreparationFailedSubscriber($this), new \PHPUnit\Logging\TeamCity\TestPreparedSubscriber($this), new \PHPUnit\Logging\TeamCity\TestFinishedSubscriber($this), new \PHPUnit\Logging\TeamCity\TestErroredSubscriber($this), new \PHPUnit\Logging\TeamCity\TestFailedSubscriber($this), new \PHPUnit\Logging\TeamCity\TestMarkedIncompleteSubscriber($this), new \PHPUnit\Logging\TeamCity\TestSkippedSubscriber($this), new \PHPUnit\Logging\TeamCity\TestSuiteSkippedSubscriber($this), new \PHPUnit\Logging\TeamCity\TestConsideredRiskySubscriber($this), new \PHPUnit\Logging\TeamCity\TestRunnerExecutionFinishedSubscriber($this), new \PHPUnit\Logging\TeamCity\TestSuiteBeforeFirstTestMethodErroredSubscriber($this), new \PHPUnit\Logging\TeamCity\TestSuiteBeforeFirstTestMethodFailedSubscriber($this)); + } + /** + * @throws InvalidArgumentException + */ + private function writeBeforeFirstTestMethodHookFailure(Event $event, string $name, Throwable $throwable): void + { + if ($this->time === null) { + $this->time = $event->telemetryInfo()->time(); + } + $this->writeMessage('testStarted', ['name' => $name]); + $parameters = ['name' => $name, 'message' => $this->message($throwable), 'details' => $this->details($throwable), 'duration' => $this->duration($event)]; + $this->writeMessage('testFailed', $parameters); + $this->writeMessage('testFinished', ['name' => $name, 'duration' => $this->duration($event)]); + $this->writeMessage('testSuiteFinished', ['name' => $name]); + $this->time = null; + } + /** + * @throws InvalidArgumentException + */ + private function writeTestFinishedIfPreparationDidNotComplete(Errored|Failed|MarkedIncomplete|Skipped $event): void + { + if (!$this->testStartedEmitted) { + return; + } + if ($this->prepared && !$this->preparationFailed) { + return; + } + $this->writeMessage('testFinished', ['name' => $event->test()->name(), 'duration' => $this->duration($event)]); + $this->time = null; + $this->testStartedEmitted = \false; + $this->prepared = \false; + $this->preparationFailed = \false; + } + private function setFlowId(): void + { + if (stripos(ini_get('disable_functions'), 'getmypid') === \false) { + $this->flowId = getmypid(); + } + } + /** + * @param array $parameters + */ + private function writeMessage(string $eventName, array $parameters = []): void + { + $this->printer->print(sprintf('##teamcity[%s', $eventName)); + if ($this->flowId !== null) { + $parameters['flowId'] = $this->flowId; + } + foreach ($parameters as $key => $value) { + $this->printer->print(sprintf(" %s='%s'", $key, $this->escape((string) $value))); + } + $this->printer->print("]\n"); + } + /** + * @throws InvalidArgumentException + */ + private function duration(Event $event): int + { + if ($this->time === null) { + // @codeCoverageIgnoreStart + return 0; + // @codeCoverageIgnoreEnd + } + return (int) round($event->telemetryInfo()->time()->duration($this->time)->asFloat() * 1000); + } + private function escape(string $string): string + { + return str_replace(['|', "'", "\n", "\r", ']', '['], ['||', "|'", '|n', '|r', '|]', '|['], $string); + } + private function message(Throwable $throwable): string + { + if (is_a($throwable->className(), FrameworkException::class, \true)) { + return $throwable->message(); + } + $buffer = $throwable->className(); + if ($throwable->message() !== '') { + $buffer .= ': ' . $throwable->message(); + } + return $buffer; + } + private function details(Throwable $throwable): string + { + $buffer = $throwable->stackTrace(); + while ($throwable->hasPrevious()) { + $throwable = $throwable->previous(); + $buffer .= sprintf("\nCaused by\n%s\n%s", $throwable->description(), $throwable->stackTrace()); + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class HtmlRenderer +{ + private const string PAGE_HEADER = <<<'EOT' + + + + + Test Documentation + + + +EOT; + private const string CLASS_HEADER = <<<'EOT' + +

      %s

      +
        + +EOT; + private const string CLASS_FOOTER = <<<'EOT' +
      +EOT; + private const string PAGE_FOOTER = <<<'EOT' + + + +EOT; + /** + * @param array $tests + */ + public function render(array $tests): string + { + $buffer = self::PAGE_HEADER; + foreach ($tests as $_tests) { + $buffer .= sprintf(self::CLASS_HEADER, $_tests->asArray()[0]->test()->testDox()->prettifiedClassName()); + foreach ($this->reduce($_tests) as $prettifiedMethodName => $outcome) { + $buffer .= sprintf("
    • %s
    • \n", $outcome, $prettifiedMethodName); + } + $buffer .= self::CLASS_FOOTER; + } + return $buffer . self::PAGE_FOOTER; + } + /** + * @return array + */ + private function reduce(\PHPUnit\Logging\TestDox\TestResultCollection $tests): array + { + $result = []; + foreach ($tests as $test) { + $prettifiedMethodName = $test->test()->testDox()->prettifiedMethodName(); + if (!isset($result[$prettifiedMethodName])) { + $result[$prettifiedMethodName] = $test->status()->isSuccess() ? 'success' : 'defect'; + continue; + } + if ($test->status()->isSuccess()) { + continue; + } + $result[$prettifiedMethodName] = 'defect'; + } + return $result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use const PHP_EOL; +use function array_key_exists; +use function array_keys; +use function array_map; +use function array_pop; +use function array_values; +use function assert; +use function class_exists; +use function explode; +use function gettype; +use function implode; +use function is_bool; +use function is_float; +use function is_int; +use function is_object; +use function is_scalar; +use function is_string; +use function method_exists; +use function preg_quote; +use function preg_replace; +use function preg_replace_callback_array; +use function rtrim; +use function sprintf; +use function str_contains; +use function str_ends_with; +use function str_replace; +use function str_starts_with; +use function strlen; +use function strtolower; +use function substr; +use function trim; +use function ucfirst; +use PHPUnit\Event\Code\TestMethodBuilder; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Metadata\TestDox; +use PHPUnit\Metadata\TestDoxFormatter; +use PHPUnit\Util\Color; +use PHPUnit\Util\Exporter; +use PHPUnit\Util\Filter; +use PHPUnit\Util\Sanitizer; +use ReflectionEnum; +use ReflectionMethod; +use ReflectionObject; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NamePrettifier +{ + /** + * @var array + */ + private array $strings = []; + /** + * @var array + */ + private array $prettifiedTestCases = []; + /** + * @var array + */ + private array $erroredFormatters = []; + /** + * @param class-string $className + */ + public function prettifyTestClassName(string $className): string + { + if (class_exists($className)) { + $classLevelTestDox = MetadataRegistry::parser()->forClass($className)->isTestDox(); + if ($classLevelTestDox->isNotEmpty()) { + $classLevelTestDox = $classLevelTestDox->asArray()[0]; + assert($classLevelTestDox instanceof TestDox); + return $classLevelTestDox->text(); + } + } + $parts = explode('\\', $className); + $className = array_pop($parts); + if (str_ends_with($className, 'Test')) { + $className = substr($className, 0, strlen($className) - strlen('Test')); + } + if ($className === '') { + $className = 'UnnamedTests'; + } + if ($parts !== []) { + $parts[] = $className; + $fullyQualifiedName = implode('\\', $parts); + } else { + $fullyQualifiedName = $className; + } + $result = preg_replace('/(?<=[[:lower:]])(?=[[:upper:]])/u', ' ', $className); + assert($result !== null); + if ($fullyQualifiedName !== $className) { + return $result . ' (' . $fullyQualifiedName . ')'; + } + return $result; + } + // NOTE: this method is on a hot path and very performance sensitive. change with care. + public function prettifyTestMethodName(string $name): string + { + if ($name === '') { + return ''; + } + $string = rtrim($name, '0123456789'); + if (array_key_exists($string, $this->strings)) { + $name = $string; + } elseif ($string === $name) { + $this->strings[$string] = 1; + } + if (str_starts_with($name, 'test_')) { + $name = substr($name, 5); + } elseif (str_starts_with($name, 'test')) { + $name = substr($name, 4); + } + if ($name === '') { + return ''; + } + $name = ucfirst($name); + $noUnderscore = str_replace('_', ' ', $name); + if ($noUnderscore !== $name) { + return trim($noUnderscore); + } + $buffer = preg_replace_callback_array(['/(?!^)([A-Z])/' => static fn(array $matches) => ' ' . strtolower($matches[1]), '/(\d+)/' => static fn(array $matches) => ' ' . $matches[1]], $name); + return trim($buffer); + } + public function prettifyTestCase(TestCase $test, bool $colorize): string + { + $key = $test::class . '#' . $test->name(); + if ($test->usesDataProvider()) { + $key .= '#' . $test->dataName(); + } + if ($colorize) { + $key .= '#colorize'; + } + if (isset($this->prettifiedTestCases[$key])) { + return $this->prettifiedTestCases[$key]; + } + $metadataCollection = MetadataRegistry::parser()->forMethod($test::class, $test->name()); + $testDox = $metadataCollection->isTestDox()->isMethodLevel(); + $callback = $metadataCollection->isTestDoxFormatter(); + $isCustomized = \false; + if ($testDox->isNotEmpty()) { + $testDox = $testDox->asArray()[0]; + assert($testDox instanceof TestDox); + [$result, $isCustomized] = $this->processTestDox($test, $testDox, $colorize); + } elseif ($callback->isNotEmpty()) { + $callback = $callback->asArray()[0]; + assert($callback instanceof TestDoxFormatter); + [$result, $isCustomized] = $this->processTestDoxFormatter($test, $callback); + } else { + $result = $this->prettifyTestMethodName($test->name()); + } + if (!$isCustomized && $test->usesDataProvider()) { + $result .= $this->prettifyDataSet($test, $colorize); + } + $this->prettifiedTestCases[$key] = $result; + return $result; + } + public function prettifyDataSet(TestCase $test, bool $colorize): string + { + if (!$colorize) { + return $test->dataSetAsString(); + } + if (is_int($test->dataName())) { + return Color::dim(' with data set ') . Color::colorize('fg-cyan', (string) $test->dataName()); + } + return Color::dim(' with ') . Color::colorize('fg-cyan', Color::visualizeWhitespace(Sanitizer::sanitizeBidirectionalControlCharacters($test->dataName()))); + } + /** + * @return array + */ + private function mapTestMethodParameterNamesToProvidedDataValues(TestCase $test, bool $colorize): array + { + assert(method_exists($test, $test->name())); + /** @noinspection PhpUnhandledExceptionInspection */ + $reflector = new ReflectionMethod($test::class, $test->name()); + $providedData = []; + $providedDataValues = $test->providedData(); + $i = 0; + $dataName = $test->dataName(); + if (is_int($dataName)) { + $providedData['$_dataName'] = $dataName; + } else { + $providedData['$_dataName'] = Sanitizer::sanitizeBidirectionalControlCharacters($dataName); + } + foreach ($reflector->getParameters() as $parameter) { + if (array_key_exists($parameter->getName(), $providedDataValues)) { + $value = $providedDataValues[$parameter->getName()]; + } elseif (array_key_exists($i, $providedDataValues)) { + $value = $providedDataValues[$i]; + } elseif ($parameter->isDefaultValueAvailable()) { + $value = $parameter->getDefaultValue(); + } else { + $value = null; + } + $i++; + if (is_object($value)) { + $value = $this->objectToString($value); + } + if (!is_scalar($value)) { + $value = gettype($value); + if ($value === 'NULL') { + $value = 'null'; + } + } + if (is_bool($value) || is_int($value) || is_float($value)) { + $value = Exporter::export($value); + } + if ($value === '') { + if ($colorize) { + $value = Color::colorize('dim,underlined', 'empty'); + } else { + $value = "''"; + } + } + $providedData['$' . $parameter->getName()] = str_replace('$', '\$', Sanitizer::sanitizeBidirectionalControlCharacters($value)); + } + if ($colorize) { + $providedData = array_map(static fn(mixed $value) => Color::colorize('fg-cyan', Color::visualizeWhitespace((string) $value, \true)), $providedData); + } + return $providedData; + } + private function objectToString(object $value): string + { + $reflector = new ReflectionObject($value); + if ($reflector->isEnum()) { + $enumReflector = new ReflectionEnum($value); + if ($enumReflector->isBacked()) { + return (string) $value->value; + } + return (string) $value->name; + } + if ($reflector->hasMethod('__toString')) { + return (string) $value; + } + return $value::class; + } + /** + * @return array{0: string, 1: bool} + */ + private function processTestDox(TestCase $test, TestDox $testDox, bool $colorize): array + { + $placeholdersUsed = \false; + $result = $testDox->text(); + if (str_contains($result, '$')) { + $annotation = $result; + $providedData = $this->mapTestMethodParameterNamesToProvidedDataValues($test, $colorize); + $variables = array_map(static fn(string $variable): string => sprintf('/%s(?=\b)/', preg_quote($variable, '/')), array_keys($providedData)); + $result = preg_replace($variables, $providedData, $annotation); + $placeholdersUsed = \true; + } + assert($result !== null); + return [$result, $placeholdersUsed]; + } + /** + * @return array{0: string, 1: bool} + */ + private function processTestDoxFormatter(TestCase $test, TestDoxFormatter $formatter): array + { + $className = $formatter->className(); + $methodName = $formatter->methodName(); + $formatterIdentifier = $className . '::' . $methodName; + if (isset($this->erroredFormatters[$formatterIdentifier])) { + return [$this->prettifyTestMethodName($test->name()), \false]; + } + if (!method_exists($className, $methodName)) { + EventFacade::emitter()->testTriggeredPhpunitError(TestMethodBuilder::fromTestCase($test, \false), sprintf('Method %s::%s() cannot be used as a TestDox formatter because it does not exist', $className, $methodName)); + $this->erroredFormatters[$formatterIdentifier] = \true; + return [$this->prettifyTestMethodName($test->name()), \false]; + } + $reflector = new ReflectionMethod($className, $methodName); + if (!$reflector->isPublic()) { + EventFacade::emitter()->testTriggeredPhpunitError(TestMethodBuilder::fromTestCase($test, \false), sprintf('Method %s::%s() cannot be used as a TestDox formatter because it is not public', $className, $methodName)); + $this->erroredFormatters[$formatterIdentifier] = \true; + return [$this->prettifyTestMethodName($test->name()), \false]; + } + if (!$reflector->isStatic()) { + EventFacade::emitter()->testTriggeredPhpunitError(TestMethodBuilder::fromTestCase($test, \false), sprintf('Method %s::%s() cannot be used as a TestDox formatter because it is not static', $className, $methodName)); + $this->erroredFormatters[$formatterIdentifier] = \true; + return [$this->prettifyTestMethodName($test->name()), \false]; + } + try { + $result = $reflector->invokeArgs(null, array_values($test->providedData())); + assert(is_string($result)); + return [$result, \true]; + } catch (Throwable $t) { + EventFacade::emitter()->testTriggeredPhpunitError(TestMethodBuilder::fromTestCase($test, \false), sprintf('TestDox formatter %s::%s() triggered an error: %s%s%s', $className, $methodName, $t->getMessage(), PHP_EOL, Filter::stackTraceFromThrowableAsString($t))); + $this->erroredFormatters[$formatterIdentifier] = \true; + return [$this->prettifyTestMethodName($test->name()), \false]; + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PlainTextRenderer +{ + /** + * @param array $tests + */ + public function render(array $tests): string + { + $buffer = ''; + foreach ($tests as $_tests) { + $buffer .= $_tests->asArray()[0]->test()->testDox()->prettifiedClassName() . "\n"; + foreach ($this->reduce($_tests) as $prettifiedMethodName => $outcome) { + $buffer .= sprintf(' [%s] %s' . "\n", $outcome, $prettifiedMethodName); + } + $buffer .= "\n"; + } + return $buffer; + } + /** + * @return array + */ + private function reduce(\PHPUnit\Logging\TestDox\TestResultCollection $tests): array + { + $result = []; + foreach ($tests as $test) { + $prettifiedMethodName = $test->test()->testDox()->prettifiedMethodName(); + $success = \true; + if ($test->status()->isError() || $test->status()->isFailure() || $test->status()->isIncomplete() || $test->status()->isSkipped()) { + $success = \false; + } + if (!isset($result[$prettifiedMethodName])) { + $result[$prettifiedMethodName] = $success ? 'x' : ' '; + continue; + } + if ($success) { + continue; + } + $result[$prettifiedMethodName] = ' '; + } + return $result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private \PHPUnit\Logging\TestDox\TestResultCollector $collector; + public function __construct(\PHPUnit\Logging\TestDox\TestResultCollector $collector) + { + $this->collector = $collector; + } + protected function collector(): \PHPUnit\Logging\TestDox\TestResultCollector + { + return $this->collector; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\ConsideredRiskySubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestConsideredRiskySubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements ConsideredRiskySubscriber +{ + public function notify(ConsideredRisky $event): void + { + $this->collector()->testConsideredRisky($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements ErroredSubscriber +{ + public function notify(Errored $event): void + { + $this->collector()->testErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements FailedSubscriber +{ + public function notify(Failed $event): void + { + $this->collector()->testFailed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements FinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->collector()->testFinished($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements MarkedIncompleteSubscriber +{ + public function notify(MarkedIncomplete $event): void + { + $this->collector()->testMarkedIncomplete($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\Passed; +use PHPUnit\Event\Test\PassedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPassedSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements PassedSubscriber +{ + public function notify(Passed $event): void + { + $this->collector()->testPassed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->collector()->testPrepared($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements SkippedSubscriber +{ + public function notify(Skipped $event): void + { + $this->collector()->testSkipped($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredDeprecationSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements DeprecationTriggeredSubscriber +{ + public function notify(DeprecationTriggered $event): void + { + $this->collector()->testTriggeredDeprecation($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\NoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredNoticeSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements NoticeTriggeredSubscriber +{ + public function notify(NoticeTriggered $event): void + { + $this->collector()->testTriggeredNotice($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpDeprecationSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements PhpDeprecationTriggeredSubscriber +{ + public function notify(PhpDeprecationTriggered $event): void + { + $this->collector()->testTriggeredPhpDeprecation($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpNoticeSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements PhpNoticeTriggeredSubscriber +{ + public function notify(PhpNoticeTriggered $event): void + { + $this->collector()->testTriggeredPhpNotice($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpWarningSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements PhpWarningTriggeredSubscriber +{ + public function notify(PhpWarningTriggered $event): void + { + $this->collector()->testTriggeredPhpWarning($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitDeprecationSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements PhpunitDeprecationTriggeredSubscriber +{ + public function notify(PhpunitDeprecationTriggered $event): void + { + $this->collector()->testTriggeredPhpunitDeprecation($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitErrorSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements PhpunitErrorTriggeredSubscriber +{ + public function notify(PhpunitErrorTriggered $event): void + { + $this->collector()->testTriggeredPhpunitError($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitWarningSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements PhpunitWarningTriggeredSubscriber +{ + public function notify(PhpunitWarningTriggered $event): void + { + $this->collector()->testTriggeredPhpunitWarning($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\Test\WarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredWarningSubscriber extends \PHPUnit\Logging\TestDox\Subscriber implements WarningTriggeredSubscriber +{ + public function notify(WarningTriggered $event): void + { + $this->collector()->testTriggeredWarning($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Framework\TestStatus\TestStatus; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestResult +{ + private TestMethod $test; + private TestStatus $status; + private ?Throwable $throwable; + public function __construct(TestMethod $test, TestStatus $status, ?Throwable $throwable) + { + $this->test = $test; + $this->status = $status; + $this->throwable = $throwable; + } + public function test(): TestMethod + { + return $this->test; + } + public function status(): TestStatus + { + return $this->status; + } + /** + * @phpstan-assert-if-true !null $this->throwable + */ + public function hasThrowable(): bool + { + return $this->throwable !== null; + } + public function throwable(): ?Throwable + { + return $this->throwable; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use IteratorAggregate; +/** + * @template-implements IteratorAggregate + * + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestResultCollection implements IteratorAggregate +{ + /** + * @var list + */ + private array $testResults; + /** + * @param list $testResults + */ + public static function fromArray(array $testResults): self + { + return new self(...$testResults); + } + private function __construct(\PHPUnit\Logging\TestDox\TestResult ...$testResults) + { + $this->testResults = $testResults; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->testResults; + } + public function getIterator(): \PHPUnit\Logging\TestDox\TestResultCollectionIterator + { + return new \PHPUnit\Logging\TestDox\TestResultCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use Iterator; +/** + * @template-implements Iterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestResultCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $testResults; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\Logging\TestDox\TestResultCollection $testResults) + { + $this->testResults = $testResults->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->testResults[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\Logging\TestDox\TestResult + { + return $this->testResults[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use function array_merge; +use function assert; +use function is_subclass_of; +use function uasort; +use function uksort; +use function usort; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Facade; +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\Passed; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Framework\TestStatus\TestStatus; +use PHPUnit\Logging\TestDox\TestResult as TestDoxTestMethod; +use PHPUnit\TestRunner\IssueFilter; +use ReflectionMethod; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestResultCollector +{ + private readonly IssueFilter $issueFilter; + /** + * @var array> + */ + private array $tests = []; + private ?TestStatus $status = null; + private ?Throwable $throwable = null; + private bool $prepared = \false; + public function __construct(Facade $facade, IssueFilter $issueFilter) + { + $this->issueFilter = $issueFilter; + $this->registerSubscribers($facade); + } + /** + * @return array + */ + public function testMethodsGroupedByClass(): array + { + $result = []; + foreach ($this->tests as $className => $tests) { + $testsByDeclaringClass = []; + foreach ($tests as $test) { + $declaringClassName = (new ReflectionMethod($test->test()->className(), $test->test()->methodName()))->getDeclaringClass()->getName(); + if (!isset($testsByDeclaringClass[$declaringClassName])) { + $testsByDeclaringClass[$declaringClassName] = []; + } + $testsByDeclaringClass[$declaringClassName][] = $test; + } + foreach ($testsByDeclaringClass as $declaringClassName) { + usort($declaringClassName, static function (TestDoxTestMethod $a, TestDoxTestMethod $b): int { + return $a->test()->line() <=> $b->test()->line(); + }); + } + uksort( + $testsByDeclaringClass, + /** + * @param class-string $a + * @param class-string $b + */ + static function (string $a, string $b): int { + if (is_subclass_of($b, $a)) { + return -1; + } + if (is_subclass_of($a, $b)) { + return 1; + } + return 0; + } + ); + $tests = []; + foreach ($testsByDeclaringClass as $_tests) { + $tests = array_merge($tests, $_tests); + } + $result[$className] = \PHPUnit\Logging\TestDox\TestResultCollection::fromArray($tests); + } + uasort($result, static function (\PHPUnit\Logging\TestDox\TestResultCollection $a, \PHPUnit\Logging\TestDox\TestResultCollection $b): int { + return $a->asArray()[0]->test()->testDox()->prettifiedClassName() <=> $b->asArray()[0]->test()->testDox()->prettifiedClassName(); + }); + return $result; + } + public function testPrepared(Prepared $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + $this->status = TestStatus::unknown(); + $this->throwable = null; + $this->prepared = \true; + } + public function testErrored(Errored $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + $this->status = TestStatus::error($event->throwable()->message()); + $this->throwable = $event->throwable(); + if (!$this->prepared) { + $test = $event->test(); + assert($test instanceof TestMethod); + $this->process($test); + } + } + public function testFailed(Failed $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + $this->status = TestStatus::failure($event->throwable()->message()); + $this->throwable = $event->throwable(); + } + public function testPassed(Passed $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + $this->updateTestStatus(TestStatus::success()); + } + public function testSkipped(Skipped $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + $this->updateTestStatus(TestStatus::skipped($event->message())); + } + public function testMarkedIncomplete(MarkedIncomplete $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + $this->updateTestStatus(TestStatus::incomplete($event->throwable()->message())); + $this->throwable = $event->throwable(); + } + public function testConsideredRisky(ConsideredRisky $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + $this->updateTestStatus(TestStatus::risky()); + } + public function testTriggeredDeprecation(DeprecationTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, \true)) { + return; + } + if ($event->ignoredByBaseline()) { + return; + } + $this->updateTestStatus(TestStatus::deprecation()); + } + public function testTriggeredNotice(NoticeTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, \true)) { + return; + } + if ($event->ignoredByBaseline()) { + return; + } + $this->updateTestStatus(TestStatus::notice()); + } + public function testTriggeredWarning(WarningTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, \true)) { + return; + } + if ($event->ignoredByBaseline()) { + return; + } + $this->updateTestStatus(TestStatus::warning()); + } + public function testTriggeredPhpDeprecation(PhpDeprecationTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, \true)) { + return; + } + if ($event->ignoredByBaseline()) { + return; + } + $this->updateTestStatus(TestStatus::deprecation()); + } + public function testTriggeredPhpNotice(PhpNoticeTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, \true)) { + return; + } + if ($event->ignoredByBaseline()) { + return; + } + $this->updateTestStatus(TestStatus::notice()); + } + public function testTriggeredPhpWarning(PhpWarningTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, \true)) { + return; + } + if ($event->ignoredByBaseline()) { + return; + } + $this->updateTestStatus(TestStatus::warning()); + } + public function testTriggeredPhpunitDeprecation(PhpunitDeprecationTriggered $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + $this->updateTestStatus(TestStatus::deprecation()); + } + public function testTriggeredPhpunitError(PhpunitErrorTriggered $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + $this->updateTestStatus(TestStatus::error()); + } + public function testTriggeredPhpunitWarning(PhpunitWarningTriggered $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + if ($event->ignoredByTest()) { + return; + } + $this->updateTestStatus(TestStatus::warning()); + } + /** + * @throws InvalidArgumentException + */ + public function testFinished(Finished $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + $test = $event->test(); + assert($test instanceof TestMethod); + $this->process($test); + $this->status = null; + $this->throwable = null; + $this->prepared = \false; + } + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers(new \PHPUnit\Logging\TestDox\TestConsideredRiskySubscriber($this), new \PHPUnit\Logging\TestDox\TestErroredSubscriber($this), new \PHPUnit\Logging\TestDox\TestFailedSubscriber($this), new \PHPUnit\Logging\TestDox\TestFinishedSubscriber($this), new \PHPUnit\Logging\TestDox\TestMarkedIncompleteSubscriber($this), new \PHPUnit\Logging\TestDox\TestPassedSubscriber($this), new \PHPUnit\Logging\TestDox\TestPreparedSubscriber($this), new \PHPUnit\Logging\TestDox\TestSkippedSubscriber($this), new \PHPUnit\Logging\TestDox\TestTriggeredDeprecationSubscriber($this), new \PHPUnit\Logging\TestDox\TestTriggeredNoticeSubscriber($this), new \PHPUnit\Logging\TestDox\TestTriggeredPhpDeprecationSubscriber($this), new \PHPUnit\Logging\TestDox\TestTriggeredPhpNoticeSubscriber($this), new \PHPUnit\Logging\TestDox\TestTriggeredPhpunitDeprecationSubscriber($this), new \PHPUnit\Logging\TestDox\TestTriggeredPhpunitErrorSubscriber($this), new \PHPUnit\Logging\TestDox\TestTriggeredPhpunitWarningSubscriber($this), new \PHPUnit\Logging\TestDox\TestTriggeredPhpWarningSubscriber($this), new \PHPUnit\Logging\TestDox\TestTriggeredWarningSubscriber($this)); + } + private function updateTestStatus(TestStatus $status): void + { + if ($this->status !== null && $this->status->isMoreImportantThan($status)) { + return; + } + $this->status = $status; + } + private function process(TestMethod $test): void + { + if (!isset($this->tests[$test->className()])) { + $this->tests[$test->className()] = []; + } + $this->tests[$test->className()][] = new TestDoxTestMethod($test, $this->status, $this->throwable); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class After extends \PHPUnit\Metadata\Metadata +{ + private int $priority; + protected function __construct(\PHPUnit\Metadata\Level $level, int $priority) + { + parent::__construct($level); + $this->priority = $priority; + } + public function isAfter(): true + { + return \true; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterClass extends \PHPUnit\Metadata\Metadata +{ + private int $priority; + protected function __construct(\PHPUnit\Metadata\Level $level, int $priority) + { + parent::__construct($level); + $this->priority = $priority; + } + public function isAfterClass(): true + { + return \true; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AllowMockObjectsWithoutExpectations extends \PHPUnit\Metadata\Metadata +{ + public function isAllowMockObjectsWithoutExpectations(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function assert; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\CoversClass; +use PHPUnit\Metadata\CoversClassesThatExtendClass; +use PHPUnit\Metadata\CoversClassesThatImplementInterface; +use PHPUnit\Metadata\CoversFunction; +use PHPUnit\Metadata\CoversMethod; +use PHPUnit\Metadata\CoversNamespace; +use PHPUnit\Metadata\CoversTrait; +use PHPUnit\Metadata\Parser\Registry; +use PHPUnit\Metadata\UsesClass; +use PHPUnit\Metadata\UsesClassesThatExtendClass; +use PHPUnit\Metadata\UsesClassesThatImplementInterface; +use PHPUnit\Metadata\UsesFunction; +use PHPUnit\Metadata\UsesMethod; +use PHPUnit\Metadata\UsesNamespace; +use PHPUnit\Metadata\UsesTrait; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\Target; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\TargetCollection; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CodeCoverage +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function coversTargets(string $className, string $methodName): TargetCollection + { + $targets = []; + foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isCoversNamespace()) { + assert($metadata instanceof CoversNamespace); + $targets[] = Target::forNamespace($metadata->namespace()); + } + if ($metadata->isCoversClass()) { + assert($metadata instanceof CoversClass); + $targets[] = Target::forClass($metadata->className()); + } + if ($metadata->isCoversClassesThatExtendClass()) { + assert($metadata instanceof CoversClassesThatExtendClass); + $targets[] = Target::forClassesThatExtendClass($metadata->className()); + } + if ($metadata->isCoversClassesThatImplementInterface()) { + assert($metadata instanceof CoversClassesThatImplementInterface); + $targets[] = Target::forClassesThatImplementInterface($metadata->interfaceName()); + } + if ($metadata->isCoversMethod()) { + assert($metadata instanceof CoversMethod); + $targets[] = Target::forMethod($metadata->className(), $metadata->methodName()); + } + if ($metadata->isCoversFunction()) { + assert($metadata instanceof CoversFunction); + $targets[] = Target::forFunction($metadata->functionName()); + } + if ($metadata->isCoversTrait()) { + assert($metadata instanceof CoversTrait); + $targets[] = Target::forTrait($metadata->traitName()); + } + } + return TargetCollection::fromArray($targets); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function usesTargets(string $className, string $methodName): TargetCollection + { + $targets = []; + foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isUsesNamespace()) { + assert($metadata instanceof UsesNamespace); + $targets[] = Target::forNamespace($metadata->namespace()); + } + if ($metadata->isUsesClass()) { + assert($metadata instanceof UsesClass); + $targets[] = Target::forClass($metadata->className()); + } + if ($metadata->isUsesClassesThatExtendClass()) { + assert($metadata instanceof UsesClassesThatExtendClass); + $targets[] = Target::forClassesThatExtendClass($metadata->className()); + } + if ($metadata->isUsesClassesThatImplementInterface()) { + assert($metadata instanceof UsesClassesThatImplementInterface); + $targets[] = Target::forClassesThatImplementInterface($metadata->interfaceName()); + } + if ($metadata->isUsesMethod()) { + assert($metadata instanceof UsesMethod); + $targets[] = Target::forMethod($metadata->className(), $metadata->methodName()); + } + if ($metadata->isUsesFunction()) { + assert($metadata instanceof UsesFunction); + $targets[] = Target::forFunction($metadata->functionName()); + } + if ($metadata->isUsesTrait()) { + assert($metadata instanceof UsesTrait); + $targets[] = Target::forTrait($metadata->traitName()); + } + } + return TargetCollection::fromArray($targets); + } + public function shouldCodeCoverageBeCollectedFor(TestCase $test): bool + { + $parser = Registry::parser(); + if ($parser->forClass($test::class)->isCoversNothing()->isNotEmpty()) { + return \false; + } + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function array_key_exists; +use function assert; +use function count; +use function get_debug_type; +use function is_array; +use function is_int; +use function is_iterable; +use function is_string; +use function sprintf; +use PHPUnit\Event; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Framework\InvalidDataProviderException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\DataProvider as DataProviderMetadata; +use PHPUnit\Metadata\DataProviderClosure as DataProviderClosureMetadata; +use PHPUnit\Metadata\MetadataCollection; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Metadata\TestWith; +use PHPUnit\Util\Test; +use ReflectionMethod; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataProvider +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @throws InvalidDataProviderException + * + * @return ?array + */ + public function providedData(string $className, string $methodName): ?array + { + $metadataCollection = MetadataRegistry::parser()->forMethod($className, $methodName); + $dataProvider = $metadataCollection->isDataProvider(); + $dataProviderClosure = $metadataCollection->isDataProviderClosure(); + $testWith = $metadataCollection->isTestWith(); + if ($dataProvider->isEmpty() && $dataProviderClosure->isEmpty() && $testWith->isEmpty()) { + return null; + } + $testMethod = new ReflectionMethod($className, $methodName); + if ($dataProvider->isNotEmpty() || $dataProviderClosure->isNotEmpty()) { + if ($testWith->isNotEmpty()) { + $this->triggerWarningForMixingOfDataProviderAndTestWith($testMethod); + } + return $this->dataProvidedByMethods($className, $testMethod, $dataProvider, $dataProviderClosure); + } + return $this->dataProvidedByMetadata($testMethod, $testWith); + } + /** + * @param class-string $testClassName + * + * @throws InvalidDataProviderException + * + * @return array + */ + private function dataProvidedByMethods(string $testClassName, ReflectionMethod $testMethod, MetadataCollection $dataProvider, MetadataCollection $dataProviderClosure): array + { + $testMethodValueObject = new Event\Code\ClassMethod($testClassName, $testMethod->getName()); + $methodsCalled = []; + $result = []; + $testMethodNumberOfParameters = $testMethod->getNumberOfParameters(); + $testMethodIsNonVariadic = !$testMethod->isVariadic(); + foreach ($dataProvider as $_dataProvider) { + assert($_dataProvider instanceof DataProviderMetadata); + $providerLabel = $_dataProvider->className() . '::' . $_dataProvider->methodName(); + $dataProviderMethod = new Event\Code\ClassMethod($_dataProvider->className(), $_dataProvider->methodName()); + $validateArgumentCount = $testMethodIsNonVariadic && $_dataProvider->validateArgumentCount(); + Event\Facade::emitter()->dataProviderMethodCalled($testMethodValueObject, $dataProviderMethod); + $methodsCalled[] = $dataProviderMethod; + try { + $method = new ReflectionMethod($_dataProvider->className(), $_dataProvider->methodName()); + $className = $_dataProvider->className(); + $methodName = $_dataProvider->methodName(); + if (Test::isTestMethod($method)) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Method %s::%s() used by test method %s::%s() is also a test method', $_dataProvider->className(), $_dataProvider->methodName(), $testMethod->getDeclaringClass()->getName(), $testMethod->getName())); + } + if (!$method->isPublic()) { + throw new InvalidDataProviderException(sprintf('Data Provider method %s::%s() is not public', $className, $methodName)); + } + if (!$method->isStatic()) { + throw new InvalidDataProviderException(sprintf('Data Provider method %s::%s() is not static', $className, $methodName)); + } + if ($method->getNumberOfParameters() > 0) { + throw new InvalidDataProviderException(sprintf('Data Provider method %s::%s() expects an argument', $className, $methodName)); + } + /** @phpstan-ignore staticMethod.dynamicName */ + $data = $className::$methodName(); + if (!is_iterable($data)) { + throw new InvalidDataProviderException(sprintf('Data Provider method %s::%s() does not return an iterable', $className, $methodName)); + } + } catch (Throwable $e) { + Event\Facade::emitter()->dataProviderMethodFinished($testMethodValueObject, ...$methodsCalled); + throw InvalidDataProviderException::forException($e, $providerLabel); + } + try { + foreach ($data as $key => $value) { + if (!is_int($key) && !is_string($key)) { + throw new InvalidDataProviderException(sprintf('The key must be an integer or a string, %s given', get_debug_type($key))); + } + if (!is_array($value)) { + throw new InvalidDataProviderException(sprintf('Data set %s provided by %s is invalid, expected array but got %s', $this->formatKey($key), $providerLabel, get_debug_type($value))); + } + if ($validateArgumentCount && $testMethodNumberOfParameters < count($value)) { + $this->triggerWarningForArgumentCount($testMethod, $this->formatKey($key), $providerLabel, count($value), $testMethodNumberOfParameters); + } + if (is_int($key)) { + $result[] = new \PHPUnit\Metadata\Api\ProvidedData($providerLabel, $value); + continue; + } + if (array_key_exists($key, $result)) { + throw new InvalidDataProviderException(sprintf('The key "%s" has already been defined by provider %s', $key, $result[$key]->label())); + } + $result[$key] = new \PHPUnit\Metadata\Api\ProvidedData($providerLabel, $value); + } + } catch (Throwable $e) { + Event\Facade::emitter()->dataProviderMethodFinished($testMethodValueObject, ...$methodsCalled); + throw new InvalidDataProviderException($e->getMessage(), $e->getCode(), $e); + } + } + foreach ($dataProviderClosure as $_dataProvider) { + assert($_dataProvider instanceof DataProviderClosureMetadata); + $providerLabel = sprintf('callable provided to %s::%s()', $testClassName, $testMethod->getName()); + $validateArgumentCount = $testMethodIsNonVariadic && $_dataProvider->validateArgumentCount(); + try { + $callable = $_dataProvider->closure(); + $data = $callable(); + if (!is_iterable($data)) { + throw new InvalidDataProviderException('Data Provider callable does not return an iterable'); + } + } catch (Throwable $e) { + Event\Facade::emitter()->dataProviderMethodFinished($testMethodValueObject, ...$methodsCalled); + throw InvalidDataProviderException::forException($e, $providerLabel); + } + foreach ($data as $key => $value) { + if (!is_int($key) && !is_string($key)) { + Event\Facade::emitter()->dataProviderMethodFinished($testMethodValueObject, ...$methodsCalled); + throw new InvalidDataProviderException(sprintf('The key must be an integer or a string, %s given', get_debug_type($key))); + } + if (!is_array($value)) { + Event\Facade::emitter()->dataProviderMethodFinished($testMethodValueObject, ...$methodsCalled); + throw new InvalidDataProviderException(sprintf('Data set %s provided by %s is invalid, expected array but got %s', $this->formatKey($key), $providerLabel, get_debug_type($value))); + } + if ($validateArgumentCount && $testMethodNumberOfParameters < count($value)) { + $this->triggerWarningForArgumentCount($testMethod, $this->formatKey($key), $providerLabel, count($value), $testMethodNumberOfParameters); + } + if (is_int($key)) { + $result[] = new \PHPUnit\Metadata\Api\ProvidedData($providerLabel, $value); + continue; + } + if (array_key_exists($key, $result)) { + Event\Facade::emitter()->dataProviderMethodFinished($testMethodValueObject, ...$methodsCalled); + throw new InvalidDataProviderException(sprintf('The key "%s" has already been defined by provider %s', $key, $result[$key]->label())); + } + $result[$key] = new \PHPUnit\Metadata\Api\ProvidedData($providerLabel, $value); + } + } + Event\Facade::emitter()->dataProviderMethodFinished($testMethodValueObject, ...$methodsCalled); + if ($result === []) { + throw new InvalidDataProviderException('Empty data set provided by data provider'); + } + return $result; + } + /** + * @return array + */ + private function dataProvidedByMetadata(ReflectionMethod $testMethod, MetadataCollection $testWith): array + { + $result = []; + foreach ($testWith as $i => $_testWith) { + assert($_testWith instanceof TestWith); + $providerLabel = sprintf('TestWith#%s attribute', $i); + if ($_testWith->hasName()) { + $key = $_testWith->name(); + if (array_key_exists($key, $result)) { + throw new InvalidDataProviderException(sprintf('The key "%s" has already been defined by %s', $key, $result[$key]->label())); + } + $result[$key] = new \PHPUnit\Metadata\Api\ProvidedData($providerLabel, $_testWith->data()); + } else { + $result[] = new \PHPUnit\Metadata\Api\ProvidedData($providerLabel, $_testWith->data()); + } + } + $testMethodNumberOfParameters = $testMethod->getNumberOfParameters(); + $testMethodIsNonVariadic = !$testMethod->isVariadic(); + foreach ($result as $key => $providedData) { + $value = $providedData->value(); + if (!is_array($value)) { + throw new InvalidDataProviderException(sprintf('Data set %s provided by %s is invalid, expected array but got %s', $this->formatKey($key), $providedData->label(), get_debug_type($value))); + } + if ($testMethodIsNonVariadic && $testMethodNumberOfParameters < count($value)) { + $this->triggerWarningForArgumentCount($testMethod, $this->formatKey($key), $providedData->label(), count($value), $testMethodNumberOfParameters); + } + } + return $result; + } + /** + * @param int|non-empty-string $key + * + * @return non-empty-string + */ + private function formatKey(int|string $key): string + { + return is_int($key) ? '#' . $key : '"' . $key . '"'; + } + private function triggerWarningForMixingOfDataProviderAndTestWith(ReflectionMethod $method): void + { + Event\Facade::emitter()->testTriggeredPhpunitWarning($this->testValueObject($method), 'Mixing #[DataProvider*] and #[TestWith*] attributes is not supported, only the data provided by #[DataProvider*] will be used'); + } + private function triggerWarningForArgumentCount(ReflectionMethod $method, string $key, string $label, int $numberOfValues, int $testMethodNumberOfParameters): void + { + Event\Facade::emitter()->testTriggeredPhpunitWarning($this->testValueObject($method), sprintf('Data set %s provided by %s has more arguments (%d) than the test method accepts (%d)', $key, $label, $numberOfValues, $testMethodNumberOfParameters)); + } + private function testValueObject(ReflectionMethod $method): TestMethod + { + return new TestMethod($method->getDeclaringClass()->getName(), $method->getName(), $method->getFileName(), $method->getStartLine(), Event\Code\TestDoxBuilder::fromClassNameAndMethodName($method->getDeclaringClass()->getName(), $method->getName()), MetadataCollection::fromArray([]), Event\TestData\TestDataCollection::fromArray([])); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function assert; +use PHPUnit\Framework\ExecutionOrderDependency; +use PHPUnit\Metadata\DependsOnClass; +use PHPUnit\Metadata\DependsOnMethod; +use PHPUnit\Metadata\Parser\Registry; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Dependencies +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @return list + */ + public static function dependencies(string $className, string $methodName): array + { + $dependencies = []; + foreach (Registry::parser()->forClassAndMethod($className, $methodName)->isDepends() as $metadata) { + if ($metadata->isDependsOnClass()) { + assert($metadata instanceof DependsOnClass); + $dependencies[] = ExecutionOrderDependency::forClass($metadata); + continue; + } + assert($metadata instanceof DependsOnMethod); + if ($metadata->methodName() === '') { + $dependencies[] = ExecutionOrderDependency::invalid(); + continue; + } + $dependencies[] = ExecutionOrderDependency::forMethod($metadata); + } + return $dependencies; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function array_flip; +use function array_key_exists; +use function array_unique; +use function assert; +use function strtolower; +use function trim; +use PHPUnit\Framework\TestSize\TestSize; +use PHPUnit\Metadata\CoversClass; +use PHPUnit\Metadata\CoversFunction; +use PHPUnit\Metadata\Group; +use PHPUnit\Metadata\Parser\Registry; +use PHPUnit\Metadata\RequiresPhpExtension; +use PHPUnit\Metadata\UsesClass; +use PHPUnit\Metadata\UsesFunction; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Groups +{ + /** + * @var array> + */ + private static array $groupCache = []; + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @return list + */ + public function groups(string $className, string $methodName, bool $includeVirtual = \true): array + { + $key = $className . '::' . $methodName . '::' . $includeVirtual; + if (array_key_exists($key, self::$groupCache)) { + return self::$groupCache[$key]; + } + $groups = []; + foreach (Registry::parser()->forClassAndMethod($className, $methodName)->isGroup() as $group) { + assert($group instanceof Group); + $groups[] = $group->groupName(); + } + if (!$includeVirtual) { + return self::$groupCache[$key] = array_unique($groups); + } + foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isCoversClass()) { + assert($metadata instanceof CoversClass); + $groups[] = '__phpunit_covers_' . $this->canonicalizeName($metadata->className()); + continue; + } + if ($metadata->isCoversFunction()) { + assert($metadata instanceof CoversFunction); + $groups[] = '__phpunit_covers_' . $this->canonicalizeName($metadata->functionName()); + continue; + } + if ($metadata->isUsesClass()) { + assert($metadata instanceof UsesClass); + $groups[] = '__phpunit_uses_' . $this->canonicalizeName($metadata->className()); + continue; + } + if ($metadata->isUsesFunction()) { + assert($metadata instanceof UsesFunction); + $groups[] = '__phpunit_uses_' . $this->canonicalizeName($metadata->functionName()); + continue; + } + if ($metadata->isRequiresPhpExtension()) { + assert($metadata instanceof RequiresPhpExtension); + $groups[] = '__phpunit_requires_php_extension' . $this->canonicalizeName($metadata->extension()); + } + } + return self::$groupCache[$key] = array_unique($groups); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function size(string $className, string $methodName): TestSize + { + $groups = array_flip($this->groups($className, $methodName)); + if (isset($groups['large'])) { + return TestSize::large(); + } + if (isset($groups['medium'])) { + return TestSize::medium(); + } + if (isset($groups['small'])) { + return TestSize::small(); + } + return TestSize::unknown(); + } + private function canonicalizeName(string $name): string + { + return strtolower(trim($name, '\\')); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function assert; +use function class_exists; +use function in_array; +use function strtolower; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\After; +use PHPUnit\Metadata\AfterClass; +use PHPUnit\Metadata\Before; +use PHPUnit\Metadata\BeforeClass; +use PHPUnit\Metadata\Parser\Registry; +use PHPUnit\Metadata\PostCondition; +use PHPUnit\Metadata\PreCondition; +use PHPUnit\Runner\HookMethod; +use PHPUnit\Runner\HookMethodCollection; +use PHPUnit\Util\Reflection; +use ReflectionClass; +use ReflectionMethod; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class HookMethods +{ + /** + * @var array + */ + private static array $hookMethods = []; + /** + * @param class-string $className + * + * @return array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} + */ + public function hookMethods(string $className): array + { + if (!class_exists($className)) { + return self::emptyHookMethodsArray(); + } + if (isset(self::$hookMethods[$className])) { + return self::$hookMethods[$className]; + } + self::$hookMethods[$className] = self::emptyHookMethodsArray(); + foreach (Reflection::methodsDeclaredDirectlyInTestClass(new ReflectionClass($className)) as $method) { + $methodName = $method->getName(); + $metadata = Registry::parser()->forMethod($className, $methodName); + if ($method->isStatic()) { + if ($metadata->isBeforeClass()->isNotEmpty()) { + $beforeClass = $metadata->isBeforeClass()->asArray()[0]; + assert($beforeClass instanceof BeforeClass); + self::$hookMethods[$className]['beforeClass']->add(new HookMethod($methodName, $beforeClass->priority())); + } + if ($metadata->isAfterClass()->isNotEmpty()) { + $afterClass = $metadata->isAfterClass()->asArray()[0]; + assert($afterClass instanceof AfterClass); + self::$hookMethods[$className]['afterClass']->add(new HookMethod($methodName, $afterClass->priority())); + } + } + if ($metadata->isBefore()->isNotEmpty()) { + $before = $metadata->isBefore()->asArray()[0]; + assert($before instanceof Before); + self::$hookMethods[$className]['before']->add(new HookMethod($methodName, $before->priority())); + } + if ($metadata->isPreCondition()->isNotEmpty()) { + $preCondition = $metadata->isPreCondition()->asArray()[0]; + assert($preCondition instanceof PreCondition); + self::$hookMethods[$className]['preCondition']->add(new HookMethod($methodName, $preCondition->priority())); + } + if ($metadata->isPostCondition()->isNotEmpty()) { + $postCondition = $metadata->isPostCondition()->asArray()[0]; + assert($postCondition instanceof PostCondition); + self::$hookMethods[$className]['postCondition']->add(new HookMethod($methodName, $postCondition->priority())); + } + if ($metadata->isAfter()->isNotEmpty()) { + $after = $metadata->isAfter()->asArray()[0]; + assert($after instanceof After); + self::$hookMethods[$className]['after']->add(new HookMethod($methodName, $after->priority())); + } + } + return self::$hookMethods[$className]; + } + public function isHookMethod(ReflectionMethod $method): bool + { + $defaultNames = ['setupbeforeclass', 'setup', 'assertpreconditions', 'assertpostconditions', 'teardown', 'teardownafterclass']; + if (in_array(strtolower($method->getName()), $defaultNames, \true)) { + return \true; + } + $metadata = Registry::parser()->forMethod($method->getDeclaringClass()->getName(), $method->getName()); + return $metadata->isBeforeClass()->isNotEmpty() || $metadata->isBefore()->isNotEmpty() || $metadata->isPreCondition()->isNotEmpty() || $metadata->isPostCondition()->isNotEmpty() || $metadata->isAfter()->isNotEmpty() || $metadata->isAfterClass()->isNotEmpty(); + } + /** + * @return array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} + */ + private function emptyHookMethodsArray(): array + { + return ['beforeClass' => HookMethodCollection::defaultBeforeClass(), 'before' => HookMethodCollection::defaultBefore(), 'preCondition' => HookMethodCollection::defaultPreCondition(), 'postCondition' => HookMethodCollection::defaultPostCondition(), 'after' => HookMethodCollection::defaultAfter(), 'afterClass' => HookMethodCollection::defaultAfterClass()]; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ProvidedData +{ + /** + * @var non-empty-string + */ + private string $label; + private mixed $value; + /** + * @param non-empty-string $label + */ + public function __construct(string $label, mixed $value) + { + $this->label = $label; + $this->value = $value; + } + /** + * @return non-empty-string + */ + public function label(): string + { + return $this->label; + } + public function value(): mixed + { + return $this->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use const PHP_OS; +use const PHP_OS_FAMILY; +use const PHP_VERSION; +use function addcslashes; +use function array_column; +use function array_key_exists; +use function assert; +use function extension_loaded; +use function function_exists; +use function in_array; +use function ini_get; +use function method_exists; +use function phpversion; +use function preg_match; +use function sprintf; +use function substr_count; +use PHPUnit\Event\Facade; +use PHPUnit\Metadata\Parser\Registry; +use PHPUnit\Metadata\RequiresEnvironmentVariable; +use PHPUnit\Metadata\RequiresFunction; +use PHPUnit\Metadata\RequiresMethod; +use PHPUnit\Metadata\RequiresOperatingSystem; +use PHPUnit\Metadata\RequiresOperatingSystemFamily; +use PHPUnit\Metadata\RequiresPhp; +use PHPUnit\Metadata\RequiresPhpExtension; +use PHPUnit\Metadata\RequiresPhpunit; +use PHPUnit\Metadata\RequiresPhpunitExtension; +use PHPUnit\Metadata\RequiresSetting; +use PHPUnit\Metadata\Version\ComparisonRequirement; +use PHPUnit\Metadata\Version\Requirement; +use PHPUnit\Runner\Version; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Requirements +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @return list + */ + public function requirementsNotSatisfiedFor(string $className, string $methodName): array + { + $notSatisfied = []; + foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isRequiresPhp()) { + assert($metadata instanceof RequiresPhp); + $versionRequirement = $metadata->versionRequirement(); + $this->warnAboutIncompleteVersion($metadata->versionRequirement(), $className, $methodName); + if (!$versionRequirement->isSatisfiedBy(PHP_VERSION)) { + $notSatisfied[] = sprintf('PHP %s is required.', $versionRequirement->asString()); + } + } + if ($metadata->isRequiresPhpExtension()) { + assert($metadata instanceof RequiresPhpExtension); + $extensionVersion = phpversion($metadata->extension()); + if ($extensionVersion === \false) { + $extensionVersion = ''; + } + if ($metadata->hasVersionRequirement()) { + $this->warnAboutIncompleteVersion($metadata->versionRequirement(), $className, $methodName); + } + if (!extension_loaded($metadata->extension()) || $metadata->hasVersionRequirement() && !$metadata->versionRequirement()->isSatisfiedBy($extensionVersion)) { + $notSatisfied[] = sprintf('PHP extension %s%s is required.', $metadata->extension(), $metadata->hasVersionRequirement() ? ' ' . $metadata->versionRequirement()->asString() : ''); + } + } + if ($metadata->isRequiresPhpunit()) { + assert($metadata instanceof RequiresPhpunit); + $versionRequirement = $metadata->versionRequirement(); + $this->warnAboutIncompleteVersion($metadata->versionRequirement(), $className, $methodName); + if (!$versionRequirement->isSatisfiedBy(Version::id())) { + $notSatisfied[] = sprintf('PHPUnit %s is required.', $versionRequirement->asString()); + } + } + if ($metadata->isRequiresPhpunitExtension()) { + assert($metadata instanceof RequiresPhpunitExtension); + $configuration = ConfigurationRegistry::get(); + $extensionBootstrappers = array_column($configuration->extensionBootstrappers(), 'className'); + if ($configuration->noExtensions() || !in_array($metadata->extensionClass(), $extensionBootstrappers, \true)) { + $notSatisfied[] = sprintf('PHPUnit extension "%s" is required.', $metadata->extensionClass()); + } + } + if ($metadata->isRequiresEnvironmentVariable()) { + assert($metadata instanceof RequiresEnvironmentVariable); + if (!array_key_exists($metadata->environmentVariableName(), $_ENV) || $metadata->value() === null && $_ENV[$metadata->environmentVariableName()] === '') { + $notSatisfied[] = sprintf('Environment variable "%s" is required.', $metadata->environmentVariableName()); + continue; + } + if ($metadata->value() !== null && $_ENV[$metadata->environmentVariableName()] !== $metadata->value()) { + $notSatisfied[] = sprintf('Environment variable "%s" is required to be "%s".', $metadata->environmentVariableName(), $metadata->value()); + } + } + if ($metadata->isRequiresOperatingSystemFamily()) { + assert($metadata instanceof RequiresOperatingSystemFamily); + if ($metadata->operatingSystemFamily() !== PHP_OS_FAMILY) { + $notSatisfied[] = sprintf('Operating system %s is required.', $metadata->operatingSystemFamily()); + } + } + if ($metadata->isRequiresOperatingSystem()) { + assert($metadata instanceof RequiresOperatingSystem); + $pattern = sprintf('/%s/i', addcslashes($metadata->operatingSystem(), '/')); + if (preg_match($pattern, PHP_OS) === 0) { + $notSatisfied[] = sprintf('Operating system %s is required.', $metadata->operatingSystem()); + } + } + if ($metadata->isRequiresFunction()) { + assert($metadata instanceof RequiresFunction); + if (!function_exists($metadata->functionName())) { + $notSatisfied[] = sprintf('Function %s() is required.', $metadata->functionName()); + } + } + if ($metadata->isRequiresMethod()) { + assert($metadata instanceof RequiresMethod); + if (!method_exists($metadata->className(), $metadata->methodName())) { + $notSatisfied[] = sprintf('Method %s::%s() is required.', $metadata->className(), $metadata->methodName()); + } + } + if ($metadata->isRequiresSetting()) { + assert($metadata instanceof RequiresSetting); + if (ini_get($metadata->setting()) !== $metadata->value()) { + $notSatisfied[] = sprintf('Setting "%s" is required to be "%s".', $metadata->setting(), $metadata->value()); + } + } + } + return $notSatisfied; + } + public function requiresXdebug(string $className, string $methodName): bool + { + foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isRequiresPhpExtension()) { + if ($metadata->extension() === 'xdebug') { + return \true; + } + } + } + return \false; + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + private function warnAboutIncompleteVersion(Requirement $versionRequirement, string $className, string $methodName): void + { + if (!$versionRequirement instanceof ComparisonRequirement) { + return; + } + if (substr_count($versionRequirement->version(), '.') === 2) { + return; + } + Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Incomplete version requirement "%s" used by %s::%s()', $versionRequirement->version(), $className, $methodName)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BackupGlobals extends \PHPUnit\Metadata\Metadata +{ + private bool $enabled; + protected function __construct(\PHPUnit\Metadata\Level $level, bool $enabled) + { + parent::__construct($level); + $this->enabled = $enabled; + } + public function isBackupGlobals(): true + { + return \true; + } + public function enabled(): bool + { + return $this->enabled; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BackupStaticProperties extends \PHPUnit\Metadata\Metadata +{ + private bool $enabled; + protected function __construct(\PHPUnit\Metadata\Level $level, bool $enabled) + { + parent::__construct($level); + $this->enabled = $enabled; + } + public function isBackupStaticProperties(): true + { + return \true; + } + public function enabled(): bool + { + return $this->enabled; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Before extends \PHPUnit\Metadata\Metadata +{ + private int $priority; + protected function __construct(\PHPUnit\Metadata\Level $level, int $priority) + { + parent::__construct($level); + $this->priority = $priority; + } + public function isBefore(): true + { + return \true; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeClass extends \PHPUnit\Metadata\Metadata +{ + private int $priority; + protected function __construct(\PHPUnit\Metadata\Level $level, int $priority) + { + parent::__construct($level); + $this->priority = $priority; + } + public function isBeforeClass(): true + { + return \true; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversClass extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className) + { + parent::__construct($level); + $this->className = $className; + } + public function isCoversClass(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversClassesThatExtendClass extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className) + { + parent::__construct($level); + $this->className = $className; + } + public function isCoversClassesThatExtendClass(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversClassesThatImplementInterface extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $interfaceName; + /** + * @param class-string $interfaceName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $interfaceName) + { + parent::__construct($level); + $this->interfaceName = $interfaceName; + } + public function isCoversClassesThatImplementInterface(): true + { + return \true; + } + /** + * @return class-string + */ + public function interfaceName(): string + { + return $this->interfaceName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversFunction extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $functionName; + /** + * @param non-empty-string $functionName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $functionName) + { + parent::__construct($level); + $this->functionName = $functionName; + } + public function isCoversFunction(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversMethod extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className, string $methodName) + { + parent::__construct($level); + $this->className = $className; + $this->methodName = $methodName; + } + public function isCoversMethod(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversNamespace extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $namespace; + /** + * @param non-empty-string $namespace + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $namespace) + { + parent::__construct($level); + $this->namespace = $namespace; + } + public function isCoversNamespace(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function namespace(): string + { + return $this->namespace; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversNothing extends \PHPUnit\Metadata\Metadata +{ + public function isCoversNothing(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversTrait extends \PHPUnit\Metadata\Metadata +{ + /** + * @var trait-string + */ + private string $traitName; + /** + * @param trait-string $traitName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $traitName) + { + parent::__construct($level); + $this->traitName = $traitName; + } + public function isCoversTrait(): true + { + return \true; + } + /** + * @return trait-string + */ + public function traitName(): string + { + return $this->traitName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataProvider extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + private bool $validateArgumentCount; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className, string $methodName, bool $validateArgumentCount) + { + parent::__construct($level); + $this->className = $className; + $this->methodName = $methodName; + $this->validateArgumentCount = $validateArgumentCount; + } + public function isDataProvider(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + public function validateArgumentCount(): bool + { + return $this->validateArgumentCount; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use Closure; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataProviderClosure extends \PHPUnit\Metadata\Metadata +{ + private Closure $closure; + private bool $validateArgumentCount; + protected function __construct(\PHPUnit\Metadata\Level $level, Closure $closure, bool $validateArgumentCount) + { + parent::__construct($level); + $this->closure = $closure; + $this->validateArgumentCount = $validateArgumentCount; + } + public function isDataProviderClosure(): true + { + return \true; + } + public function closure(): Closure + { + return $this->closure; + } + public function validateArgumentCount(): bool + { + return $this->validateArgumentCount; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DependsOnClass extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + private bool $deepClone; + private bool $shallowClone; + /** + * @param class-string $className + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className, bool $deepClone, bool $shallowClone) + { + parent::__construct($level); + $this->className = $className; + $this->deepClone = $deepClone; + $this->shallowClone = $shallowClone; + } + public function isDependsOnClass(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + public function deepClone(): bool + { + return $this->deepClone; + } + public function shallowClone(): bool + { + return $this->shallowClone; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DependsOnMethod extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + private bool $deepClone; + private bool $shallowClone; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className, string $methodName, bool $deepClone, bool $shallowClone) + { + parent::__construct($level); + $this->className = $className; + $this->methodName = $methodName; + $this->deepClone = $deepClone; + $this->shallowClone = $shallowClone; + } + public function isDependsOnMethod(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + public function deepClone(): bool + { + return $this->deepClone; + } + public function shallowClone(): bool + { + return $this->shallowClone; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DisableReturnValueGenerationForTestDoubles extends \PHPUnit\Metadata\Metadata +{ + public function isDisableReturnValueGenerationForTestDoubles(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DoesNotPerformAssertions extends \PHPUnit\Metadata\Metadata +{ + public function isDoesNotPerformAssertions(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends \PHPUnit\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Exception; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidAttributeException extends RuntimeException implements Exception +{ + /** + * @param non-empty-string $attributeName + * @param non-empty-string $target + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $message + */ + public function __construct(string $attributeName, string $target, string $file, int $line, string $message) + { + parent::__construct(sprintf('Invalid attribute %s for %s in %s:%d%s%s', $attributeName, $target, $file, $line, PHP_EOL, $message)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidVersionRequirementException extends RuntimeException implements \PHPUnit\Metadata\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class NoVersionRequirementException extends RuntimeException implements \PHPUnit\Metadata\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExcludeGlobalVariableFromBackup extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $globalVariableName; + /** + * @param non-empty-string $globalVariableName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $globalVariableName) + { + parent::__construct($level); + $this->globalVariableName = $globalVariableName; + } + public function isExcludeGlobalVariableFromBackup(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function globalVariableName(): string + { + return $this->globalVariableName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExcludeStaticPropertyFromBackup extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $propertyName; + /** + * @param class-string $className + * @param non-empty-string $propertyName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className, string $propertyName) + { + parent::__construct($level); + $this->className = $className; + $this->propertyName = $propertyName; + } + public function isExcludeStaticPropertyFromBackup(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function propertyName(): string + { + return $this->propertyName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Group extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $groupName; + /** + * @param non-empty-string $groupName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $groupName) + { + parent::__construct($level); + $this->groupName = $groupName; + } + public function isGroup(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function groupName(): string + { + return $this->groupName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IgnoreDeprecations extends \PHPUnit\Metadata\Metadata +{ + /** @var null|non-empty-string */ + private ?string $messagePattern; + /** + * @param null|non-empty-string $messagePattern + */ + protected function __construct(\PHPUnit\Metadata\Level $level, null|string $messagePattern) + { + parent::__construct($level); + $this->messagePattern = $messagePattern; + } + public function isIgnoreDeprecations(): true + { + return \true; + } + /** + * @return null|non-empty-string + */ + public function messagePattern(): ?string + { + return $this->messagePattern; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IgnorePhpunitDeprecations extends \PHPUnit\Metadata\Metadata +{ + public function isIgnorePhpunitDeprecations(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IgnorePhpunitWarnings extends \PHPUnit\Metadata\Metadata +{ + /** @var null|non-empty-string */ + private ?string $messagePattern; + /** + * @param null|non-empty-string $messagePattern + */ + protected function __construct(\PHPUnit\Metadata\Level $level, null|string $messagePattern) + { + parent::__construct($level); + $this->messagePattern = $messagePattern; + } + public function isIgnorePhpunitWarnings(): true + { + return \true; + } + /** + * @return null|non-empty-string + */ + public function messagePattern(): ?string + { + return $this->messagePattern; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @internal This enumeration is not covered by the backward compatibility promise for PHPUnit + */ +enum Level +{ + case CLASS_LEVEL; + case METHOD_LEVEL; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use Closure; +use PHPUnit\Metadata\Version\Requirement; +use PHPUnit\Runner\Extension\Extension; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Metadata +{ + private \PHPUnit\Metadata\Level $level; + public static function after(int $priority): \PHPUnit\Metadata\After + { + return new \PHPUnit\Metadata\After(\PHPUnit\Metadata\Level::METHOD_LEVEL, $priority); + } + public static function afterClass(int $priority): \PHPUnit\Metadata\AfterClass + { + return new \PHPUnit\Metadata\AfterClass(\PHPUnit\Metadata\Level::METHOD_LEVEL, $priority); + } + public static function allowMockObjectsWithoutExpectationsOnClass(): \PHPUnit\Metadata\AllowMockObjectsWithoutExpectations + { + return new \PHPUnit\Metadata\AllowMockObjectsWithoutExpectations(\PHPUnit\Metadata\Level::CLASS_LEVEL); + } + public static function allowMockObjectsWithoutExpectationsOnMethod(): \PHPUnit\Metadata\AllowMockObjectsWithoutExpectations + { + return new \PHPUnit\Metadata\AllowMockObjectsWithoutExpectations(\PHPUnit\Metadata\Level::METHOD_LEVEL); + } + public static function backupGlobalsOnClass(bool $enabled): \PHPUnit\Metadata\BackupGlobals + { + return new \PHPUnit\Metadata\BackupGlobals(\PHPUnit\Metadata\Level::CLASS_LEVEL, $enabled); + } + public static function backupGlobalsOnMethod(bool $enabled): \PHPUnit\Metadata\BackupGlobals + { + return new \PHPUnit\Metadata\BackupGlobals(\PHPUnit\Metadata\Level::METHOD_LEVEL, $enabled); + } + public static function backupStaticPropertiesOnClass(bool $enabled): \PHPUnit\Metadata\BackupStaticProperties + { + return new \PHPUnit\Metadata\BackupStaticProperties(\PHPUnit\Metadata\Level::CLASS_LEVEL, $enabled); + } + public static function backupStaticPropertiesOnMethod(bool $enabled): \PHPUnit\Metadata\BackupStaticProperties + { + return new \PHPUnit\Metadata\BackupStaticProperties(\PHPUnit\Metadata\Level::METHOD_LEVEL, $enabled); + } + public static function before(int $priority): \PHPUnit\Metadata\Before + { + return new \PHPUnit\Metadata\Before(\PHPUnit\Metadata\Level::METHOD_LEVEL, $priority); + } + public static function beforeClass(int $priority): \PHPUnit\Metadata\BeforeClass + { + return new \PHPUnit\Metadata\BeforeClass(\PHPUnit\Metadata\Level::METHOD_LEVEL, $priority); + } + /** + * @param non-empty-string $namespace + */ + public static function coversNamespace(string $namespace): \PHPUnit\Metadata\CoversNamespace + { + return new \PHPUnit\Metadata\CoversNamespace(\PHPUnit\Metadata\Level::CLASS_LEVEL, $namespace); + } + /** + * @param class-string $className + */ + public static function coversClass(string $className): \PHPUnit\Metadata\CoversClass + { + return new \PHPUnit\Metadata\CoversClass(\PHPUnit\Metadata\Level::CLASS_LEVEL, $className); + } + /** + * @param class-string $className + */ + public static function coversClassesThatExtendClass(string $className): \PHPUnit\Metadata\CoversClassesThatExtendClass + { + return new \PHPUnit\Metadata\CoversClassesThatExtendClass(\PHPUnit\Metadata\Level::CLASS_LEVEL, $className); + } + /** + * @param class-string $interfaceName + */ + public static function coversClassesThatImplementInterface(string $interfaceName): \PHPUnit\Metadata\CoversClassesThatImplementInterface + { + return new \PHPUnit\Metadata\CoversClassesThatImplementInterface(\PHPUnit\Metadata\Level::CLASS_LEVEL, $interfaceName); + } + /** + * @param trait-string $traitName + */ + public static function coversTrait(string $traitName): \PHPUnit\Metadata\CoversTrait + { + return new \PHPUnit\Metadata\CoversTrait(\PHPUnit\Metadata\Level::CLASS_LEVEL, $traitName); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function coversMethod(string $className, string $methodName): \PHPUnit\Metadata\CoversMethod + { + return new \PHPUnit\Metadata\CoversMethod(\PHPUnit\Metadata\Level::CLASS_LEVEL, $className, $methodName); + } + /** + * @param non-empty-string $functionName + */ + public static function coversFunction(string $functionName): \PHPUnit\Metadata\CoversFunction + { + return new \PHPUnit\Metadata\CoversFunction(\PHPUnit\Metadata\Level::CLASS_LEVEL, $functionName); + } + public static function coversNothingOnClass(): \PHPUnit\Metadata\CoversNothing + { + return new \PHPUnit\Metadata\CoversNothing(\PHPUnit\Metadata\Level::CLASS_LEVEL); + } + public static function coversNothingOnMethod(): \PHPUnit\Metadata\CoversNothing + { + return new \PHPUnit\Metadata\CoversNothing(\PHPUnit\Metadata\Level::METHOD_LEVEL); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function dataProvider(string $className, string $methodName, bool $validateArgumentCount): \PHPUnit\Metadata\DataProvider + { + return new \PHPUnit\Metadata\DataProvider(\PHPUnit\Metadata\Level::METHOD_LEVEL, $className, $methodName, $validateArgumentCount); + } + public static function dataProviderClosure(Closure $callable, bool $validateArgumentCount): \PHPUnit\Metadata\DataProviderClosure + { + return new \PHPUnit\Metadata\DataProviderClosure(\PHPUnit\Metadata\Level::METHOD_LEVEL, $callable, $validateArgumentCount); + } + /** + * @param class-string $className + */ + public static function dependsOnClass(string $className, bool $deepClone, bool $shallowClone): \PHPUnit\Metadata\DependsOnClass + { + return new \PHPUnit\Metadata\DependsOnClass(\PHPUnit\Metadata\Level::METHOD_LEVEL, $className, $deepClone, $shallowClone); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function dependsOnMethod(string $className, string $methodName, bool $deepClone, bool $shallowClone): \PHPUnit\Metadata\DependsOnMethod + { + return new \PHPUnit\Metadata\DependsOnMethod(\PHPUnit\Metadata\Level::METHOD_LEVEL, $className, $methodName, $deepClone, $shallowClone); + } + public static function disableReturnValueGenerationForTestDoubles(): \PHPUnit\Metadata\DisableReturnValueGenerationForTestDoubles + { + return new \PHPUnit\Metadata\DisableReturnValueGenerationForTestDoubles(\PHPUnit\Metadata\Level::CLASS_LEVEL); + } + public static function doesNotPerformAssertionsOnClass(): \PHPUnit\Metadata\DoesNotPerformAssertions + { + return new \PHPUnit\Metadata\DoesNotPerformAssertions(\PHPUnit\Metadata\Level::CLASS_LEVEL); + } + public static function doesNotPerformAssertionsOnMethod(): \PHPUnit\Metadata\DoesNotPerformAssertions + { + return new \PHPUnit\Metadata\DoesNotPerformAssertions(\PHPUnit\Metadata\Level::METHOD_LEVEL); + } + /** + * @param non-empty-string $globalVariableName + */ + public static function excludeGlobalVariableFromBackupOnClass(string $globalVariableName): \PHPUnit\Metadata\ExcludeGlobalVariableFromBackup + { + return new \PHPUnit\Metadata\ExcludeGlobalVariableFromBackup(\PHPUnit\Metadata\Level::CLASS_LEVEL, $globalVariableName); + } + /** + * @param non-empty-string $globalVariableName + */ + public static function excludeGlobalVariableFromBackupOnMethod(string $globalVariableName): \PHPUnit\Metadata\ExcludeGlobalVariableFromBackup + { + return new \PHPUnit\Metadata\ExcludeGlobalVariableFromBackup(\PHPUnit\Metadata\Level::METHOD_LEVEL, $globalVariableName); + } + /** + * @param class-string $className + * @param non-empty-string $propertyName + */ + public static function excludeStaticPropertyFromBackupOnClass(string $className, string $propertyName): \PHPUnit\Metadata\ExcludeStaticPropertyFromBackup + { + return new \PHPUnit\Metadata\ExcludeStaticPropertyFromBackup(\PHPUnit\Metadata\Level::CLASS_LEVEL, $className, $propertyName); + } + /** + * @param class-string $className + * @param non-empty-string $propertyName + */ + public static function excludeStaticPropertyFromBackupOnMethod(string $className, string $propertyName): \PHPUnit\Metadata\ExcludeStaticPropertyFromBackup + { + return new \PHPUnit\Metadata\ExcludeStaticPropertyFromBackup(\PHPUnit\Metadata\Level::METHOD_LEVEL, $className, $propertyName); + } + /** + * @param non-empty-string $groupName + */ + public static function groupOnClass(string $groupName): \PHPUnit\Metadata\Group + { + return new \PHPUnit\Metadata\Group(\PHPUnit\Metadata\Level::CLASS_LEVEL, $groupName); + } + /** + * @param non-empty-string $groupName + */ + public static function groupOnMethod(string $groupName): \PHPUnit\Metadata\Group + { + return new \PHPUnit\Metadata\Group(\PHPUnit\Metadata\Level::METHOD_LEVEL, $groupName); + } + /** + * @param null|non-empty-string $messagePattern + */ + public static function ignoreDeprecationsOnClass(?string $messagePattern = null): \PHPUnit\Metadata\IgnoreDeprecations + { + return new \PHPUnit\Metadata\IgnoreDeprecations(\PHPUnit\Metadata\Level::CLASS_LEVEL, $messagePattern); + } + /** + * @param null|non-empty-string $messagePattern + */ + public static function ignoreDeprecationsOnMethod(?string $messagePattern = null): \PHPUnit\Metadata\IgnoreDeprecations + { + return new \PHPUnit\Metadata\IgnoreDeprecations(\PHPUnit\Metadata\Level::METHOD_LEVEL, $messagePattern); + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public static function ignorePhpunitDeprecationsOnClass(): \PHPUnit\Metadata\IgnorePhpunitDeprecations + { + return new \PHPUnit\Metadata\IgnorePhpunitDeprecations(\PHPUnit\Metadata\Level::CLASS_LEVEL); + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public static function ignorePhpunitDeprecationsOnMethod(): \PHPUnit\Metadata\IgnorePhpunitDeprecations + { + return new \PHPUnit\Metadata\IgnorePhpunitDeprecations(\PHPUnit\Metadata\Level::METHOD_LEVEL); + } + public static function postCondition(int $priority): \PHPUnit\Metadata\PostCondition + { + return new \PHPUnit\Metadata\PostCondition(\PHPUnit\Metadata\Level::METHOD_LEVEL, $priority); + } + public static function preCondition(int $priority): \PHPUnit\Metadata\PreCondition + { + return new \PHPUnit\Metadata\PreCondition(\PHPUnit\Metadata\Level::METHOD_LEVEL, $priority); + } + public static function preserveGlobalStateOnClass(bool $enabled): \PHPUnit\Metadata\PreserveGlobalState + { + return new \PHPUnit\Metadata\PreserveGlobalState(\PHPUnit\Metadata\Level::CLASS_LEVEL, $enabled); + } + public static function preserveGlobalStateOnMethod(bool $enabled): \PHPUnit\Metadata\PreserveGlobalState + { + return new \PHPUnit\Metadata\PreserveGlobalState(\PHPUnit\Metadata\Level::METHOD_LEVEL, $enabled); + } + /** + * @param non-empty-string $functionName + */ + public static function requiresFunctionOnClass(string $functionName): \PHPUnit\Metadata\RequiresFunction + { + return new \PHPUnit\Metadata\RequiresFunction(\PHPUnit\Metadata\Level::CLASS_LEVEL, $functionName); + } + /** + * @param non-empty-string $functionName + */ + public static function requiresFunctionOnMethod(string $functionName): \PHPUnit\Metadata\RequiresFunction + { + return new \PHPUnit\Metadata\RequiresFunction(\PHPUnit\Metadata\Level::METHOD_LEVEL, $functionName); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function requiresMethodOnClass(string $className, string $methodName): \PHPUnit\Metadata\RequiresMethod + { + return new \PHPUnit\Metadata\RequiresMethod(\PHPUnit\Metadata\Level::CLASS_LEVEL, $className, $methodName); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function requiresMethodOnMethod(string $className, string $methodName): \PHPUnit\Metadata\RequiresMethod + { + return new \PHPUnit\Metadata\RequiresMethod(\PHPUnit\Metadata\Level::METHOD_LEVEL, $className, $methodName); + } + /** + * @param non-empty-string $operatingSystem + */ + public static function requiresOperatingSystemOnClass(string $operatingSystem): \PHPUnit\Metadata\RequiresOperatingSystem + { + return new \PHPUnit\Metadata\RequiresOperatingSystem(\PHPUnit\Metadata\Level::CLASS_LEVEL, $operatingSystem); + } + /** + * @param non-empty-string $operatingSystem + */ + public static function requiresOperatingSystemOnMethod(string $operatingSystem): \PHPUnit\Metadata\RequiresOperatingSystem + { + return new \PHPUnit\Metadata\RequiresOperatingSystem(\PHPUnit\Metadata\Level::METHOD_LEVEL, $operatingSystem); + } + /** + * @param non-empty-string $operatingSystemFamily + */ + public static function requiresOperatingSystemFamilyOnClass(string $operatingSystemFamily): \PHPUnit\Metadata\RequiresOperatingSystemFamily + { + return new \PHPUnit\Metadata\RequiresOperatingSystemFamily(\PHPUnit\Metadata\Level::CLASS_LEVEL, $operatingSystemFamily); + } + /** + * @param non-empty-string $operatingSystemFamily + */ + public static function requiresOperatingSystemFamilyOnMethod(string $operatingSystemFamily): \PHPUnit\Metadata\RequiresOperatingSystemFamily + { + return new \PHPUnit\Metadata\RequiresOperatingSystemFamily(\PHPUnit\Metadata\Level::METHOD_LEVEL, $operatingSystemFamily); + } + public static function requiresPhpOnClass(Requirement $versionRequirement): \PHPUnit\Metadata\RequiresPhp + { + return new \PHPUnit\Metadata\RequiresPhp(\PHPUnit\Metadata\Level::CLASS_LEVEL, $versionRequirement); + } + public static function requiresPhpOnMethod(Requirement $versionRequirement): \PHPUnit\Metadata\RequiresPhp + { + return new \PHPUnit\Metadata\RequiresPhp(\PHPUnit\Metadata\Level::METHOD_LEVEL, $versionRequirement); + } + /** + * @param non-empty-string $extension + */ + public static function requiresPhpExtensionOnClass(string $extension, ?Requirement $versionRequirement): \PHPUnit\Metadata\RequiresPhpExtension + { + return new \PHPUnit\Metadata\RequiresPhpExtension(\PHPUnit\Metadata\Level::CLASS_LEVEL, $extension, $versionRequirement); + } + /** + * @param non-empty-string $extension + */ + public static function requiresPhpExtensionOnMethod(string $extension, ?Requirement $versionRequirement): \PHPUnit\Metadata\RequiresPhpExtension + { + return new \PHPUnit\Metadata\RequiresPhpExtension(\PHPUnit\Metadata\Level::METHOD_LEVEL, $extension, $versionRequirement); + } + public static function requiresPhpunitOnClass(Requirement $versionRequirement): \PHPUnit\Metadata\RequiresPhpunit + { + return new \PHPUnit\Metadata\RequiresPhpunit(\PHPUnit\Metadata\Level::CLASS_LEVEL, $versionRequirement); + } + public static function requiresPhpunitOnMethod(Requirement $versionRequirement): \PHPUnit\Metadata\RequiresPhpunit + { + return new \PHPUnit\Metadata\RequiresPhpunit(\PHPUnit\Metadata\Level::METHOD_LEVEL, $versionRequirement); + } + /** + * @param class-string $extensionClass + */ + public static function requiresPhpunitExtensionOnClass(string $extensionClass): \PHPUnit\Metadata\RequiresPhpunitExtension + { + return new \PHPUnit\Metadata\RequiresPhpunitExtension(\PHPUnit\Metadata\Level::CLASS_LEVEL, $extensionClass); + } + /** + * @param class-string $extensionClass + */ + public static function requiresPhpunitExtensionOnMethod(string $extensionClass): \PHPUnit\Metadata\RequiresPhpunitExtension + { + return new \PHPUnit\Metadata\RequiresPhpunitExtension(\PHPUnit\Metadata\Level::METHOD_LEVEL, $extensionClass); + } + public static function requiresEnvironmentVariableOnClass(string $environmentVariableName, null|string $value): \PHPUnit\Metadata\RequiresEnvironmentVariable + { + return new \PHPUnit\Metadata\RequiresEnvironmentVariable(\PHPUnit\Metadata\Level::CLASS_LEVEL, $environmentVariableName, $value); + } + public static function requiresEnvironmentVariableOnMethod(string $environmentVariableName, null|string $value): \PHPUnit\Metadata\RequiresEnvironmentVariable + { + return new \PHPUnit\Metadata\RequiresEnvironmentVariable(\PHPUnit\Metadata\Level::METHOD_LEVEL, $environmentVariableName, $value); + } + public static function withEnvironmentVariableOnClass(string $environmentVariableName, null|string $value): \PHPUnit\Metadata\WithEnvironmentVariable + { + return new \PHPUnit\Metadata\WithEnvironmentVariable(\PHPUnit\Metadata\Level::CLASS_LEVEL, $environmentVariableName, $value); + } + public static function withEnvironmentVariableOnMethod(string $environmentVariableName, null|string $value): \PHPUnit\Metadata\WithEnvironmentVariable + { + return new \PHPUnit\Metadata\WithEnvironmentVariable(\PHPUnit\Metadata\Level::METHOD_LEVEL, $environmentVariableName, $value); + } + /** + * @param non-empty-string $setting + * @param non-empty-string $value + */ + public static function requiresSettingOnClass(string $setting, string $value): \PHPUnit\Metadata\RequiresSetting + { + return new \PHPUnit\Metadata\RequiresSetting(\PHPUnit\Metadata\Level::CLASS_LEVEL, $setting, $value); + } + /** + * @param non-empty-string $setting + * @param non-empty-string $value + */ + public static function requiresSettingOnMethod(string $setting, string $value): \PHPUnit\Metadata\RequiresSetting + { + return new \PHPUnit\Metadata\RequiresSetting(\PHPUnit\Metadata\Level::METHOD_LEVEL, $setting, $value); + } + public static function runTestsInSeparateProcesses(): \PHPUnit\Metadata\RunTestsInSeparateProcesses + { + return new \PHPUnit\Metadata\RunTestsInSeparateProcesses(\PHPUnit\Metadata\Level::CLASS_LEVEL); + } + public static function runInSeparateProcess(): \PHPUnit\Metadata\RunInSeparateProcess + { + return new \PHPUnit\Metadata\RunInSeparateProcess(\PHPUnit\Metadata\Level::METHOD_LEVEL); + } + public static function test(): \PHPUnit\Metadata\Test + { + return new \PHPUnit\Metadata\Test(\PHPUnit\Metadata\Level::METHOD_LEVEL); + } + /** + * @param non-empty-string $text + */ + public static function testDoxOnClass(string $text): \PHPUnit\Metadata\TestDox + { + return new \PHPUnit\Metadata\TestDox(\PHPUnit\Metadata\Level::CLASS_LEVEL, $text); + } + /** + * @param non-empty-string $text + */ + public static function testDoxOnMethod(string $text): \PHPUnit\Metadata\TestDox + { + return new \PHPUnit\Metadata\TestDox(\PHPUnit\Metadata\Level::METHOD_LEVEL, $text); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function testDoxFormatter(string $className, string $methodName): \PHPUnit\Metadata\TestDoxFormatter + { + return new \PHPUnit\Metadata\TestDoxFormatter(\PHPUnit\Metadata\Level::METHOD_LEVEL, $className, $methodName); + } + /** + * @param ?non-empty-string $name + */ + public static function testWith(mixed $data, ?string $name = null): \PHPUnit\Metadata\TestWith + { + return new \PHPUnit\Metadata\TestWith(\PHPUnit\Metadata\Level::METHOD_LEVEL, $data, $name); + } + /** + * @param non-empty-string $namespace + */ + public static function usesNamespace(string $namespace): \PHPUnit\Metadata\UsesNamespace + { + return new \PHPUnit\Metadata\UsesNamespace(\PHPUnit\Metadata\Level::CLASS_LEVEL, $namespace); + } + /** + * @param class-string $className + */ + public static function usesClass(string $className): \PHPUnit\Metadata\UsesClass + { + return new \PHPUnit\Metadata\UsesClass(\PHPUnit\Metadata\Level::CLASS_LEVEL, $className); + } + /** + * @param class-string $className + */ + public static function usesClassesThatExtendClass(string $className): \PHPUnit\Metadata\UsesClassesThatExtendClass + { + return new \PHPUnit\Metadata\UsesClassesThatExtendClass(\PHPUnit\Metadata\Level::CLASS_LEVEL, $className); + } + /** + * @param class-string $interfaceName + */ + public static function usesClassesThatImplementInterface(string $interfaceName): \PHPUnit\Metadata\UsesClassesThatImplementInterface + { + return new \PHPUnit\Metadata\UsesClassesThatImplementInterface(\PHPUnit\Metadata\Level::CLASS_LEVEL, $interfaceName); + } + /** + * @param trait-string $traitName + */ + public static function usesTrait(string $traitName): \PHPUnit\Metadata\UsesTrait + { + return new \PHPUnit\Metadata\UsesTrait(\PHPUnit\Metadata\Level::CLASS_LEVEL, $traitName); + } + /** + * @param non-empty-string $functionName + */ + public static function usesFunction(string $functionName): \PHPUnit\Metadata\UsesFunction + { + return new \PHPUnit\Metadata\UsesFunction(\PHPUnit\Metadata\Level::CLASS_LEVEL, $functionName); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function usesMethod(string $className, string $methodName): \PHPUnit\Metadata\UsesMethod + { + return new \PHPUnit\Metadata\UsesMethod(\PHPUnit\Metadata\Level::CLASS_LEVEL, $className, $methodName); + } + public static function withoutErrorHandler(): \PHPUnit\Metadata\WithoutErrorHandler + { + return new \PHPUnit\Metadata\WithoutErrorHandler(\PHPUnit\Metadata\Level::METHOD_LEVEL); + } + /** + * @param null|non-empty-string $messagePattern + */ + public static function ignorePhpunitWarnings(?string $messagePattern): \PHPUnit\Metadata\IgnorePhpunitWarnings + { + return new \PHPUnit\Metadata\IgnorePhpunitWarnings(\PHPUnit\Metadata\Level::METHOD_LEVEL, $messagePattern); + } + protected function __construct(\PHPUnit\Metadata\Level $level) + { + $this->level = $level; + } + public function isClassLevel(): bool + { + return $this->level === \PHPUnit\Metadata\Level::CLASS_LEVEL; + } + public function isMethodLevel(): bool + { + return $this->level === \PHPUnit\Metadata\Level::METHOD_LEVEL; + } + /** + * @phpstan-assert-if-true After $this + */ + public function isAfter(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true AfterClass $this + */ + public function isAfterClass(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true AllowMockObjectsWithoutExpectations $this + */ + public function isAllowMockObjectsWithoutExpectations(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true BackupGlobals $this + */ + public function isBackupGlobals(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true BackupStaticProperties $this + */ + public function isBackupStaticProperties(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true BeforeClass $this + */ + public function isBeforeClass(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Before $this + */ + public function isBefore(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true CoversNamespace $this + */ + public function isCoversNamespace(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true CoversClass $this + */ + public function isCoversClass(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true CoversClassesThatExtendClass $this + */ + public function isCoversClassesThatExtendClass(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true CoversClassesThatImplementInterface $this + */ + public function isCoversClassesThatImplementInterface(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true CoversTrait $this + */ + public function isCoversTrait(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true CoversFunction $this + */ + public function isCoversFunction(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true CoversMethod $this + */ + public function isCoversMethod(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true CoversNothing $this + */ + public function isCoversNothing(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true DataProvider $this + */ + public function isDataProvider(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true DataProviderClosure $this + */ + public function isDataProviderClosure(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true DependsOnClass $this + */ + public function isDependsOnClass(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true DependsOnMethod $this + */ + public function isDependsOnMethod(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true DisableReturnValueGenerationForTestDoubles $this + */ + public function isDisableReturnValueGenerationForTestDoubles(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true DoesNotPerformAssertions $this + */ + public function isDoesNotPerformAssertions(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true ExcludeGlobalVariableFromBackup $this + */ + public function isExcludeGlobalVariableFromBackup(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true ExcludeStaticPropertyFromBackup $this + */ + public function isExcludeStaticPropertyFromBackup(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Group $this + */ + public function isGroup(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true IgnoreDeprecations $this + */ + public function isIgnoreDeprecations(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true IgnorePhpunitDeprecations $this + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function isIgnorePhpunitDeprecations(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RunInSeparateProcess $this + */ + public function isRunInSeparateProcess(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RunTestsInSeparateProcesses $this + */ + public function isRunTestsInSeparateProcesses(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true Test $this + */ + public function isTest(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true PreCondition $this + */ + public function isPreCondition(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true PostCondition $this + */ + public function isPostCondition(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true PreserveGlobalState $this + */ + public function isPreserveGlobalState(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RequiresMethod $this + */ + public function isRequiresMethod(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RequiresFunction $this + */ + public function isRequiresFunction(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RequiresOperatingSystem $this + */ + public function isRequiresOperatingSystem(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RequiresOperatingSystemFamily $this + */ + public function isRequiresOperatingSystemFamily(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RequiresPhp $this + */ + public function isRequiresPhp(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RequiresPhpExtension $this + */ + public function isRequiresPhpExtension(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RequiresPhpunit $this + */ + public function isRequiresPhpunit(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RequiresPhpunitExtension $this + */ + public function isRequiresPhpunitExtension(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RequiresEnvironmentVariable $this + */ + public function isRequiresEnvironmentVariable(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true WithEnvironmentVariable $this + */ + public function isWithEnvironmentVariable(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true RequiresSetting $this + */ + public function isRequiresSetting(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true TestDox $this + */ + public function isTestDox(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true TestDoxFormatter $this + */ + public function isTestDoxFormatter(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true TestWith $this + */ + public function isTestWith(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true UsesNamespace $this + */ + public function isUsesNamespace(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true UsesClass $this + */ + public function isUsesClass(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true UsesClassesThatExtendClass $this + */ + public function isUsesClassesThatExtendClass(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true UsesClassesThatImplementInterface $this + */ + public function isUsesClassesThatImplementInterface(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true UsesTrait $this + */ + public function isUsesTrait(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true UsesFunction $this + */ + public function isUsesFunction(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true UsesMethod $this + */ + public function isUsesMethod(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true WithoutErrorHandler $this + */ + public function isWithoutErrorHandler(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true IgnorePhpunitWarnings $this + */ + public function isIgnorePhpunitWarnings(): bool + { + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use function array_filter; +use function array_merge; +use function count; +use Countable; +use IteratorAggregate; +/** + * @template-implements IteratorAggregate + * + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MetadataCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $metadata; + /** + * @param list $metadata + */ + public static function fromArray(array $metadata): self + { + return new self(...$metadata); + } + private function __construct(\PHPUnit\Metadata\Metadata ...$metadata) + { + $this->metadata = $metadata; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->metadata; + } + public function count(): int + { + return count($this->metadata); + } + /** + * @phpstan-assert-if-true 0 $this->count() + * @phpstan-assert-if-true array{} $this->asArray() + */ + public function isEmpty(): bool + { + return $this->count() === 0; + } + /** + * @phpstan-assert-if-true positive-int $this->count() + * @phpstan-assert-if-true non-empty-list $this->asArray() + */ + public function isNotEmpty(): bool + { + return $this->count() > 0; + } + public function getIterator(): \PHPUnit\Metadata\MetadataCollectionIterator + { + return new \PHPUnit\Metadata\MetadataCollectionIterator($this); + } + public function mergeWith(self $other): self + { + return new self(...array_merge($this->asArray(), $other->asArray())); + } + public function isClassLevel(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isClassLevel())); + } + public function isMethodLevel(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isMethodLevel())); + } + public function isAfter(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isAfter())); + } + public function isAfterClass(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isAfterClass())); + } + public function isAllowMockObjectsWithoutExpectations(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isAllowMockObjectsWithoutExpectations())); + } + public function isBackupGlobals(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isBackupGlobals())); + } + public function isBackupStaticProperties(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isBackupStaticProperties())); + } + public function isBeforeClass(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isBeforeClass())); + } + public function isBefore(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isBefore())); + } + public function isCoversNamespace(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isCoversNamespace())); + } + public function isCoversClass(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isCoversClass())); + } + public function isCoversClassesThatExtendClass(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isCoversClassesThatExtendClass())); + } + public function isCoversClassesThatImplementInterface(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isCoversClassesThatImplementInterface())); + } + public function isCoversTrait(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isCoversTrait())); + } + public function isCoversFunction(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isCoversFunction())); + } + public function isCoversMethod(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isCoversMethod())); + } + public function isExcludeGlobalVariableFromBackup(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isExcludeGlobalVariableFromBackup())); + } + public function isExcludeStaticPropertyFromBackup(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isExcludeStaticPropertyFromBackup())); + } + public function isCoversNothing(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isCoversNothing())); + } + public function isDataProvider(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isDataProvider())); + } + public function isDataProviderClosure(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isDataProviderClosure())); + } + public function isDepends(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isDependsOnClass() || $metadata->isDependsOnMethod())); + } + public function isDependsOnClass(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isDependsOnClass())); + } + public function isDependsOnMethod(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isDependsOnMethod())); + } + public function isDisableReturnValueGenerationForTestDoubles(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isDisableReturnValueGenerationForTestDoubles())); + } + public function isDoesNotPerformAssertions(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isDoesNotPerformAssertions())); + } + public function isGroup(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isGroup())); + } + public function isIgnoreDeprecations(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isIgnoreDeprecations())); + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function isIgnorePhpunitDeprecations(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isIgnorePhpunitDeprecations())); + } + public function isIgnorePhpunitWarnings(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isIgnorePhpunitWarnings())); + } + public function isRunInSeparateProcess(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRunInSeparateProcess())); + } + public function isRunTestsInSeparateProcesses(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRunTestsInSeparateProcesses())); + } + public function isTest(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isTest())); + } + public function isPreCondition(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isPreCondition())); + } + public function isPostCondition(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isPostCondition())); + } + public function isPreserveGlobalState(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isPreserveGlobalState())); + } + public function isRequiresMethod(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRequiresMethod())); + } + public function isRequiresFunction(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRequiresFunction())); + } + public function isRequiresOperatingSystem(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRequiresOperatingSystem())); + } + public function isRequiresOperatingSystemFamily(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRequiresOperatingSystemFamily())); + } + public function isRequiresPhp(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRequiresPhp())); + } + public function isRequiresPhpExtension(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRequiresPhpExtension())); + } + public function isRequiresPhpunit(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRequiresPhpunit())); + } + public function isRequiresPhpunitExtension(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRequiresPhpunitExtension())); + } + public function isRequiresEnvironmentVariable(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRequiresEnvironmentVariable())); + } + public function isWithEnvironmentVariable(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isWithEnvironmentVariable())); + } + public function isRequiresSetting(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isRequiresSetting())); + } + public function isTestDox(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isTestDox())); + } + public function isTestDoxFormatter(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isTestDoxFormatter())); + } + public function isTestWith(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isTestWith())); + } + public function isUsesNamespace(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isUsesNamespace())); + } + public function isUsesClass(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isUsesClass())); + } + public function isUsesClassesThatExtendClass(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isUsesClassesThatExtendClass())); + } + public function isUsesClassesThatImplementInterface(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isUsesClassesThatImplementInterface())); + } + public function isUsesTrait(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isUsesTrait())); + } + public function isUsesFunction(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isUsesFunction())); + } + public function isUsesMethod(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isUsesMethod())); + } + public function isWithoutErrorHandler(): self + { + return new self(...array_filter($this->metadata, static fn(\PHPUnit\Metadata\Metadata $metadata): bool => $metadata->isWithoutErrorHandler())); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use Iterator; +/** + * @template-implements Iterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class MetadataCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $metadata; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\Metadata\MetadataCollection $metadata) + { + $this->metadata = $metadata->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->metadata[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\Metadata\Metadata + { + return $this->metadata[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Parser; + +use const JSON_THROW_ON_ERROR; +use function assert; +use function class_exists; +use function is_numeric; +use function json_decode; +use function method_exists; +use function sprintf; +use function str_starts_with; +use function strtolower; +use function trim; +use Error; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\AfterClass; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; +use PHPUnit\Framework\Attributes\BackupGlobals; +use PHPUnit\Framework\Attributes\BackupStaticProperties; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\BeforeClass; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversClassesThatExtendClass; +use PHPUnit\Framework\Attributes\CoversClassesThatImplementInterface; +use PHPUnit\Framework\Attributes\CoversFunction; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\CoversNamespace; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\CoversTrait; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderClosure; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\DependsExternal; +use PHPUnit\Framework\Attributes\DependsExternalUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsExternalUsingShallowClone; +use PHPUnit\Framework\Attributes\DependsOnClass; +use PHPUnit\Framework\Attributes\DependsOnClassUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsOnClassUsingShallowClone; +use PHPUnit\Framework\Attributes\DependsUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsUsingShallowClone; +use PHPUnit\Framework\Attributes\DisableReturnValueGenerationForTestDoubles; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\Attributes\ExcludeGlobalVariableFromBackup; +use PHPUnit\Framework\Attributes\ExcludeStaticPropertyFromBackup; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\Attributes\IgnorePhpunitDeprecations; +use PHPUnit\Framework\Attributes\IgnorePhpunitWarnings; +use PHPUnit\Framework\Attributes\Large; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\PostCondition; +use PHPUnit\Framework\Attributes\PreCondition; +use PHPUnit\Framework\Attributes\PreserveGlobalState; +use PHPUnit\Framework\Attributes\RequiresEnvironmentVariable; +use PHPUnit\Framework\Attributes\RequiresFunction; +use PHPUnit\Framework\Attributes\RequiresMethod; +use PHPUnit\Framework\Attributes\RequiresOperatingSystem; +use PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily; +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\Attributes\RequiresPhpunitExtension; +use PHPUnit\Framework\Attributes\RequiresSetting; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\Attributes\TestDoxFormatter; +use PHPUnit\Framework\Attributes\TestDoxFormatterExternal; +use PHPUnit\Framework\Attributes\TestWith; +use PHPUnit\Framework\Attributes\TestWithJson; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\Attributes\UsesClassesThatExtendClass; +use PHPUnit\Framework\Attributes\UsesClassesThatImplementInterface; +use PHPUnit\Framework\Attributes\UsesFunction; +use PHPUnit\Framework\Attributes\UsesMethod; +use PHPUnit\Framework\Attributes\UsesNamespace; +use PHPUnit\Framework\Attributes\UsesTrait; +use PHPUnit\Framework\Attributes\WithEnvironmentVariable; +use PHPUnit\Framework\Attributes\WithoutErrorHandler; +use PHPUnit\Metadata\InvalidAttributeException; +use PHPUnit\Metadata\Metadata; +use PHPUnit\Metadata\MetadataCollection; +use PHPUnit\Metadata\Version\Requirement; +use ReflectionClass; +use ReflectionMethod; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AttributeParser implements \PHPUnit\Metadata\Parser\Parser +{ + /** + * @param class-string $className + */ + public function forClass(string $className): MetadataCollection + { + assert(class_exists($className)); + $reflector = new ReflectionClass($className); + $result = []; + $small = \false; + $medium = \false; + $large = \false; + foreach ($reflector->getAttributes() as $attribute) { + if (!str_starts_with($attribute->getName(), 'PHPUnit\Framework\Attributes\\')) { + continue; + } + if (!class_exists($attribute->getName())) { + continue; + } + try { + $attributeInstance = $attribute->newInstance(); + } catch (Error $e) { + throw new InvalidAttributeException($attribute->getName(), 'class ' . $className, $reflector->getFileName(), $reflector->getStartLine(), $e->getMessage()); + } + switch ($attribute->getName()) { + case AllowMockObjectsWithoutExpectations::class: + assert($attributeInstance instanceof AllowMockObjectsWithoutExpectations); + $result[] = Metadata::allowMockObjectsWithoutExpectationsOnClass(); + break; + case BackupGlobals::class: + assert($attributeInstance instanceof BackupGlobals); + $result[] = Metadata::backupGlobalsOnClass($attributeInstance->enabled()); + break; + case BackupStaticProperties::class: + assert($attributeInstance instanceof BackupStaticProperties); + $result[] = Metadata::backupStaticPropertiesOnClass($attributeInstance->enabled()); + break; + case CoversNamespace::class: + assert($attributeInstance instanceof CoversNamespace); + $result[] = Metadata::coversNamespace($attributeInstance->namespace()); + break; + case CoversClass::class: + assert($attributeInstance instanceof CoversClass); + $result[] = Metadata::coversClass($attributeInstance->className()); + break; + case CoversClassesThatExtendClass::class: + assert($attributeInstance instanceof CoversClassesThatExtendClass); + $result[] = Metadata::coversClassesThatExtendClass($attributeInstance->className()); + break; + case CoversClassesThatImplementInterface::class: + assert($attributeInstance instanceof CoversClassesThatImplementInterface); + $result[] = Metadata::coversClassesThatImplementInterface($attributeInstance->interfaceName()); + break; + case CoversTrait::class: + assert($attributeInstance instanceof CoversTrait); + $result[] = Metadata::coversTrait($attributeInstance->traitName()); + break; + case CoversFunction::class: + assert($attributeInstance instanceof CoversFunction); + $result[] = Metadata::coversFunction($attributeInstance->functionName()); + break; + case CoversMethod::class: + assert($attributeInstance instanceof CoversMethod); + $result[] = Metadata::coversMethod($attributeInstance->className(), $attributeInstance->methodName()); + break; + case CoversNothing::class: + $result[] = Metadata::coversNothingOnClass(); + break; + case DisableReturnValueGenerationForTestDoubles::class: + $result[] = Metadata::disableReturnValueGenerationForTestDoubles(); + break; + case DoesNotPerformAssertions::class: + $result[] = Metadata::doesNotPerformAssertionsOnClass(); + break; + case ExcludeGlobalVariableFromBackup::class: + assert($attributeInstance instanceof ExcludeGlobalVariableFromBackup); + $result[] = Metadata::excludeGlobalVariableFromBackupOnClass($attributeInstance->globalVariableName()); + break; + case ExcludeStaticPropertyFromBackup::class: + assert($attributeInstance instanceof ExcludeStaticPropertyFromBackup); + $result[] = Metadata::excludeStaticPropertyFromBackupOnClass($attributeInstance->className(), $attributeInstance->propertyName()); + break; + case Group::class: + assert($attributeInstance instanceof Group); + if (!$this->isSizeGroup($attributeInstance->name(), $className)) { + $result[] = Metadata::groupOnClass($attributeInstance->name()); + } + break; + case Small::class: + if (!$medium && !$large) { + $result[] = Metadata::groupOnClass('small'); + $small = \true; + } else { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('#[Small] cannot be combined with #[Medium] or #[Large] for %s', $this->testAsString($className))); + } + break; + case Medium::class: + if (!$small && !$large) { + $result[] = Metadata::groupOnClass('medium'); + $medium = \true; + } else { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('#[Medium] cannot be combined with #[Small] or #[Large] for %s', $this->testAsString($className))); + } + break; + case Large::class: + if (!$small && !$medium) { + $result[] = Metadata::groupOnClass('large'); + $large = \true; + } else { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('#[Large] cannot be combined with #[Small] or #[Medium] for %s', $this->testAsString($className))); + } + break; + case IgnoreDeprecations::class: + assert($attributeInstance instanceof IgnoreDeprecations); + $result[] = Metadata::ignoreDeprecationsOnClass($attributeInstance->messagePattern()); + break; + case IgnorePhpunitDeprecations::class: + assert($attributeInstance instanceof IgnorePhpunitDeprecations); + $result[] = Metadata::ignorePhpunitDeprecationsOnClass(); + break; + case PreserveGlobalState::class: + assert($attributeInstance instanceof PreserveGlobalState); + $result[] = Metadata::preserveGlobalStateOnClass($attributeInstance->enabled()); + break; + case RequiresMethod::class: + assert($attributeInstance instanceof RequiresMethod); + $result[] = Metadata::requiresMethodOnClass($attributeInstance->className(), $attributeInstance->methodName()); + break; + case RequiresFunction::class: + assert($attributeInstance instanceof RequiresFunction); + $result[] = Metadata::requiresFunctionOnClass($attributeInstance->functionName()); + break; + case RequiresOperatingSystem::class: + assert($attributeInstance instanceof RequiresOperatingSystem); + $result[] = Metadata::requiresOperatingSystemOnClass($attributeInstance->regularExpression()); + break; + case RequiresOperatingSystemFamily::class: + assert($attributeInstance instanceof RequiresOperatingSystemFamily); + $result[] = Metadata::requiresOperatingSystemFamilyOnClass($attributeInstance->operatingSystemFamily()); + break; + case RequiresPhp::class: + assert($attributeInstance instanceof RequiresPhp); + $requirement = $this->requirement($attributeInstance->versionRequirement(), $className); + if ($requirement !== null) { + $result[] = Metadata::requiresPhpOnClass($requirement); + } + break; + case RequiresPhpExtension::class: + assert($attributeInstance instanceof RequiresPhpExtension); + $versionConstraint = null; + $versionRequirement = $attributeInstance->versionRequirement(); + if ($versionRequirement !== null) { + $versionConstraint = $this->requirement($versionRequirement, $className); + } + $result[] = Metadata::requiresPhpExtensionOnClass($attributeInstance->extension(), $versionConstraint); + break; + case RequiresPhpunit::class: + assert($attributeInstance instanceof RequiresPhpunit); + $requirement = $this->requirement($attributeInstance->versionRequirement(), $className); + if ($requirement !== null) { + $result[] = Metadata::requiresPhpunitOnClass($requirement); + } + break; + case RequiresPhpunitExtension::class: + assert($attributeInstance instanceof RequiresPhpunitExtension); + $result[] = Metadata::requiresPhpunitExtensionOnClass($attributeInstance->extensionClass()); + break; + case RequiresEnvironmentVariable::class: + assert($attributeInstance instanceof RequiresEnvironmentVariable); + $result[] = Metadata::requiresEnvironmentVariableOnClass($attributeInstance->environmentVariableName(), $attributeInstance->value()); + break; + case WithEnvironmentVariable::class: + assert($attributeInstance instanceof WithEnvironmentVariable); + $result[] = Metadata::withEnvironmentVariableOnClass($attributeInstance->environmentVariableName(), $attributeInstance->value()); + break; + case RequiresSetting::class: + assert($attributeInstance instanceof RequiresSetting); + $result[] = Metadata::requiresSettingOnClass($attributeInstance->setting(), $attributeInstance->value()); + break; + case RunTestsInSeparateProcesses::class: + $result[] = Metadata::runTestsInSeparateProcesses(); + break; + case TestDox::class: + assert($attributeInstance instanceof TestDox); + $result[] = Metadata::testDoxOnClass($attributeInstance->text()); + break; + case Ticket::class: + assert($attributeInstance instanceof Ticket); + $result[] = Metadata::groupOnClass($attributeInstance->text()); + break; + case UsesNamespace::class: + assert($attributeInstance instanceof UsesNamespace); + $result[] = Metadata::usesNamespace($attributeInstance->namespace()); + break; + case UsesClass::class: + assert($attributeInstance instanceof UsesClass); + $result[] = Metadata::usesClass($attributeInstance->className()); + break; + case UsesClassesThatExtendClass::class: + assert($attributeInstance instanceof UsesClassesThatExtendClass); + $result[] = Metadata::usesClassesThatExtendClass($attributeInstance->className()); + break; + case UsesClassesThatImplementInterface::class: + assert($attributeInstance instanceof UsesClassesThatImplementInterface); + $result[] = Metadata::usesClassesThatImplementInterface($attributeInstance->interfaceName()); + break; + case UsesTrait::class: + assert($attributeInstance instanceof UsesTrait); + $result[] = Metadata::usesTrait($attributeInstance->traitName()); + break; + case UsesFunction::class: + assert($attributeInstance instanceof UsesFunction); + $result[] = Metadata::usesFunction($attributeInstance->functionName()); + break; + case UsesMethod::class: + assert($attributeInstance instanceof UsesMethod); + $result[] = Metadata::usesMethod($attributeInstance->className(), $attributeInstance->methodName()); + break; + } + } + return MetadataCollection::fromArray($result); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forMethod(string $className, string $methodName): MetadataCollection + { + assert(class_exists($className)); + assert(method_exists($className, $methodName)); + $reflector = new ReflectionMethod($className, $methodName); + $result = []; + foreach ($reflector->getAttributes() as $attribute) { + if (!str_starts_with($attribute->getName(), 'PHPUnit\Framework\Attributes\\')) { + continue; + } + if (!class_exists($attribute->getName())) { + continue; + } + try { + $attributeInstance = $attribute->newInstance(); + } catch (Error $e) { + throw new InvalidAttributeException($attribute->getName(), 'method ' . $className . '::' . $methodName . '()', $reflector->getFileName(), $reflector->getStartLine(), $e->getMessage()); + } + switch ($attribute->getName()) { + case After::class: + assert($attributeInstance instanceof After); + $result[] = Metadata::after($attributeInstance->priority()); + break; + case AfterClass::class: + assert($attributeInstance instanceof AfterClass); + $result[] = Metadata::afterClass($attributeInstance->priority()); + break; + case AllowMockObjectsWithoutExpectations::class: + assert($attributeInstance instanceof AllowMockObjectsWithoutExpectations); + $result[] = Metadata::allowMockObjectsWithoutExpectationsOnMethod(); + break; + case BackupGlobals::class: + assert($attributeInstance instanceof BackupGlobals); + $result[] = Metadata::backupGlobalsOnMethod($attributeInstance->enabled()); + break; + case BackupStaticProperties::class: + assert($attributeInstance instanceof BackupStaticProperties); + $result[] = Metadata::backupStaticPropertiesOnMethod($attributeInstance->enabled()); + break; + case Before::class: + assert($attributeInstance instanceof Before); + $result[] = Metadata::before($attributeInstance->priority()); + break; + case BeforeClass::class: + assert($attributeInstance instanceof BeforeClass); + $result[] = Metadata::beforeClass($attributeInstance->priority()); + break; + case CoversNothing::class: + $result[] = Metadata::coversNothingOnMethod(); + break; + case DataProvider::class: + assert($attributeInstance instanceof DataProvider); + $result[] = Metadata::dataProvider($className, $attributeInstance->methodName(), $attributeInstance->validateArgumentCount()); + break; + case DataProviderExternal::class: + assert($attributeInstance instanceof DataProviderExternal); + $result[] = Metadata::dataProvider($attributeInstance->className(), $attributeInstance->methodName(), $attributeInstance->validateArgumentCount()); + break; + case DataProviderClosure::class: + assert($attributeInstance instanceof DataProviderClosure); + $result[] = Metadata::dataProviderClosure($attributeInstance->closure(), $attributeInstance->validateArgumentCount()); + break; + case Depends::class: + assert($attributeInstance instanceof Depends); + $result[] = Metadata::dependsOnMethod($className, $attributeInstance->methodName(), \false, \false); + break; + case DependsUsingDeepClone::class: + assert($attributeInstance instanceof DependsUsingDeepClone); + $result[] = Metadata::dependsOnMethod($className, $attributeInstance->methodName(), \true, \false); + break; + case DependsUsingShallowClone::class: + assert($attributeInstance instanceof DependsUsingShallowClone); + $result[] = Metadata::dependsOnMethod($className, $attributeInstance->methodName(), \false, \true); + break; + case DependsExternal::class: + assert($attributeInstance instanceof DependsExternal); + $result[] = Metadata::dependsOnMethod($attributeInstance->className(), $attributeInstance->methodName(), \false, \false); + break; + case DependsExternalUsingDeepClone::class: + assert($attributeInstance instanceof DependsExternalUsingDeepClone); + $result[] = Metadata::dependsOnMethod($attributeInstance->className(), $attributeInstance->methodName(), \true, \false); + break; + case DependsExternalUsingShallowClone::class: + assert($attributeInstance instanceof DependsExternalUsingShallowClone); + $result[] = Metadata::dependsOnMethod($attributeInstance->className(), $attributeInstance->methodName(), \false, \true); + break; + case DependsOnClass::class: + assert($attributeInstance instanceof DependsOnClass); + $result[] = Metadata::dependsOnClass($attributeInstance->className(), \false, \false); + break; + case DependsOnClassUsingDeepClone::class: + assert($attributeInstance instanceof DependsOnClassUsingDeepClone); + $result[] = Metadata::dependsOnClass($attributeInstance->className(), \true, \false); + break; + case DependsOnClassUsingShallowClone::class: + assert($attributeInstance instanceof DependsOnClassUsingShallowClone); + $result[] = Metadata::dependsOnClass($attributeInstance->className(), \false, \true); + break; + case DoesNotPerformAssertions::class: + assert($attributeInstance instanceof DoesNotPerformAssertions); + $result[] = Metadata::doesNotPerformAssertionsOnMethod(); + break; + case ExcludeGlobalVariableFromBackup::class: + assert($attributeInstance instanceof ExcludeGlobalVariableFromBackup); + $result[] = Metadata::excludeGlobalVariableFromBackupOnMethod($attributeInstance->globalVariableName()); + break; + case ExcludeStaticPropertyFromBackup::class: + assert($attributeInstance instanceof ExcludeStaticPropertyFromBackup); + $result[] = Metadata::excludeStaticPropertyFromBackupOnMethod($attributeInstance->className(), $attributeInstance->propertyName()); + break; + case Group::class: + assert($attributeInstance instanceof Group); + if (!$this->isSizeGroup($attributeInstance->name(), $className, $methodName)) { + $result[] = Metadata::groupOnMethod($attributeInstance->name()); + } + break; + case IgnoreDeprecations::class: + assert($attributeInstance instanceof IgnoreDeprecations); + $result[] = Metadata::ignoreDeprecationsOnMethod($attributeInstance->messagePattern()); + break; + case IgnorePhpunitDeprecations::class: + assert($attributeInstance instanceof IgnorePhpunitDeprecations); + $result[] = Metadata::ignorePhpunitDeprecationsOnMethod(); + break; + case PostCondition::class: + assert($attributeInstance instanceof PostCondition); + $result[] = Metadata::postCondition($attributeInstance->priority()); + break; + case PreCondition::class: + assert($attributeInstance instanceof PreCondition); + $result[] = Metadata::preCondition($attributeInstance->priority()); + break; + case PreserveGlobalState::class: + assert($attributeInstance instanceof PreserveGlobalState); + $result[] = Metadata::preserveGlobalStateOnMethod($attributeInstance->enabled()); + break; + case RequiresMethod::class: + assert($attributeInstance instanceof RequiresMethod); + $result[] = Metadata::requiresMethodOnMethod($attributeInstance->className(), $attributeInstance->methodName()); + break; + case RequiresFunction::class: + assert($attributeInstance instanceof RequiresFunction); + $result[] = Metadata::requiresFunctionOnMethod($attributeInstance->functionName()); + break; + case RequiresOperatingSystem::class: + assert($attributeInstance instanceof RequiresOperatingSystem); + $result[] = Metadata::requiresOperatingSystemOnMethod($attributeInstance->regularExpression()); + break; + case RequiresOperatingSystemFamily::class: + assert($attributeInstance instanceof RequiresOperatingSystemFamily); + $result[] = Metadata::requiresOperatingSystemFamilyOnMethod($attributeInstance->operatingSystemFamily()); + break; + case RequiresPhp::class: + assert($attributeInstance instanceof RequiresPhp); + $requirement = $this->requirement($attributeInstance->versionRequirement(), $className, $methodName); + if ($requirement !== null) { + $result[] = Metadata::requiresPhpOnMethod($requirement); + } + break; + case RequiresPhpExtension::class: + assert($attributeInstance instanceof RequiresPhpExtension); + $versionConstraint = null; + $versionRequirement = $attributeInstance->versionRequirement(); + if ($versionRequirement !== null) { + $versionConstraint = $this->requirement($versionRequirement, $className, $methodName); + } + $result[] = Metadata::requiresPhpExtensionOnMethod($attributeInstance->extension(), $versionConstraint); + break; + case RequiresPhpunit::class: + assert($attributeInstance instanceof RequiresPhpunit); + $requirement = $this->requirement($attributeInstance->versionRequirement(), $className, $methodName); + if ($requirement !== null) { + $result[] = Metadata::requiresPhpunitOnMethod($requirement); + } + break; + case RequiresPhpunitExtension::class: + assert($attributeInstance instanceof RequiresPhpunitExtension); + $result[] = Metadata::requiresPhpunitExtensionOnMethod($attributeInstance->extensionClass()); + break; + case RequiresEnvironmentVariable::class: + assert($attributeInstance instanceof RequiresEnvironmentVariable); + $result[] = Metadata::requiresEnvironmentVariableOnMethod($attributeInstance->environmentVariableName(), $attributeInstance->value()); + break; + case WithEnvironmentVariable::class: + assert($attributeInstance instanceof WithEnvironmentVariable); + $result[] = Metadata::withEnvironmentVariableOnMethod($attributeInstance->environmentVariableName(), $attributeInstance->value()); + break; + case RequiresSetting::class: + assert($attributeInstance instanceof RequiresSetting); + $result[] = Metadata::requiresSettingOnMethod($attributeInstance->setting(), $attributeInstance->value()); + break; + case RunInSeparateProcess::class: + $result[] = Metadata::runInSeparateProcess(); + break; + case Test::class: + $result[] = Metadata::test(); + break; + case TestDox::class: + assert($attributeInstance instanceof TestDox); + $result[] = Metadata::testDoxOnMethod($attributeInstance->text()); + break; + case TestDoxFormatter::class: + assert($attributeInstance instanceof TestDoxFormatter); + $result[] = Metadata::testDoxFormatter($className, $attributeInstance->methodName()); + break; + case TestDoxFormatterExternal::class: + assert($attributeInstance instanceof TestDoxFormatterExternal); + $result[] = Metadata::testDoxFormatter($attributeInstance->className(), $attributeInstance->methodName()); + break; + case TestWith::class: + assert($attributeInstance instanceof TestWith); + $result[] = Metadata::testWith($attributeInstance->data(), $attributeInstance->name()); + break; + case TestWithJson::class: + assert($attributeInstance instanceof TestWithJson); + $result[] = Metadata::testWith(json_decode($attributeInstance->json(), \true, 512, JSON_THROW_ON_ERROR), $attributeInstance->name()); + break; + case Ticket::class: + assert($attributeInstance instanceof Ticket); + $result[] = Metadata::groupOnMethod($attributeInstance->text()); + break; + case WithoutErrorHandler::class: + assert($attributeInstance instanceof WithoutErrorHandler); + $result[] = Metadata::withoutErrorHandler(); + break; + case IgnorePhpunitWarnings::class: + assert($attributeInstance instanceof IgnorePhpunitWarnings); + $result[] = Metadata::ignorePhpunitWarnings($attributeInstance->messagePattern()); + break; + } + } + return MetadataCollection::fromArray($result); + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forClassAndMethod(string $className, string $methodName): MetadataCollection + { + return $this->forClass($className)->mergeWith($this->forMethod($className, $methodName)); + } + /** + * @param non-empty-string $groupName + * @param class-string $testClassName + * @param ?non-empty-string $testMethodName + */ + private function isSizeGroup(string $groupName, string $testClassName, ?string $testMethodName = null): bool + { + $_groupName = strtolower(trim($groupName)); + if ($_groupName !== 'small' && $_groupName !== 'medium' && $_groupName !== 'large') { + return \false; + } + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Group name "%s" is not allowed for %s', $_groupName, $this->testAsString($testClassName, $testMethodName))); + return \true; + } + /** + * @param non-empty-string $versionRequirement + * @param class-string $testClassName + * @param ?non-empty-string $testMethodName + */ + private function requirement(string $versionRequirement, string $testClassName, ?string $testMethodName = null): ?Requirement + { + if (is_numeric(trim($versionRequirement))) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Test %s has attribute with version constraint string argument without explicit version comparison operator ("%s"), version constraint is ignored', $this->testAsString($testClassName, $testMethodName), $versionRequirement)); + return null; + } + return Requirement::from($versionRequirement); + } + /** + * @param class-string $testClassName + * @param ?non-empty-string $testMethodName + * + * @return non-empty-string + */ + private function testAsString(string $testClassName, ?string $testMethodName = null): string + { + return sprintf('%s %s%s%s', $testMethodName !== null ? 'method' : 'class', $testClassName, $testMethodName !== null ? '::' : '', $testMethodName !== null ? $testMethodName : ''); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Parser; + +use function assert; +use function class_exists; +use function method_exists; +use PHPUnit\Metadata\MetadataCollection; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CachingParser implements \PHPUnit\Metadata\Parser\Parser +{ + private readonly \PHPUnit\Metadata\Parser\Parser $reader; + /** + * @var array + */ + private array $classCache = []; + /** + * @var array + */ + private array $methodCache = []; + /** + * @var array + */ + private array $classAndMethodCache = []; + public function __construct(\PHPUnit\Metadata\Parser\Parser $reader) + { + $this->reader = $reader; + } + /** + * @param class-string $className + */ + public function forClass(string $className): MetadataCollection + { + assert(class_exists($className)); + if (isset($this->classCache[$className])) { + return $this->classCache[$className]; + } + $this->classCache[$className] = $this->reader->forClass($className); + return $this->classCache[$className]; + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forMethod(string $className, string $methodName): MetadataCollection + { + assert(class_exists($className)); + assert(method_exists($className, $methodName)); + $key = $className . '::' . $methodName; + if (isset($this->methodCache[$key])) { + return $this->methodCache[$key]; + } + $this->methodCache[$key] = $this->reader->forMethod($className, $methodName); + return $this->methodCache[$key]; + } + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forClassAndMethod(string $className, string $methodName): MetadataCollection + { + $key = $className . '::' . $methodName; + if (isset($this->classAndMethodCache[$key])) { + return $this->classAndMethodCache[$key]; + } + $this->classAndMethodCache[$key] = $this->forClass($className)->mergeWith($this->forMethod($className, $methodName)); + return $this->classAndMethodCache[$key]; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Parser; + +use PHPUnit\Metadata\MetadataCollection; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Parser +{ + /** + * @param class-string $className + */ + public function forClass(string $className): MetadataCollection; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forMethod(string $className, string $methodName): MetadataCollection; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forClassAndMethod(string $className, string $methodName): MetadataCollection; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Parser; + +/** + * Attribute information is static within a single PHP process. + * It is therefore okay to use a Singleton registry here. + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Registry +{ + private static ?\PHPUnit\Metadata\Parser\Parser $instance = null; + public static function parser(): \PHPUnit\Metadata\Parser\Parser + { + return self::$instance ?? self::$instance = self::build(); + } + private static function build(): \PHPUnit\Metadata\Parser\Parser + { + return new \PHPUnit\Metadata\Parser\CachingParser(new \PHPUnit\Metadata\Parser\AttributeParser()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PostCondition extends \PHPUnit\Metadata\Metadata +{ + private int $priority; + protected function __construct(\PHPUnit\Metadata\Level $level, int $priority) + { + parent::__construct($level); + $this->priority = $priority; + } + public function isPostCondition(): true + { + return \true; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreCondition extends \PHPUnit\Metadata\Metadata +{ + private int $priority; + protected function __construct(\PHPUnit\Metadata\Level $level, int $priority) + { + parent::__construct($level); + $this->priority = $priority; + } + public function isPreCondition(): true + { + return \true; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreserveGlobalState extends \PHPUnit\Metadata\Metadata +{ + private bool $enabled; + protected function __construct(\PHPUnit\Metadata\Level $level, bool $enabled) + { + parent::__construct($level); + $this->enabled = $enabled; + } + public function isPreserveGlobalState(): true + { + return \true; + } + public function enabled(): bool + { + return $this->enabled; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresEnvironmentVariable extends \PHPUnit\Metadata\Metadata +{ + private string $environmentVariableName; + private null|string $value; + protected function __construct(\PHPUnit\Metadata\Level $level, string $environmentVariableName, null|string $value) + { + parent::__construct($level); + $this->environmentVariableName = $environmentVariableName; + $this->value = $value; + } + public function isRequiresEnvironmentVariable(): true + { + return \true; + } + public function environmentVariableName(): string + { + return $this->environmentVariableName; + } + public function value(): null|string + { + return $this->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresFunction extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $functionName; + /** + * @param non-empty-string $functionName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $functionName) + { + parent::__construct($level); + $this->functionName = $functionName; + } + public function isRequiresFunction(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresMethod extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className, string $methodName) + { + parent::__construct($level); + $this->className = $className; + $this->methodName = $methodName; + } + public function isRequiresMethod(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresOperatingSystem extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $operatingSystem; + /** + * @param non-empty-string $operatingSystem + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $operatingSystem) + { + parent::__construct($level); + $this->operatingSystem = $operatingSystem; + } + public function isRequiresOperatingSystem(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function operatingSystem(): string + { + return $this->operatingSystem; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresOperatingSystemFamily extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $operatingSystemFamily; + /** + * @param non-empty-string $operatingSystemFamily + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $operatingSystemFamily) + { + parent::__construct($level); + $this->operatingSystemFamily = $operatingSystemFamily; + } + public function isRequiresOperatingSystemFamily(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function operatingSystemFamily(): string + { + return $this->operatingSystemFamily; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Metadata\Version\Requirement; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresPhp extends \PHPUnit\Metadata\Metadata +{ + private Requirement $versionRequirement; + protected function __construct(\PHPUnit\Metadata\Level $level, Requirement $versionRequirement) + { + parent::__construct($level); + $this->versionRequirement = $versionRequirement; + } + public function isRequiresPhp(): true + { + return \true; + } + public function versionRequirement(): Requirement + { + return $this->versionRequirement; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Metadata\Version\Requirement; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresPhpExtension extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $extension; + private ?Requirement $versionRequirement; + /** + * @param non-empty-string $extension + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $extension, ?Requirement $versionRequirement) + { + parent::__construct($level); + $this->extension = $extension; + $this->versionRequirement = $versionRequirement; + } + public function isRequiresPhpExtension(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function extension(): string + { + return $this->extension; + } + /** + * @phpstan-assert-if-true !null $this->versionRequirement + */ + public function hasVersionRequirement(): bool + { + return $this->versionRequirement !== null; + } + /** + * @throws NoVersionRequirementException + */ + public function versionRequirement(): Requirement + { + if ($this->versionRequirement === null) { + throw new \PHPUnit\Metadata\NoVersionRequirementException(); + } + return $this->versionRequirement; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Metadata\Version\Requirement; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresPhpunit extends \PHPUnit\Metadata\Metadata +{ + private Requirement $versionRequirement; + protected function __construct(\PHPUnit\Metadata\Level $level, Requirement $versionRequirement) + { + parent::__construct($level); + $this->versionRequirement = $versionRequirement; + } + public function isRequiresPhpunit(): true + { + return \true; + } + public function versionRequirement(): Requirement + { + return $this->versionRequirement; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Runner\Extension\Extension; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresPhpunitExtension extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $extensionClass; + /** + * @param class-string $extensionClass + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $extensionClass) + { + parent::__construct($level); + $this->extensionClass = $extensionClass; + } + public function isRequiresPhpunitExtension(): true + { + return \true; + } + /** + * @return class-string + */ + public function extensionClass(): string + { + return $this->extensionClass; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresSetting extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $setting; + /** + * @var non-empty-string + */ + private string $value; + /** + * @param non-empty-string $setting + * @param non-empty-string $value + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $setting, string $value) + { + parent::__construct($level); + $this->setting = $setting; + $this->value = $value; + } + public function isRequiresSetting(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function setting(): string + { + return $this->setting; + } + /** + * @return non-empty-string + */ + public function value(): string + { + return $this->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RunInSeparateProcess extends \PHPUnit\Metadata\Metadata +{ + public function isRunInSeparateProcess(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RunTestsInSeparateProcesses extends \PHPUnit\Metadata\Metadata +{ + public function isRunTestsInSeparateProcesses(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Test extends \PHPUnit\Metadata\Metadata +{ + public function isTest(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestDox extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $text; + /** + * @param non-empty-string $text + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $text) + { + parent::__construct($level); + $this->text = $text; + } + public function isTestDox(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function text(): string + { + return $this->text; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestDoxFormatter extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className, string $methodName) + { + parent::__construct($level); + $this->className = $className; + $this->methodName = $methodName; + } + public function isTestDoxFormatter(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestWith extends \PHPUnit\Metadata\Metadata +{ + private mixed $data; + /** + * @var ?non-empty-string + */ + private ?string $name; + /** + * @param ?non-empty-string $name + */ + protected function __construct(\PHPUnit\Metadata\Level $level, mixed $data, ?string $name = null) + { + parent::__construct($level); + $this->data = $data; + $this->name = $name; + } + public function isTestWith(): true + { + return \true; + } + public function data(): mixed + { + return $this->data; + } + /** + * @phpstan-assert-if-true !null $this->name + */ + public function hasName(): bool + { + return $this->name !== null; + } + /** + * @return ?non-empty-string + */ + public function name(): ?string + { + return $this->name; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesClass extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className) + { + parent::__construct($level); + $this->className = $className; + } + public function isUsesClass(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesClassesThatExtendClass extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + /** + * @param class-string $className + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className) + { + parent::__construct($level); + $this->className = $className; + } + public function isUsesClassesThatExtendClass(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesClassesThatImplementInterface extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $interfaceName; + /** + * @param class-string $interfaceName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $interfaceName) + { + parent::__construct($level); + $this->interfaceName = $interfaceName; + } + public function isUsesClassesThatImplementInterface(): true + { + return \true; + } + /** + * @return class-string + */ + public function interfaceName(): string + { + return $this->interfaceName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesFunction extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $functionName; + /** + * @param non-empty-string $functionName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $functionName) + { + parent::__construct($level); + $this->functionName = $functionName; + } + public function isUsesFunction(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesMethod extends \PHPUnit\Metadata\Metadata +{ + /** + * @var class-string + */ + private string $className; + /** + * @var non-empty-string + */ + private string $methodName; + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $className, string $methodName) + { + parent::__construct($level); + $this->className = $className; + $this->methodName = $methodName; + } + public function isUsesMethod(): true + { + return \true; + } + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesNamespace extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $namespace; + /** + * @param non-empty-string $namespace + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $namespace) + { + parent::__construct($level); + $this->namespace = $namespace; + } + public function isUsesNamespace(): true + { + return \true; + } + /** + * @return class-string + */ + public function namespace(): string + { + return $this->namespace; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesTrait extends \PHPUnit\Metadata\Metadata +{ + /** + * @var trait-string + */ + private string $traitName; + /** + * @param trait-string $traitName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $traitName) + { + parent::__construct($level); + $this->traitName = $traitName; + } + public function isUsesTrait(): true + { + return \true; + } + /** + * @return trait-string + */ + public function traitName(): string + { + return $this->traitName; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Version; + +use function version_compare; +use PHPUnit\Util\VersionComparisonOperator; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ComparisonRequirement extends \PHPUnit\Metadata\Version\Requirement +{ + private string $version; + private VersionComparisonOperator $operator; + public function __construct(string $version, VersionComparisonOperator $operator) + { + $this->version = $version; + $this->operator = $operator; + } + public function isSatisfiedBy(string $version): bool + { + return version_compare($version, $this->version, $this->operator->asString()); + } + public function asString(): string + { + return $this->operator->asString() . ' ' . $this->version; + } + public function version(): string + { + return $this->version; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Version; + +use function preg_replace; +use PHPUnitPHAR\PharIo\Version\Version; +use PHPUnitPHAR\PharIo\Version\VersionConstraint; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ConstraintRequirement extends \PHPUnit\Metadata\Version\Requirement +{ + private VersionConstraint $constraint; + public function __construct(VersionConstraint $constraint) + { + $this->constraint = $constraint; + } + public function isSatisfiedBy(string $version): bool + { + return $this->constraint->complies(new Version($this->sanitize($version))); + } + public function asString(): string + { + return $this->constraint->asString(); + } + private function sanitize(string $version): string + { + return preg_replace('/^(\d+\.\d+(?:.\d+)?).*$/', '$1', $version); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Version; + +use function preg_match; +use PHPUnitPHAR\PharIo\Version\UnsupportedVersionConstraintException; +use PHPUnitPHAR\PharIo\Version\VersionConstraintParser; +use PHPUnit\Metadata\InvalidVersionRequirementException; +use PHPUnit\Util\InvalidVersionOperatorException; +use PHPUnit\Util\VersionComparisonOperator; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Requirement +{ + private const string VERSION_COMPARISON = "/(?P!=|<|<=|<>|=|==|>|>=)?\\s*(?P[\\d\\.-]+(dev|(RC|alpha|beta)[\\d\\.])?)[ \t]*\r?\$/m"; + /** + * @throws InvalidVersionOperatorException + * @throws InvalidVersionRequirementException + */ + public static function from(string $versionRequirement): self + { + try { + return new \PHPUnit\Metadata\Version\ConstraintRequirement((new VersionConstraintParser())->parse($versionRequirement)); + } catch (UnsupportedVersionConstraintException) { + if (preg_match(self::VERSION_COMPARISON, $versionRequirement, $matches) > 0) { + return new \PHPUnit\Metadata\Version\ComparisonRequirement($matches['version'], new VersionComparisonOperator($matches['operator'] !== '' ? $matches['operator'] : '>=')); + } + } + throw new InvalidVersionRequirementException(); + } + abstract public function isSatisfiedBy(string $version): bool; + abstract public function asString(): string; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class WithEnvironmentVariable extends \PHPUnit\Metadata\Metadata +{ + /** + * @var non-empty-string + */ + private string $environmentVariableName; + private null|string $value; + /** + * @param non-empty-string $environmentVariableName + */ + protected function __construct(\PHPUnit\Metadata\Level $level, string $environmentVariableName, null|string $value) + { + parent::__construct($level); + $this->environmentVariableName = $environmentVariableName; + $this->value = $value; + } + public function isWithEnvironmentVariable(): true + { + return \true; + } + /** + * @return non-empty-string + */ + public function environmentVariableName(): string + { + return $this->environmentVariableName; + } + public function value(): null|string + { + return $this->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class WithoutErrorHandler extends \PHPUnit\Metadata\Metadata +{ + public function isWithoutErrorHandler(): true + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function getenv; +use function putenv; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BackedUpEnvironmentVariable +{ + private const string FROM_GETENV = 'getenv'; + private const string FROM_SUPERGLOBAL = 'superglobal'; + /** + * @var self::FROM_GETENV|self::FROM_SUPERGLOBAL + */ + private string $from; + /** + * @var non-empty-string + */ + private string $name; + private null|string $value; + /** + * @param non-empty-string $name + * + * @return array{0: self, 1: self} + */ + public static function create(string $name): array + { + $getenv = getenv($name); + if ($getenv === \false) { + $getenv = null; + } + return [new self(self::FROM_SUPERGLOBAL, $name, $_ENV[$name] ?? null), new self(self::FROM_GETENV, $name, $getenv)]; + } + /** + * @param self::FROM_GETENV|self::FROM_SUPERGLOBAL $from + * @param non-empty-string $name + */ + private function __construct(string $from, string $name, null|string $value) + { + $this->from = $from; + $this->name = $name; + $this->value = $value; + } + public function restore(): void + { + if ($this->from === self::FROM_GETENV) { + $this->restoreGetEnv(); + } else { + $this->restoreSuperGlobal(); + } + } + private function restoreGetEnv(): void + { + if ($this->value === null) { + putenv($this->name); + } else { + putenv("{$this->name}={$this->value}"); + } + } + private function restoreSuperGlobal(): void + { + if ($this->value === null) { + unset($_ENV[$this->name]); + } else { + $_ENV[$this->name] = $this->value; + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use function ksort; +use function strcmp; +use function usort; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Baseline +{ + public const int VERSION = 1; + /** + * @var array>> + */ + private array $issues = []; + public function add(\PHPUnit\Runner\Baseline\Issue $issue): void + { + if (!isset($this->issues[$issue->file()])) { + $this->issues[$issue->file()] = []; + } + if (!isset($this->issues[$issue->file()][$issue->line()])) { + $this->issues[$issue->file()][$issue->line()] = []; + } + $this->issues[$issue->file()][$issue->line()][] = $issue; + } + public function has(\PHPUnit\Runner\Baseline\Issue $issue): bool + { + if (!isset($this->issues[$issue->file()][$issue->line()])) { + return \false; + } + foreach ($this->issues[$issue->file()][$issue->line()] as $_issue) { + if ($_issue->equals($issue)) { + return \true; + } + } + return \false; + } + /** + * @return array>> + */ + public function groupedByFileAndLine(): array + { + $issues = $this->issues; + ksort($issues); + foreach ($issues as &$lines) { + ksort($lines); + foreach ($lines as &$issuesOnLine) { + usort($issuesOnLine, static fn(\PHPUnit\Runner\Baseline\Issue $a, \PHPUnit\Runner\Baseline\Issue $b): int => strcmp($a->description(), $b->description())); + } + } + return $issues; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Runner\Exception; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CannotLoadBaselineException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Runner\Exception; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CannotWriteBaselineException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use function sprintf; +use PHPUnit\Runner\Exception; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class FileDoesNotHaveLineException extends RuntimeException implements Exception +{ + public function __construct(string $file, int $line) + { + parent::__construct(sprintf('File "%s" does not have line %d', $file, $line)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Runner\FileDoesNotExistException; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\SourceFilter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Generator +{ + private \PHPUnit\Runner\Baseline\Baseline $baseline; + private Source $source; + public function __construct(Facade $facade, Source $source) + { + $facade->registerSubscribers(new \PHPUnit\Runner\Baseline\TestTriggeredDeprecationSubscriber($this), new \PHPUnit\Runner\Baseline\TestTriggeredNoticeSubscriber($this), new \PHPUnit\Runner\Baseline\TestTriggeredPhpDeprecationSubscriber($this), new \PHPUnit\Runner\Baseline\TestTriggeredPhpNoticeSubscriber($this), new \PHPUnit\Runner\Baseline\TestTriggeredPhpWarningSubscriber($this), new \PHPUnit\Runner\Baseline\TestTriggeredWarningSubscriber($this)); + $this->baseline = new \PHPUnit\Runner\Baseline\Baseline(); + $this->source = $source; + } + public function baseline(): \PHPUnit\Runner\Baseline\Baseline + { + return $this->baseline; + } + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function testTriggeredIssue(DeprecationTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event): void + { + if ($event->wasSuppressed() && !$this->isSuppressionIgnored($event)) { + return; + } + if ($this->restrict($event) && !SourceFilter::instance()->includes($event->file())) { + return; + } + $this->baseline->add(\PHPUnit\Runner\Baseline\Issue::from($event->file(), $event->line(), null, $event->message())); + } + private function restrict(DeprecationTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event): bool + { + if ($event instanceof WarningTriggered || $event instanceof PhpWarningTriggered) { + return $this->source->restrictWarnings(); + } + if ($event instanceof NoticeTriggered || $event instanceof PhpNoticeTriggered) { + return $this->source->restrictNotices(); + } + return \false; + } + private function isSuppressionIgnored(DeprecationTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event): bool + { + if ($event instanceof WarningTriggered) { + return $this->source->ignoreSuppressionOfWarnings(); + } + if ($event instanceof PhpWarningTriggered) { + return $this->source->ignoreSuppressionOfPhpWarnings(); + } + if ($event instanceof PhpNoticeTriggered) { + return $this->source->ignoreSuppressionOfPhpNotices(); + } + if ($event instanceof NoticeTriggered) { + return $this->source->ignoreSuppressionOfNotices(); + } + if ($event instanceof PhpDeprecationTriggered) { + return $this->source->ignoreSuppressionOfPhpDeprecations(); + } + return $this->source->ignoreSuppressionOfDeprecations(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use const FILE_IGNORE_NEW_LINES; +use function assert; +use function file; +use function is_file; +use function sha1; +use PHPUnit\Runner\FileDoesNotExistException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Issue +{ + /** + * @var non-empty-string + */ + private string $file; + /** + * @var positive-int + */ + private int $line; + /** + * @var non-empty-string + */ + private string $hash; + /** + * @var non-empty-string + */ + private string $description; + /** + * @param non-empty-string $file + * @param positive-int $line + * @param ?non-empty-string $hash + * @param non-empty-string $description + * + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public static function from(string $file, int $line, ?string $hash, string $description): self + { + if ($hash === null) { + $hash = self::calculateHash($file, $line); + } + return new self($file, $line, $hash, $description); + } + /** + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $hash + * @param non-empty-string $description + */ + private function __construct(string $file, int $line, string $hash, string $description) + { + $this->file = $file; + $this->line = $line; + $this->hash = $hash; + $this->description = $description; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + /** + * @return non-empty-string + */ + public function hash(): string + { + return $this->hash; + } + /** + * @return non-empty-string + */ + public function description(): string + { + return $this->description; + } + public function equals(self $other): bool + { + return $this->file() === $other->file() && $this->line() === $other->line() && $this->hash() === $other->hash() && $this->description() === $other->description(); + } + /** + * @param non-empty-string $file + * @param positive-int $line + * + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + * + * @return non-empty-string + */ + private static function calculateHash(string $file, int $line): string + { + $lines = @file($file, FILE_IGNORE_NEW_LINES); + if ($lines === \false && !is_file($file)) { + throw new FileDoesNotExistException($file); + } + $key = $line - 1; + if (!isset($lines[$key])) { + throw new \PHPUnit\Runner\Baseline\FileDoesNotHaveLineException($file, $line); + } + $hash = sha1($lines[$key]); + assert($hash !== ''); + return $hash; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use const DIRECTORY_SEPARATOR; +use function assert; +use function dirname; +use function is_file; +use function realpath; +use function sprintf; +use function str_replace; +use function trim; +use DOMElement; +use DOMXPath; +use PHPUnit\Util\Xml\Loader as XmlLoader; +use PHPUnit\Util\Xml\XmlException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Reader +{ + /** + * @param non-empty-string $baselineFile + * + * @throws CannotLoadBaselineException + */ + public function read(string $baselineFile): \PHPUnit\Runner\Baseline\Baseline + { + if (!is_file($baselineFile)) { + throw new \PHPUnit\Runner\Baseline\CannotLoadBaselineException(sprintf('Cannot read baseline %s, file does not exist', $baselineFile)); + } + try { + $document = (new XmlLoader())->loadFile($baselineFile); + } catch (XmlException $e) { + throw new \PHPUnit\Runner\Baseline\CannotLoadBaselineException(sprintf('Cannot read baseline %s: %s', $baselineFile, trim($e->getMessage()))); + } + $version = (int) $document->documentElement->getAttribute('version'); + if ($version !== \PHPUnit\Runner\Baseline\Baseline::VERSION) { + throw new \PHPUnit\Runner\Baseline\CannotLoadBaselineException(sprintf('Cannot read baseline %s, version %d is not supported', $baselineFile, $version)); + } + $baseline = new \PHPUnit\Runner\Baseline\Baseline(); + $baselineDirectory = dirname(realpath($baselineFile)); + $xpath = new DOMXPath($document); + foreach ($xpath->query('file') as $fileElement) { + assert($fileElement instanceof DOMElement); + $file = $baselineDirectory . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $fileElement->getAttribute('path')); + foreach ($xpath->query('line', $fileElement) as $lineElement) { + assert($lineElement instanceof DOMElement); + $line = (int) $lineElement->getAttribute('number'); + $hash = $lineElement->getAttribute('hash'); + foreach ($xpath->query('issue', $lineElement) as $issueElement) { + assert($issueElement instanceof DOMElement); + $description = $issueElement->textContent; + assert($line > 0); + assert($hash !== ''); + assert($description !== ''); + $baseline->add(\PHPUnit\Runner\Baseline\Issue::from($file, $line, $hash, $description)); + } + } + } + return $baseline; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use function array_fill; +use function array_merge; +use function array_slice; +use function assert; +use function count; +use function explode; +use function implode; +use function str_replace; +use function strpos; +use function substr; +use function trim; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @see Copied from https://github.com/phpstan/phpstan-src/blob/1.10.33/src/File/ParentDirectoryRelativePathHelper.php + */ +final readonly class RelativePathCalculator +{ + /** + * @var non-empty-string + */ + private string $baselineDirectory; + /** + * @param non-empty-string $baselineDirectory + */ + public function __construct(string $baselineDirectory) + { + $this->baselineDirectory = $baselineDirectory; + } + /** + * @param non-empty-string $filename + * + * @return non-empty-string + */ + public function calculate(string $filename): string + { + $result = implode('/', $this->parts($filename)); + assert($result !== ''); + return $result; + } + /** + * @param non-empty-string $filename + * + * @return list + */ + public function parts(string $filename): array + { + $schemePosition = strpos($filename, '://'); + if ($schemePosition !== \false) { + $filename = substr($filename, $schemePosition + 3); + assert($filename !== ''); + } + $parentParts = explode('/', trim(str_replace('\\', '/', $this->baselineDirectory), '/')); + $parentPartsCount = count($parentParts); + $filenameParts = explode('/', trim(str_replace('\\', '/', $filename), '/')); + $filenamePartsCount = count($filenameParts); + $i = 0; + for (; $i < $filenamePartsCount; $i++) { + if ($parentPartsCount < $i + 1) { + break; + } + $parentPath = implode('/', array_slice($parentParts, 0, $i + 1)); + $filenamePath = implode('/', array_slice($filenameParts, 0, $i + 1)); + if ($parentPath !== $filenamePath) { + break; + } + } + if ($i === 0) { + return [$filename]; + } + $dotsCount = $parentPartsCount - $i; + assert($dotsCount >= 0); + return array_merge(array_fill(0, $dotsCount, '..'), array_slice($filenameParts, $i)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private \PHPUnit\Runner\Baseline\Generator $generator; + public function __construct(\PHPUnit\Runner\Baseline\Generator $generator) + { + $this->generator = $generator; + } + protected function generator(): \PHPUnit\Runner\Baseline\Generator + { + return $this->generator; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredDeprecationSubscriber extends \PHPUnit\Runner\Baseline\Subscriber implements DeprecationTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(DeprecationTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\NoticeTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredNoticeSubscriber extends \PHPUnit\Runner\Baseline\Subscriber implements NoticeTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(NoticeTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpDeprecationSubscriber extends \PHPUnit\Runner\Baseline\Subscriber implements PhpDeprecationTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(PhpDeprecationTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpNoticeSubscriber extends \PHPUnit\Runner\Baseline\Subscriber implements PhpNoticeTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(PhpNoticeTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpWarningSubscriber extends \PHPUnit\Runner\Baseline\Subscriber implements PhpWarningTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(PhpWarningTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\Test\WarningTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredWarningSubscriber extends \PHPUnit\Runner\Baseline\Subscriber implements WarningTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(WarningTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use function dirname; +use function file_put_contents; +use function is_dir; +use function realpath; +use function sprintf; +use XMLWriter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Writer +{ + /** + * @param non-empty-string $baselineFile + * + * @throws CannotWriteBaselineException + */ + public function write(string $baselineFile, \PHPUnit\Runner\Baseline\Baseline $baseline): void + { + $normalizedBaselineFile = realpath(dirname($baselineFile)); + if ($normalizedBaselineFile === \false || !is_dir($normalizedBaselineFile)) { + throw new \PHPUnit\Runner\Baseline\CannotWriteBaselineException(sprintf('Cannot write baseline to "%s".', $baselineFile)); + } + $pathCalculator = new \PHPUnit\Runner\Baseline\RelativePathCalculator($normalizedBaselineFile); + $writer = new XMLWriter(); + $writer->openMemory(); + $writer->setIndent(\true); + $writer->startDocument(); + $writer->startElement('files'); + $writer->writeAttribute('version', (string) \PHPUnit\Runner\Baseline\Baseline::VERSION); + foreach ($baseline->groupedByFileAndLine() as $file => $lines) { + $writer->startElement('file'); + $writer->writeAttribute('path', $pathCalculator->calculate($file)); + foreach ($lines as $line => $issues) { + $writer->startElement('line'); + $writer->writeAttribute('number', (string) $line); + $writer->writeAttribute('hash', $issues[0]->hash()); + foreach ($issues as $issue) { + $writer->startElement('issue'); + $writer->writeCdata($issue->description()); + $writer->endElement(); + } + $writer->endElement(); + } + $writer->endElement(); + } + $writer->endElement(); + file_put_contents($baselineFile, $writer->outputMemory()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function assert; +use function implode; +use function sprintf; +use function sys_get_temp_dir; +use DateTimeImmutable; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\TestCase; +use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Output\Printer; +use PHPUnit\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\Driver; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\Selector; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Exception as CodeCoverageException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Filter; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Facade as ReportFacade; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html\Colors; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html\CustomCssFile; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Thresholds; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Serialization\Serializer; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\CacheWarmer; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\TargetCollection; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\Target\ValidationFailure; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestSize; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestStatus; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Version as CodeCoverageVersion; +use PHPUnitPHAR\SebastianBergmann\Comparator\Comparator; +use PHPUnitPHAR\SebastianBergmann\Environment\Runtime; +use PHPUnitPHAR\SebastianBergmann\Timer\NoActiveTimerException; +use PHPUnitPHAR\SebastianBergmann\Timer\Timer; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ +final class CodeCoverage +{ + private static ?self $instance = null; + private ?\PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage $codeCoverage = null; + /** + * @phpstan-ignore property.internalClass + */ + private ?Driver $driver = null; + private bool $collecting = \false; + private ?TestCase $test = null; + private ?Timer $timer = null; + public static function instance(): self + { + if (self::$instance === null) { + self::$instance = new self(); + } + return self::$instance; + } + public function init(Configuration $configuration, CodeCoverageFilterRegistry $codeCoverageFilterRegistry, bool $extensionRequiresCodeCoverageCollection): \PHPUnit\Runner\CodeCoverageInitializationStatus + { + $codeCoverageFilterRegistry->init($configuration); + if (!$configuration->hasCoverageReport() && !$extensionRequiresCodeCoverageCollection) { + return \PHPUnit\Runner\CodeCoverageInitializationStatus::NOT_REQUESTED; + } + $this->activate($codeCoverageFilterRegistry->get(), $configuration->pathCoverage()); + if (!$this->isActive()) { + return \PHPUnit\Runner\CodeCoverageInitializationStatus::FAILED; + } + if ($configuration->hasCoverageCacheDirectory()) { + $coverageCacheDirectory = $configuration->coverageCacheDirectory(); + } else { + $candidate = sys_get_temp_dir() . '/phpunit-code-coverage-cache'; + if (Filesystem::createDirectory($candidate)) { + $coverageCacheDirectory = $candidate; + } + } + if (isset($coverageCacheDirectory)) { + $this->codeCoverage()->cacheStaticAnalysis($coverageCacheDirectory); + } + $this->codeCoverage()->excludeSubclassesOfThisClassFromUnintentionallyCoveredCodeCheck(Comparator::class); + if ($configuration->strictCoverage()) { + $this->codeCoverage()->enableCheckForUnintentionallyCoveredCode(); + } + if ($configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage()) { + $this->codeCoverage()->ignoreDeprecatedCode(); + } else { + $this->codeCoverage()->doNotIgnoreDeprecatedCode(); + } + if ($configuration->disableCodeCoverageIgnore()) { + $this->codeCoverage()->disableAnnotationsForIgnoringCode(); + } else { + $this->codeCoverage()->enableAnnotationsForIgnoringCode(); + } + if ($configuration->includeUncoveredFiles()) { + $this->codeCoverage()->includeUncoveredFiles(); + } else { + $this->codeCoverage()->excludeUncoveredFiles(); + } + $this->warnIfFilterIsNotConfigured($codeCoverageFilterRegistry, $configuration); + if (isset($coverageCacheDirectory) && $configuration->includeUncoveredFiles()) { + EventFacade::emitter()->testRunnerStartedStaticAnalysisForCodeCoverage(); + /** @phpstan-ignore new.internalClass,method.internalClass */ + $statistics = (new CacheWarmer())->warmCache($coverageCacheDirectory, !$configuration->disableCodeCoverageIgnore(), $configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage(), $codeCoverageFilterRegistry->get()); + EventFacade::emitter()->testRunnerFinishedStaticAnalysisForCodeCoverage($statistics['cacheHits'], $statistics['cacheMisses']); + } + return \PHPUnit\Runner\CodeCoverageInitializationStatus::SUCCEEDED; + } + /** + * @phpstan-assert-if-true !null $this->codeCoverage + */ + public function isActive(): bool + { + return $this->codeCoverage !== null; + } + public function codeCoverage(): \PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage + { + return $this->codeCoverage; + } + /** + * @return non-empty-string + */ + public function driverNameAndVersion(): string + { + return $this->driver->nameAndVersion(); + } + public function start(TestCase $test): void + { + if ($this->collecting) { + return; + } + $size = TestSize::Unknown; + if ($test->size()->isSmall()) { + $size = TestSize::Small; + } elseif ($test->size()->isMedium()) { + $size = TestSize::Medium; + } elseif ($test->size()->isLarge()) { + $size = TestSize::Large; + } + $this->test = $test; + $this->codeCoverage->start($test->valueObjectForEvents()->id(), $size); + $this->collecting = \true; + $this->timer()->start(); + } + public function stop(bool $append, null|false|TargetCollection $covers = null, ?TargetCollection $uses = null): void + { + if (!$this->collecting) { + return; + } + $time = $this->timer()->stop()->asSeconds(); + $status = TestStatus::Unknown; + $this->collecting = \false; + if ($this->test !== null) { + if ($this->test->status()->isSuccess()) { + $status = TestStatus::Success; + } else { + $status = TestStatus::Failure; + } + } + if ($covers instanceof TargetCollection) { + $result = $this->codeCoverage->validate($covers); + if ($result->isFailure()) { + assert($result instanceof ValidationFailure); + EventFacade::emitter()->testTriggeredPhpunitWarning($this->test->valueObjectForEvents(), $result->message()); + $append = \false; + } + } + if ($uses instanceof TargetCollection) { + $result = $this->codeCoverage->validate($uses); + if ($result->isFailure()) { + assert($result instanceof ValidationFailure); + EventFacade::emitter()->testTriggeredPhpunitWarning($this->test->valueObjectForEvents(), $result->message()); + $append = \false; + } + } + $this->codeCoverage->stop($append, $status, $covers, $uses, $time); + $this->test = null; + } + public function deactivate(): void + { + $this->driver = null; + $this->codeCoverage = null; + $this->test = null; + } + public function generateReports(Printer $printer, Configuration $configuration): void + { + if (!$this->isActive()) { + return; + } + if ($configuration->hasCoveragePhp()) { + $this->codeCoverageGenerationStart($printer, 'PHP'); + $serializer = new Serializer(); + $serializer->serialize($configuration->coveragePhp(), $this->codeCoverage(), $configuration->includeGitInformation()); + $this->codeCoverageGenerationSucceeded($printer); + unset($serializer); + } + $facade = ReportFacade::fromObject($this->codeCoverage()); + if ($configuration->hasCoverageClover()) { + $this->codeCoverageGenerationStart($printer, 'Clover XML'); + try { + $facade->renderClover($configuration->coverageClover(), 'Clover Coverage'); + $this->codeCoverageGenerationSucceeded($printer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + if ($configuration->hasCoverageOpenClover()) { + $this->codeCoverageGenerationStart($printer, 'OpenClover XML'); + try { + $facade->renderOpenClover($configuration->coverageOpenClover(), 'OpenClover Coverage'); + $this->codeCoverageGenerationSucceeded($printer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + if ($configuration->hasCoverageCobertura()) { + $this->codeCoverageGenerationStart($printer, 'Cobertura XML'); + try { + $facade->renderCobertura($configuration->coverageCobertura()); + $this->codeCoverageGenerationSucceeded($printer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + if ($configuration->hasCoverageCrap4j()) { + $this->codeCoverageGenerationStart($printer, 'Crap4J XML'); + try { + $facade->renderCrap4j($configuration->coverageCrap4j(), $configuration->coverageCrap4jThreshold()); + $this->codeCoverageGenerationSucceeded($printer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + if ($configuration->hasCoverageHtml()) { + $this->codeCoverageGenerationStart($printer, 'HTML'); + try { + $customCssFile = CustomCssFile::default(); + if ($configuration->hasCoverageHtmlCustomCssFile()) { + $customCssFile = CustomCssFile::from($configuration->coverageHtmlCustomCssFile()); + } + $facade->renderHtml($configuration->coverageHtml(), sprintf(' and PHPUnit %s', \PHPUnit\Runner\Version::id()), Colors::from($configuration->coverageHtmlColorSuccessLow(), $configuration->coverageHtmlColorSuccessLowDark(), $configuration->coverageHtmlColorSuccessMedium(), $configuration->coverageHtmlColorSuccessMediumDark(), $configuration->coverageHtmlColorSuccessHigh(), $configuration->coverageHtmlColorSuccessHighDark(), $configuration->coverageHtmlColorSuccessBar(), $configuration->coverageHtmlColorSuccessBarDark(), $configuration->coverageHtmlColorWarning(), $configuration->coverageHtmlColorWarningDark(), $configuration->coverageHtmlColorWarningBar(), $configuration->coverageHtmlColorWarningBarDark(), $configuration->coverageHtmlColorDanger(), $configuration->coverageHtmlColorDangerDark(), $configuration->coverageHtmlColorDangerBar(), $configuration->coverageHtmlColorDangerBarDark(), $configuration->coverageHtmlColorBreadcrumbs(), $configuration->coverageHtmlColorBreadcrumbsDark()), Thresholds::from($configuration->coverageHtmlLowUpperBound(), $configuration->coverageHtmlHighLowerBound()), $customCssFile); + $this->codeCoverageGenerationSucceeded($printer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + if ($configuration->hasCoverageText()) { + if ($configuration->coverageText() === 'php://stdout') { + if (!$configuration->noOutput() && !$configuration->debug()) { + $printer->print($facade->renderText(null, Thresholds::default(), $configuration->coverageTextShowUncoveredFiles(), $configuration->coverageTextShowOnlySummary(), $configuration->colors())); + } + } else { + $facade->renderText($configuration->coverageText(), Thresholds::default(), $configuration->coverageTextShowUncoveredFiles(), $configuration->coverageTextShowOnlySummary(), $configuration->colors()); + } + } + if ($configuration->hasCoverageXml()) { + $this->codeCoverageGenerationStart($printer, 'PHPUnit XML'); + try { + $driverInformation = $this->codeCoverage->driverInformation(); + $facade->renderXml($configuration->coverageXml(), $configuration->coverageXmlIncludeSource(), new Runtime(), new DateTimeImmutable(), \PHPUnit\Runner\Version::id(), CodeCoverageVersion::id(), $driverInformation['name'], $driverInformation['version']); + $this->codeCoverageGenerationSucceeded($printer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + } + public function warnIfFilterIsNotConfigured(CodeCoverageFilterRegistry $codeCoverageFilterRegistry, Configuration $configuration): void + { + if (!$codeCoverageFilterRegistry->get()->isEmpty()) { + return; + } + if (!$codeCoverageFilterRegistry->configured()) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning('No filter is configured, code coverage will not be processed'); + $this->deactivate(); + return; + } + $paths = []; + foreach ($configuration->source()->includeDirectories() as $directory) { + $paths[] = $directory->path(); + } + foreach ($configuration->source()->includeFiles() as $file) { + $paths[] = $file->path(); + } + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Configured source filter (include-path: %s) does not match any files, code coverage will not be processed', implode(', ', $paths))); + $this->deactivate(); + } + private function activate(Filter $filter, bool $pathCoverage): void + { + try { + if ($pathCoverage) { + $this->driver = (new Selector())->forLineAndPathCoverage($filter); + } else { + $this->driver = (new Selector())->forLineCoverage($filter); + } + $this->codeCoverage = new \PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage($this->driver, $filter); + } catch (CodeCoverageException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning($e->getMessage()); + } + } + private function codeCoverageGenerationStart(Printer $printer, string $format): void + { + $printer->print(sprintf("\nGenerating code coverage report in %s format ... ", $format)); + $this->timer()->start(); + } + /** + * @throws NoActiveTimerException + */ + private function codeCoverageGenerationSucceeded(Printer $printer): void + { + $printer->print(sprintf("done [%s]\n", $this->timer()->stop()->asString())); + } + /** + * @throws NoActiveTimerException + */ + private function codeCoverageGenerationFailed(Printer $printer, CodeCoverageException $e): void + { + $printer->print(sprintf("failed [%s]\n%s\n", $this->timer()->stop()->asString(), $e->getMessage())); + } + private function timer(): Timer + { + if ($this->timer === null) { + $this->timer = new Timer(); + } + return $this->timer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This enumeration is not covered by the backward compatibility promise for PHPUnit + */ +enum CodeCoverageInitializationStatus +{ + case NOT_REQUESTED; + case SUCCEEDED; + case FAILED; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\TestRunner\IssueFilter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Collector +{ + private readonly IssueFilter $issueFilter; + /** + * @var list + */ + private array $deprecations = []; + /** + * @var list + */ + private array $filteredDeprecations = []; + public function __construct(Facade $facade, IssueFilter $issueFilter) + { + $facade->registerSubscribers(new \PHPUnit\Runner\DeprecationCollector\TestPreparedSubscriber($this), new \PHPUnit\Runner\DeprecationCollector\TestTriggeredDeprecationSubscriber($this)); + $this->issueFilter = $issueFilter; + } + /** + * @return list + */ + public function deprecations(): array + { + return $this->deprecations; + } + /** + * @return list + */ + public function filteredDeprecations(): array + { + return $this->filteredDeprecations; + } + public function testPrepared(): void + { + $this->deprecations = []; + } + public function testTriggeredDeprecation(DeprecationTriggered $event): void + { + $this->deprecations[] = $event->message(); + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + $this->filteredDeprecations[] = $event->message(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +use PHPUnit\Event\EventFacadeIsSealedException; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Event\UnknownSubscriberTypeException; +use PHPUnit\TestRunner\IssueFilter; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Facade +{ + private static null|\PHPUnit\Runner\DeprecationCollector\Collector|\PHPUnit\Runner\DeprecationCollector\InIsolationCollector $collector = null; + private static bool $inIsolation = \false; + public static function init(): void + { + self::collector(); + } + public static function initForIsolation(): void + { + self::collector(); + self::$inIsolation = \true; + } + /** + * @return list + */ + public static function deprecations(): array + { + return self::collector()->deprecations(); + } + /** + * @return list + */ + public static function filteredDeprecations(): array + { + return self::collector()->filteredDeprecations(); + } + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public static function collector(): \PHPUnit\Runner\DeprecationCollector\Collector|\PHPUnit\Runner\DeprecationCollector\InIsolationCollector + { + if (self::$collector !== null) { + return self::$collector; + } + $issueFilter = new IssueFilter(ConfigurationRegistry::get()->source()); + if (self::$inIsolation) { + self::$collector = new \PHPUnit\Runner\DeprecationCollector\InIsolationCollector($issueFilter); + return self::$collector; + } + self::$collector = new \PHPUnit\Runner\DeprecationCollector\Collector(EventFacade::instance(), $issueFilter); + return self::$collector; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\TestRunner\IssueFilter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InIsolationCollector +{ + private readonly IssueFilter $issueFilter; + /** + * @var list + */ + private array $deprecations = []; + /** + * @var list + */ + private array $filteredDeprecations = []; + public function __construct(IssueFilter $issueFilter) + { + $this->issueFilter = $issueFilter; + } + /** + * @return list + */ + public function deprecations(): array + { + return $this->deprecations; + } + /** + * @return list + */ + public function filteredDeprecations(): array + { + return $this->filteredDeprecations; + } + public function testTriggeredDeprecation(DeprecationTriggered $event): void + { + $this->deprecations[] = $event->message(); + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + $this->filteredDeprecations[] = $event->message(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract class Subscriber +{ + private readonly \PHPUnit\Runner\DeprecationCollector\Collector|\PHPUnit\Runner\DeprecationCollector\InIsolationCollector $collector; + public function __construct(\PHPUnit\Runner\DeprecationCollector\Collector|\PHPUnit\Runner\DeprecationCollector\InIsolationCollector $collector) + { + $this->collector = $collector; + } + protected function collector(): \PHPUnit\Runner\DeprecationCollector\Collector|\PHPUnit\Runner\DeprecationCollector\InIsolationCollector + { + return $this->collector; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestPreparedSubscriber extends \PHPUnit\Runner\DeprecationCollector\Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->collector()->testPrepared(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestTriggeredDeprecationSubscriber extends \PHPUnit\Runner\DeprecationCollector\Subscriber implements DeprecationTriggeredSubscriber +{ + public function notify(DeprecationTriggered $event): void + { + $this->collector()->testTriggeredDeprecation($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use const DEBUG_BACKTRACE_IGNORE_ARGS; +use const E_COMPILE_ERROR; +use const E_COMPILE_WARNING; +use const E_CORE_ERROR; +use const E_CORE_WARNING; +use const E_DEPRECATED; +use const E_ERROR; +use const E_NOTICE; +use const E_PARSE; +use const E_RECOVERABLE_ERROR; +use const E_USER_DEPRECATED; +use const E_USER_ERROR; +use const E_USER_NOTICE; +use const E_USER_WARNING; +use const E_WARNING; +use function array_keys; +use function array_unshift; +use function array_values; +use function assert; +use function count; +use function debug_backtrace; +use function defined; +use function error_reporting; +use function preg_match; +use function restore_error_handler; +use function set_error_handler; +use function sprintf; +use PHPUnit\Event; +use PHPUnit\Event\Code\IssueTrigger\Code; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\NoTestCaseObjectOnCallStackException; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\IgnoreDeprecations; +use PHPUnit\Metadata\Parser\Registry as MetadataParserRegistry; +use PHPUnit\Runner\Baseline\Baseline; +use PHPUnit\Runner\Baseline\Issue; +use PHPUnit\Runner\IssueTriggerResolver\DefaultResolver as DefaultIssueTriggerResolver; +use PHPUnit\Runner\IssueTriggerResolver\Resolver as IssueTriggerResolver; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use PHPUnit\TextUI\Configuration\SourceFilter; +use PHPUnit\Util\ExcludeList; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ErrorHandler +{ + private const int UNHANDLEABLE_LEVELS = E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING; + private const int INSUPPRESSIBLE_LEVELS = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR; + private static ?self $instance = null; + private ?Baseline $baseline = null; + private ExcludeList $excludeList; + private bool $enabled = \false; + private ?int $originalErrorReportingLevel = null; + private readonly bool $identifyIssueTrigger; + /** + * @var list + */ + private array $globalDeprecations = []; + /** + * @var array> + */ + private array $testCaseContextDeprecations = []; + private ?string $testCaseContext = null; + /** + * @var ?array{functions: list, methods: list} + */ + private ?array $deprecationTriggers = null; + /** + * @var non-empty-list + */ + private array $issueTriggerResolvers; + public static function instance(): self + { + $source = ConfigurationRegistry::get()->source(); + $identifyIssueTrigger = \true; + if (!$source->identifyIssueTrigger()) { + $identifyIssueTrigger = \false; + } + if (!$source->notEmpty()) { + $identifyIssueTrigger = \false; + } + return self::$instance ?? self::$instance = new self($identifyIssueTrigger); + } + private function __construct(bool $identifyIssueTrigger) + { + $this->excludeList = new ExcludeList(); + $this->identifyIssueTrigger = $identifyIssueTrigger; + $this->issueTriggerResolvers = [new DefaultIssueTriggerResolver()]; + } + /** + * @throws NoTestCaseObjectOnCallStackException + */ + public function __invoke(int $errorNumber, string $errorString, string $errorFile, int $errorLine): false + { + $suppressed = (error_reporting() & ~self::INSUPPRESSIBLE_LEVELS) === 0; + if ($suppressed && $this->excludeList->isExcluded($errorFile)) { + // @codeCoverageIgnoreStart + return \false; + // @codeCoverageIgnoreEnd + } + /** + * E_STRICT is deprecated since PHP 8.4. + * + * @see https://github.com/sebastianbergmann/phpunit/issues/5956 + */ + if (defined('E_STRICT') && $errorNumber === 2048) { + // @codeCoverageIgnoreStart + $errorNumber = E_NOTICE; + // @codeCoverageIgnoreEnd + } + $test = Event\Code\TestMethodBuilder::fromCallStack(); + if ($errorNumber === E_USER_DEPRECATED) { + $deprecationFrame = $this->guessDeprecationFrame(); + $errorFile = $deprecationFrame['file'] ?? $errorFile; + $errorLine = $deprecationFrame['line'] ?? $errorLine; + } + $ignoredByBaseline = $this->ignoredByBaseline($errorFile, $errorLine, $errorString); + $ignoredByTest = $this->deprecationIgnoredByTest($test, $errorString); + switch ($errorNumber) { + case E_NOTICE: + Event\Facade::emitter()->testTriggeredPhpNotice($test, $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline); + break; + case E_USER_NOTICE: + Event\Facade::emitter()->testTriggeredNotice($test, $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline); + break; + case E_WARNING: + Event\Facade::emitter()->testTriggeredPhpWarning($test, $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline); + break; + case E_USER_WARNING: + Event\Facade::emitter()->testTriggeredWarning($test, $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline); + break; + case E_DEPRECATED: + Event\Facade::emitter()->testTriggeredPhpDeprecation($test, $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline, $ignoredByTest, $this->trigger($test, \false, $errorString, $errorFile)); + break; + case E_USER_DEPRECATED: + Event\Facade::emitter()->testTriggeredDeprecation($test, $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline, $ignoredByTest, $this->trigger($test, \true, $errorString), $this->stackTrace()); + break; + case E_USER_ERROR: + Event\Facade::emitter()->testTriggeredError($test, $errorString, $errorFile, $errorLine, $suppressed); + throw new \PHPUnit\Runner\ErrorException('E_USER_ERROR was triggered'); + default: + return \false; + } + return \false; + } + public function deprecationHandler(int $errorNumber, string $errorString, string $errorFile, int $errorLine): true + { + if ($this->testCaseContext !== null) { + $this->testCaseContextDeprecations[$this->testCaseContext][] = [$errorNumber, $errorString, $errorFile, $errorLine]; + } else { + $this->globalDeprecations[] = [$errorNumber, $errorString, $errorFile, $errorLine]; + } + return \true; + } + public function registerDeprecationHandler(): void + { + set_error_handler([self::$instance, 'deprecationHandler'], E_USER_DEPRECATED | E_DEPRECATED); + } + public function restoreDeprecationHandler(): void + { + restore_error_handler(); + } + public function enable(TestCase $test): void + { + assert(!$this->enabled); + $oldErrorHandler = set_error_handler($this); + if ($oldErrorHandler !== null) { + restore_error_handler(); + return; + } + $this->enabled = \true; + $this->originalErrorReportingLevel = error_reporting(); + $this->triggerGlobalDeprecations($test); + error_reporting($this->originalErrorReportingLevel & self::UNHANDLEABLE_LEVELS); + } + public function disable(): void + { + if (!$this->enabled) { + return; + } + restore_error_handler(); + error_reporting(error_reporting() | $this->originalErrorReportingLevel); + $this->enabled = \false; + $this->originalErrorReportingLevel = null; + } + public function useBaseline(Baseline $baseline): void + { + $this->baseline = $baseline; + } + /** + * @param array{functions: list, methods: list} $deprecationTriggers + */ + public function useDeprecationTriggers(array $deprecationTriggers): void + { + $this->deprecationTriggers = $deprecationTriggers; + } + public function addIssueTriggerResolver(IssueTriggerResolver $resolver): void + { + array_unshift($this->issueTriggerResolvers, $resolver); + } + public function enterTestCaseContext(string $className, string $methodName): void + { + $this->testCaseContext = $this->testCaseContext($className, $methodName); + } + public function leaveTestCaseContext(): void + { + $this->testCaseContext = null; + } + /** + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $description + */ + private function ignoredByBaseline(string $file, int $line, string $description): bool + { + if ($this->baseline === null) { + return \false; + } + return $this->baseline->has(Issue::from($file, $line, null, $description)); + } + /** + * @param null|non-empty-string $errorFile + */ + private function trigger(TestMethod $test, bool $isUserland, string $errorString, ?string $errorFile = null): IssueTrigger + { + if (!$this->identifyIssueTrigger) { + return IssueTrigger::from(null, null); + } + if (!$isUserland) { + assert($errorFile !== null); + return IssueTrigger::from(Code::PHP, $this->categorizeFile($errorFile, $test)); + } + $trace = $this->filteredStackTrace(); + return $this->triggerForUserlandDeprecation($test, $errorString, $trace); + } + /** + * @param list}> $trace + */ + private function triggerForUserlandDeprecation(TestMethod $test, string $message, array $trace): IssueTrigger + { + foreach ($this->issueTriggerResolvers as $resolver) { + $result = $resolver->resolve($trace, $message); + if ($result === null) { + continue; + } + $callee = null; + if ($result->hasCallee()) { + $callee = $this->categorizeFile($result->callee(), $test); + } + $caller = null; + if ($result->hasCaller()) { + $caller = $this->categorizeFile($result->caller(), $test); + } + return IssueTrigger::from($callee, $caller); + } + // @codeCoverageIgnoreStart + return IssueTrigger::from(null, null); + // @codeCoverageIgnoreEnd + } + /** + * @param non-empty-string $file + */ + private function categorizeFile(string $file, TestMethod $test): Code + { + if ($file === $test->file()) { + return Code::Test; + } + if (SourceFilter::instance()->includes($file)) { + return Code::FirstParty; + } + if ($this->excludeList->isExcluded($file)) { + return Code::PHPUnit; + } + return Code::ThirdParty; + } + /** + * @return list, object?: object}> + */ + private function filteredStackTrace(): array + { + $ignoreArguments = count($this->issueTriggerResolvers) === 1; + $trace = $this->errorStackTrace($ignoreArguments); + if ($this->deprecationTriggers === null) { + return array_values($trace); + } + foreach (array_keys($trace) as $frame) { + foreach ($this->deprecationTriggers['functions'] as $function) { + if ($this->frameIsFunction($trace[$frame], $function)) { + unset($trace[$frame]); + continue 2; + } + } + foreach ($this->deprecationTriggers['methods'] as $method) { + if ($this->frameIsMethod($trace[$frame], $method)) { + unset($trace[$frame]); + continue 2; + } + } + } + return array_values($trace); + } + /** + * @return ?array{file: non-empty-string, line: positive-int} + */ + private function guessDeprecationFrame(): ?array + { + if ($this->deprecationTriggers === null) { + return null; + } + $trace = $this->errorStackTrace(); + foreach ($trace as $frame) { + foreach ($this->deprecationTriggers['functions'] as $function) { + if ($this->frameIsFunction($frame, $function)) { + return $frame; + } + } + foreach ($this->deprecationTriggers['methods'] as $method) { + if ($this->frameIsMethod($frame, $method)) { + return $frame; + } + } + } + return null; + } + /** + * @return list, object?: object}> + */ + private function errorStackTrace(bool $ignoreArgs = \true): array + { + if ($ignoreArgs) { + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + } else { + $trace = debug_backtrace(); + } + $i = 0; + do { + unset($trace[$i]); + } while (self::class === ($trace[++$i]['class'] ?? null)); + return array_values($trace); + } + /** + * @param array{class? : class-string, function?: non-empty-string} $frame + * @param non-empty-string $function + */ + private function frameIsFunction(array $frame, string $function): bool + { + return !isset($frame['class']) && isset($frame['function']) && $frame['function'] === $function; + } + /** + * @param array{class? : class-string, function?: non-empty-string} $frame + * @param array{className: class-string, methodName: non-empty-string} $method + */ + private function frameIsMethod(array $frame, array $method): bool + { + return isset($frame['class']) && $frame['class'] === $method['className'] && isset($frame['function']) && $frame['function'] === $method['methodName']; + } + /** + * @return non-empty-string + */ + private function stackTrace(): string + { + $buffer = ''; + foreach ($this->errorStackTrace() as $frame) { + /** + * @see https://github.com/sebastianbergmann/phpunit/issues/6043 + */ + if (!isset($frame['file'])) { + continue; + } + if ($this->excludeList->isExcluded($frame['file'])) { + continue; + } + $buffer .= sprintf("%s:%s\n", $frame['file'], $frame['line'] ?? '?'); + } + return $buffer; + } + private function triggerGlobalDeprecations(TestCase $test): void + { + foreach ($this->globalDeprecations as $d) { + $this->__invoke(...$d); + } + $testCaseContext = $this->testCaseContext($test::class, $test->name()); + foreach ($this->testCaseContextDeprecations[$testCaseContext] ?? [] as $d) { + $this->__invoke(...$d); + } + } + private function testCaseContext(string $className, string $methodName): string + { + return "{$className}::{$methodName}"; + } + private function deprecationIgnoredByTest(TestMethod $test, string $message): bool + { + $metadata = MetadataParserRegistry::parser()->forClassAndMethod($test->className(), $test->methodName())->isIgnoreDeprecations()->asArray(); + foreach ($metadata as $metadatum) { + assert($metadatum instanceof IgnoreDeprecations); + $ignoreDeprecationMessagePattern = $metadatum->messagePattern(); + if ($ignoreDeprecationMessagePattern === null || (bool) preg_match('{' . $ignoreDeprecationMessagePattern . '}', $message)) { + return \true; + } + } + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ClassCannotBeFoundException extends RuntimeException implements \PHPUnit\Runner\Exception +{ + public function __construct(string $className, string $file) + { + parent::__construct(sprintf('Class %s cannot be found in %s', $className, $file)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ClassDoesNotExtendTestCaseException extends RuntimeException implements \PHPUnit\Runner\Exception +{ + public function __construct(string $className, string $file) + { + parent::__construct(sprintf('Class %s declared in %s does not extend PHPUnit\Framework\TestCase', $className, $file)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ClassIsAbstractException extends RuntimeException implements \PHPUnit\Runner\Exception +{ + public function __construct(string $className, string $file) + { + parent::__construct(sprintf('Class %s declared in %s is abstract', $className, $file)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CodeCoverageFileExistsException extends RuntimeException implements \PHPUnit\Runner\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DirectoryDoesNotExistException extends RuntimeException implements \PHPUnit\Runner\Exception +{ + public function __construct(string $directory) + { + parent::__construct(sprintf('Directory "%s" does not exist and could not be created', $directory)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use Error; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ErrorException extends Error implements \PHPUnit\Runner\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends \PHPUnit\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class FileDoesNotExistException extends RuntimeException implements \PHPUnit\Runner\Exception +{ + public function __construct(string $file) + { + parent::__construct(sprintf('File "%s" does not exist', $file)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidOrderException extends RuntimeException implements \PHPUnit\Runner\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ParameterDoesNotExistException extends RuntimeException implements \PHPUnit\Runner\Exception +{ + public function __construct(string $name) + { + parent::__construct(sprintf('Parameter "%s" does not exist', $name)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Extension; + +use PHPUnit\TextUI\Configuration\Configuration; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Extension +{ + public function bootstrap(Configuration $configuration, \PHPUnit\Runner\Extension\Facade $facade, \PHPUnit\Runner\Extension\ParameterCollection $parameters): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Extension; + +use const PHP_EOL; +use function assert; +use function class_exists; +use function class_implements; +use function in_array; +use function sprintf; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\TextUI\Configuration\Configuration; +use ReflectionClass; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExtensionBootstrapper +{ + private Configuration $configuration; + private \PHPUnit\Runner\Extension\Facade $facade; + public function __construct(Configuration $configuration, \PHPUnit\Runner\Extension\Facade $facade) + { + $this->configuration = $configuration; + $this->facade = $facade; + } + /** + * @param non-empty-string $className + * @param array $parameters + */ + public function bootstrap(string $className, array $parameters): void + { + if (!class_exists($className)) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot bootstrap extension because class %s does not exist', $className)); + return; + } + if (!in_array(\PHPUnit\Runner\Extension\Extension::class, class_implements($className), \true)) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot bootstrap extension because class %s does not implement interface %s', $className, \PHPUnit\Runner\Extension\Extension::class)); + return; + } + try { + $instance = (new ReflectionClass($className))->newInstance(); + assert($instance instanceof \PHPUnit\Runner\Extension\Extension); + $instance->bootstrap($this->configuration, $this->facade, \PHPUnit\Runner\Extension\ParameterCollection::fromArray($parameters)); + } catch (Throwable $t) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Bootstrapping of extension %s failed: %s%s%s', $className, $t->getMessage(), PHP_EOL, $t->getTraceAsString())); + return; + } + EventFacade::emitter()->testRunnerBootstrappedExtension($className, $parameters); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Extension; + +use PHPUnit\Event\EventFacadeIsSealedException; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Event\Subscriber; +use PHPUnit\Event\Tracer\Tracer; +use PHPUnit\Event\UnknownSubscriberTypeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExtensionFacade implements \PHPUnit\Runner\Extension\Facade +{ + private bool $replacesOutput = \false; + private bool $replacesProgressOutput = \false; + private bool $replacesResultOutput = \false; + private bool $requiresCodeCoverageCollection = \false; + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public function registerSubscribers(Subscriber ...$subscribers): void + { + EventFacade::instance()->registerSubscribers(...$subscribers); + } + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public function registerSubscriber(Subscriber $subscriber): void + { + EventFacade::instance()->registerSubscriber($subscriber); + } + /** + * @throws EventFacadeIsSealedException + */ + public function registerTracer(Tracer $tracer): void + { + EventFacade::instance()->registerTracer($tracer); + } + public function replaceOutput(): void + { + $this->replacesOutput = \true; + } + public function replacesOutput(): bool + { + return $this->replacesOutput; + } + public function replaceProgressOutput(): void + { + $this->replacesProgressOutput = \true; + } + public function replacesProgressOutput(): bool + { + return $this->replacesOutput || $this->replacesProgressOutput; + } + public function replaceResultOutput(): void + { + $this->replacesResultOutput = \true; + } + public function replacesResultOutput(): bool + { + return $this->replacesOutput || $this->replacesResultOutput; + } + public function requireCodeCoverageCollection(): void + { + $this->requiresCodeCoverageCollection = \true; + } + public function requiresCodeCoverageCollection(): bool + { + return $this->requiresCodeCoverageCollection; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Extension; + +use PHPUnit\Event\EventFacadeIsSealedException; +use PHPUnit\Event\Subscriber; +use PHPUnit\Event\Tracer\Tracer; +use PHPUnit\Event\UnknownSubscriberTypeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Facade +{ + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public function registerSubscribers(Subscriber ...$subscribers): void; + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public function registerSubscriber(Subscriber $subscriber): void; + /** + * @throws EventFacadeIsSealedException + */ + public function registerTracer(Tracer $tracer): void; + public function replaceOutput(): void; + public function replaceProgressOutput(): void; + public function replaceResultOutput(): void; + public function requireCodeCoverageCollection(): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Extension; + +use function array_key_exists; +use PHPUnit\Runner\ParameterDoesNotExistException; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ParameterCollection +{ + /** + * @var array + */ + private array $parameters; + /** + * @param array $parameters + */ + public static function fromArray(array $parameters): self + { + return new self($parameters); + } + /** + * @param array $parameters + */ + private function __construct(array $parameters) + { + $this->parameters = $parameters; + } + public function has(string $name): bool + { + return array_key_exists($name, $this->parameters); + } + /** + * @throws ParameterDoesNotExistException + */ + public function get(string $name): string + { + if (!$this->has($name)) { + throw new ParameterDoesNotExistException($name); + } + return $this->parameters[$name]; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Extension; + +use function count; +use function explode; +use function extension_loaded; +use function implode; +use function is_file; +use function sprintf; +use function str_contains; +use PHPUnitPHAR\PharIo\Manifest\ApplicationName; +use PHPUnitPHAR\PharIo\Manifest\Exception as ManifestException; +use PHPUnitPHAR\PharIo\Manifest\ManifestLoader; +use PHPUnitPHAR\PharIo\Version\Version as PharIoVersion; +use PHPUnit\Event; +use PHPUnit\Runner\Version; +use PHPUnitPHAR\SebastianBergmann\FileIterator\Facade as FileIteratorFacade; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PharLoader +{ + /** + * @param non-empty-string $directory + * + * @return list + */ + public function loadPharExtensionsInDirectory(string $directory): array + { + $pharExtensionLoaded = extension_loaded('phar'); + $loadedExtensions = []; + foreach ((new FileIteratorFacade())->getFilesAsArray($directory, '.phar') as $file) { + if (!$pharExtensionLoaded) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot load extension from %s because the PHAR extension is not available', $file)); + continue; + } + if (!is_file('phar://' . $file . '/manifest.xml')) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('%s is not an extension for PHPUnit', $file)); + continue; + } + try { + $applicationName = new ApplicationName('phpunit/phpunit'); + $version = new PharIoVersion($this->phpunitVersion()); + $manifest = ManifestLoader::fromFile('phar://' . $file . '/manifest.xml'); + if (!$manifest->isExtensionFor($applicationName)) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('%s is not an extension for PHPUnit', $file)); + continue; + } + if (!$manifest->isExtensionFor($applicationName, $version)) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('%s is not compatible with PHPUnit %s', $file, Version::series())); + continue; + } + } catch (ManifestException $e) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot load extension from %s: %s', $file, $e->getMessage())); + continue; + } + try { + @require $file; + } catch (Throwable $t) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot load extension from %s: %s', $file, $t->getMessage())); + continue; + } + $loadedExtensions[] = $manifest->getName()->asString() . ' ' . $manifest->getVersion()->getVersionString(); + Event\Facade::emitter()->testRunnerLoadedExtensionFromPhar($file, $manifest->getName()->asString(), $manifest->getVersion()->getVersionString()); + } + return $loadedExtensions; + } + private function phpunitVersion(): string + { + $version = Version::id(); + if (!str_contains($version, '-')) { + return $version; + } + $parts = explode('.', explode('-', $version)[0]); + if (count($parts) === 2) { + $parts[] = 0; + } + return implode('.', $parts); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function in_array; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExcludeGroupFilterIterator extends \PHPUnit\Runner\Filter\GroupFilterIterator +{ + /** + * @param non-empty-string $id + * @param list $groupTests + */ + protected function doAccept(string $id, array $groupTests): bool + { + return !in_array($id, $groupTests, \true); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExcludeNameFilterIterator extends \PHPUnit\Runner\Filter\NameFilterIterator +{ + protected function doAccept(bool $result): bool + { + return !$result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function assert; +use FilterIterator; +use Iterator; +use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestSuite; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Factory +{ + /** + * @var list>>, argument: list|non-empty-string}> + */ + private array $filters = []; + /** + * @param list $testIds + */ + public function addTestIdFilter(array $testIds): void + { + $this->filters[] = ['className' => \PHPUnit\Runner\Filter\TestIdFilterIterator::class, 'argument' => $testIds]; + } + /** + * @param list $groups + */ + public function addIncludeGroupFilter(array $groups): void + { + $this->filters[] = ['className' => \PHPUnit\Runner\Filter\IncludeGroupFilterIterator::class, 'argument' => $groups]; + } + /** + * @param list $groups + */ + public function addExcludeGroupFilter(array $groups): void + { + $this->filters[] = ['className' => \PHPUnit\Runner\Filter\ExcludeGroupFilterIterator::class, 'argument' => $groups]; + } + /** + * @param non-empty-string $name + */ + public function addIncludeNameFilter(string $name): void + { + $this->filters[] = ['className' => \PHPUnit\Runner\Filter\IncludeNameFilterIterator::class, 'argument' => $name]; + } + /** + * @param non-empty-string $name + */ + public function addExcludeNameFilter(string $name): void + { + $this->filters[] = ['className' => \PHPUnit\Runner\Filter\ExcludeNameFilterIterator::class, 'argument' => $name]; + } + /** + * @param Iterator $iterator + * + * @return FilterIterator> + */ + public function factory(Iterator $iterator, TestSuite $suite): FilterIterator + { + foreach ($this->filters as $filter) { + $iterator = new $filter['className']($iterator, $filter['argument'], $suite); + } + assert($iterator instanceof FilterIterator); + return $iterator; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function array_merge; +use function array_push; +use function in_array; +use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use RecursiveFilterIterator; +use RecursiveIterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract class GroupFilterIterator extends RecursiveFilterIterator +{ + /** + * @var list + */ + private readonly array $groupTests; + /** + * @param RecursiveIterator $iterator + * @param list $groups + */ + public function __construct(RecursiveIterator $iterator, array $groups, TestSuite $suite) + { + parent::__construct($iterator); + $groupTests = []; + foreach ($suite->groups() as $group => $tests) { + if (in_array($group, $groups, \true)) { + $groupTests = array_merge($groupTests, $tests); + array_push($groupTests, ...$groupTests); + } + } + $this->groupTests = $groupTests; + } + public function accept(): bool + { + $test = $this->getInnerIterator()->current(); + if ($test instanceof TestSuite) { + return \true; + } + if ($test instanceof TestCase || $test instanceof PhptTestCase) { + return $this->doAccept($test->valueObjectForEvents()->id(), $this->groupTests); + } + return \true; + } + /** + * @param non-empty-string $id + * @param list $groupTests + */ + abstract protected function doAccept(string $id, array $groupTests): bool; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function in_array; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class IncludeGroupFilterIterator extends \PHPUnit\Runner\Filter\GroupFilterIterator +{ + /** + * @param non-empty-string $id + * @param list $groupTests + */ + protected function doAccept(string $id, array $groupTests): bool + { + return in_array($id, $groupTests, \true); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class IncludeNameFilterIterator extends \PHPUnit\Runner\Filter\NameFilterIterator +{ + protected function doAccept(bool $result): bool + { + return $result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function end; +use function preg_match; +use function sprintf; +use function substr; +use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use RecursiveFilterIterator; +use RecursiveIterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract class NameFilterIterator extends RecursiveFilterIterator +{ + /** + * @var non-empty-string + */ + private readonly string $regularExpression; + private readonly ?int $dataSetMinimum; + private readonly ?int $dataSetMaximum; + /** + * @param RecursiveIterator $iterator + * @param non-empty-string $filter + */ + public function __construct(RecursiveIterator $iterator, string $filter) + { + parent::__construct($iterator); + $preparedFilter = $this->prepareFilter($filter); + $this->regularExpression = $preparedFilter['regularExpression']; + $this->dataSetMinimum = $preparedFilter['dataSetMinimum']; + $this->dataSetMaximum = $preparedFilter['dataSetMaximum']; + } + public function accept(): bool + { + $test = $this->getInnerIterator()->current(); + if ($test instanceof TestSuite) { + return \true; + } + if ($test instanceof PhptTestCase) { + return \false; + } + $name = $test::class . '::' . $test->nameWithDataSet(); + $accepted = @preg_match($this->regularExpression, $name, $matches) === 1; + if ($accepted && isset($this->dataSetMaximum)) { + $set = end($matches); + $accepted = $set >= $this->dataSetMinimum && $set <= $this->dataSetMaximum; + } + return $this->doAccept($accepted); + } + abstract protected function doAccept(bool $result): bool; + /** + * @param non-empty-string $filter + * + * @return array{regularExpression: non-empty-string, dataSetMinimum: ?int, dataSetMaximum: ?int} + */ + private function prepareFilter(string $filter): array + { + $dataSetMinimum = null; + $dataSetMaximum = null; + if (preg_match('/[a-zA-Z0-9]/', substr($filter, 0, 1)) === 1 || @preg_match($filter, '') === \false) { + // Handles: + // * testAssertEqualsSucceeds#4 + // * testAssertEqualsSucceeds#4-8 + if (preg_match('/^(.*?)#(\d+)(?:-(\d+))?$/', $filter, $matches)) { + if (isset($matches[3]) && $matches[2] < $matches[3]) { + $filter = sprintf('%s.*with data set #(\d+)$', $matches[1]); + $dataSetMinimum = (int) $matches[2]; + $dataSetMaximum = (int) $matches[3]; + } elseif ($matches[1] !== '') { + $filter = sprintf('%s.*with data set #%s$', $matches[1], $matches[2]); + } + } elseif (preg_match('/^(.*?)@(.+)$/', $filter, $matches)) { + $filter = sprintf('%s.*with data set "%s"$', $matches[1], $matches[2]); + } + // Do NOT use preg_quote, to keep magic characters. + $filter = sprintf('{%s}i', $filter); + } + return ['regularExpression' => $filter, 'dataSetMinimum' => $dataSetMinimum, 'dataSetMaximum' => $dataSetMaximum]; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function in_array; +use PHPUnit\Event\TestData\NoDataSetFromDataProviderException; +use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use RecursiveFilterIterator; +use RecursiveIterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestIdFilterIterator extends RecursiveFilterIterator +{ + /** + * @var non-empty-list + */ + private readonly array $testIds; + /** + * @param RecursiveIterator $iterator + * @param non-empty-list $testIds + */ + public function __construct(RecursiveIterator $iterator, array $testIds) + { + parent::__construct($iterator); + $this->testIds = $testIds; + } + public function accept(): bool + { + $test = $this->getInnerIterator()->current(); + if ($test instanceof TestSuite) { + return \true; + } + if (!$test instanceof TestCase && !$test instanceof PhptTestCase) { + return \false; + } + try { + return in_array($test->valueObjectForEvents()->id(), $this->testIds, \true); + } catch (NoDataSetFromDataProviderException) { + return \false; + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\GarbageCollection; + +use function gc_collect_cycles; +use function gc_disable; +use function gc_enable; +use PHPUnit\Event\Facade; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class GarbageCollectionHandler +{ + private readonly Facade $facade; + private readonly int $threshold; + private int $tests = 0; + public function __construct(Facade $facade, int $threshold) + { + $this->facade = $facade; + $this->threshold = $threshold; + $this->registerSubscribers(); + } + public function executionStarted(): void + { + gc_disable(); + $this->facade->emitter()->testRunnerDisabledGarbageCollection(); + gc_collect_cycles(); + $this->facade->emitter()->testRunnerTriggeredGarbageCollection(); + } + public function executionFinished(): void + { + gc_collect_cycles(); + $this->facade->emitter()->testRunnerTriggeredGarbageCollection(); + gc_enable(); + $this->facade->emitter()->testRunnerEnabledGarbageCollection(); + } + public function testFinished(): void + { + $this->tests++; + if ($this->tests === $this->threshold) { + gc_collect_cycles(); + $this->facade->emitter()->testRunnerTriggeredGarbageCollection(); + $this->tests = 0; + } + } + private function registerSubscribers(): void + { + $this->facade->registerSubscribers(new \PHPUnit\Runner\GarbageCollection\ExecutionStartedSubscriber($this), new \PHPUnit\Runner\GarbageCollection\ExecutionFinishedSubscriber($this), new \PHPUnit\Runner\GarbageCollection\TestFinishedSubscriber($this)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\GarbageCollection; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber as TestRunnerExecutionFinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionFinishedSubscriber extends \PHPUnit\Runner\GarbageCollection\Subscriber implements TestRunnerExecutionFinishedSubscriber +{ + /** + * @throws \PHPUnit\Framework\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function notify(ExecutionFinished $event): void + { + $this->handler()->executionFinished(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\GarbageCollection; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber as TestRunnerExecutionStartedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionStartedSubscriber extends \PHPUnit\Runner\GarbageCollection\Subscriber implements TestRunnerExecutionStartedSubscriber +{ + /** + * @throws \PHPUnit\Framework\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function notify(ExecutionStarted $event): void + { + $this->handler()->executionStarted(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\GarbageCollection; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private \PHPUnit\Runner\GarbageCollection\GarbageCollectionHandler $handler; + public function __construct(\PHPUnit\Runner\GarbageCollection\GarbageCollectionHandler $handler) + { + $this->handler = $handler; + } + protected function handler(): \PHPUnit\Runner\GarbageCollection\GarbageCollectionHandler + { + return $this->handler; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\GarbageCollection; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends \PHPUnit\Runner\GarbageCollection\Subscriber implements FinishedSubscriber +{ + /** + * @throws \PHPUnit\Framework\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->handler()->testFinished(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class HookMethod +{ + /** + * @var non-empty-string + */ + private string $methodName; + private int $priority; + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName, int $priority) + { + $this->methodName = $methodName; + $this->priority = $priority; + } + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + public function priority(): int + { + return $this->priority; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function array_map; +use function usort; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class HookMethodCollection +{ + private readonly bool $shouldPrepend; + /** + * @var non-empty-list + */ + private array $hookMethods; + public static function defaultBeforeClass(): self + { + return new self(new \PHPUnit\Runner\HookMethod('setUpBeforeClass', 0), \true); + } + public static function defaultBefore(): self + { + return new self(new \PHPUnit\Runner\HookMethod('setUp', 0), \true); + } + public static function defaultPreCondition(): self + { + return new self(new \PHPUnit\Runner\HookMethod('assertPreConditions', 0), \true); + } + public static function defaultPostCondition(): self + { + return new self(new \PHPUnit\Runner\HookMethod('assertPostConditions', 0), \false); + } + public static function defaultAfter(): self + { + return new self(new \PHPUnit\Runner\HookMethod('tearDown', 0), \false); + } + public static function defaultAfterClass(): self + { + return new self(new \PHPUnit\Runner\HookMethod('tearDownAfterClass', 0), \false); + } + private function __construct(\PHPUnit\Runner\HookMethod $default, bool $shouldPrepend) + { + $this->hookMethods = [$default]; + $this->shouldPrepend = $shouldPrepend; + } + public function add(\PHPUnit\Runner\HookMethod $hookMethod): self + { + if ($this->shouldPrepend) { + $this->hookMethods = [$hookMethod, ...$this->hookMethods]; + } else { + $this->hookMethods[] = $hookMethod; + } + return $this; + } + /** + * @return list + */ + public function methodNamesSortedByPriority(): array + { + $hookMethods = $this->hookMethods; + usort($hookMethods, static fn(\PHPUnit\Runner\HookMethod $a, \PHPUnit\Runner\HookMethod $b) => $b->priority() <=> $a->priority()); + return array_map(static fn(\PHPUnit\Runner\HookMethod $hookMethod) => $hookMethod->methodName(), $hookMethods); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\SourceFilter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IssueFilter +{ + private Source $source; + public function __construct(Source $source) + { + $this->source = $source; + } + public function shouldBeProcessed(DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event, bool $onlyTestMethods = \false): bool + { + if ($onlyTestMethods && !$event->test()->isTestMethod()) { + return \false; + } + if ($event instanceof DeprecationTriggered || $event instanceof PhpDeprecationTriggered) { + if ($event->ignoredByTest()) { + return \false; + } + if ($this->source->ignoreSelfDeprecations() && $event->trigger()->isSelf()) { + return \false; + } + if ($this->source->ignoreDirectDeprecations() && $event->trigger()->isDirect()) { + return \false; + } + if ($this->source->ignoreIndirectDeprecations() && $event->trigger()->isIndirect()) { + return \false; + } + if (!$this->source->ignoreSuppressionOfDeprecations() && $event->wasSuppressed()) { + return \false; + } + } + if ($event instanceof NoticeTriggered) { + if (!$this->source->ignoreSuppressionOfNotices() && $event->wasSuppressed()) { + return \false; + } + if ($this->source->restrictNotices() && !SourceFilter::instance()->includes($event->file())) { + return \false; + } + } + if ($event instanceof PhpNoticeTriggered) { + if (!$this->source->ignoreSuppressionOfPhpNotices() && $event->wasSuppressed()) { + return \false; + } + if ($this->source->restrictNotices() && !SourceFilter::instance()->includes($event->file())) { + return \false; + } + } + if ($event instanceof WarningTriggered) { + if (!$this->source->ignoreSuppressionOfWarnings() && $event->wasSuppressed()) { + return \false; + } + if ($this->source->restrictWarnings() && !SourceFilter::instance()->includes($event->file())) { + return \false; + } + } + if ($event instanceof PhpWarningTriggered) { + if (!$this->source->ignoreSuppressionOfPhpWarnings() && $event->wasSuppressed()) { + return \false; + } + if ($this->source->restrictWarnings() && !SourceFilter::instance()->includes($event->file())) { + return \false; + } + } + if ($event instanceof ErrorTriggered) { + if (!$this->source->ignoreSuppressionOfErrors() && $event->wasSuppressed()) { + return \false; + } + } + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\IssueTriggerResolver; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DefaultResolver implements \PHPUnit\Runner\IssueTriggerResolver\Resolver +{ + /** + * @param list}> $trace + */ + public function resolve(array $trace, string $message): \PHPUnit\Runner\IssueTriggerResolver\Resolution + { + return new \PHPUnit\Runner\IssueTriggerResolver\Resolution($trace[0]['file'] ?? null, $trace[1]['file'] ?? null); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\IssueTriggerResolver; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Resolution +{ + private ?string $callee; + private ?string $caller; + public function __construct(?string $callee, ?string $caller) + { + $this->callee = $callee; + $this->caller = $caller; + } + /** + * @phpstan-assert-if-true !null $this->callee + */ + public function hasCallee(): bool + { + return $this->callee !== null; + } + public function callee(): ?string + { + return $this->callee; + } + /** + * @phpstan-assert-if-true !null $this->caller + */ + public function hasCaller(): bool + { + return $this->caller !== null; + } + public function caller(): ?string + { + return $this->caller; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\IssueTriggerResolver; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Resolver +{ + /** + * Return null to defer to the next resolver in the chain. + * + * @param list, object?: object}> $trace + */ + public function resolve(array $trace, string $message): ?\PHPUnit\Runner\IssueTriggerResolver\Resolution; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use PHPUnit\Runner\Exception as RunnerException; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidPhptFileException extends RuntimeException implements RunnerException +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use function sprintf; +use PHPUnit\Runner\Exception as RunnerException; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class PhptExternalFileCannotBeLoadedException extends RuntimeException implements RunnerException +{ + public function __construct(string $section, string $file) + { + parent::__construct(sprintf('Could not load --%s-- %s for PHPT file', $section . '_EXTERNAL', $file)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use function sprintf; +use PHPUnit\Runner\Exception as RunnerException; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class UnsupportedPhptSectionException extends RuntimeException implements RunnerException +{ + public function __construct(string $section) + { + parent::__construct(sprintf('PHPUnit does not support PHPT --%s-- sections', $section)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use const DIRECTORY_SEPARATOR; +use function assert; +use function dirname; +use function explode; +use function file; +use function file_get_contents; +use function is_file; +use function is_readable; +use function is_string; +use function preg_match; +use function realpath; +use function rtrim; +use function str_contains; +use function trim; +use PHPUnit\Runner\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @see https://qa.php.net/phpt_details.php + */ +final readonly class Parser +{ + /** + * @param non-empty-string $phptFile + * + * @throws Exception + * + * @return array + */ + public function parse(string $phptFile): array + { + $sections = []; + $section = ''; + $unsupportedSections = ['CGI', 'COOKIE', 'DEFLATE_POST', 'EXPECTHEADERS', 'EXTENSIONS', 'GET', 'GZIP_POST', 'HEADERS', 'PHPDBG', 'POST', 'POST_RAW', 'PUT', 'REDIRECTTEST', 'REQUEST']; + $lineNr = 0; + foreach (file($phptFile) as $line) { + $lineNr++; + if (preg_match('/^--([_A-Z]+)--/', $line, $result)) { + $section = $result[1]; + $sections[$section] = ''; + $sections[$section . '_offset'] = $lineNr; + continue; + } + if ($section === '') { + throw new \PHPUnit\Runner\Phpt\InvalidPhptFileException(); + } + $sections[$section] .= $line; + } + if (isset($sections['FILEEOF'])) { + $sections['FILE'] = rtrim($sections['FILEEOF'], "\r\n"); + unset($sections['FILEEOF']); + } + $this->parseExternal($phptFile, $sections); + $this->validate($sections); + foreach ($unsupportedSections as $unsupportedSection) { + if (isset($sections[$unsupportedSection])) { + throw new \PHPUnit\Runner\Phpt\UnsupportedPhptSectionException($unsupportedSection); + } + } + return $sections; + } + /** + * @return array + */ + public function parseEnvSection(string $content): array + { + $env = []; + foreach (explode("\n", trim($content)) as $e) { + $e = explode('=', trim($e), 2); + if ($e[0] !== '' && isset($e[1])) { + $env[$e[0]] = $e[1]; + } + } + return $env; + } + /** + * @param array|string $content + * @param array|non-empty-string> $ini + * + * @return array|non-empty-string> + */ + public function parseIniSection(array|string $content, array $ini = []): array + { + if (is_string($content)) { + $content = explode("\n", trim($content)); + } + foreach ($content as $setting) { + if (!str_contains($setting, '=')) { + continue; + } + $setting = explode('=', $setting, 2); + $name = trim($setting[0]); + $value = trim($setting[1]); + if ($name === 'extension' || $name === 'zend_extension') { + if (!isset($ini[$name])) { + $ini[$name] = []; + } + $ini[$name][] = $value; + continue; + } + $ini[$name] = $value; + } + return $ini; + } + /** + * @param non-empty-string $phptFile + * @param array $sections + * + * @throws Exception + */ + private function parseExternal(string $phptFile, array &$sections): void + { + $allowSections = ['FILE', 'EXPECT', 'EXPECTF', 'EXPECTREGEX']; + $testDirectory = dirname($phptFile) . DIRECTORY_SEPARATOR; + foreach ($allowSections as $section) { + if (isset($sections[$section . '_EXTERNAL'])) { + $externalFilename = trim($sections[$section . '_EXTERNAL']); + if (!is_file($testDirectory . $externalFilename) || !is_readable($testDirectory . $externalFilename)) { + throw new \PHPUnit\Runner\Phpt\PhptExternalFileCannotBeLoadedException($section, $testDirectory . $externalFilename); + } + $externalPath = $testDirectory . $externalFilename; + $contents = file_get_contents($externalPath); + assert($contents !== \false && $contents !== ''); + $sections[$section] = $contents; + if ($section === 'FILE') { + $resolvedPath = realpath($externalPath); + assert(is_string($resolvedPath) && $resolvedPath !== ''); + $sections['FILE_EXTERNAL_PATH'] = $resolvedPath; + } + } + } + } + /** + * @param array $sections + * + * @throws InvalidPhptFileException + */ + private function validate(array $sections): void + { + if (!isset($sections['FILE'])) { + throw new \PHPUnit\Runner\Phpt\InvalidPhptFileException(); + } + if (!isset($sections['EXPECT']) && !isset($sections['EXPECTF']) && !isset($sections['EXPECTREGEX'])) { + throw new \PHPUnit\Runner\Phpt\InvalidPhptFileException(); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use function assert; +use function defined; +use function dirname; +use function file_put_contents; +use function str_replace; +use function var_export; +use PHPUnitPHAR\SebastianBergmann\Template\InvalidArgumentException; +use PHPUnitPHAR\SebastianBergmann\Template\Template; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @see https://qa.php.net/phpt_details.php + */ +final readonly class Renderer +{ + /** + * @param non-empty-string $phptFile + * @param non-empty-string $code + * + * @return non-empty-string + */ + public function render(string $phptFile, string $code): string + { + return str_replace(['__DIR__', '__FILE__'], ["'" . dirname($phptFile) . "'", "'" . $phptFile . "'"], $code); + } + /** + * @param non-empty-string $job + * @param array{coverage: non-empty-string, job: non-empty-string} $files + * + * @param-out non-empty-string $job + * + * @throws InvalidArgumentException + */ + public function renderForCoverage(string &$job, bool $pathCoverage, ?string $codeCoverageCacheDirectory, string $bootstrap, array $files): void + { + $template = new Template(__DIR__ . '/templates/phpt.tpl'); + $composerAutoload = '\'\''; + if (defined('PHPUNIT_COMPOSER_INSTALL')) { + $composerAutoload = var_export(PHPUNIT_COMPOSER_INSTALL, \true); + } + $phar = '\'\''; + if (defined('__PHPUNIT_PHAR__')) { + // @codeCoverageIgnoreStart + $phar = var_export(__PHPUNIT_PHAR__, \true); + // @codeCoverageIgnoreEnd + } + if ($codeCoverageCacheDirectory === null) { + $codeCoverageCacheDirectory = 'null'; + } else { + $codeCoverageCacheDirectory = "'" . $codeCoverageCacheDirectory . "'"; + } + $template->setVar(['bootstrap' => $bootstrap, 'composerAutoload' => $composerAutoload, 'phar' => $phar, 'job' => $files['job'], 'coverageFile' => $files['coverage'], 'driverMethod' => $pathCoverage ? 'forLineAndPathCoverage' : 'forLineCoverage', 'codeCoverageCacheDirectory' => $codeCoverageCacheDirectory]); + file_put_contents($files['job'], $job); + $rendered = $template->render(); + assert($rendered !== ''); + $job = $rendered; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use const DEBUG_BACKTRACE_IGNORE_ARGS; +use const DIRECTORY_SEPARATOR; +use function array_merge; +use function basename; +use function debug_backtrace; +use function dirname; +use function explode; +use function extension_loaded; +use function file_exists; +use function file_get_contents; +use function is_array; +use function is_file; +use function ltrim; +use function ob_get_clean; +use function ob_start; +use function preg_match; +use function preg_replace; +use function preg_split; +use function realpath; +use function sprintf; +use function str_contains; +use function str_starts_with; +use function strncasecmp; +use function substr; +use function trim; +use function unlink; +use function unserialize; +use PHPUnit\Event\Code\Phpt; +use PHPUnit\Event\Code\ThrowableBuilder; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Event\NoPreviousThrowableException; +use PHPUnit\Framework\Assert; +use PHPUnit\Framework\AssertionFailedError; +use PHPUnit\Framework\ExecutionOrderDependency; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\IncompleteTestError; +use PHPUnit\Framework\PhptAssertionFailedError; +use PHPUnit\Framework\Reorderable; +use PHPUnit\Framework\SelfDescribing; +use PHPUnit\Framework\Test; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\Runner\CodeCoverageFileExistsException; +use PHPUnit\Runner\Exception; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use PHPUnit\Util\PHP\Job; +use PHPUnit\Util\PHP\JobRunnerRegistry; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\InvalidArgumentException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\ReflectionException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestSize; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestStatus; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\TestIdMissingException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException; +use PHPUnitPHAR\staabm\SideEffectsDetector\SideEffect; +use PHPUnitPHAR\staabm\SideEffectsDetector\SideEffectsDetector; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @see https://qa.php.net/phpt_details.php + */ +final readonly class TestCase implements Reorderable, SelfDescribing, Test +{ + /** + * @var non-empty-string + */ + private string $filename; + /** + * @param non-empty-string $filename + */ + public function __construct(string $filename) + { + $this->filename = $filename; + $this->ensureCoverageFileDoesNotExist(); + } + public function count(): int + { + return 1; + } + /** + * @throws \PHPUnit\Framework\Exception + * @throws \SebastianBergmann\Template\InvalidArgumentException + * @throws Exception + * @throws InvalidArgumentException + * @throws NoPreviousThrowableException + * @throws ReflectionException + * @throws TestIdMissingException + * @throws UnintentionallyCoveredCodeException + */ + public function run(): void + { + $emitter = EventFacade::emitter(); + $parser = new \PHPUnit\Runner\Phpt\Parser(); + $emitter->testPreparationStarted($this->valueObjectForEvents()); + try { + $sections = $parser->parse($this->filename); + } catch (Exception $e) { + $emitter->testPrepared($this->valueObjectForEvents()); + $emitter->testErrored($this->valueObjectForEvents(), ThrowableBuilder::from($e)); + $emitter->testFinished($this->valueObjectForEvents(), 0); + return; + } + $code = (new \PHPUnit\Runner\Phpt\Renderer())->render($sections['FILE_EXTERNAL_PATH'] ?? $this->filename, $sections['FILE']); + $xfail = \false; + $environmentVariables = []; + $phpSettings = $parser->parseIniSection($this->settings(CodeCoverage::instance()->isActive())); + $input = null; + $arguments = []; + $emitter->testPrepared($this->valueObjectForEvents()); + if (isset($sections['INI'])) { + $phpSettings = $parser->parseIniSection($sections['INI'], $phpSettings); + } + if (isset($sections['ENV'])) { + $environmentVariables = $parser->parseEnvSection($sections['ENV']); + } + if ($this->shouldTestBeSkipped($sections, $phpSettings)) { + return; + } + if (isset($sections['XFAIL'])) { + $xfail = trim($sections['XFAIL']); + } + if (isset($sections['STDIN'])) { + $input = $sections['STDIN']; + } + if (isset($sections['ARGS'])) { + $arguments = explode(' ', $sections['ARGS']); + } + if (CodeCoverage::instance()->isActive()) { + // @codeCoverageIgnoreStart + $codeCoverageCacheDirectory = null; + if (CodeCoverage::instance()->codeCoverage()->cachesStaticAnalysis()) { + $codeCoverageCacheDirectory = CodeCoverage::instance()->codeCoverage()->cacheDirectory(); + } + $bootstrap = ''; + if (ConfigurationRegistry::get()->hasBootstrap()) { + $bootstrap = ConfigurationRegistry::get()->bootstrap(); + } + (new \PHPUnit\Runner\Phpt\Renderer())->renderForCoverage($code, CodeCoverage::instance()->codeCoverage()->collectsBranchAndPathCoverage(), $codeCoverageCacheDirectory, $bootstrap, $this->coverageFiles()); + // @codeCoverageIgnoreEnd + } + $jobResult = JobRunnerRegistry::run(new Job($code, $this->stringifyIni($phpSettings), $environmentVariables, $arguments, $input, \true)); + EventFacade::emitter()->childProcessFinished($jobResult->stdout(), $jobResult->stderr()); + $output = $jobResult->stdout(); + if (CodeCoverage::instance()->isActive()) { + // @codeCoverageIgnoreStart + $coverage = $this->cleanupForCoverage(); + CodeCoverage::instance()->codeCoverage()->start($this->filename, TestSize::Large); + CodeCoverage::instance()->codeCoverage()->append($coverage, $this->filename, \true, TestStatus::Unknown); + // @codeCoverageIgnoreEnd + } + $passed = \true; + try { + $this->assertPhptExpectation($sections, $output); + } catch (AssertionFailedError $e) { + $failure = $e; + if ($xfail !== \false) { + $failure = new IncompleteTestError($xfail, 0, $e); + } elseif ($e instanceof ExpectationFailedException) { + $comparisonFailure = $e->getComparisonFailure(); + if ($comparisonFailure !== null) { + $diff = $comparisonFailure->getDiff(); + } else { + $diff = $e->getMessage(); + } + $hint = $this->locationHintFromDiff($diff, $sections); + $trace = array_merge($hint, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)); + $failure = new PhptAssertionFailedError($e->getMessage(), 0, (string) $trace[0]['file'], (int) $trace[0]['line'], $trace, $comparisonFailure !== null ? $diff : ''); + } + if ($failure instanceof IncompleteTestError) { + $emitter->testMarkedAsIncomplete($this->valueObjectForEvents(), ThrowableBuilder::from($failure)); + } else { + $emitter->testFailed($this->valueObjectForEvents(), ThrowableBuilder::from($failure), null); + } + $passed = \false; + } + if ($passed) { + $emitter->testPassed($this->valueObjectForEvents()); + } + $this->runClean($sections, CodeCoverage::instance()->isActive()); + $emitter->testFinished($this->valueObjectForEvents(), 1); + } + /** + * Returns the name of the test case. + */ + public function getName(): string + { + return $this->toString(); + } + /** + * Returns a string representation of the test case. + */ + public function toString(): string + { + return $this->filename; + } + public function sortId(): string + { + return $this->filename; + } + /** + * @return list + */ + public function provides(): array + { + return []; + } + /** + * @return list + */ + public function requires(): array + { + return []; + } + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function valueObjectForEvents(): Phpt + { + return new Phpt($this->filename); + } + /** + * @param array $sections + * + * @throws ExpectationFailedException + */ + private function assertPhptExpectation(array $sections, string $output): void + { + $assertions = ['EXPECT' => 'assertEquals', 'EXPECTF' => 'assertStringMatchesFormat', 'EXPECTREGEX' => 'assertMatchesRegularExpression']; + $actual = preg_replace('/\r\n/', "\n", trim($output)); + foreach ($assertions as $sectionName => $sectionAssertion) { + if (isset($sections[$sectionName])) { + $sectionContent = preg_replace('/\r\n/', "\n", trim($sections[$sectionName])); + $expected = $sectionName === 'EXPECTREGEX' ? "/{$sectionContent}/" : $sectionContent; + /** @phpstan-ignore staticMethod.dynamicName */ + Assert::$sectionAssertion($expected, $actual); + return; + } + } + } + /** + * @param array $sections + * @param array|non-empty-string> $settings + */ + private function shouldTestBeSkipped(array $sections, array $settings): bool + { + if (!isset($sections['SKIPIF'])) { + return \false; + } + $skipIfCode = (new \PHPUnit\Runner\Phpt\Renderer())->render($this->filename, $sections['SKIPIF']); + if ($this->shouldRunInSubprocess($sections, $skipIfCode)) { + $jobResult = JobRunnerRegistry::run(new Job($skipIfCode, $this->stringifyIni($settings))); + $output = $jobResult->stdout(); + EventFacade::emitter()->childProcessFinished($output, $jobResult->stderr()); + } else { + $output = $this->runCodeInLocalSandbox($skipIfCode); + } + $this->triggerRunnerWarningOnPhpErrors('SKIPIF', $output); + if (strncasecmp('skip', ltrim($output), 4) === 0) { + $message = ''; + if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $skipMatch)) { + $message = substr($skipMatch[1], 2); + } + EventFacade::emitter()->testSkipped($this->valueObjectForEvents(), $message); + EventFacade::emitter()->testFinished($this->valueObjectForEvents(), 0); + return \true; + } + return \false; + } + /** + * @param array $sections + */ + private function shouldRunInSubprocess(array $sections, string $cleanCode): bool + { + if (isset($sections['INI'])) { + // to get per-test INI settings, we need a dedicated subprocess + return \true; + } + $detector = new SideEffectsDetector(); + $sideEffects = $detector->getSideEffects($cleanCode); + if ($sideEffects === []) { + // no side-effects + return \false; + } + foreach ($sideEffects as $sideEffect) { + if ($sideEffect === SideEffect::STANDARD_OUTPUT) { + // stdout is fine, we will catch it using output-buffering + continue; + } + if ($sideEffect === SideEffect::INPUT_OUTPUT) { + // IO is fine, as it doesn't pollute the main process + continue; + } + return \true; + } + return \false; + } + private function runCodeInLocalSandbox(string $code): string + { + $code = preg_replace('/^<\?(?:php)?|\?>\s*+$/', '', $code); + $code = preg_replace('/declare\S?\([^)]+\)\S?;/', '', $code); + // wrap in immediately invoked function to isolate local-side-effects of $code from our own process + $code = '(function() {' . $code . '})();'; + ob_start(); + @eval($code); + return ob_get_clean(); + } + /** + * @param array $sections + */ + private function runClean(array $sections, bool $collectCoverage): void + { + if (!isset($sections['CLEAN'])) { + return; + } + $cleanCode = (new \PHPUnit\Runner\Phpt\Renderer())->render($this->filename, $sections['CLEAN']); + if ($this->shouldRunInSubprocess($sections, $cleanCode)) { + $jobResult = JobRunnerRegistry::run(new Job($cleanCode, $this->settings($collectCoverage))); + $output = $jobResult->stdout(); + EventFacade::emitter()->childProcessFinished($jobResult->stdout(), $jobResult->stderr()); + } else { + $output = $this->runCodeInLocalSandbox($cleanCode); + } + $this->triggerRunnerWarningOnPhpErrors('CLEAN', $output); + } + /** + * @codeCoverageIgnore + * + * @phpstan-ignore return.internalClass + */ + private function cleanupForCoverage(): RawCodeCoverageData + { + /** + * @phpstan-ignore staticMethod.internalClass + */ + $coverage = RawCodeCoverageData::fromXdebugWithoutPathCoverage([]); + $files = $this->coverageFiles(); + $buffer = \false; + if (is_file($files['coverage'])) { + $buffer = @file_get_contents($files['coverage']); + } + if ($buffer !== \false) { + $coverage = @unserialize($buffer, ['allowed_classes' => [ + /** @phpstan-ignore classConstant.internalClass */ + RawCodeCoverageData::class, + ]]); + if ($coverage === \false) { + /** + * @phpstan-ignore staticMethod.internalClass + */ + $coverage = RawCodeCoverageData::fromXdebugWithoutPathCoverage([]); + } + } + foreach ($files as $file) { + @unlink($file); + } + return $coverage; + } + /** + * @return array{coverage: non-empty-string, job: non-empty-string} + */ + private function coverageFiles(): array + { + $baseDir = dirname(realpath($this->filename)) . DIRECTORY_SEPARATOR; + $basename = basename($this->filename, 'phpt'); + return ['coverage' => $baseDir . $basename . 'coverage', 'job' => $baseDir . $basename . 'php']; + } + /** + * @param array|non-empty-string> $ini + * + * @return list + */ + private function stringifyIni(array $ini): array + { + $settings = []; + foreach ($ini as $key => $value) { + if (is_array($value)) { + foreach ($value as $val) { + $settings[] = $key . '=' . $val; + } + continue; + } + $settings[] = $key . '=' . $value; + } + return $settings; + } + /** + * @param array $sections + * + * @return non-empty-list + */ + private function locationHintFromDiff(string $message, array $sections): array + { + $needle = ''; + $previousLine = ''; + $block = 'message'; + foreach (preg_split('/\r\n|\r|\n/', $message) as $line) { + $line = trim($line); + if ($block === 'message' && $line === '--- Expected') { + $block = 'expected'; + } + if ($block === 'expected' && $line === '@@ @@') { + $block = 'diff'; + } + if ($block === 'diff') { + if (str_starts_with($line, '+')) { + $needle = $this->cleanDiffLine($previousLine); + break; + } + if (str_starts_with($line, '-')) { + $needle = $this->cleanDiffLine($line); + break; + } + } + if ($line !== '') { + $previousLine = $line; + } + } + return $this->locationHint($needle, $sections); + } + private function cleanDiffLine(string $line): string + { + if (preg_match('/^[\-+]([\'\"]?)(.*)\1$/', $line, $matches)) { + $line = $matches[2]; + } + return $line; + } + /** + * @param array $sections + * + * @return non-empty-list + */ + private function locationHint(string $needle, array $sections): array + { + $needle = trim($needle); + if ($needle === '') { + return [['file' => realpath($this->filename), 'line' => 1]]; + } + $search = [ + // 'FILE', + 'EXPECT', + 'EXPECTF', + 'EXPECTREGEX', + ]; + foreach ($search as $section) { + if (!isset($sections[$section])) { + continue; + } + if (isset($sections[$section . '_EXTERNAL'])) { + $externalFile = trim($sections[$section . '_EXTERNAL']); + return [['file' => realpath(dirname($this->filename) . DIRECTORY_SEPARATOR . $externalFile), 'line' => 1], ['file' => realpath($this->filename), 'line' => ($sections[$section . '_EXTERNAL_offset'] ?? 0) + 1]]; + } + $sectionOffset = $sections[$section . '_offset'] ?? 0; + $offset = $sectionOffset + 1; + foreach (preg_split('/\r\n|\r|\n/', $sections[$section]) as $line) { + if (str_contains($line, $needle)) { + return [['file' => realpath($this->filename), 'line' => $offset]]; + } + $offset++; + } + } + return [['file' => realpath($this->filename), 'line' => 1]]; + } + /** + * @return list + */ + private function settings(bool $collectCoverage): array + { + $settings = ['allow_url_fopen=1', 'auto_append_file=', 'auto_prepend_file=', 'disable_functions=', 'display_errors=1', 'docref_ext=.html', 'docref_root=', 'error_append_string=', 'error_prepend_string=', 'error_reporting=-1', 'html_errors=0', 'log_errors=0', 'open_basedir=', 'output_buffering=Off', 'output_handler=', 'report_zend_debug=0']; + // @codeCoverageIgnoreStart + if (extension_loaded('pcov')) { + if ($collectCoverage) { + $settings[] = 'pcov.enabled=1'; + } else { + $settings[] = 'pcov.enabled=0'; + } + } + if (extension_loaded('xdebug')) { + if ($collectCoverage) { + $settings[] = 'xdebug.mode=coverage'; + } + } + // @codeCoverageIgnoreEnd + return $settings; + } + private function triggerRunnerWarningOnPhpErrors(string $section, string $output): void + { + if (str_contains($output, 'Parse error:')) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('%s section triggered a parse error: %s', $section, $output)); + } + if (str_contains($output, 'Fatal error:')) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('%s section triggered a fatal error: %s', $section, $output)); + } + } + /** + * @throws CodeCoverageFileExistsException + */ + private function ensureCoverageFileDoesNotExist(): void + { + $files = $this->coverageFiles(); + if (file_exists($files['coverage'])) { + throw new CodeCoverageFileExistsException(sprintf('File %s exists, PHPT test %s will not be executed', $files['coverage'], $this->filename)); + } + } +} +{driverMethod}($__phpunit_filter), + $__phpunit_filter + ); + + if ({codeCoverageCacheDirectory}) { + $__phpunit_coverage->cacheStaticAnalysis({codeCoverageCacheDirectory}); + } + + $__phpunit_coverage->start(__FILE__); +} + +register_shutdown_function( + function() use ($__phpunit_coverage) { + $output = null; + + if ($__phpunit_coverage) { + $output = $__phpunit_coverage->stop(); + } + + file_put_contents('{coverageFile}', serialize($output)); + } +); + +ob_end_clean(); + +require '{job}'; + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use const DIRECTORY_SEPARATOR; +use const LOCK_EX; +use function array_keys; +use function assert; +use function dirname; +use function file_get_contents; +use function file_put_contents; +use function is_array; +use function is_dir; +use function is_file; +use function json_decode; +use function json_encode; +use PHPUnit\Framework\TestStatus\TestStatus; +use PHPUnit\Runner\DirectoryDoesNotExistException; +use PHPUnit\Runner\Exception; +use PHPUnit\Util\Filesystem; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DefaultResultCache implements \PHPUnit\Runner\ResultCache\ResultCache +{ + private const int VERSION = 2; + private const string DEFAULT_RESULT_CACHE_FILENAME = '.phpunit.result.cache'; + private readonly string $cacheFilename; + /** + * @var array + */ + private array $defects = []; + /** + * @var array + */ + private array $times = []; + public function __construct(string $filepath) + { + if (is_dir($filepath)) { + $filepath .= DIRECTORY_SEPARATOR . self::DEFAULT_RESULT_CACHE_FILENAME; + } + $this->cacheFilename = $filepath; + } + public function setStatus(\PHPUnit\Runner\ResultCache\ResultCacheId $id, TestStatus $status): void + { + if ($status->isSuccess()) { + return; + } + $this->defects[$id->asString()] = $status; + } + public function status(\PHPUnit\Runner\ResultCache\ResultCacheId $id): TestStatus + { + return $this->defects[$id->asString()] ?? TestStatus::unknown(); + } + public function setTime(\PHPUnit\Runner\ResultCache\ResultCacheId $id, float $time): void + { + $this->times[$id->asString()] = $time; + } + public function time(\PHPUnit\Runner\ResultCache\ResultCacheId $id): float + { + return $this->times[$id->asString()] ?? 0.0; + } + public function mergeWith(self $other): void + { + foreach ($other->defects as $id => $defect) { + $this->defects[$id] = $defect; + } + foreach ($other->times as $id => $time) { + $this->times[$id] = $time; + } + } + public function load(): void + { + if (!is_file($this->cacheFilename)) { + return; + } + $contents = file_get_contents($this->cacheFilename); + if ($contents === \false) { + return; + } + $data = json_decode($contents, \true); + if ($data === null) { + return; + } + if (!isset($data['version'])) { + return; + } + if ($data['version'] !== self::VERSION) { + return; + } + assert(isset($data['defects']) && is_array($data['defects'])); + assert(isset($data['times']) && is_array($data['times'])); + foreach (array_keys($data['defects']) as $test) { + $data['defects'][$test] = TestStatus::from($data['defects'][$test]); + } + $this->defects = $data['defects']; + $this->times = $data['times']; + } + /** + * @throws Exception + */ + public function persist(): void + { + if (!Filesystem::createDirectory(dirname($this->cacheFilename))) { + throw new DirectoryDoesNotExistException(dirname($this->cacheFilename)); + } + $data = ['version' => self::VERSION, 'defects' => [], 'times' => $this->times]; + foreach ($this->defects as $test => $status) { + $data['defects'][$test] = $status->asInt(); + } + file_put_contents($this->cacheFilename, json_encode($data), LOCK_EX); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Framework\TestStatus\TestStatus; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class NullResultCache implements \PHPUnit\Runner\ResultCache\ResultCache +{ + public function setStatus(\PHPUnit\Runner\ResultCache\ResultCacheId $id, TestStatus $status): void + { + } + public function status(\PHPUnit\Runner\ResultCache\ResultCacheId $id): TestStatus + { + return TestStatus::unknown(); + } + public function setTime(\PHPUnit\Runner\ResultCache\ResultCacheId $id, float $time): void + { + } + public function time(\PHPUnit\Runner\ResultCache\ResultCacheId $id): float + { + return 0; + } + public function load(): void + { + } + public function persist(): void + { + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Framework\TestStatus\TestStatus; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface ResultCache +{ + public function setStatus(\PHPUnit\Runner\ResultCache\ResultCacheId $id, TestStatus $status): void; + public function status(\PHPUnit\Runner\ResultCache\ResultCacheId $id): TestStatus; + public function setTime(\PHPUnit\Runner\ResultCache\ResultCacheId $id, float $time): void; + public function time(\PHPUnit\Runner\ResultCache\ResultCacheId $id): float; + public function load(): void; + public function persist(): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use function round; +use PHPUnit\Event\Event; +use PHPUnit\Event\Facade; +use PHPUnit\Event\Telemetry\HRTime; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Framework\InvalidArgumentException; +use PHPUnit\Framework\TestStatus\TestStatus; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ResultCacheHandler +{ + private readonly \PHPUnit\Runner\ResultCache\ResultCache $cache; + private ?HRTime $time = null; + private int $testSuite = 0; + public function __construct(\PHPUnit\Runner\ResultCache\ResultCache $cache, Facade $facade) + { + $this->cache = $cache; + $this->registerSubscribers($facade); + } + public function testSuiteStarted(): void + { + $this->testSuite++; + } + public function testSuiteFinished(): void + { + $this->testSuite--; + if ($this->testSuite === 0) { + $this->cache->persist(); + } + } + public function testPrepared(Prepared $event): void + { + $this->time = $event->telemetryInfo()->time(); + } + public function testMarkedIncomplete(MarkedIncomplete $event): void + { + $this->cache->setStatus(\PHPUnit\Runner\ResultCache\ResultCacheId::fromTest($event->test()), TestStatus::incomplete($event->throwable()->message())); + } + public function testConsideredRisky(ConsideredRisky $event): void + { + $this->cache->setStatus(\PHPUnit\Runner\ResultCache\ResultCacheId::fromTest($event->test()), TestStatus::risky($event->message())); + } + public function testErrored(Errored $event): void + { + $this->cache->setStatus(\PHPUnit\Runner\ResultCache\ResultCacheId::fromTest($event->test()), TestStatus::error($event->throwable()->message())); + } + public function testFailed(Failed $event): void + { + $this->cache->setStatus(\PHPUnit\Runner\ResultCache\ResultCacheId::fromTest($event->test()), TestStatus::failure($event->throwable()->message())); + } + /** + * @throws \PHPUnit\Event\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function testSkipped(Skipped $event): void + { + $this->cache->setStatus(\PHPUnit\Runner\ResultCache\ResultCacheId::fromTest($event->test()), TestStatus::skipped($event->message())); + $this->cache->setTime(\PHPUnit\Runner\ResultCache\ResultCacheId::fromTest($event->test()), $this->duration($event)); + } + /** + * @throws \PHPUnit\Event\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function testFinished(Finished $event): void + { + $this->cache->setTime(\PHPUnit\Runner\ResultCache\ResultCacheId::fromTest($event->test()), $this->duration($event)); + $this->time = null; + } + /** + * @throws \PHPUnit\Event\InvalidArgumentException + * @throws InvalidArgumentException + */ + private function duration(Event $event): float + { + if ($this->time === null) { + return 0.0; + } + return round($event->telemetryInfo()->time()->duration($this->time)->asFloat(), 3); + } + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers(new \PHPUnit\Runner\ResultCache\TestSuiteStartedSubscriber($this), new \PHPUnit\Runner\ResultCache\TestSuiteFinishedSubscriber($this), new \PHPUnit\Runner\ResultCache\TestPreparedSubscriber($this), new \PHPUnit\Runner\ResultCache\TestMarkedIncompleteSubscriber($this), new \PHPUnit\Runner\ResultCache\TestConsideredRiskySubscriber($this), new \PHPUnit\Runner\ResultCache\TestErroredSubscriber($this), new \PHPUnit\Runner\ResultCache\TestFailedSubscriber($this), new \PHPUnit\Runner\ResultCache\TestSkippedSubscriber($this), new \PHPUnit\Runner\ResultCache\TestFinishedSubscriber($this)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Framework\Reorderable; +use PHPUnit\Framework\TestCase; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ResultCacheId +{ + public static function fromTest(Test $test): self + { + if ($test instanceof TestMethod) { + return new self($test->className() . '::' . $test->name()); + } + return new self($test->id()); + } + public static function fromReorderable(Reorderable $reorderable): self + { + return new self($reorderable->sortId()); + } + /** + * For use in PHPUnit tests only! + * + * @param class-string $class + */ + public static function fromTestClassAndMethodName(string $class, string $methodName): self + { + return new self($class . '::' . $methodName); + } + private function __construct(private string $id) + { + } + public function asString(): string + { + return $this->id; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private \PHPUnit\Runner\ResultCache\ResultCacheHandler $handler; + public function __construct(\PHPUnit\Runner\ResultCache\ResultCacheHandler $handler) + { + $this->handler = $handler; + } + protected function handler(): \PHPUnit\Runner\ResultCache\ResultCacheHandler + { + return $this->handler; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\ConsideredRiskySubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestConsideredRiskySubscriber extends \PHPUnit\Runner\ResultCache\Subscriber implements ConsideredRiskySubscriber +{ + public function notify(ConsideredRisky $event): void + { + $this->handler()->testConsideredRisky($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends \PHPUnit\Runner\ResultCache\Subscriber implements ErroredSubscriber +{ + public function notify(Errored $event): void + { + $this->handler()->testErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends \PHPUnit\Runner\ResultCache\Subscriber implements FailedSubscriber +{ + public function notify(Failed $event): void + { + $this->handler()->testFailed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends \PHPUnit\Runner\ResultCache\Subscriber implements FinishedSubscriber +{ + /** + * @throws \PHPUnit\Framework\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->handler()->testFinished($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends \PHPUnit\Runner\ResultCache\Subscriber implements MarkedIncompleteSubscriber +{ + public function notify(MarkedIncomplete $event): void + { + $this->handler()->testMarkedIncomplete($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends \PHPUnit\Runner\ResultCache\Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->handler()->testPrepared($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends \PHPUnit\Runner\ResultCache\Subscriber implements SkippedSubscriber +{ + /** + * @throws \PHPUnit\Framework\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->handler()->testSkipped($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\TestSuite\Finished; +use PHPUnit\Event\TestSuite\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFinishedSubscriber extends \PHPUnit\Runner\ResultCache\Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->handler()->testSuiteFinished(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\Event\TestSuite\StartedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteStartedSubscriber extends \PHPUnit\Runner\ResultCache\Subscriber implements StartedSubscriber +{ + public function notify(Started $event): void + { + $this->handler()->testSuiteStarted(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use const PHP_EOL; +use function getmypid; +use function register_shutdown_function; +use function rtrim; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ShutdownHandler +{ + private static bool $registered = \false; + private static string $message = ''; + public static function setMessage(string $message): void + { + self::register(); + self::$message = $message; + } + public static function resetMessage(): void + { + self::$message = ''; + } + private static function register(): void + { + if (self::$registered) { + return; + } + self::$registered = \true; + $pid = getmypid(); + register_shutdown_function(static function () use ($pid): void { + $message = rtrim(self::$message); + if ($message === '' || $pid !== getmypid()) { + return; + } + print $message . PHP_EOL; + exit(2); + }); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use function array_values; +use function assert; +use function count; +use function implode; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\AfterLastTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\Skipped as TestSkipped; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\TestRunner\ChildProcessErrored; +use PHPUnit\Event\TestRunner\DeprecationTriggered as TestRunnerDeprecationTriggered; +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Event\TestRunner\NoticeTriggered as TestRunnerNoticeTriggered; +use PHPUnit\Event\TestRunner\WarningTriggered as TestRunnerWarningTriggered; +use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; +use PHPUnit\Event\TestSuite\TestSuiteForTestClass; +use PHPUnit\Event\TestSuite\TestSuiteForTestMethodWithDataProvider; +use PHPUnit\TestRunner\IssueFilter; +use PHPUnit\TestRunner\TestResult\Issues\Issue; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Collector +{ + private readonly IssueFilter $issueFilter; + private int $numberOfTests = 0; + private int $numberOfTestsRun = 0; + private int $numberOfAssertions = 0; + private bool $prepared = \false; + private bool $childProcessErrored = \false; + /** + * @var non-negative-int + */ + private int $numberOfIssuesIgnoredByBaseline = 0; + /** + * @var list + */ + private array $testErroredEvents = []; + /** + * @var list + */ + private array $testFailedEvents = []; + /** + * @var list + */ + private array $testMarkedIncompleteEvents = []; + /** + * @var list + */ + private array $testSuiteSkippedEvents = []; + /** + * @var list + */ + private array $testSkippedEvents = []; + /** + * @var array> + */ + private array $testConsideredRiskyEvents = []; + /** + * @var array> + */ + private array $testTriggeredPhpunitDeprecationEvents = []; + /** + * @var array> + */ + private array $testTriggeredPhpunitErrorEvents = []; + /** + * @var array> + */ + private array $testTriggeredPhpunitNoticeEvents = []; + /** + * @var array> + */ + private array $testTriggeredPhpunitWarningEvents = []; + /** + * @var list + */ + private array $testRunnerTriggeredDeprecationEvents = []; + /** + * @var list + */ + private array $testRunnerTriggeredNoticeEvents = []; + /** + * @var list + */ + private array $testRunnerTriggeredWarningEvents = []; + /** + * @var array + */ + private array $errors = []; + /** + * @var array + */ + private array $deprecations = []; + /** + * @var array + */ + private array $notices = []; + /** + * @var array + */ + private array $warnings = []; + /** + * @var array + */ + private array $phpDeprecations = []; + /** + * @var array + */ + private array $phpNotices = []; + /** + * @var array + */ + private array $phpWarnings = []; + public function __construct(Facade $facade, IssueFilter $issueFilter) + { + $facade->registerSubscribers(new \PHPUnit\TestRunner\TestResult\ExecutionStartedSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestSuiteSkippedSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestSuiteStartedSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestSuiteFinishedSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestPreparedSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestFinishedSubscriber($this), new \PHPUnit\TestRunner\TestResult\BeforeTestClassMethodErroredSubscriber($this), new \PHPUnit\TestRunner\TestResult\BeforeTestClassMethodFailedSubscriber($this), new \PHPUnit\TestRunner\TestResult\AfterTestClassMethodErroredSubscriber($this), new \PHPUnit\TestRunner\TestResult\AfterTestClassMethodFailedSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestErroredSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestFailedSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestMarkedIncompleteSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestSkippedSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestConsideredRiskySubscriber($this), new \PHPUnit\TestRunner\TestResult\TestTriggeredDeprecationSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestTriggeredErrorSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestTriggeredNoticeSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestTriggeredPhpDeprecationSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestTriggeredPhpNoticeSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestTriggeredPhpunitDeprecationSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestTriggeredPhpunitErrorSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestTriggeredPhpunitNoticeSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestTriggeredPhpunitWarningSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestTriggeredPhpWarningSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestTriggeredWarningSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestRunnerTriggeredDeprecationSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestRunnerTriggeredNoticeSubscriber($this), new \PHPUnit\TestRunner\TestResult\TestRunnerTriggeredWarningSubscriber($this), new \PHPUnit\TestRunner\TestResult\ChildProcessErroredSubscriber($this)); + $this->issueFilter = $issueFilter; + } + public function result(): \PHPUnit\TestRunner\TestResult\TestResult + { + return new \PHPUnit\TestRunner\TestResult\TestResult($this->numberOfTests, $this->numberOfTestsRun, $this->numberOfAssertions, $this->testErroredEvents, $this->testFailedEvents, $this->testConsideredRiskyEvents, $this->testSuiteSkippedEvents, $this->testSkippedEvents, $this->testMarkedIncompleteEvents, $this->testTriggeredPhpunitDeprecationEvents, $this->testTriggeredPhpunitErrorEvents, $this->testTriggeredPhpunitNoticeEvents, $this->testTriggeredPhpunitWarningEvents, $this->testRunnerTriggeredDeprecationEvents, $this->testRunnerTriggeredNoticeEvents, $this->testRunnerTriggeredWarningEvents, array_values($this->errors), array_values($this->deprecations), array_values($this->notices), array_values($this->warnings), array_values($this->phpDeprecations), array_values($this->phpNotices), array_values($this->phpWarnings), $this->numberOfIssuesIgnoredByBaseline); + } + public function executionStarted(ExecutionStarted $event): void + { + $this->numberOfTests = $event->testSuite()->count(); + } + public function testSuiteSkipped(TestSuiteSkipped $event): void + { + $testSuite = $event->testSuite(); + if (!$testSuite->isForTestClass()) { + return; + } + $this->testSuiteSkippedEvents[] = $event; + $this->numberOfTestsRun += $event->testSuite()->count(); + } + public function testSuiteStarted(TestSuiteStarted $event): void + { + $testSuite = $event->testSuite(); + if (!$testSuite->isForTestClass()) { + return; + } + } + public function testSuiteFinished(TestSuiteFinished $event): void + { + $testSuite = $event->testSuite(); + if ($testSuite->isWithName()) { + return; + } + if ($testSuite->isForTestMethodWithDataProvider()) { + assert($testSuite instanceof TestSuiteForTestMethodWithDataProvider); + assert(count($testSuite->tests()->asArray()) > 0); + $test = $testSuite->tests()->asArray()[0]; + assert($test instanceof TestMethod); + foreach ($this->testFailedEvents as $testFailedEvent) { + if ($testFailedEvent instanceof AfterLastTestMethodFailed || $testFailedEvent instanceof BeforeFirstTestMethodFailed) { + continue; + } + if ($testFailedEvent->test()->isTestMethod() && $testFailedEvent->test()->methodName() === $test->methodName()) { + return; + } + } + \PHPUnit\TestRunner\TestResult\PassedTests::instance()->testMethodPassed($test, null); + return; + } + assert($testSuite instanceof TestSuiteForTestClass); + \PHPUnit\TestRunner\TestResult\PassedTests::instance()->testClassPassed($testSuite->className()); + } + public function testPrepared(): void + { + $this->prepared = \true; + } + public function testFinished(Finished $event): void + { + $this->numberOfAssertions += $event->numberOfAssertionsPerformed(); + $this->numberOfTestsRun++; + $this->prepared = \false; + $this->childProcessErrored = \false; + } + public function beforeTestClassMethodErrored(BeforeFirstTestMethodErrored $event): void + { + $this->testErroredEvents[] = $event; + $this->numberOfTestsRun++; + } + public function beforeTestClassMethodFailed(BeforeFirstTestMethodFailed $event): void + { + $this->testFailedEvents[] = $event; + $this->numberOfTestsRun++; + } + public function afterTestClassMethodErrored(AfterLastTestMethodErrored $event): void + { + $this->testErroredEvents[] = $event; + } + public function afterTestClassMethodFailed(AfterLastTestMethodFailed $event): void + { + $this->testFailedEvents[] = $event; + } + public function testErrored(Errored $event): void + { + $this->testErroredEvents[] = $event; + if ($this->childProcessErrored) { + return; + } + if (!$this->prepared) { + $this->numberOfTestsRun++; + } + } + public function testFailed(Failed $event): void + { + $this->testFailedEvents[] = $event; + } + public function testMarkedIncomplete(MarkedIncomplete $event): void + { + $this->testMarkedIncompleteEvents[] = $event; + } + public function testSkipped(TestSkipped $event): void + { + $this->testSkippedEvents[] = $event; + if (!$this->prepared) { + $this->numberOfTestsRun++; + } + } + public function testConsideredRisky(ConsideredRisky $event): void + { + if (!isset($this->testConsideredRiskyEvents[$event->test()->id()])) { + $this->testConsideredRiskyEvents[$event->test()->id()] = []; + } + $this->testConsideredRiskyEvents[$event->test()->id()][] = $event; + } + public function testTriggeredDeprecation(DeprecationTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + return; + } + $id = $this->issueId($event); + if (!isset($this->deprecations[$id])) { + $this->deprecations[$id] = Issue::from($event->file(), $event->line(), $event->message(), $event->test(), $event->stackTrace()); + return; + } + $this->deprecations[$id]->triggeredBy($event->test()); + } + public function testTriggeredPhpDeprecation(PhpDeprecationTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + return; + } + $id = $this->issueId($event); + if (!isset($this->phpDeprecations[$id])) { + $this->phpDeprecations[$id] = Issue::from($event->file(), $event->line(), $event->message(), $event->test()); + return; + } + $this->phpDeprecations[$id]->triggeredBy($event->test()); + } + public function testTriggeredPhpunitDeprecation(PhpunitDeprecationTriggered $event): void + { + if (!isset($this->testTriggeredPhpunitDeprecationEvents[$event->test()->id()])) { + $this->testTriggeredPhpunitDeprecationEvents[$event->test()->id()] = []; + } + $this->testTriggeredPhpunitDeprecationEvents[$event->test()->id()][] = $event; + } + public function testTriggeredPhpunitNotice(PhpunitNoticeTriggered $event): void + { + if (!isset($this->testTriggeredPhpunitNoticeEvents[$event->test()->id()])) { + $this->testTriggeredPhpunitNoticeEvents[$event->test()->id()] = []; + } + $this->testTriggeredPhpunitNoticeEvents[$event->test()->id()][] = $event; + } + public function testTriggeredError(ErrorTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + $id = $this->issueId($event); + if (!isset($this->errors[$id])) { + $this->errors[$id] = Issue::from($event->file(), $event->line(), $event->message(), $event->test()); + return; + } + $this->errors[$id]->triggeredBy($event->test()); + } + public function testTriggeredNotice(NoticeTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + return; + } + $id = $this->issueId($event); + if (!isset($this->notices[$id])) { + $this->notices[$id] = Issue::from($event->file(), $event->line(), $event->message(), $event->test()); + return; + } + $this->notices[$id]->triggeredBy($event->test()); + } + public function testTriggeredPhpNotice(PhpNoticeTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + return; + } + $id = $this->issueId($event); + if (!isset($this->phpNotices[$id])) { + $this->phpNotices[$id] = Issue::from($event->file(), $event->line(), $event->message(), $event->test()); + return; + } + $this->phpNotices[$id]->triggeredBy($event->test()); + } + public function testTriggeredWarning(WarningTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + return; + } + $id = $this->issueId($event); + if (!isset($this->warnings[$id])) { + $this->warnings[$id] = Issue::from($event->file(), $event->line(), $event->message(), $event->test()); + return; + } + $this->warnings[$id]->triggeredBy($event->test()); + } + public function testTriggeredPhpWarning(PhpWarningTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + return; + } + $id = $this->issueId($event); + if (!isset($this->phpWarnings[$id])) { + $this->phpWarnings[$id] = Issue::from($event->file(), $event->line(), $event->message(), $event->test()); + return; + } + $this->phpWarnings[$id]->triggeredBy($event->test()); + } + public function testTriggeredPhpunitError(PhpunitErrorTriggered $event): void + { + if (!isset($this->testTriggeredPhpunitErrorEvents[$event->test()->id()])) { + $this->testTriggeredPhpunitErrorEvents[$event->test()->id()] = []; + } + $this->testTriggeredPhpunitErrorEvents[$event->test()->id()][] = $event; + } + public function testTriggeredPhpunitWarning(PhpunitWarningTriggered $event): void + { + if ($event->ignoredByTest()) { + return; + } + if (!isset($this->testTriggeredPhpunitWarningEvents[$event->test()->id()])) { + $this->testTriggeredPhpunitWarningEvents[$event->test()->id()] = []; + } + $this->testTriggeredPhpunitWarningEvents[$event->test()->id()][] = $event; + } + public function testRunnerTriggeredDeprecation(TestRunnerDeprecationTriggered $event): void + { + $this->testRunnerTriggeredDeprecationEvents[] = $event; + } + public function testRunnerTriggeredNotice(TestRunnerNoticeTriggered $event): void + { + $this->testRunnerTriggeredNoticeEvents[] = $event; + } + public function testRunnerTriggeredWarning(TestRunnerWarningTriggered $event): void + { + $this->testRunnerTriggeredWarningEvents[] = $event; + } + public function childProcessErrored(ChildProcessErrored $event): void + { + $this->childProcessErrored = \true; + } + public function hasErroredTests(): bool + { + return $this->testErroredEvents !== []; + } + public function hasFailedTests(): bool + { + return $this->testFailedEvents !== []; + } + public function hasRiskyTests(): bool + { + return $this->testConsideredRiskyEvents !== []; + } + public function hasSkippedTests(): bool + { + return $this->testSkippedEvents !== []; + } + public function hasIncompleteTests(): bool + { + return $this->testMarkedIncompleteEvents !== []; + } + public function hasDeprecations(): bool + { + return $this->deprecations !== [] || $this->phpDeprecations !== [] || $this->testTriggeredPhpunitDeprecationEvents !== [] || $this->testRunnerTriggeredDeprecationEvents !== []; + } + public function hasNotices(): bool + { + return $this->notices !== [] || $this->phpNotices !== []; + } + public function hasWarnings(): bool + { + return $this->warnings !== [] || $this->phpWarnings !== [] || $this->testTriggeredPhpunitWarningEvents !== [] || $this->testRunnerTriggeredWarningEvents !== []; + } + /** + * @return non-empty-string + */ + private function issueId(DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event): string + { + return implode(':', [$event->file(), $event->line(), $event->message()]); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use function array_any; +use function str_contains; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollectorFacade; +use PHPUnit\TestRunner\IssueFilter; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Facade +{ + private static ?\PHPUnit\TestRunner\TestResult\Collector $collector = null; + public static function init(): void + { + self::collector(); + } + public static function result(): \PHPUnit\TestRunner\TestResult\TestResult + { + return self::collector()->result(); + } + public static function shouldStop(): bool + { + $configuration = ConfigurationRegistry::get(); + $collector = self::collector(); + if (($configuration->stopOnDefect() || $configuration->stopOnError()) && $collector->hasErroredTests()) { + return \true; + } + if (($configuration->stopOnDefect() || $configuration->stopOnFailure()) && $collector->hasFailedTests()) { + return \true; + } + if (($configuration->stopOnDefect() || $configuration->stopOnWarning()) && $collector->hasWarnings()) { + return \true; + } + if (($configuration->stopOnDefect() || $configuration->stopOnRisky()) && $collector->hasRiskyTests()) { + return \true; + } + if (self::stopOnDeprecation($configuration)) { + return \true; + } + if ($configuration->stopOnNotice() && $collector->hasNotices()) { + return \true; + } + if ($configuration->stopOnIncomplete() && $collector->hasIncompleteTests()) { + return \true; + } + if ($configuration->stopOnSkipped() && $collector->hasSkippedTests()) { + return \true; + } + return \false; + } + private static function collector(): \PHPUnit\TestRunner\TestResult\Collector + { + if (self::$collector === null) { + $configuration = ConfigurationRegistry::get(); + self::$collector = new \PHPUnit\TestRunner\TestResult\Collector(EventFacade::instance(), new IssueFilter($configuration->source())); + } + return self::$collector; + } + private static function stopOnDeprecation(Configuration $configuration): bool + { + if (!$configuration->stopOnDeprecation()) { + return \false; + } + $deprecations = DeprecationCollectorFacade::filteredDeprecations(); + if (!$configuration->hasSpecificDeprecationToStopOn()) { + return $deprecations !== []; + } + return array_any($deprecations, static fn(string $deprecation) => str_contains($deprecation, $configuration->specificDeprecationToStopOn())); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult\Issues; + +use function array_keys; +use function count; +use PHPUnit\Event\Code\Test; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Issue +{ + /** + * @var non-empty-string + */ + private readonly string $file; + /** + * @var positive-int + */ + private readonly int $line; + /** + * @var non-empty-string + */ + private readonly string $description; + /** + * @var non-empty-array + */ + private array $triggeringTests; + /** + * @var ?non-empty-string + */ + private ?string $stackTrace; + /** + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $description + */ + public static function from(string $file, int $line, string $description, Test $triggeringTest, ?string $stackTrace = null): self + { + return new self($file, $line, $description, $triggeringTest, $stackTrace); + } + /** + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $description + */ + private function __construct(string $file, int $line, string $description, Test $triggeringTest, ?string $stackTrace) + { + $this->file = $file; + $this->line = $line; + $this->description = $description; + $this->stackTrace = $stackTrace; + $this->triggeringTests = [$triggeringTest->id() => ['test' => $triggeringTest, 'count' => 1]]; + } + public function triggeredBy(Test $test): void + { + if (isset($this->triggeringTests[$test->id()])) { + $this->triggeringTests[$test->id()]['count']++; + return; + } + $this->triggeringTests[$test->id()] = ['test' => $test, 'count' => 1]; + } + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + /** + * @return non-empty-string + */ + public function description(): string + { + return $this->description; + } + /** + * @return non-empty-array + */ + public function triggeringTests(): array + { + return $this->triggeringTests; + } + /** + * @phpstan-assert-if-true !null $this->stackTrace + */ + public function hasStackTrace(): bool + { + return $this->stackTrace !== null; + } + /** + * @return ?non-empty-string + */ + public function stackTrace(): ?string + { + return $this->stackTrace; + } + public function triggeredInTest(): bool + { + return count($this->triggeringTests) === 1 && $this->file === $this->triggeringTests[array_keys($this->triggeringTests)[0]]['test']->file(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use function array_merge; +use function assert; +use function explode; +use function in_array; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Framework\TestSize\Known; +use PHPUnit\Framework\TestSize\TestSize; +use PHPUnit\Metadata\Api\Groups; +use ReflectionMethod; +use ReflectionNamedType; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class PassedTests +{ + private static ?self $instance = null; + /** + * @var list + */ + private array $passedTestClasses = []; + /** + * @var array + */ + private array $passedTestMethods = []; + public static function instance(): self + { + if (self::$instance !== null) { + return self::$instance; + } + self::$instance = new self(); + return self::$instance; + } + /** + * @param class-string $className + */ + public function testClassPassed(string $className): void + { + $this->passedTestClasses[] = $className; + } + public function testMethodPassed(TestMethod $test, mixed $returnValue): void + { + $size = (new Groups())->size($test->className(), $test->methodName()); + $this->passedTestMethods[$test->className() . '::' . $test->methodName()] = ['returnValue' => $returnValue, 'size' => $size]; + } + public function import(self $other): void + { + $this->passedTestClasses = array_merge($this->passedTestClasses, $other->passedTestClasses); + $this->passedTestMethods = array_merge($this->passedTestMethods, $other->passedTestMethods); + } + /** + * @param class-string $className + */ + public function hasTestClassPassed(string $className): bool + { + return in_array($className, $this->passedTestClasses, \true); + } + public function hasTestMethodPassed(string $method): bool + { + return isset($this->passedTestMethods[$method]); + } + public function isGreaterThan(string $method, TestSize $other): bool + { + if ($other->isUnknown()) { + return \false; + } + assert($other instanceof Known); + $size = $this->passedTestMethods[$method]['size']; + if ($size->isUnknown()) { + return \false; + } + assert($size instanceof Known); + return $size->isGreaterThan($other); + } + public function hasReturnValue(string $method): bool + { + $returnType = (new ReflectionMethod(...explode('::', $method)))->getReturnType(); + return !$returnType instanceof ReflectionNamedType || !in_array($returnType->getName(), ['never', 'void'], \true); + } + public function returnValue(string $method): mixed + { + if (isset($this->passedTestMethods[$method])) { + return $this->passedTestMethods[$method]['returnValue']; + } + return null; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\AfterLastTestMethodErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestClassMethodErroredSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements AfterLastTestMethodErroredSubscriber +{ + public function notify(AfterLastTestMethodErrored $event): void + { + $this->collector()->afterTestClassMethodErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\AfterLastTestMethodFailed; +use PHPUnit\Event\Test\AfterLastTestMethodFailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestClassMethodFailedSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements AfterLastTestMethodFailedSubscriber +{ + public function notify(AfterLastTestMethodFailed $event): void + { + $this->collector()->afterTestClassMethodFailed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestClassMethodErroredSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements BeforeFirstTestMethodErroredSubscriber +{ + public function notify(BeforeFirstTestMethodErrored $event): void + { + $this->collector()->beforeTestClassMethodErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestClassMethodFailedSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements BeforeFirstTestMethodFailedSubscriber +{ + public function notify(BeforeFirstTestMethodFailed $event): void + { + $this->collector()->beforeTestClassMethodFailed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestRunner\ChildProcessErrored; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessErroredSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements \PHPUnit\Event\TestRunner\ChildProcessErroredSubscriber +{ + public function notify(ChildProcessErrored $event): void + { + $this->collector()->childProcessErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber as TestRunnerExecutionStartedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionStartedSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements TestRunnerExecutionStartedSubscriber +{ + public function notify(ExecutionStarted $event): void + { + $this->collector()->executionStarted($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private \PHPUnit\TestRunner\TestResult\Collector $collector; + public function __construct(\PHPUnit\TestRunner\TestResult\Collector $collector) + { + $this->collector = $collector; + } + protected function collector(): \PHPUnit\TestRunner\TestResult\Collector + { + return $this->collector; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\ConsideredRiskySubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestConsideredRiskySubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements ConsideredRiskySubscriber +{ + public function notify(ConsideredRisky $event): void + { + $this->collector()->testConsideredRisky($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements ErroredSubscriber +{ + public function notify(Errored $event): void + { + $this->collector()->testErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements FailedSubscriber +{ + public function notify(Failed $event): void + { + $this->collector()->testFailed($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->collector()->testFinished($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements MarkedIncompleteSubscriber +{ + public function notify(MarkedIncomplete $event): void + { + $this->collector()->testMarkedIncomplete($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->collector()->testPrepared(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestRunner\DeprecationTriggered; +use PHPUnit\Event\TestRunner\DeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerTriggeredDeprecationSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements DeprecationTriggeredSubscriber +{ + public function notify(DeprecationTriggered $event): void + { + $this->collector()->testRunnerTriggeredDeprecation($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestRunner\NoticeTriggered; +use PHPUnit\Event\TestRunner\NoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerTriggeredNoticeSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements NoticeTriggeredSubscriber +{ + public function notify(NoticeTriggered $event): void + { + $this->collector()->testRunnerTriggeredNotice($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestRunner\WarningTriggered; +use PHPUnit\Event\TestRunner\WarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerTriggeredWarningSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements WarningTriggeredSubscriber +{ + public function notify(WarningTriggered $event): void + { + $this->collector()->testRunnerTriggeredWarning($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements SkippedSubscriber +{ + public function notify(Skipped $event): void + { + $this->collector()->testSkipped($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestSuite\Finished; +use PHPUnit\Event\TestSuite\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFinishedSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->collector()->testSuiteFinished($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestSuite\Skipped; +use PHPUnit\Event\TestSuite\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteSkippedSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements SkippedSubscriber +{ + public function notify(Skipped $event): void + { + $this->collector()->testSuiteSkipped($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\Event\TestSuite\StartedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteStartedSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements StartedSubscriber +{ + public function notify(Started $event): void + { + $this->collector()->testSuiteStarted($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredDeprecationSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements DeprecationTriggeredSubscriber +{ + public function notify(DeprecationTriggered $event): void + { + $this->collector()->testTriggeredDeprecation($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\ErrorTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredErrorSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements ErrorTriggeredSubscriber +{ + public function notify(ErrorTriggered $event): void + { + $this->collector()->testTriggeredError($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\NoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredNoticeSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements NoticeTriggeredSubscriber +{ + public function notify(NoticeTriggered $event): void + { + $this->collector()->testTriggeredNotice($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpDeprecationSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements PhpDeprecationTriggeredSubscriber +{ + public function notify(PhpDeprecationTriggered $event): void + { + $this->collector()->testTriggeredPhpDeprecation($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpNoticeSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements PhpNoticeTriggeredSubscriber +{ + public function notify(PhpNoticeTriggered $event): void + { + $this->collector()->testTriggeredPhpNotice($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpWarningSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements PhpWarningTriggeredSubscriber +{ + public function notify(PhpWarningTriggered $event): void + { + $this->collector()->testTriggeredPhpWarning($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitDeprecationSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements PhpunitDeprecationTriggeredSubscriber +{ + public function notify(PhpunitDeprecationTriggered $event): void + { + $this->collector()->testTriggeredPhpunitDeprecation($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitErrorSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements PhpunitErrorTriggeredSubscriber +{ + public function notify(PhpunitErrorTriggered $event): void + { + $this->collector()->testTriggeredPhpunitError($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitNoticeSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements PhpunitNoticeTriggeredSubscriber +{ + public function notify(PhpunitNoticeTriggered $event): void + { + $this->collector()->testTriggeredPhpunitNotice($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitWarningSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements PhpunitWarningTriggeredSubscriber +{ + public function notify(PhpunitWarningTriggered $event): void + { + $this->collector()->testTriggeredPhpunitWarning($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\Test\WarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredWarningSubscriber extends \PHPUnit\TestRunner\TestResult\Subscriber implements WarningTriggeredSubscriber +{ + public function notify(WarningTriggered $event): void + { + $this->collector()->testTriggeredWarning($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use function array_map; +use function array_sum; +use function count; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\AfterLastTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\Skipped as TestSkipped; +use PHPUnit\Event\TestRunner\DeprecationTriggered as TestRunnerDeprecationTriggered; +use PHPUnit\Event\TestRunner\NoticeTriggered as TestRunnerNoticeTriggered; +use PHPUnit\Event\TestRunner\WarningTriggered as TestRunnerWarningTriggered; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\TestRunner\TestResult\Issues\Issue; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestResult +{ + private int $numberOfTests; + private int $numberOfTestsRun; + private int $numberOfAssertions; + /** + * @var list + */ + private array $testErroredEvents; + /** + * @var list + */ + private array $testFailedEvents; + /** + * @var list + */ + private array $testMarkedIncompleteEvents; + /** + * @var list + */ + private array $testSuiteSkippedEvents; + /** + * @var list + */ + private array $testSkippedEvents; + /** + * @var array> + */ + private array $testConsideredRiskyEvents; + /** + * @var array> + */ + private array $testTriggeredPhpunitDeprecationEvents; + /** + * @var array> + */ + private array $testTriggeredPhpunitErrorEvents; + /** + * @var array> + */ + private array $testTriggeredPhpunitNoticeEvents; + /** + * @var array> + */ + private array $testTriggeredPhpunitWarningEvents; + /** + * @var list + */ + private array $testRunnerTriggeredDeprecationEvents; + /** + * @var list + */ + private array $testRunnerTriggeredNoticeEvents; + /** + * @var list + */ + private array $testRunnerTriggeredWarningEvents; + /** + * @var list + */ + private array $errors; + /** + * @var list + */ + private array $deprecations; + /** + * @var list + */ + private array $notices; + /** + * @var list + */ + private array $warnings; + /** + * @var list + */ + private array $phpDeprecations; + /** + * @var list + */ + private array $phpNotices; + /** + * @var list + */ + private array $phpWarnings; + /** + * @var non-negative-int + */ + private int $numberOfIssuesIgnoredByBaseline; + /** + * @param list $testErroredEvents + * @param list $testFailedEvents + * @param array> $testConsideredRiskyEvents + * @param list $testSuiteSkippedEvents + * @param list $testSkippedEvents + * @param list $testMarkedIncompleteEvents + * @param array> $testTriggeredPhpunitDeprecationEvents + * @param array> $testTriggeredPhpunitErrorEvents + * @param array> $testTriggeredPhpunitNoticeEvents + * @param array> $testTriggeredPhpunitWarningEvents + * @param list $testRunnerTriggeredDeprecationEvents + * @param list $testRunnerTriggeredNoticeEvents + * @param list $testRunnerTriggeredWarningEvents + * @param list $errors + * @param list $deprecations + * @param list $notices + * @param list $warnings + * @param list $phpDeprecations + * @param list $phpNotices + * @param list $phpWarnings + * @param non-negative-int $numberOfIssuesIgnoredByBaseline + */ + public function __construct(int $numberOfTests, int $numberOfTestsRun, int $numberOfAssertions, array $testErroredEvents, array $testFailedEvents, array $testConsideredRiskyEvents, array $testSuiteSkippedEvents, array $testSkippedEvents, array $testMarkedIncompleteEvents, array $testTriggeredPhpunitDeprecationEvents, array $testTriggeredPhpunitErrorEvents, array $testTriggeredPhpunitNoticeEvents, array $testTriggeredPhpunitWarningEvents, array $testRunnerTriggeredDeprecationEvents, array $testRunnerTriggeredNoticeEvents, array $testRunnerTriggeredWarningEvents, array $errors, array $deprecations, array $notices, array $warnings, array $phpDeprecations, array $phpNotices, array $phpWarnings, int $numberOfIssuesIgnoredByBaseline) + { + $this->numberOfTests = $numberOfTests; + $this->numberOfTestsRun = $numberOfTestsRun; + $this->numberOfAssertions = $numberOfAssertions; + $this->testErroredEvents = $testErroredEvents; + $this->testFailedEvents = $testFailedEvents; + $this->testConsideredRiskyEvents = $testConsideredRiskyEvents; + $this->testSuiteSkippedEvents = $testSuiteSkippedEvents; + $this->testSkippedEvents = $testSkippedEvents; + $this->testMarkedIncompleteEvents = $testMarkedIncompleteEvents; + $this->testTriggeredPhpunitDeprecationEvents = $testTriggeredPhpunitDeprecationEvents; + $this->testTriggeredPhpunitErrorEvents = $testTriggeredPhpunitErrorEvents; + $this->testTriggeredPhpunitNoticeEvents = $testTriggeredPhpunitNoticeEvents; + $this->testTriggeredPhpunitWarningEvents = $testTriggeredPhpunitWarningEvents; + $this->testRunnerTriggeredDeprecationEvents = $testRunnerTriggeredDeprecationEvents; + $this->testRunnerTriggeredNoticeEvents = $testRunnerTriggeredNoticeEvents; + $this->testRunnerTriggeredWarningEvents = $testRunnerTriggeredWarningEvents; + $this->errors = $errors; + $this->deprecations = $deprecations; + $this->notices = $notices; + $this->warnings = $warnings; + $this->phpDeprecations = $phpDeprecations; + $this->phpNotices = $phpNotices; + $this->phpWarnings = $phpWarnings; + $this->numberOfIssuesIgnoredByBaseline = $numberOfIssuesIgnoredByBaseline; + } + public function numberOfTestsRun(): int + { + return $this->numberOfTestsRun; + } + public function numberOfAssertions(): int + { + return $this->numberOfAssertions; + } + /** + * @return list + */ + public function testErroredEvents(): array + { + return $this->testErroredEvents; + } + public function numberOfTestErroredEvents(): int + { + return count($this->testErroredEvents); + } + public function hasTestErroredEvents(): bool + { + return $this->numberOfTestErroredEvents() > 0; + } + /** + * @return list + */ + public function testFailedEvents(): array + { + return $this->testFailedEvents; + } + public function numberOfTestFailedEvents(): int + { + return count($this->testFailedEvents); + } + public function hasTestFailedEvents(): bool + { + return $this->numberOfTestFailedEvents() > 0; + } + /** + * @return array> + */ + public function testConsideredRiskyEvents(): array + { + return $this->testConsideredRiskyEvents; + } + public function numberOfTestsWithTestConsideredRiskyEvents(): int + { + return count($this->testConsideredRiskyEvents); + } + public function hasTestConsideredRiskyEvents(): bool + { + return $this->numberOfTestsWithTestConsideredRiskyEvents() > 0; + } + /** + * @return list + */ + public function testSuiteSkippedEvents(): array + { + return $this->testSuiteSkippedEvents; + } + public function numberOfTestSkippedByTestSuiteSkippedEvents(): int + { + return array_sum(array_map(static fn(TestSuiteSkipped $event): int => $event->testSuite()->count(), $this->testSuiteSkippedEvents)); + } + public function hasTestSuiteSkippedEvents(): bool + { + return $this->numberOfTestSkippedByTestSuiteSkippedEvents() > 0; + } + /** + * @return list + */ + public function testSkippedEvents(): array + { + return $this->testSkippedEvents; + } + public function numberOfTestSkippedEvents(): int + { + return count($this->testSkippedEvents); + } + public function hasTestSkippedEvents(): bool + { + return $this->numberOfTestSkippedEvents() > 0; + } + /** + * @return list + */ + public function testMarkedIncompleteEvents(): array + { + return $this->testMarkedIncompleteEvents; + } + public function numberOfTestMarkedIncompleteEvents(): int + { + return count($this->testMarkedIncompleteEvents); + } + public function hasTestMarkedIncompleteEvents(): bool + { + return $this->numberOfTestMarkedIncompleteEvents() > 0; + } + /** + * @return array> + */ + public function testTriggeredPhpunitDeprecationEvents(): array + { + return $this->testTriggeredPhpunitDeprecationEvents; + } + public function numberOfTestsWithTestTriggeredPhpunitDeprecationEvents(): int + { + return count($this->testTriggeredPhpunitDeprecationEvents); + } + public function hasTestTriggeredPhpunitDeprecationEvents(): bool + { + return $this->numberOfTestsWithTestTriggeredPhpunitDeprecationEvents() > 0; + } + /** + * @return array> + */ + public function testTriggeredPhpunitErrorEvents(): array + { + return $this->testTriggeredPhpunitErrorEvents; + } + public function numberOfTestsWithTestTriggeredPhpunitErrorEvents(): int + { + return count($this->testTriggeredPhpunitErrorEvents); + } + public function hasTestTriggeredPhpunitErrorEvents(): bool + { + return $this->numberOfTestsWithTestTriggeredPhpunitErrorEvents() > 0; + } + /** + * @return array> + */ + public function testTriggeredPhpunitNoticeEvents(): array + { + return $this->testTriggeredPhpunitNoticeEvents; + } + public function numberOfTestsWithTestTriggeredPhpunitNoticeEvents(): int + { + return count($this->testTriggeredPhpunitNoticeEvents); + } + public function hasTestTriggeredPhpunitNoticeEvents(): bool + { + return $this->numberOfTestsWithTestTriggeredPhpunitNoticeEvents() > 0; + } + /** + * @return array> + */ + public function testTriggeredPhpunitWarningEvents(): array + { + return $this->testTriggeredPhpunitWarningEvents; + } + public function numberOfTestsWithTestTriggeredPhpunitWarningEvents(): int + { + return count($this->testTriggeredPhpunitWarningEvents); + } + public function hasTestTriggeredPhpunitWarningEvents(): bool + { + return $this->numberOfTestsWithTestTriggeredPhpunitWarningEvents() > 0; + } + /** + * @return list + */ + public function testRunnerTriggeredDeprecationEvents(): array + { + return $this->testRunnerTriggeredDeprecationEvents; + } + public function numberOfTestRunnerTriggeredDeprecationEvents(): int + { + return count($this->testRunnerTriggeredDeprecationEvents); + } + public function hasTestRunnerTriggeredDeprecationEvents(): bool + { + return $this->numberOfTestRunnerTriggeredDeprecationEvents() > 0; + } + /** + * @return list + */ + public function testRunnerTriggeredNoticeEvents(): array + { + return $this->testRunnerTriggeredNoticeEvents; + } + public function numberOfTestRunnerTriggeredNoticeEvents(): int + { + return count($this->testRunnerTriggeredNoticeEvents); + } + public function hasTestRunnerTriggeredNoticeEvents(): bool + { + return $this->numberOfTestRunnerTriggeredNoticeEvents() > 0; + } + /** + * @return list + */ + public function testRunnerTriggeredWarningEvents(): array + { + return $this->testRunnerTriggeredWarningEvents; + } + public function numberOfTestRunnerTriggeredWarningEvents(): int + { + return count($this->testRunnerTriggeredWarningEvents); + } + public function hasTestRunnerTriggeredWarningEvents(): bool + { + return $this->numberOfTestRunnerTriggeredWarningEvents() > 0; + } + public function wasSuccessful(): bool + { + return !$this->hasTestErroredEvents() && !$this->hasTestFailedEvents() && !$this->hasTestTriggeredPhpunitErrorEvents(); + } + public function hasIssues(): bool + { + return $this->hasTestsWithIssues() || $this->hasTestRunnerTriggeredWarningEvents(); + } + public function hasTestsWithIssues(): bool + { + return $this->hasRiskyTests() || $this->hasIncompleteTests() || $this->hasDeprecations() || $this->errors !== [] || $this->hasNotices() || $this->hasWarnings() || $this->hasPhpunitNotices() || $this->hasPhpunitWarnings(); + } + /** + * @return list + */ + public function errors(): array + { + return $this->errors; + } + /** + * @return list + */ + public function deprecations(): array + { + return $this->deprecations; + } + /** + * @return list + */ + public function notices(): array + { + return $this->notices; + } + /** + * @return list + */ + public function warnings(): array + { + return $this->warnings; + } + /** + * @return list + */ + public function phpDeprecations(): array + { + return $this->phpDeprecations; + } + /** + * @return list + */ + public function phpNotices(): array + { + return $this->phpNotices; + } + /** + * @return list + */ + public function phpWarnings(): array + { + return $this->phpWarnings; + } + public function hasTests(): bool + { + return $this->numberOfTests > 0; + } + public function hasErrors(): bool + { + return $this->numberOfErrors() > 0; + } + public function numberOfErrors(): int + { + return $this->numberOfTestErroredEvents() + count($this->errors) + $this->numberOfTestsWithTestTriggeredPhpunitErrorEvents(); + } + public function hasDeprecations(): bool + { + return $this->numberOfDeprecations() > 0; + } + public function hasPhpOrUserDeprecations(): bool + { + return $this->numberOfPhpOrUserDeprecations() > 0; + } + public function numberOfPhpOrUserDeprecations(): int + { + return count($this->deprecations) + count($this->phpDeprecations); + } + public function hasPhpunitDeprecations(): bool + { + return $this->numberOfPhpunitDeprecations() > 0; + } + public function numberOfPhpunitDeprecations(): int + { + return count($this->testTriggeredPhpunitDeprecationEvents) + count($this->testRunnerTriggeredDeprecationEvents); + } + public function hasPhpunitWarnings(): bool + { + return $this->numberOfPhpunitWarnings() > 0; + } + public function numberOfPhpunitWarnings(): int + { + return count($this->testTriggeredPhpunitWarningEvents) + count($this->testRunnerTriggeredWarningEvents); + } + public function numberOfDeprecations(): int + { + return count($this->deprecations) + count($this->phpDeprecations) + count($this->testTriggeredPhpunitDeprecationEvents) + count($this->testRunnerTriggeredDeprecationEvents); + } + public function hasNotices(): bool + { + return $this->numberOfNotices() > 0; + } + public function numberOfNotices(): int + { + return count($this->notices) + count($this->phpNotices); + } + public function hasWarnings(): bool + { + return $this->numberOfWarnings() > 0; + } + public function numberOfWarnings(): int + { + return count($this->warnings) + count($this->phpWarnings); + } + public function hasIncompleteTests(): bool + { + return $this->testMarkedIncompleteEvents !== []; + } + public function hasRiskyTests(): bool + { + return $this->testConsideredRiskyEvents !== []; + } + public function hasSkippedTests(): bool + { + return $this->testSkippedEvents !== []; + } + public function hasIssuesIgnoredByBaseline(): bool + { + return $this->numberOfIssuesIgnoredByBaseline > 0; + } + /** + * @return non-negative-int + */ + public function numberOfIssuesIgnoredByBaseline(): int + { + return $this->numberOfIssuesIgnoredByBaseline; + } + public function hasPhpunitNotices(): bool + { + return $this->numberOfPhpunitNotices() > 0; + } + public function numberOfPhpunitNotices(): int + { + return $this->numberOfTestsWithTestTriggeredPhpunitNoticeEvents() + $this->numberOfTestRunnerTriggeredNoticeEvents(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function array_diff; +use function basename; +use function get_declared_classes; +use function realpath; +use function str_ends_with; +use function strpos; +use function strtolower; +use function substr; +use PHPUnit\Framework\TestCase; +use ReflectionClass; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestSuiteLoader +{ + /** + * @var list + */ + private static array $declaredClasses = []; + /** + * @var array> + */ + private static array $fileToClassesMap = []; + /** + * @throws Exception + * + * @return ReflectionClass + */ + public function load(string $suiteClassFile): ReflectionClass + { + $suiteClassFile = realpath($suiteClassFile); + $suiteClassName = $this->classNameFromFileName($suiteClassFile); + $loadedClasses = $this->loadSuiteClassFile($suiteClassFile); + foreach ($loadedClasses as $className) { + /** @noinspection PhpUnhandledExceptionInspection */ + $class = new ReflectionClass($className); + if ($class->isAnonymous()) { + continue; + } + if ($class->getFileName() !== $suiteClassFile) { + continue; + } + if (!$class->isSubclassOf(TestCase::class)) { + continue; + } + if (!str_ends_with(strtolower($class->getShortName()), strtolower($suiteClassName))) { + continue; + } + if (!$class->isAbstract()) { + return $class; + } + $e = new \PHPUnit\Runner\ClassIsAbstractException($class->getName(), $suiteClassFile); + } + if (isset($e)) { + throw $e; + } + foreach ($loadedClasses as $className) { + if (str_ends_with(strtolower($className), strtolower($suiteClassName))) { + throw new \PHPUnit\Runner\ClassDoesNotExtendTestCaseException($className, $suiteClassFile); + } + } + throw new \PHPUnit\Runner\ClassCannotBeFoundException($suiteClassName, $suiteClassFile); + } + private function classNameFromFileName(string $suiteClassFile): string + { + $className = basename($suiteClassFile, '.php'); + $dotPos = strpos($className, '.'); + if ($dotPos !== \false) { + $className = substr($className, 0, $dotPos); + } + return $className; + } + /** + * @return array + */ + private function loadSuiteClassFile(string $suiteClassFile): array + { + if (isset(self::$fileToClassesMap[$suiteClassFile])) { + return self::$fileToClassesMap[$suiteClassFile]; + } + if (self::$declaredClasses === []) { + self::$declaredClasses = get_declared_classes(); + } + require_once $suiteClassFile; + $loadedClasses = array_diff(get_declared_classes(), self::$declaredClasses); + foreach ($loadedClasses as $loadedClass) { + /** @noinspection PhpUnhandledExceptionInspection */ + $class = new ReflectionClass($loadedClass); + if (!isset(self::$fileToClassesMap[$class->getFileName()])) { + self::$fileToClassesMap[$class->getFileName()] = []; + } + self::$fileToClassesMap[$class->getFileName()][] = $class->getName(); + } + self::$declaredClasses = get_declared_classes(); + if (!isset(self::$fileToClassesMap[$suiteClassFile])) { + return self::$declaredClasses; + } + return self::$fileToClassesMap[$suiteClassFile]; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function array_diff; +use function array_merge; +use function array_reverse; +use function array_splice; +use function assert; +use function count; +use function in_array; +use function max; +use function shuffle; +use function usort; +use PHPUnit\Framework\DataProviderTestSuite; +use PHPUnit\Framework\Reorderable; +use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\ResultCache\NullResultCache; +use PHPUnit\Runner\ResultCache\ResultCache; +use PHPUnit\Runner\ResultCache\ResultCacheId; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestSuiteSorter +{ + public const int ORDER_DEFAULT = 0; + public const int ORDER_RANDOMIZED = 1; + public const int ORDER_REVERSED = 2; + public const int ORDER_DEFECTS_FIRST = 3; + public const int ORDER_DURATION = 4; + public const int ORDER_SIZE = 5; + /** + * @var non-empty-array + */ + private const array SIZE_SORT_WEIGHT = ['small' => 1, 'medium' => 2, 'large' => 3, 'unknown' => 4]; + /** + * @var array Associative array of (string => DEFECT_SORT_WEIGHT) elements + */ + private array $defectSortOrder = []; + public function __construct(private readonly ?ResultCache $cache = new NullResultCache()) + { + } + /** + * @throws Exception + */ + public function reorderTestsInSuite(Test $suite, int $order, bool $resolveDependencies, int $orderDefects): void + { + $allowedOrders = [self::ORDER_DEFAULT, self::ORDER_REVERSED, self::ORDER_RANDOMIZED, self::ORDER_DURATION, self::ORDER_SIZE]; + if (!in_array($order, $allowedOrders, \true)) { + // @codeCoverageIgnoreStart + throw new \PHPUnit\Runner\InvalidOrderException(); + // @codeCoverageIgnoreEnd + } + $allowedOrderDefects = [self::ORDER_DEFAULT, self::ORDER_DEFECTS_FIRST]; + if (!in_array($orderDefects, $allowedOrderDefects, \true)) { + // @codeCoverageIgnoreStart + throw new \PHPUnit\Runner\InvalidOrderException(); + // @codeCoverageIgnoreEnd + } + if ($suite instanceof TestSuite) { + foreach ($suite as $_suite) { + $this->reorderTestsInSuite($_suite, $order, $resolveDependencies, $orderDefects); + } + if ($orderDefects === self::ORDER_DEFECTS_FIRST) { + $this->addSuiteToDefectSortOrder($suite); + } + $this->sort($suite, $order, $resolveDependencies, $orderDefects); + } + } + private function sort(TestSuite $suite, int $order, bool $resolveDependencies, int $orderDefects): void + { + if ($suite->tests() === []) { + return; + } + if ($order === self::ORDER_REVERSED) { + $suite->setTests($this->reverse($suite->tests())); + } elseif ($order === self::ORDER_RANDOMIZED) { + $suite->setTests($this->randomize($suite->tests())); + } elseif ($order === self::ORDER_DURATION) { + $suite->setTests($this->sortByDuration($suite->tests())); + } elseif ($order === self::ORDER_SIZE) { + $suite->setTests($this->sortBySize($suite->tests())); + } + if ($orderDefects === self::ORDER_DEFECTS_FIRST) { + $suite->setTests($this->sortDefectsFirst($suite->tests())); + } + if ($resolveDependencies && !$suite instanceof DataProviderTestSuite) { + $tests = $suite->tests(); + /** @noinspection PhpParamsInspection */ + /** @phpstan-ignore argument.type */ + $suite->setTests($this->resolveDependencies($tests)); + } + } + private function addSuiteToDefectSortOrder(TestSuite $suite): void + { + $max = 0; + foreach ($suite->tests() as $test) { + assert($test instanceof Reorderable); + $sortId = $test->sortId(); + if (!isset($this->defectSortOrder[$sortId])) { + $this->defectSortOrder[$sortId] = $this->cache->status(ResultCacheId::fromReorderable($test))->asInt(); + $max = max($max, $this->defectSortOrder[$sortId]); + } + } + $this->defectSortOrder[$suite->sortId()] = $max; + } + /** + * @param list $tests + * + * @return list + */ + private function reverse(array $tests): array + { + return array_reverse($tests); + } + /** + * @param list $tests + * + * @return list + */ + private function randomize(array $tests): array + { + shuffle($tests); + return $tests; + } + /** + * @param list $tests + * + * @return list + */ + private function sortDefectsFirst(array $tests): array + { + usort($tests, fn(Test $left, Test $right) => $this->cmpDefectPriorityAndTime($left, $right)); + return $tests; + } + /** + * @param list $tests + * + * @return list + */ + private function sortByDuration(array $tests): array + { + usort($tests, fn(Test $left, Test $right) => $this->cmpDuration($left, $right)); + return $tests; + } + /** + * @param list $tests + * + * @return list + */ + private function sortBySize(array $tests): array + { + usort($tests, fn(Test $left, Test $right) => $this->cmpSize($left, $right)); + return $tests; + } + /** + * Comparator callback function to sort tests for "reach failure as fast as possible". + * + * 1. sort tests by defect weight defined in self::DEFECT_SORT_WEIGHT + * 2. when tests are equally defective, sort the fastest to the front + * 3. do not reorder successful tests + */ + private function cmpDefectPriorityAndTime(Test $a, Test $b): int + { + assert($a instanceof Reorderable); + assert($b instanceof Reorderable); + $priorityA = $this->defectSortOrder[$a->sortId()] ?? 0; + $priorityB = $this->defectSortOrder[$b->sortId()] ?? 0; + if ($priorityA !== $priorityB) { + // Sort defect weight descending + return $priorityB <=> $priorityA; + } + if ($priorityA > 0 || $priorityB > 0) { + return $this->cmpDuration($a, $b); + } + // do not change execution order + return 0; + } + /** + * Compares test duration for sorting tests by duration ascending. + */ + private function cmpDuration(Test $a, Test $b): int + { + if (!($a instanceof Reorderable && $b instanceof Reorderable)) { + return 0; + } + return $this->cache->time(ResultCacheId::fromReorderable($a)) <=> $this->cache->time(ResultCacheId::fromReorderable($b)); + } + /** + * Compares test size for sorting tests small->medium->large->unknown. + */ + private function cmpSize(Test $a, Test $b): int + { + $sizeA = $a instanceof TestCase || $a instanceof DataProviderTestSuite ? $a->size()->asString() : 'unknown'; + $sizeB = $b instanceof TestCase || $b instanceof DataProviderTestSuite ? $b->size()->asString() : 'unknown'; + return self::SIZE_SORT_WEIGHT[$sizeA] <=> self::SIZE_SORT_WEIGHT[$sizeB]; + } + /** + * Reorder Tests within a TestCase in such a way as to resolve as many dependencies as possible. + * The algorithm will leave the tests in original running order when it can. + * For more details see the documentation for test dependencies. + * + * Short description of algorithm: + * 1. Pick the next Test from remaining tests to be checked for dependencies. + * 2. If the test has no dependencies: mark done, start again from the top + * 3. If the test has dependencies but none left to do: mark done, start again from the top + * 4. When we reach the end add any leftover tests to the end. These will be marked 'skipped' during execution. + * + * @param array $tests + * + * @return array + */ + private function resolveDependencies(array $tests): array + { + $newTestOrder = []; + $i = 0; + $provided = []; + do { + if ([] === array_diff($tests[$i]->requires(), $provided)) { + $provided = array_merge($provided, $tests[$i]->provides()); + $newTestOrder = array_merge($newTestOrder, array_splice($tests, $i, 1)); + $i = 0; + } else { + $i++; + } + } while ($tests !== [] && $i < count($tests)); + return array_merge($newTestOrder, $tests); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function array_slice; +use function assert; +use function dirname; +use function explode; +use function implode; +use function str_contains; +use PHPUnitPHAR\SebastianBergmann\Version as VersionId; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class Version +{ + private static string $pharVersion = '13.1.13'; + private static string $version = ''; + /** + * @return non-empty-string + */ + public static function id(): string + { + if (self::$pharVersion !== '') { + return self::$pharVersion; + } + if (self::$version === '') { + self::$version = (new VersionId('13.1.13', dirname(__DIR__, 2)))->asString(); + } + return self::$version; + } + /** + * @return non-empty-string + */ + public static function series(): string + { + if (str_contains(self::id(), '-')) { + $version = explode('-', self::id(), 2)[0]; + } else { + $version = self::id(); + } + return implode('.', array_slice(explode('.', $version), 0, 2)); + } + /** + * @return positive-int + */ + public static function majorVersionNumber(): int + { + $majorVersion = (int) explode('.', self::series())[0]; + assert($majorVersion > 0); + return $majorVersion; + } + /** + * @return non-empty-string + */ + public static function getVersionString(): string + { + return 'PHPUnit ' . self::id() . ' by Sebastian Bergmann and contributors.'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use const PHP_EOL; +use const PHP_VERSION; +use function array_reverse; +use function assert; +use function class_exists; +use function class_implements; +use function defined; +use function dirname; +use function explode; +use function function_exists; +use function in_array; +use function is_file; +use function method_exists; +use function printf; +use function realpath; +use function sprintf; +use function str_contains; +use function str_starts_with; +use function trim; +use function unlink; +use PHPUnit\Event\EventFacadeIsSealedException; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Event\UnknownSubscriberTypeException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Logging\EventLogger; +use PHPUnit\Logging\JUnit\JunitXmlLogger; +use PHPUnit\Logging\OpenTestReporting\CannotOpenUriForWritingException; +use PHPUnit\Logging\OpenTestReporting\OtrXmlLogger; +use PHPUnit\Logging\TeamCity\TeamCityLogger; +use PHPUnit\Logging\TestDox\HtmlRenderer as TestDoxHtmlRenderer; +use PHPUnit\Logging\TestDox\PlainTextRenderer as TestDoxTextRenderer; +use PHPUnit\Logging\TestDox\TestResultCollector as TestDoxResultCollector; +use PHPUnit\Runner\Baseline\CannotLoadBaselineException; +use PHPUnit\Runner\Baseline\Generator as BaselineGenerator; +use PHPUnit\Runner\Baseline\Reader; +use PHPUnit\Runner\Baseline\Writer; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\Runner\CodeCoverageInitializationStatus; +use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollector; +use PHPUnit\Runner\DirectoryDoesNotExistException; +use PHPUnit\Runner\ErrorHandler; +use PHPUnit\Runner\Extension\ExtensionBootstrapper; +use PHPUnit\Runner\Extension\ExtensionFacade; +use PHPUnit\Runner\Extension\PharLoader; +use PHPUnit\Runner\GarbageCollection\GarbageCollectionHandler; +use PHPUnit\Runner\IssueTriggerResolver\Resolver; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use PHPUnit\Runner\ResultCache\DefaultResultCache; +use PHPUnit\Runner\ResultCache\NullResultCache; +use PHPUnit\Runner\ResultCache\ResultCache; +use PHPUnit\Runner\ResultCache\ResultCacheHandler; +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\Runner\Version; +use PHPUnit\TestRunner\IssueFilter; +use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade; +use PHPUnit\TextUI\CliArguments\Builder; +use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; +use PHPUnit\TextUI\CliArguments\Exception as ArgumentsException; +use PHPUnit\TextUI\CliArguments\XmlConfigurationFileFinder; +use PHPUnit\TextUI\Command\AtLeastVersionCommand; +use PHPUnit\TextUI\Command\CheckPhpConfigurationCommand; +use PHPUnit\TextUI\Command\GenerateConfigurationCommand; +use PHPUnit\TextUI\Command\ListGroupsCommand; +use PHPUnit\TextUI\Command\ListTestFilesCommand; +use PHPUnit\TextUI\Command\ListTestsAsTextCommand; +use PHPUnit\TextUI\Command\ListTestsAsXmlCommand; +use PHPUnit\TextUI\Command\ListTestSuitesCommand; +use PHPUnit\TextUI\Command\MigrateConfigurationCommand; +use PHPUnit\TextUI\Command\Result; +use PHPUnit\TextUI\Command\ShowHelpCommand; +use PHPUnit\TextUI\Command\ShowVersionCommand; +use PHPUnit\TextUI\Command\VersionCheckCommand; +use PHPUnit\TextUI\Command\WarmCodeCoverageCacheCommand; +use PHPUnit\TextUI\Configuration\BootstrapLoader; +use PHPUnit\TextUI\Configuration\BootstrapScriptDoesNotExistException; +use PHPUnit\TextUI\Configuration\BootstrapScriptException; +use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\PhpHandler; +use PHPUnit\TextUI\Configuration\Registry; +use PHPUnit\TextUI\Configuration\TestSuiteBuilder; +use PHPUnit\TextUI\Output\DefaultPrinter; +use PHPUnit\TextUI\Output\Facade as OutputFacade; +use PHPUnit\TextUI\Output\Printer; +use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; +use PHPUnit\TextUI\XmlConfiguration\DefaultConfiguration; +use PHPUnit\TextUI\XmlConfiguration\Loader; +use PHPUnit\Util\Http\PhpDownloader; +use PHPUnitPHAR\SebastianBergmann\Timer\Timer; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Application +{ + /** + * @param list $argv + */ + public function run(array $argv): int + { + $this->preload(); + try { + EventFacade::emitter()->applicationStarted(); + $cliConfiguration = $this->buildCliConfiguration($argv); + $pathToXmlConfigurationFile = (new XmlConfigurationFileFinder())->find($cliConfiguration); + $this->executeCommandsThatOnlyRequireCliConfiguration($cliConfiguration, $pathToXmlConfigurationFile); + $xmlConfiguration = $this->loadXmlConfiguration($pathToXmlConfigurationFile); + $configuration = Registry::init($cliConfiguration, $xmlConfiguration); + (new PhpHandler())->handle($configuration->php()); + try { + (new BootstrapLoader())->handle($configuration); + } catch (BootstrapScriptDoesNotExistException|BootstrapScriptException $e) { + $this->exitWithErrorMessage($e->getMessage()); + } + $this->executeCommandsThatDoNotRequireTheTestSuite($configuration, $cliConfiguration); + $pharExtensions = null; + $extensionRequiresCodeCoverageCollection = \false; + $extensionReplacesOutput = \false; + $extensionReplacesProgressOutput = \false; + $extensionReplacesResultOutput = \false; + if (!$configuration->noExtensions()) { + if ($configuration->hasPharExtensionDirectory()) { + $pharExtensions = (new PharLoader())->loadPharExtensionsInDirectory($configuration->pharExtensionDirectory()); + } + $bootstrappedExtensions = $this->bootstrapExtensions($configuration); + $extensionRequiresCodeCoverageCollection = $bootstrappedExtensions['requiresCodeCoverageCollection']; + $extensionReplacesOutput = $bootstrappedExtensions['replacesOutput']; + $extensionReplacesProgressOutput = $bootstrappedExtensions['replacesProgressOutput']; + $extensionReplacesResultOutput = $bootstrappedExtensions['replacesResultOutput']; + } + $printer = OutputFacade::init($configuration, $extensionReplacesProgressOutput, $extensionReplacesResultOutput); + if ($configuration->debug()) { + EventFacade::instance()->registerTracer(new EventLogger('php://stdout', $configuration->withTelemetry())); + } + TestResultFacade::init(); + DeprecationCollector::init(); + $this->registerLogfileWriters($configuration); + $testDoxResultCollector = $this->testDoxResultCollector($configuration); + $resultCache = $this->initializeTestResultCache($configuration); + if ($configuration->controlGarbageCollector()) { + new GarbageCollectionHandler(EventFacade::instance(), $configuration->numberOfTestsBeforeGarbageCollection()); + } + $baselineGenerator = $this->configureBaseline($configuration); + EventFacade::instance()->seal(); + ErrorHandler::instance()->registerDeprecationHandler(); + $testSuite = $this->buildTestSuite($configuration); + ErrorHandler::instance()->restoreDeprecationHandler(); + $this->executeCommandsThatRequireTheTestSuite($configuration, $cliConfiguration, $testSuite); + if ($testSuite->isEmpty() && !$configuration->hasCliArguments() && $configuration->testSuite()->isEmpty()) { + $this->execute(new ShowHelpCommand(Result::FAILURE)); + } + $coverageInitializationStatus = CodeCoverage::instance()->init($configuration, CodeCoverageFilterRegistry::instance(), $extensionRequiresCodeCoverageCollection); + if (!$configuration->debug() && !$extensionReplacesOutput) { + $this->writeRuntimeInformation($printer, $configuration); + $this->writePharExtensionInformation($printer, $pharExtensions); + $this->writeRandomSeedInformation($printer, $configuration); + $printer->print(PHP_EOL); + } + $this->configureDeprecationTriggers($configuration); + $this->configureIssueTriggerResolvers($configuration); + $timer = new Timer(); + $timer->start(); + if ($coverageInitializationStatus === CodeCoverageInitializationStatus::NOT_REQUESTED || $coverageInitializationStatus === CodeCoverageInitializationStatus::SUCCEEDED) { + $runner = new \PHPUnit\TextUI\TestRunner(); + $runner->run($configuration, $resultCache, $testSuite); + } + $duration = $timer->stop(); + $testDoxResult = null; + if (isset($testDoxResultCollector)) { + $testDoxResult = $testDoxResultCollector->testMethodsGroupedByClass(); + } + if ($testDoxResult !== null && $configuration->hasLogfileTestdoxHtml()) { + try { + OutputFacade::printerFor($configuration->logfileTestdoxHtml())->print((new TestDoxHtmlRenderer())->render($testDoxResult)); + } catch (DirectoryDoesNotExistException|\PHPUnit\TextUI\InvalidSocketException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot log test results in TestDox HTML format to "%s": %s', $configuration->logfileTestdoxHtml(), $e->getMessage())); + } + } + if ($testDoxResult !== null && $configuration->hasLogfileTestdoxText()) { + try { + OutputFacade::printerFor($configuration->logfileTestdoxText())->print((new TestDoxTextRenderer())->render($testDoxResult)); + } catch (DirectoryDoesNotExistException|\PHPUnit\TextUI\InvalidSocketException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot log test results in TestDox plain text format to "%s": %s', $configuration->logfileTestdoxText(), $e->getMessage())); + } + } + $result = TestResultFacade::result(); + if (!$extensionReplacesResultOutput && !$configuration->debug()) { + OutputFacade::printResult($result, $testDoxResult, $duration, $configuration->hasSpecificDeprecationToStopOn()); + } + CodeCoverage::instance()->generateReports($printer, $configuration); + if (isset($baselineGenerator)) { + (new Writer())->write($configuration->generateBaseline(), $baselineGenerator->baseline()); + $printer->print(sprintf(PHP_EOL . 'Baseline written to %s.' . PHP_EOL, realpath($configuration->generateBaseline()))); + } + $shellExitCode = (new \PHPUnit\TextUI\ShellExitCodeCalculator())->calculate($configuration, $result); + EventFacade::emitter()->applicationFinished($shellExitCode); + return $shellExitCode; + // @codeCoverageIgnoreStart + } catch (Throwable $t) { + $this->exitWithCrashMessage($t); + } + // @codeCoverageIgnoreEnd + } + private function execute(\PHPUnit\TextUI\Command\Command $command, bool $requiresResultCollectedFromEvents = \false): never + { + $errored = \false; + if ($requiresResultCollectedFromEvents) { + try { + TestResultFacade::init(); + EventFacade::instance()->seal(); + $resultCollectedFromEvents = TestResultFacade::result(); + $errored = $resultCollectedFromEvents->hasTestTriggeredPhpunitErrorEvents(); + } catch (EventFacadeIsSealedException|UnknownSubscriberTypeException) { + } + } + print Version::getVersionString() . PHP_EOL . PHP_EOL; + if (!$errored) { + $result = $command->execute(); + print $result->output(); + exit($result->shellExitCode()); + } + assert(isset($resultCollectedFromEvents)); + print 'There were errors:' . PHP_EOL; + foreach ($resultCollectedFromEvents->testTriggeredPhpunitErrorEvents() as $events) { + foreach ($events as $event) { + print PHP_EOL . trim($event->message()) . PHP_EOL; + } + } + exit(Result::EXCEPTION); + } + /** + * @param list $argv + */ + private function buildCliConfiguration(array $argv): CliConfiguration + { + try { + $cliConfiguration = (new Builder())->fromParameters($argv); + } catch (ArgumentsException $e) { + $this->exitWithErrorMessage($e->getMessage()); + } + return $cliConfiguration; + } + private function loadXmlConfiguration(false|string $configurationFile): XmlConfiguration + { + if ($configurationFile === \false) { + return DefaultConfiguration::create(); + } + try { + return (new Loader())->load($configurationFile); + } catch (Throwable $e) { + $this->exitWithErrorMessage($e->getMessage()); + } + } + private function buildTestSuite(Configuration $configuration): TestSuite + { + try { + return (new TestSuiteBuilder())->build($configuration); + } catch (\PHPUnit\TextUI\Exception $e) { + $this->exitWithErrorMessage($e->getMessage()); + } + } + /** + * @return array{requiresCodeCoverageCollection: bool, replacesOutput: bool, replacesProgressOutput: bool, replacesResultOutput: bool} + */ + private function bootstrapExtensions(Configuration $configuration): array + { + $facade = new ExtensionFacade(); + $extensionBootstrapper = new ExtensionBootstrapper($configuration, $facade); + foreach ($configuration->extensionBootstrappers() as $bootstrapper) { + $extensionBootstrapper->bootstrap($bootstrapper['className'], $bootstrapper['parameters']); + } + return ['requiresCodeCoverageCollection' => $facade->requiresCodeCoverageCollection(), 'replacesOutput' => $facade->replacesOutput(), 'replacesProgressOutput' => $facade->replacesProgressOutput(), 'replacesResultOutput' => $facade->replacesResultOutput()]; + } + private function executeCommandsThatOnlyRequireCliConfiguration(CliConfiguration $cliConfiguration, false|string $configurationFile): void + { + if ($cliConfiguration->generateConfiguration()) { + $this->execute(new GenerateConfigurationCommand()); + } + if ($cliConfiguration->migrateConfiguration()) { + if ($configurationFile === \false) { + $this->exitWithErrorMessage('No configuration file found to migrate'); + } + $this->execute(new MigrateConfigurationCommand(realpath($configurationFile))); + } + if ($cliConfiguration->hasAtLeastVersion()) { + $this->execute(new AtLeastVersionCommand($cliConfiguration->atLeastVersion())); + } + if ($cliConfiguration->version()) { + $this->execute(new ShowVersionCommand()); + } + if ($cliConfiguration->checkPhpConfiguration()) { + $this->execute(new CheckPhpConfigurationCommand()); + } + if ($cliConfiguration->checkVersion()) { + $this->execute(new VersionCheckCommand(new PhpDownloader(), Version::majorVersionNumber(), Version::id())); + } + if ($cliConfiguration->help()) { + $this->execute(new ShowHelpCommand(Result::SUCCESS)); + } + } + private function executeCommandsThatDoNotRequireTheTestSuite(Configuration $configuration, CliConfiguration $cliConfiguration): void + { + if ($cliConfiguration->warmCoverageCache()) { + $this->execute(new WarmCodeCoverageCacheCommand($configuration, CodeCoverageFilterRegistry::instance())); + } + } + private function executeCommandsThatRequireTheTestSuite(Configuration $configuration, CliConfiguration $cliConfiguration, TestSuite $testSuite): void + { + if ($cliConfiguration->listSuites()) { + $this->execute(new ListTestSuitesCommand($testSuite)); + } + if ($cliConfiguration->listGroups()) { + $this->execute(new ListGroupsCommand($this->filteredTests($configuration, $testSuite)), \true); + } + if ($cliConfiguration->listTests()) { + $this->execute(new ListTestsAsTextCommand($this->filteredTests($configuration, $testSuite)), \true); + } + if ($cliConfiguration->hasListTestsXml()) { + $this->execute(new ListTestsAsXmlCommand($this->filteredTests($configuration, $testSuite), $cliConfiguration->listTestsXml()), \true); + } + if ($cliConfiguration->listTestFiles()) { + $this->execute(new ListTestFilesCommand($this->filteredTests($configuration, $testSuite)), \true); + } + } + private function writeRuntimeInformation(Printer $printer, Configuration $configuration): void + { + $printer->print(Version::getVersionString() . PHP_EOL . PHP_EOL); + $runtime = 'PHP ' . PHP_VERSION; + if (CodeCoverage::instance()->isActive()) { + $runtime .= ' with ' . CodeCoverage::instance()->driverNameAndVersion(); + } + $this->writeMessage($printer, 'Runtime', $runtime); + if ($configuration->hasConfigurationFile()) { + $this->writeMessage($printer, 'Configuration', $configuration->configurationFile()); + } + } + /** + * @param ?list $pharExtensions + */ + private function writePharExtensionInformation(Printer $printer, ?array $pharExtensions): void + { + if ($pharExtensions === null) { + return; + } + foreach ($pharExtensions as $extension) { + $this->writeMessage($printer, 'Extension', $extension); + } + } + private function writeMessage(Printer $printer, string $type, string $message): void + { + $printer->print(sprintf("%-15s%s\n", $type . ':', $message)); + } + private function writeRandomSeedInformation(Printer $printer, Configuration $configuration): void + { + if ($configuration->executionOrder() === TestSuiteSorter::ORDER_RANDOMIZED) { + $this->writeMessage($printer, 'Random Seed', (string) $configuration->randomOrderSeed()); + } + } + private function registerLogfileWriters(Configuration $configuration): void + { + if ($configuration->hasLogEventsText()) { + if (is_file($configuration->logEventsText())) { + unlink($configuration->logEventsText()); + } + EventFacade::instance()->registerTracer(new EventLogger($configuration->logEventsText(), $configuration->withTelemetry())); + } + if ($configuration->hasLogEventsVerboseText()) { + EventFacade::emitter()->testRunnerTriggeredPhpunitDeprecation('The "--log-events-verbose-text " CLI option is deprecated and will be removed in PHPUnit 14. Use "--log-events-text --with-telemetry" instead.'); + if (is_file($configuration->logEventsVerboseText())) { + unlink($configuration->logEventsVerboseText()); + } + EventFacade::instance()->registerTracer(new EventLogger($configuration->logEventsVerboseText(), \true)); + } + if ($configuration->hasLogfileJunit()) { + try { + new JunitXmlLogger(OutputFacade::printerFor($configuration->logfileJunit()), EventFacade::instance()); + } catch (DirectoryDoesNotExistException|\PHPUnit\TextUI\InvalidSocketException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot log test results in JUnit XML format to "%s": %s', $configuration->logfileJunit(), $e->getMessage())); + } + } + if ($configuration->hasLogfileOtr()) { + try { + new OtrXmlLogger(EventFacade::instance(), $configuration->logfileOtr(), $configuration->includeGitInformationInOtrLogfile()); + } catch (CannotOpenUriForWritingException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot log test results in Open Test Reporting XML format to "%s": %s', $configuration->logfileOtr(), $e->getMessage())); + } + } + if ($configuration->hasLogfileTeamcity()) { + try { + new TeamCityLogger(DefaultPrinter::from($configuration->logfileTeamcity()), EventFacade::instance()); + } catch (DirectoryDoesNotExistException|\PHPUnit\TextUI\InvalidSocketException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot log test results in TeamCity format to "%s": %s', $configuration->logfileTeamcity(), $e->getMessage())); + } + } + } + private function testDoxResultCollector(Configuration $configuration): ?TestDoxResultCollector + { + if ($configuration->hasLogfileTestdoxHtml() || $configuration->hasLogfileTestdoxText() || $configuration->outputIsTestDox()) { + return new TestDoxResultCollector(EventFacade::instance(), new IssueFilter($configuration->source())); + } + return null; + } + private function initializeTestResultCache(Configuration $configuration): ResultCache + { + if ($configuration->cacheResult()) { + $cache = new DefaultResultCache($configuration->testResultCacheFile()); + new ResultCacheHandler($cache, EventFacade::instance()); + return $cache; + } + return new NullResultCache(); + } + private function configureBaseline(Configuration $configuration): ?BaselineGenerator + { + if ($configuration->hasGenerateBaseline()) { + return new BaselineGenerator(EventFacade::instance(), $configuration->source()); + } + if ($configuration->source()->useBaseline()) { + $baselineFile = $configuration->source()->baseline(); + $baseline = null; + try { + $baseline = (new Reader())->read($baselineFile); + } catch (CannotLoadBaselineException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning($e->getMessage()); + } + if ($baseline !== null) { + ErrorHandler::instance()->useBaseline($baseline); + } + } + return null; + } + /** + * @codeCoverageIgnore + */ + private function exitWithCrashMessage(Throwable $t): never + { + $message = $t->getMessage(); + if (trim($message) === '') { + $message = '(no message)'; + } + printf('%s%sAn error occurred inside PHPUnit.%s%sMessage: %s', PHP_EOL, PHP_EOL, PHP_EOL, PHP_EOL, $message); + $first = \true; + if ($t->getPrevious() !== null) { + $t = $t->getPrevious(); + } + do { + printf('%s%s: %s:%d%s%s%s%s', PHP_EOL, $first ? 'Location' : 'Caused by', $t->getFile(), $t->getLine(), PHP_EOL, PHP_EOL, $t->getTraceAsString(), PHP_EOL); + $first = \false; + } while ($t = $t->getPrevious()); + exit(Result::CRASH); + } + private function exitWithErrorMessage(string $message): never + { + print Version::getVersionString() . PHP_EOL . PHP_EOL . $message . PHP_EOL; + exit(Result::EXCEPTION); + } + /** + * @return list + */ + private function filteredTests(Configuration $configuration, TestSuite $suite): array + { + (new \PHPUnit\TextUI\TestSuiteFilterProcessor())->process($configuration, $suite); + return $suite->collect(); + } + private function configureDeprecationTriggers(Configuration $configuration): void + { + $deprecationTriggers = ['functions' => [], 'methods' => []]; + $ignoreUndefinedTriggers = $configuration->source()->deprecationTriggers()['ignoreUndefinedTriggers'] ?? \false; + foreach ($configuration->source()->deprecationTriggers()['functions'] as $function) { + if (!function_exists($function)) { + if (!$ignoreUndefinedTriggers) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Function %s cannot be configured as a deprecation trigger because it is not declared', $function)); + } + continue; + } + $deprecationTriggers['functions'][] = $function; + } + foreach ($configuration->source()->deprecationTriggers()['methods'] as $method) { + if (!str_contains($method, '::')) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('%s cannot be configured as a deprecation trigger because it is not in ClassName::methodName format', $method)); + continue; + } + [$className, $methodName] = explode('::', $method); + if (!class_exists($className) || !method_exists($className, $methodName)) { + if (!$ignoreUndefinedTriggers) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Method %s::%s cannot be configured as a deprecation trigger because it is not declared', $className, $methodName)); + } + continue; + } + $deprecationTriggers['methods'][] = ['className' => $className, 'methodName' => $methodName]; + } + if ($deprecationTriggers !== ['functions' => [], 'methods' => []]) { + ErrorHandler::instance()->useDeprecationTriggers($deprecationTriggers); + } + } + private function configureIssueTriggerResolvers(Configuration $configuration): void + { + $classNames = $configuration->source()->issueTriggerResolvers(); + foreach (array_reverse($classNames) as $className) { + if (!class_exists($className)) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Class %s cannot be used as an issue trigger resolver because it does not exist', $className)); + continue; + } + if (!in_array(Resolver::class, class_implements($className), \true)) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Class %s cannot be used as an issue trigger resolver because it does not implement %s', $className, Resolver::class)); + continue; + } + ErrorHandler::instance()->addIssueTriggerResolver(new $className()); + } + } + private function preload(): void + { + if (!defined('PHPUNIT_COMPOSER_INSTALL')) { + return; + } + $classMapFile = dirname(PHPUNIT_COMPOSER_INSTALL) . '/composer/autoload_classmap.php'; + if (!is_file($classMapFile)) { + return; + } + foreach (require $classMapFile as $codeUnitName => $sourceCodeFile) { + if (!str_starts_with($codeUnitName, 'PHPUnit\\') && !str_starts_with($codeUnitName, 'SebastianBergmann\\')) { + continue; + } + if (str_contains($sourceCodeFile, '/tests/')) { + continue; + } + require_once $sourceCodeFile; + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Command +{ + public function execute(): \PHPUnit\TextUI\Command\Result; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use function version_compare; +use PHPUnit\Runner\Version; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AtLeastVersionCommand implements \PHPUnit\TextUI\Command\Command +{ + private string $version; + public function __construct(string $version) + { + $this->version = $version; + } + public function execute(): \PHPUnit\TextUI\Command\Result + { + if (version_compare(Version::id(), $this->version, '>=')) { + return \PHPUnit\TextUI\Command\Result::from(); + } + return \PHPUnit\TextUI\Command\Result::from('', \PHPUnit\TextUI\Command\Result::FAILURE); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const E_ALL; +use const PHP_EOL; +use function assert; +use function extension_loaded; +use function in_array; +use function ini_get; +use function max; +use function sprintf; +use function strlen; +use PHPUnit\Runner\Version; +use PHPUnit\Util\Color; +use PHPUnitPHAR\SebastianBergmann\Environment\Console; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CheckPhpConfigurationCommand implements \PHPUnit\TextUI\Command\Command +{ + private bool $colorize; + public function __construct() + { + $this->colorize = (new Console())->hasColorSupport(); + } + public function execute(): \PHPUnit\TextUI\Command\Result + { + $lines = []; + $shellExitCode = 0; + foreach ($this->settings() as $name => $setting) { + foreach ($setting['requiredExtensions'] as $extension) { + if (!extension_loaded($extension)) { + // @codeCoverageIgnoreStart + continue 2; + // @codeCoverageIgnoreEnd + } + } + $actualValue = ini_get($name); + if (in_array($actualValue, $setting['expectedValues'], \true)) { + $check = $this->ok(); + } else { + $check = $this->notOk($actualValue); + $shellExitCode = 1; + } + $lines[] = [sprintf('%s = %s', $name, $setting['valueForConfiguration']), $check]; + } + $maxLength = 0; + foreach ($lines as $line) { + $maxLength = max($maxLength, strlen($line[0])); + } + $buffer = sprintf('Checking whether PHP is configured according to https://docs.phpunit.de/en/%s/installation.html#configuring-php-for-development' . PHP_EOL . PHP_EOL, Version::series()); + foreach ($lines as $line) { + $buffer .= sprintf('%-' . $maxLength . 's ... %s' . PHP_EOL, $line[0], $line[1]); + } + return \PHPUnit\TextUI\Command\Result::from($buffer, $shellExitCode); + } + /** + * @return non-empty-string + */ + private function ok(): string + { + if (!$this->colorize) { + return 'ok'; + } + // @codeCoverageIgnoreStart + $result = Color::colorizeTextBox('fg-green, bold', 'ok'); + assert($result !== ''); + return $result; + // @codeCoverageIgnoreEnd + } + /** + * @return non-empty-string + */ + private function notOk(string $actualValue): string + { + $message = sprintf('not ok (%s)', $actualValue); + if (!$this->colorize) { + return $message; + } + // @codeCoverageIgnoreStart + $result = Color::colorizeTextBox('fg-red, bold', $message); + assert($result !== ''); + return $result; + // @codeCoverageIgnoreEnd + } + /** + * @return non-empty-array, valueForConfiguration: non-empty-string, requiredExtensions: list}> + */ + private function settings(): array + { + return ['display_errors' => ['expectedValues' => ['1'], 'valueForConfiguration' => 'On', 'requiredExtensions' => []], 'display_startup_errors' => ['expectedValues' => ['1'], 'valueForConfiguration' => 'On', 'requiredExtensions' => []], 'error_reporting' => ['expectedValues' => ['-1', (string) E_ALL], 'valueForConfiguration' => '-1', 'requiredExtensions' => []], 'xdebug.show_exception_trace' => ['expectedValues' => ['0'], 'valueForConfiguration' => '0', 'requiredExtensions' => ['xdebug']], 'zend.assertions' => ['expectedValues' => ['1'], 'valueForConfiguration' => '1', 'requiredExtensions' => []], 'assert.exception' => ['expectedValues' => ['1'], 'valueForConfiguration' => '1', 'requiredExtensions' => []], 'memory_limit' => ['expectedValues' => ['-1'], 'valueForConfiguration' => '-1', 'requiredExtensions' => []]]; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use const STDIN; +use function assert; +use function defined; +use function fgets; +use function file_put_contents; +use function getcwd; +use function is_file; +use function sprintf; +use function trim; +use PHPUnit\Runner\Version; +use PHPUnit\TextUI\XmlConfiguration\Generator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GenerateConfigurationCommand implements \PHPUnit\TextUI\Command\Command +{ + public function execute(): \PHPUnit\TextUI\Command\Result + { + $directory = getcwd(); + print 'Generating phpunit.xml in ' . $directory . PHP_EOL . PHP_EOL; + print 'Bootstrap script (relative to path shown above; default: vendor/autoload.php): '; + $bootstrapScript = $this->read(); + print 'Tests directory (relative to path shown above; default: tests): '; + $testsDirectory = $this->read(); + print 'Source directory (relative to path shown above; default: src): '; + $src = $this->read(); + print 'Cache directory (relative to path shown above; default: .phpunit.cache): '; + $cacheDirectory = $this->read(); + if ($bootstrapScript === '') { + $bootstrapScript = 'vendor/autoload.php'; + } + if ($testsDirectory === '') { + $testsDirectory = 'tests'; + } + if ($src === '') { + $src = 'src'; + } + if ($cacheDirectory === '') { + $cacheDirectory = '.phpunit.cache'; + } + if (defined('PHPUNIT_COMPOSER_INSTALL') && is_file($directory . '/vendor/phpunit/phpunit/phpunit.xsd')) { + $schemaLocation = 'vendor/phpunit/phpunit/phpunit.xsd'; + } else { + $schemaLocation = sprintf('https://schema.phpunit.de/%s/phpunit.xsd', Version::series()); + } + $generator = new Generator(); + $result = @file_put_contents($directory . '/phpunit.xml', $generator->generateDefaultConfiguration($schemaLocation, $bootstrapScript, $testsDirectory, $src, $cacheDirectory)); + if ($result !== \false) { + return \PHPUnit\TextUI\Command\Result::from(sprintf(PHP_EOL . 'Generated phpunit.xml in %s.' . PHP_EOL . 'Make sure to exclude the %s directory from version control.' . PHP_EOL, $directory, $cacheDirectory)); + } + // @codeCoverageIgnoreStart + return \PHPUnit\TextUI\Command\Result::from(sprintf(PHP_EOL . 'Could not write phpunit.xml in %s.' . PHP_EOL, $directory), \PHPUnit\TextUI\Command\Result::EXCEPTION); + // @codeCoverageIgnoreEnd + } + private function read(): string + { + $buffer = fgets(STDIN); + assert($buffer !== \false); + return trim($buffer); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function count; +use function ksort; +use function sprintf; +use function str_starts_with; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ListGroupsCommand implements \PHPUnit\TextUI\Command\Command +{ + /** + * @var list + */ + private array $tests; + /** + * @param list $tests + */ + public function __construct(array $tests) + { + $this->tests = $tests; + } + public function execute(): \PHPUnit\TextUI\Command\Result + { + /** @var array $groups */ + $groups = []; + foreach ($this->tests as $test) { + if ($test instanceof PhptTestCase) { + $_groups = ['default']; + } else { + $_groups = $test->groups(); + } + foreach ($_groups as $group) { + if (!isset($groups[$group])) { + $groups[$group] = 1; + } else { + $groups[$group]++; + } + } + } + ksort($groups); + $buffer = sprintf('Available test group%s:' . PHP_EOL, count($groups) > 1 ? 's' : ''); + foreach ($groups as $group => $numberOfTests) { + if (str_starts_with((string) $group, '__phpunit_')) { + continue; + } + $buffer .= sprintf(' - %s (%d test%s)' . PHP_EOL, (string) $group, $numberOfTests, $numberOfTests > 1 ? 's' : ''); + } + return \PHPUnit\TextUI\Command\Result::from($buffer); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function array_unique; +use function assert; +use function sprintf; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use ReflectionClass; +use ReflectionException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ListTestFilesCommand implements \PHPUnit\TextUI\Command\Command +{ + /** + * @var list + */ + private array $tests; + /** + * @param list $tests + */ + public function __construct(array $tests) + { + $this->tests = $tests; + } + /** + * @throws ReflectionException + */ + public function execute(): \PHPUnit\TextUI\Command\Result + { + $buffer = 'Available test files:' . PHP_EOL; + $results = []; + foreach ($this->tests as $test) { + if ($test instanceof TestCase) { + $name = (new ReflectionClass($test))->getFileName(); + assert($name !== \false); + $results[] = $name; + continue; + } + $results[] = $test->getName(); + } + foreach (array_unique($results) as $result) { + $buffer .= sprintf(' - %s' . PHP_EOL, $result); + } + return \PHPUnit\TextUI\Command\Result::from($buffer); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function assert; +use function count; +use function ksort; +use function sprintf; +use PHPUnit\Framework\TestSuite; +use PHPUnit\TextUI\Configuration\Registry; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ListTestSuitesCommand implements \PHPUnit\TextUI\Command\Command +{ + private TestSuite $testSuite; + public function __construct(TestSuite $testSuite) + { + $this->testSuite = $testSuite; + } + public function execute(): \PHPUnit\TextUI\Command\Result + { + /** @var array $suites */ + $suites = []; + foreach ($this->testSuite->tests() as $test) { + assert($test instanceof TestSuite); + $suites[$test->name()] = count($test->collect()); + } + ksort($suites); + $buffer = $this->warnAboutConflictingOptions(); + $buffer .= sprintf('Available test suite%s:' . PHP_EOL, count($suites) > 1 ? 's' : ''); + foreach ($suites as $suite => $numberOfTests) { + $buffer .= sprintf(' - %s (%d test%s)' . PHP_EOL, $suite, $numberOfTests, $numberOfTests > 1 ? 's' : ''); + } + return \PHPUnit\TextUI\Command\Result::from($buffer); + } + private function warnAboutConflictingOptions(): string + { + $buffer = ''; + $configuration = Registry::get(); + if ($configuration->includeTestSuites() !== [] && !$configuration->hasDefaultTestSuite()) { + $buffer .= 'The --testsuite and --list-suites options cannot be combined, --testsuite is ignored' . PHP_EOL; + } + if ($configuration->hasFilter()) { + $buffer .= 'The --filter and --list-suites options cannot be combined, --filter is ignored' . PHP_EOL; + } + if ($configuration->hasGroups()) { + $buffer .= 'The --group (CLI) and (XML) options cannot be combined with --list-suites, --group and are ignored' . PHP_EOL; + } + if ($configuration->hasExcludeGroups()) { + $buffer .= 'The --exclude-group (CLI) and (XML) options cannot be combined with --list-suites, --exclude-group and are ignored' . PHP_EOL; + } + if ($buffer !== '') { + $buffer .= PHP_EOL; + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function count; +use function sprintf; +use function str_replace; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ListTestsAsTextCommand implements \PHPUnit\TextUI\Command\Command +{ + /** + * @var list + */ + private array $tests; + /** + * @param list $tests + */ + public function __construct(array $tests) + { + $this->tests = $tests; + } + public function execute(): \PHPUnit\TextUI\Command\Result + { + $buffer = sprintf('Available test%s:' . PHP_EOL, count($this->tests) > 1 ? 's' : ''); + foreach ($this->tests as $test) { + if ($test instanceof TestCase) { + $name = sprintf('%s::%s', $test::class, str_replace(' with data set ', '', $test->nameWithDataSet())); + } else { + $name = $test->getName(); + } + $buffer .= sprintf(' - %s' . PHP_EOL, $name); + } + return \PHPUnit\TextUI\Command\Result::from($buffer); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function assert; +use function file_put_contents; +use function ksort; +use function sprintf; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use ReflectionClass; +use XMLWriter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ListTestsAsXmlCommand implements \PHPUnit\TextUI\Command\Command +{ + /** + * @var list + */ + private array $tests; + private string $filename; + /** + * @param list $tests + */ + public function __construct(array $tests, string $filename) + { + $this->tests = $tests; + $this->filename = $filename; + } + public function execute(): \PHPUnit\TextUI\Command\Result + { + $writer = new XMLWriter(); + $writer->openMemory(); + $writer->setIndent(\true); + $writer->startDocument(); + $writer->startElement('testSuite'); + $writer->writeAttribute('xmlns', 'https://xml.phpunit.de/testSuite'); + $writer->startElement('tests'); + $currentTestClass = null; + $groups = []; + foreach ($this->tests as $test) { + if ($test instanceof TestCase) { + foreach ($test->groups() as $group) { + if (!isset($groups[$group])) { + $groups[$group] = []; + } + $groups[$group][] = $test->valueObjectForEvents()->id(); + } + if ($test::class !== $currentTestClass) { + if ($currentTestClass !== null) { + $writer->endElement(); + } + $file = (new ReflectionClass($test))->getFileName(); + assert($file !== \false); + $writer->startElement('testClass'); + $writer->writeAttribute('name', $test::class); + $writer->writeAttribute('file', $file); + $currentTestClass = $test::class; + } + $writer->startElement('testMethod'); + $writer->writeAttribute('id', $test->valueObjectForEvents()->id()); + $writer->writeAttribute('name', $test->valueObjectForEvents()->methodName()); + $writer->endElement(); + continue; + } + if ($currentTestClass !== null) { + $writer->endElement(); + $currentTestClass = null; + } + $writer->startElement('phpt'); + $writer->writeAttribute('file', $test->getName()); + $writer->endElement(); + } + if ($currentTestClass !== null) { + $writer->endElement(); + } + $writer->endElement(); + ksort($groups); + $writer->startElement('groups'); + foreach ($groups as $groupName => $testIds) { + $writer->startElement('group'); + $writer->writeAttribute('name', (string) $groupName); + foreach ($testIds as $testId) { + $writer->startElement('test'); + $writer->writeAttribute('id', $testId); + $writer->endElement(); + } + $writer->endElement(); + } + $writer->endElement(); + $writer->endElement(); + file_put_contents($this->filename, $writer->outputMemory()); + return \PHPUnit\TextUI\Command\Result::from(sprintf('Wrote list of tests that would have been run to %s' . PHP_EOL, $this->filename)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function copy; +use function file_put_contents; +use function sprintf; +use PHPUnit\TextUI\XmlConfiguration\Migrator; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MigrateConfigurationCommand implements \PHPUnit\TextUI\Command\Command +{ + private string $filename; + public function __construct(string $filename) + { + $this->filename = $filename; + } + public function execute(): \PHPUnit\TextUI\Command\Result + { + try { + $migrated = (new Migrator())->migrate($this->filename); + copy($this->filename, $this->filename . '.bak'); + file_put_contents($this->filename, $migrated); + return \PHPUnit\TextUI\Command\Result::from(sprintf('Created backup: %s.bak%sMigrated configuration: %s%s', $this->filename, PHP_EOL, $this->filename, PHP_EOL)); + } catch (Throwable $t) { + return \PHPUnit\TextUI\Command\Result::from(sprintf('Migration of %s failed:%s%s%s', $this->filename, PHP_EOL, $t->getMessage(), PHP_EOL), \PHPUnit\TextUI\Command\Result::FAILURE); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use PHPUnit\TextUI\Help; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ShowHelpCommand implements \PHPUnit\TextUI\Command\Command +{ + private int $shellExitCode; + public function __construct(int $shellExitCode) + { + $this->shellExitCode = $shellExitCode; + } + public function execute(): \PHPUnit\TextUI\Command\Result + { + return \PHPUnit\TextUI\Command\Result::from((new Help())->generate(), $this->shellExitCode); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ShowVersionCommand implements \PHPUnit\TextUI\Command\Command +{ + public function execute(): \PHPUnit\TextUI\Command\Result + { + return \PHPUnit\TextUI\Command\Result::from(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function assert; +use function sprintf; +use function version_compare; +use PHPUnit\Util\Http\Downloader; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class VersionCheckCommand implements \PHPUnit\TextUI\Command\Command +{ + private Downloader $downloader; + private int $majorVersionNumber; + private string $versionId; + public function __construct(Downloader $downloader, int $majorVersionNumber, string $versionId) + { + $this->downloader = $downloader; + $this->majorVersionNumber = $majorVersionNumber; + $this->versionId = $versionId; + } + public function execute(): \PHPUnit\TextUI\Command\Result + { + $latestVersion = $this->downloader->download('https://phar.phpunit.de/latest-version-of/phpunit'); + assert($latestVersion !== \false); + $latestCompatibleVersion = $this->downloader->download('https://phar.phpunit.de/latest-version-of/phpunit-' . $this->majorVersionNumber); + $notLatest = version_compare($latestVersion, $this->versionId, '>'); + $notLatestCompatible = \false; + if ($latestCompatibleVersion !== \false) { + $notLatestCompatible = version_compare($latestCompatibleVersion, $this->versionId, '>'); + } + if (!$notLatest && !$notLatestCompatible) { + return \PHPUnit\TextUI\Command\Result::from('You are using the latest version of PHPUnit.' . PHP_EOL); + } + $buffer = 'You are not using the latest version of PHPUnit.' . PHP_EOL; + if ($notLatestCompatible) { + $buffer .= sprintf('The latest version compatible with PHPUnit %s is PHPUnit %s.' . PHP_EOL, $this->versionId, $latestCompatibleVersion); + } + if ($notLatest) { + $buffer .= sprintf('The latest version is PHPUnit %s.' . PHP_EOL, $latestVersion); + } + return \PHPUnit\TextUI\Command\Result::from($buffer, \PHPUnit\TextUI\Command\Result::FAILURE); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function printf; +use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\NoCoverageCacheDirectoryException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\CacheWarmer; +use PHPUnitPHAR\SebastianBergmann\Timer\NoActiveTimerException; +use PHPUnitPHAR\SebastianBergmann\Timer\Timer; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ +final readonly class WarmCodeCoverageCacheCommand implements \PHPUnit\TextUI\Command\Command +{ + private Configuration $configuration; + private CodeCoverageFilterRegistry $codeCoverageFilterRegistry; + public function __construct(Configuration $configuration, CodeCoverageFilterRegistry $codeCoverageFilterRegistry) + { + $this->configuration = $configuration; + $this->codeCoverageFilterRegistry = $codeCoverageFilterRegistry; + } + /** + * @throws NoActiveTimerException + * @throws NoCoverageCacheDirectoryException + */ + public function execute(): \PHPUnit\TextUI\Command\Result + { + if (!$this->configuration->hasCoverageCacheDirectory()) { + return \PHPUnit\TextUI\Command\Result::from('Cache for static analysis has not been configured' . PHP_EOL, \PHPUnit\TextUI\Command\Result::FAILURE); + } + $this->codeCoverageFilterRegistry->init($this->configuration, \true); + if (!$this->codeCoverageFilterRegistry->configured()) { + return \PHPUnit\TextUI\Command\Result::from('Filter for code coverage has not been configured' . PHP_EOL, \PHPUnit\TextUI\Command\Result::FAILURE); + } + $timer = new Timer(); + $timer->start(); + print 'Warming cache for static analysis ... '; + /** @phpstan-ignore new.internalClass,method.internalClass */ + $statistics = (new CacheWarmer())->warmCache($this->configuration->coverageCacheDirectory(), !$this->configuration->disableCodeCoverageIgnore(), $this->configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage(), $this->codeCoverageFilterRegistry->get()); + printf('[%s]%s%s%d file%s processed, %d cache hit%s, %d cache miss%s%s', $timer->stop()->asString(), PHP_EOL, PHP_EOL, $statistics['cacheHits'] + $statistics['cacheMisses'], $statistics['cacheHits'] + $statistics['cacheMisses'] !== 1 ? 's' : '', $statistics['cacheHits'], $statistics['cacheHits'] !== 1 ? 's' : '', $statistics['cacheMisses'], $statistics['cacheMisses'] !== 1 ? 'es' : '', PHP_EOL); + return \PHPUnit\TextUI\Command\Result::from(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Result +{ + public const int SUCCESS = 0; + public const int FAILURE = 1; + public const int EXCEPTION = 2; + public const int CRASH = 255; + private string $output; + private int $shellExitCode; + public static function from(string $output = '', int $shellExitCode = self::SUCCESS): self + { + return new self($output, $shellExitCode); + } + private function __construct(string $output, int $shellExitCode) + { + $this->output = $output; + $this->shellExitCode = $shellExitCode; + } + public function output(): string + { + return $this->output; + } + public function shellExitCode(): int + { + return $this->shellExitCode; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const PHP_EOL; +use function in_array; +use function is_readable; +use function sprintf; +use PHPUnit\Event\Facade as EventFacade; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class BootstrapLoader +{ + /** + * @throws BootstrapScriptDoesNotExistException + * @throws BootstrapScriptException + */ + public function handle(\PHPUnit\TextUI\Configuration\Configuration $configuration): void + { + if (!$configuration->hasBootstrap()) { + return; + } + $this->load($configuration->bootstrap()); + foreach ($configuration->bootstrapForTestSuite() as $testSuiteName => $bootstrapForTestSuite) { + if ($configuration->includeTestSuites() !== [] && !in_array($testSuiteName, $configuration->includeTestSuites(), \true)) { + continue; + } + if ($configuration->excludeTestSuites() !== [] && in_array($testSuiteName, $configuration->excludeTestSuites(), \true)) { + continue; + } + $this->load($bootstrapForTestSuite); + } + } + /** + * @param non-empty-string $filename + */ + private function load(string $filename): void + { + if (!is_readable($filename)) { + throw new \PHPUnit\TextUI\Configuration\BootstrapScriptDoesNotExistException($filename); + } + try { + include_once $filename; + } catch (Throwable $t) { + $message = sprintf('Error in bootstrap script: %s:%s%s%s%s', $t::class, PHP_EOL, $t->getMessage(), PHP_EOL, $t->getTraceAsString()); + while ($t = $t->getPrevious()) { + $message .= sprintf('%s%sPrevious error: %s:%s%s%s%s', PHP_EOL, PHP_EOL, $t::class, PHP_EOL, $t->getMessage(), PHP_EOL, $t->getTraceAsString()); + } + throw new \PHPUnit\TextUI\Configuration\BootstrapScriptException($message); + } + EventFacade::emitter()->testRunnerBootstrapFinished($filename); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\TextUI\CliArguments\Builder as CliConfigurationBuilder; +use PHPUnit\TextUI\CliArguments\Exception as CliConfigurationException; +use PHPUnit\TextUI\CliArguments\XmlConfigurationFileFinder; +use PHPUnit\TextUI\XmlConfiguration\DefaultConfiguration; +use PHPUnit\TextUI\XmlConfiguration\Exception as XmlConfigurationException; +use PHPUnit\TextUI\XmlConfiguration\Loader; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ +final readonly class Builder +{ + /** + * @param list $argv + * + * @throws ConfigurationCannotBeBuiltException + */ + public function build(array $argv): \PHPUnit\TextUI\Configuration\Configuration + { + try { + $cliConfiguration = (new CliConfigurationBuilder())->fromParameters($argv); + $configurationFile = (new XmlConfigurationFileFinder())->find($cliConfiguration); + $xmlConfiguration = DefaultConfiguration::create(); + if ($configurationFile !== \false) { + $xmlConfiguration = (new Loader())->load($configurationFile); + } + return \PHPUnit\TextUI\Configuration\Registry::init($cliConfiguration, $xmlConfiguration); + } catch (CliConfigurationException|XmlConfigurationException $e) { + throw new \PHPUnit\TextUI\Configuration\ConfigurationCannotBeBuiltException($e->getMessage(), $e->getCode(), $e); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\CliArguments; + +use const DIRECTORY_SEPARATOR; +use function assert; +use function basename; +use function explode; +use function getcwd; +use function is_file; +use function is_numeric; +use function sprintf; +use function strtolower; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\CliParser\Exception as CliParserException; +use PHPUnitPHAR\SebastianBergmann\CliParser\Parser as CliParser; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Builder +{ + /** + * @var non-empty-list + */ + private const array LONG_OPTIONS = ['all', 'atleast-version=', 'bootstrap=', 'cache-result', 'do-not-cache-result', 'cache-directory=', 'check-version', 'check-php-configuration', 'colors==', 'columns=', 'configuration=', 'warm-coverage-cache', 'coverage-filter=', 'coverage-clover=', 'coverage-cobertura=', 'coverage-crap4j=', 'coverage-html=', 'coverage-openclover=', 'coverage-php=', 'coverage-text==', 'only-summary-for-coverage-text', 'show-uncovered-for-coverage-text', 'coverage-xml=', 'exclude-source-from-xml-coverage', 'path-coverage', 'disallow-test-output', 'display-all-issues', 'display-incomplete', 'display-skipped', 'display-deprecations', 'display-phpunit-deprecations', 'display-phpunit-notices', 'display-errors', 'display-notices', 'display-warnings', 'default-time-limit=', 'enforce-time-limit', 'exclude-group=', 'filter=', 'exclude-filter=', 'generate-baseline=', 'use-baseline=', 'ignore-baseline', 'generate-configuration', 'globals-backup', 'group=', 'covers=', 'uses=', 'requires-php-extension=', 'help', 'resolve-dependencies', 'ignore-dependencies', 'include-path=', 'list-groups', 'list-suites', 'list-test-files', 'list-tests', 'list-tests-xml=', 'log-junit=', 'log-otr=', 'include-git-information', 'log-teamcity=', 'migrate-configuration', 'no-configuration', 'no-coverage', 'no-logging', 'no-extensions', 'no-output', 'no-progress', 'no-results', 'order-by=', 'process-isolation', 'do-not-report-useless-tests', 'random-order', 'random-order-seed=', 'reverse-order', 'reverse-list', 'static-backup', 'stderr', 'fail-on-all-issues', 'fail-on-deprecation', 'fail-on-phpunit-deprecation', 'fail-on-phpunit-notice', 'fail-on-phpunit-warning', 'fail-on-empty-test-suite', 'fail-on-incomplete', 'fail-on-notice', 'fail-on-risky', 'fail-on-skipped', 'fail-on-warning', 'do-not-fail-on-deprecation', 'do-not-fail-on-phpunit-deprecation', 'do-not-fail-on-phpunit-notice', 'do-not-fail-on-phpunit-warning', 'do-not-fail-on-empty-test-suite', 'do-not-fail-on-incomplete', 'do-not-fail-on-notice', 'do-not-fail-on-risky', 'do-not-fail-on-skipped', 'do-not-fail-on-warning', 'stop-on-defect', 'stop-on-deprecation==', 'stop-on-error', 'stop-on-failure', 'stop-on-incomplete', 'stop-on-notice', 'stop-on-risky', 'stop-on-skipped', 'stop-on-warning', 'strict-coverage', 'disable-coverage-ignore', 'strict-global-state', 'teamcity', 'testdox', 'testdox-summary', 'testdox-html=', 'testdox-text=', 'test-suffix=', 'testsuite=', 'exclude-testsuite=', 'test-files-file=', 'log-events-text=', 'log-events-verbose-text=', 'version', 'debug', 'with-telemetry', 'extension=']; + private const string SHORT_OPTIONS = 'd:c:h'; + /** + * @var array + */ + private array $processed = []; + /** + * @param list $parameters + * + * @throws Exception + */ + public function fromParameters(array $parameters): \PHPUnit\TextUI\CliArguments\Configuration + { + try { + $options = (new CliParser())->parse($parameters, self::SHORT_OPTIONS, self::LONG_OPTIONS); + } catch (CliParserException $e) { + throw new \PHPUnit\TextUI\CliArguments\Exception($e->getMessage(), $e->getCode(), $e); + } + $all = null; + $atLeastVersion = null; + $backupGlobals = null; + $backupStaticProperties = null; + $beStrictAboutChangesToGlobalState = null; + $bootstrap = null; + $cacheDirectory = null; + $cacheResult = null; + $checkPhpConfiguration = \false; + $checkVersion = \false; + $colors = null; + $columns = null; + $configuration = null; + $warmCoverageCache = \false; + $coverageFilter = null; + $coverageClover = null; + $coverageCobertura = null; + $coverageCrap4J = null; + $coverageHtml = null; + $coverageOpenClover = null; + $coveragePhp = null; + $coverageText = null; + $coverageTextShowUncoveredFiles = null; + $coverageTextShowOnlySummary = null; + $coverageXml = null; + $excludeSourceFromXmlCoverage = null; + $pathCoverage = null; + $defaultTimeLimit = null; + $disableCodeCoverageIgnore = null; + $disallowTestOutput = null; + $displayAllIssues = null; + $displayIncomplete = null; + $displaySkipped = null; + $displayDeprecations = null; + $displayPhpunitDeprecations = null; + $displayPhpunitNotices = null; + $displayErrors = null; + $displayNotices = null; + $displayWarnings = null; + $enforceTimeLimit = null; + $excludeGroups = null; + $executionOrder = null; + $executionOrderDefects = null; + $failOnAllIssues = null; + $failOnDeprecation = null; + $failOnPhpunitDeprecation = null; + $failOnPhpunitNotice = null; + $failOnPhpunitWarning = null; + $failOnEmptyTestSuite = null; + $failOnIncomplete = null; + $failOnNotice = null; + $failOnRisky = null; + $failOnSkipped = null; + $failOnWarning = null; + $doNotFailOnDeprecation = null; + $doNotFailOnPhpunitDeprecation = null; + $doNotFailOnPhpunitNotice = null; + $doNotFailOnPhpunitWarning = null; + $doNotFailOnEmptyTestSuite = null; + $doNotFailOnIncomplete = null; + $doNotFailOnNotice = null; + $doNotFailOnRisky = null; + $doNotFailOnSkipped = null; + $doNotFailOnWarning = null; + $stopOnDefect = null; + $stopOnDeprecation = null; + $specificDeprecationToStopOn = null; + $stopOnError = null; + $stopOnFailure = null; + $stopOnIncomplete = null; + $stopOnNotice = null; + $stopOnRisky = null; + $stopOnSkipped = null; + $stopOnWarning = null; + $filter = null; + $excludeFilter = null; + $generateBaseline = null; + $useBaseline = null; + $ignoreBaseline = \false; + $generateConfiguration = \false; + $migrateConfiguration = \false; + $groups = null; + $testsCovering = null; + $testsUsing = null; + $testsRequiringPhpExtension = null; + $help = \false; + $includePath = null; + $iniSettings = []; + $junitLogfile = null; + $otrLogfile = null; + $includeGitInformation = null; + $listGroups = \false; + $listSuites = \false; + $listTestFiles = \false; + $listTests = \false; + $listTestsXml = null; + $noCoverage = null; + $noExtensions = null; + $noOutput = null; + $noProgress = null; + $noResults = null; + $noLogging = null; + $processIsolation = null; + $randomOrderSeed = null; + $reportUselessTests = null; + $resolveDependencies = null; + $reverseList = null; + $stderr = null; + $strictCoverage = null; + $teamcityLogfile = null; + $testdoxHtmlFile = null; + $testdoxTextFile = null; + $testSuffixes = null; + $testSuite = null; + $excludeTestSuite = null; + $testFilesFile = null; + $useDefaultConfiguration = \true; + $version = \false; + $logEventsText = null; + $logEventsVerboseText = null; + $printerTeamCity = null; + $printerTestDox = null; + $printerTestDoxSummary = null; + $debug = \false; + $withTelemetry = \false; + $extensions = []; + foreach ($options[0] as $option) { + $optionAllowedMultipleTimes = \false; + switch ($option[0]) { + case '--all': + $all = \true; + break; + case '--colors': + $colors = \PHPUnit\TextUI\Configuration\Configuration::COLOR_AUTO; + if ($option[1] !== null) { + $colors = $option[1]; + } + break; + case '--bootstrap': + $bootstrap = $option[1]; + break; + case '--cache-directory': + $cacheDirectory = $option[1]; + break; + case '--cache-result': + $cacheResult = \true; + break; + case '--do-not-cache-result': + $cacheResult = \false; + break; + case '--columns': + if (is_numeric($option[1])) { + $columns = (int) $option[1]; + } elseif ($option[1] === 'max') { + $columns = 'max'; + } + break; + case 'c': + case '--configuration': + $configuration = $option[1]; + break; + case '--warm-coverage-cache': + $warmCoverageCache = \true; + break; + case '--coverage-clover': + $coverageClover = $option[1]; + break; + case '--coverage-cobertura': + $coverageCobertura = $option[1]; + break; + case '--coverage-crap4j': + $coverageCrap4J = $option[1]; + break; + case '--coverage-html': + $coverageHtml = $option[1]; + break; + case '--coverage-php': + $coveragePhp = $option[1]; + break; + case '--coverage-openclover': + $coverageOpenClover = $option[1]; + break; + case '--coverage-text': + if ($option[1] === null) { + $option[1] = 'php://stdout'; + } + $coverageText = $option[1]; + break; + case '--only-summary-for-coverage-text': + $coverageTextShowOnlySummary = \true; + break; + case '--show-uncovered-for-coverage-text': + $coverageTextShowUncoveredFiles = \true; + break; + case '--coverage-xml': + $coverageXml = $option[1]; + break; + case '--exclude-source-from-xml-coverage': + $excludeSourceFromXmlCoverage = \true; + break; + case '--path-coverage': + $pathCoverage = \true; + break; + case 'd': + $tmp = explode('=', $option[1]); + if (isset($tmp[0])) { + assert($tmp[0] !== ''); + if (isset($tmp[1])) { + assert($tmp[1] !== ''); + $iniSettings[$tmp[0]] = $tmp[1]; + } else { + $iniSettings[$tmp[0]] = '1'; + } + } + $optionAllowedMultipleTimes = \true; + break; + case 'h': + case '--help': + $help = \true; + break; + case '--filter': + $filter = $option[1]; + break; + case '--exclude-filter': + $excludeFilter = $option[1]; + break; + case '--testsuite': + $testSuite = $option[1]; + break; + case '--exclude-testsuite': + $excludeTestSuite = $option[1]; + break; + case '--test-files-file': + $testFilesFile = $option[1]; + break; + case '--generate-baseline': + $generateBaseline = $option[1]; + if (basename($generateBaseline) === $generateBaseline) { + $generateBaseline = getcwd() . DIRECTORY_SEPARATOR . $generateBaseline; + } + break; + case '--use-baseline': + $useBaseline = $option[1]; + if (basename($useBaseline) === $useBaseline && !is_file($useBaseline)) { + $useBaseline = getcwd() . DIRECTORY_SEPARATOR . $useBaseline; + } + break; + case '--ignore-baseline': + $ignoreBaseline = \true; + break; + case '--generate-configuration': + $generateConfiguration = \true; + break; + case '--migrate-configuration': + $migrateConfiguration = \true; + break; + case '--group': + if ($groups === null) { + $groups = []; + } + $groups[] = $option[1]; + $optionAllowedMultipleTimes = \true; + break; + case '--exclude-group': + if ($excludeGroups === null) { + $excludeGroups = []; + } + $excludeGroups[] = $option[1]; + $optionAllowedMultipleTimes = \true; + break; + case '--covers': + if ($testsCovering === null) { + $testsCovering = []; + } + $testsCovering[] = strtolower($option[1]); + $optionAllowedMultipleTimes = \true; + break; + case '--uses': + if ($testsUsing === null) { + $testsUsing = []; + } + $testsUsing[] = strtolower($option[1]); + $optionAllowedMultipleTimes = \true; + break; + case '--requires-php-extension': + if ($testsRequiringPhpExtension === null) { + $testsRequiringPhpExtension = []; + } + $testsRequiringPhpExtension[] = strtolower($option[1]); + $optionAllowedMultipleTimes = \true; + break; + case '--test-suffix': + if ($testSuffixes === null) { + $testSuffixes = []; + } + $testSuffixes[] = $option[1]; + $optionAllowedMultipleTimes = \true; + break; + case '--include-path': + $includePath = $option[1]; + break; + case '--list-groups': + $listGroups = \true; + break; + case '--list-suites': + $listSuites = \true; + break; + case '--list-test-files': + $listTestFiles = \true; + break; + case '--list-tests': + $listTests = \true; + break; + case '--list-tests-xml': + $listTestsXml = $option[1]; + break; + case '--log-junit': + $junitLogfile = $option[1]; + break; + case '--log-otr': + $otrLogfile = $option[1]; + break; + case '--include-git-information': + $includeGitInformation = \true; + break; + case '--log-teamcity': + $teamcityLogfile = $option[1]; + break; + case '--order-by': + foreach (explode(',', $option[1]) as $order) { + switch ($order) { + case 'default': + $executionOrder = TestSuiteSorter::ORDER_DEFAULT; + $executionOrderDefects = TestSuiteSorter::ORDER_DEFAULT; + $resolveDependencies = \true; + break; + case 'defects': + $executionOrderDefects = TestSuiteSorter::ORDER_DEFECTS_FIRST; + break; + case 'depends': + $resolveDependencies = \true; + break; + case 'duration': + $executionOrder = TestSuiteSorter::ORDER_DURATION; + break; + case 'no-depends': + $resolveDependencies = \false; + break; + case 'random': + $executionOrder = TestSuiteSorter::ORDER_RANDOMIZED; + break; + case 'reverse': + $executionOrder = TestSuiteSorter::ORDER_REVERSED; + break; + case 'size': + $executionOrder = TestSuiteSorter::ORDER_SIZE; + break; + default: + throw new \PHPUnit\TextUI\CliArguments\Exception(sprintf('unrecognized --order-by option: %s', $order)); + } + } + break; + case '--process-isolation': + $processIsolation = \true; + break; + case '--stderr': + $stderr = \true; + break; + case '--fail-on-all-issues': + $failOnAllIssues = \true; + break; + case '--fail-on-deprecation': + $this->warnWhenOptionsConflict($doNotFailOnDeprecation, '--fail-on-deprecation', '--do-not-fail-on-deprecation'); + $failOnDeprecation = \true; + break; + case '--fail-on-phpunit-deprecation': + $this->warnWhenOptionsConflict($doNotFailOnPhpunitDeprecation, '--fail-on-phpunit-deprecation', '--do-not-fail-on-phpunit-deprecation'); + $failOnPhpunitDeprecation = \true; + break; + case '--fail-on-phpunit-notice': + $this->warnWhenOptionsConflict($doNotFailOnPhpunitNotice, '--fail-on-phpunit-notice', '--do-not-fail-on-phpunit-notice'); + $failOnPhpunitNotice = \true; + break; + case '--fail-on-phpunit-warning': + $this->warnWhenOptionsConflict($doNotFailOnPhpunitWarning, '--fail-on-phpunit-warning', '--do-not-fail-on-phpunit-warning'); + $failOnPhpunitWarning = \true; + break; + case '--fail-on-empty-test-suite': + $this->warnWhenOptionsConflict($doNotFailOnEmptyTestSuite, '--fail-on-empty-test-suite', '--do-not-fail-on-empty-test-suite'); + $failOnEmptyTestSuite = \true; + break; + case '--fail-on-incomplete': + $this->warnWhenOptionsConflict($doNotFailOnIncomplete, '--fail-on-incomplete', '--do-not-fail-on-incomplete'); + $failOnIncomplete = \true; + break; + case '--fail-on-notice': + $this->warnWhenOptionsConflict($doNotFailOnNotice, '--fail-on-notice', '--do-not-fail-on-notice'); + $failOnNotice = \true; + break; + case '--fail-on-risky': + $this->warnWhenOptionsConflict($doNotFailOnRisky, '--fail-on-risky', '--do-not-fail-on-risky'); + $failOnRisky = \true; + break; + case '--fail-on-skipped': + $this->warnWhenOptionsConflict($doNotFailOnSkipped, '--fail-on-skipped', '--do-not-fail-on-skipped'); + $failOnSkipped = \true; + break; + case '--fail-on-warning': + $this->warnWhenOptionsConflict($doNotFailOnWarning, '--fail-on-warning', '--do-not-fail-on-warning'); + $failOnWarning = \true; + break; + case '--do-not-fail-on-deprecation': + $this->warnWhenOptionsConflict($failOnDeprecation, '--do-not-fail-on-deprecation', '--fail-on-deprecation'); + $doNotFailOnDeprecation = \true; + break; + case '--do-not-fail-on-phpunit-deprecation': + $this->warnWhenOptionsConflict($failOnPhpunitDeprecation, '--do-not-fail-on-phpunit-deprecation', '--fail-on-phpunit-deprecation'); + $doNotFailOnPhpunitDeprecation = \true; + break; + case '--do-not-fail-on-phpunit-notice': + $this->warnWhenOptionsConflict($failOnPhpunitNotice, '--do-not-fail-on-phpunit-notice', '--fail-on-phpunit-notice'); + $doNotFailOnPhpunitNotice = \true; + break; + case '--do-not-fail-on-phpunit-warning': + $this->warnWhenOptionsConflict($failOnPhpunitWarning, '--do-not-fail-on-phpunit-warning', '--fail-on-phpunit-warning'); + $doNotFailOnPhpunitWarning = \true; + break; + case '--do-not-fail-on-empty-test-suite': + $this->warnWhenOptionsConflict($failOnEmptyTestSuite, '--do-not-fail-on-empty-test-suite', '--fail-on-empty-test-suite'); + $doNotFailOnEmptyTestSuite = \true; + break; + case '--do-not-fail-on-incomplete': + $this->warnWhenOptionsConflict($failOnIncomplete, '--do-not-fail-on-incomplete', '--fail-on-incomplete'); + $doNotFailOnIncomplete = \true; + break; + case '--do-not-fail-on-notice': + $this->warnWhenOptionsConflict($failOnNotice, '--do-not-fail-on-notice', '--fail-on-notice'); + $doNotFailOnNotice = \true; + break; + case '--do-not-fail-on-risky': + $this->warnWhenOptionsConflict($failOnRisky, '--do-not-fail-on-risky', '--fail-on-risky'); + $doNotFailOnRisky = \true; + break; + case '--do-not-fail-on-skipped': + $this->warnWhenOptionsConflict($failOnSkipped, '--do-not-fail-on-skipped', '--fail-on-skipped'); + $doNotFailOnSkipped = \true; + break; + case '--do-not-fail-on-warning': + $this->warnWhenOptionsConflict($failOnWarning, '--do-not-fail-on-warning', '--fail-on-warning'); + $doNotFailOnWarning = \true; + break; + case '--stop-on-defect': + $stopOnDefect = \true; + break; + case '--stop-on-deprecation': + $stopOnDeprecation = \true; + if ($option[1] !== null) { + $specificDeprecationToStopOn = $option[1]; + } + break; + case '--stop-on-error': + $stopOnError = \true; + break; + case '--stop-on-failure': + $stopOnFailure = \true; + break; + case '--stop-on-incomplete': + $stopOnIncomplete = \true; + break; + case '--stop-on-notice': + $stopOnNotice = \true; + break; + case '--stop-on-risky': + $stopOnRisky = \true; + break; + case '--stop-on-skipped': + $stopOnSkipped = \true; + break; + case '--stop-on-warning': + $stopOnWarning = \true; + break; + case '--teamcity': + $printerTeamCity = \true; + break; + case '--testdox': + $printerTestDox = \true; + break; + case '--testdox-summary': + $printerTestDoxSummary = \true; + break; + case '--testdox-html': + $testdoxHtmlFile = $option[1]; + break; + case '--testdox-text': + $testdoxTextFile = $option[1]; + break; + case '--no-configuration': + $useDefaultConfiguration = \false; + break; + case '--no-extensions': + $noExtensions = \true; + break; + case '--no-coverage': + $noCoverage = \true; + break; + case '--no-logging': + $noLogging = \true; + break; + case '--no-output': + $noOutput = \true; + break; + case '--no-progress': + $noProgress = \true; + break; + case '--no-results': + $noResults = \true; + break; + case '--globals-backup': + $backupGlobals = \true; + break; + case '--static-backup': + $backupStaticProperties = \true; + break; + case '--atleast-version': + $atLeastVersion = $option[1]; + break; + case '--version': + $version = \true; + break; + case '--do-not-report-useless-tests': + $reportUselessTests = \false; + break; + case '--strict-coverage': + $strictCoverage = \true; + break; + case '--disable-coverage-ignore': + $disableCodeCoverageIgnore = \true; + break; + case '--strict-global-state': + $beStrictAboutChangesToGlobalState = \true; + break; + case '--disallow-test-output': + $disallowTestOutput = \true; + break; + case '--display-all-issues': + $displayAllIssues = \true; + break; + case '--display-incomplete': + $displayIncomplete = \true; + break; + case '--display-skipped': + $displaySkipped = \true; + break; + case '--display-deprecations': + $displayDeprecations = \true; + break; + case '--display-phpunit-deprecations': + $displayPhpunitDeprecations = \true; + break; + case '--display-phpunit-notices': + $displayPhpunitNotices = \true; + break; + case '--display-errors': + $displayErrors = \true; + break; + case '--display-notices': + $displayNotices = \true; + break; + case '--display-warnings': + $displayWarnings = \true; + break; + case '--default-time-limit': + $defaultTimeLimit = (int) $option[1]; + break; + case '--enforce-time-limit': + $enforceTimeLimit = \true; + break; + case '--reverse-list': + $reverseList = \true; + break; + case '--check-php-configuration': + $checkPhpConfiguration = \true; + break; + case '--check-version': + $checkVersion = \true; + break; + case '--coverage-filter': + if ($coverageFilter === null) { + $coverageFilter = []; + } + $coverageFilter[] = $option[1]; + $optionAllowedMultipleTimes = \true; + break; + case '--random-order': + $executionOrder = TestSuiteSorter::ORDER_RANDOMIZED; + break; + case '--random-order-seed': + $randomOrderSeed = (int) $option[1]; + break; + case '--resolve-dependencies': + $resolveDependencies = \true; + break; + case '--ignore-dependencies': + $resolveDependencies = \false; + break; + case '--reverse-order': + $executionOrder = TestSuiteSorter::ORDER_REVERSED; + break; + case '--log-events-text': + $logEventsText = Filesystem::resolveStreamOrFile($option[1]); + if ($logEventsText === \false) { + throw new \PHPUnit\TextUI\CliArguments\Exception(sprintf('The path "%s" specified for the --log-events-text option could not be resolved', $option[1])); + } + break; + case '--log-events-verbose-text': + $logEventsVerboseText = Filesystem::resolveStreamOrFile($option[1]); + if ($logEventsVerboseText === \false) { + throw new \PHPUnit\TextUI\CliArguments\Exception(sprintf('The path "%s" specified for the --log-events-verbose-text option could not be resolved', $option[1])); + } + break; + case '--debug': + $debug = \true; + break; + case '--with-telemetry': + $withTelemetry = \true; + break; + case '--extension': + $extensions[] = $option[1]; + $optionAllowedMultipleTimes = \true; + break; + } + if (!$optionAllowedMultipleTimes) { + $this->markProcessed($option[0]); + } + } + if ($iniSettings === []) { + $iniSettings = null; + } + if ($extensions === []) { + $extensions = null; + } + if ($randomOrderSeed !== null && $executionOrder !== TestSuiteSorter::ORDER_RANDOMIZED) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning('--random-order-seed is only used when execution order is "random" (use --order-by random or --random-order)'); + } + return new \PHPUnit\TextUI\CliArguments\Configuration($options[1], $testFilesFile, $all, $atLeastVersion, $backupGlobals, $backupStaticProperties, $beStrictAboutChangesToGlobalState, $bootstrap, $cacheDirectory, $cacheResult, $checkPhpConfiguration, $checkVersion, $colors, $columns, $configuration, $coverageClover, $coverageCobertura, $coverageCrap4J, $coverageHtml, $coverageOpenClover, $coveragePhp, $coverageText, $coverageTextShowUncoveredFiles, $coverageTextShowOnlySummary, $coverageXml, $excludeSourceFromXmlCoverage, $pathCoverage, $warmCoverageCache, $defaultTimeLimit, $disableCodeCoverageIgnore, $disallowTestOutput, $enforceTimeLimit, $excludeGroups, $executionOrder, $executionOrderDefects, $failOnAllIssues, $failOnDeprecation, $failOnPhpunitDeprecation, $failOnPhpunitNotice, $failOnPhpunitWarning, $failOnEmptyTestSuite, $failOnIncomplete, $failOnNotice, $failOnRisky, $failOnSkipped, $failOnWarning, $doNotFailOnDeprecation, $doNotFailOnPhpunitDeprecation, $doNotFailOnPhpunitNotice, $doNotFailOnPhpunitWarning, $doNotFailOnEmptyTestSuite, $doNotFailOnIncomplete, $doNotFailOnNotice, $doNotFailOnRisky, $doNotFailOnSkipped, $doNotFailOnWarning, $stopOnDefect, $stopOnDeprecation, $specificDeprecationToStopOn, $stopOnError, $stopOnFailure, $stopOnIncomplete, $stopOnNotice, $stopOnRisky, $stopOnSkipped, $stopOnWarning, $filter, $excludeFilter, $generateBaseline, $useBaseline, $ignoreBaseline, $generateConfiguration, $migrateConfiguration, $groups, $testsCovering, $testsUsing, $testsRequiringPhpExtension, $help, $includePath, $iniSettings, $junitLogfile, $otrLogfile, $includeGitInformation, $listGroups, $listSuites, $listTestFiles, $listTests, $listTestsXml, $noCoverage, $noExtensions, $noOutput, $noProgress, $noResults, $noLogging, $processIsolation, $randomOrderSeed, $reportUselessTests, $resolveDependencies, $reverseList, $stderr, $strictCoverage, $teamcityLogfile, $testdoxHtmlFile, $testdoxTextFile, $testSuffixes, $testSuite, $excludeTestSuite, $useDefaultConfiguration, $displayAllIssues, $displayIncomplete, $displaySkipped, $displayDeprecations, $displayPhpunitDeprecations, $displayPhpunitNotices, $displayErrors, $displayNotices, $displayWarnings, $version, $coverageFilter, $logEventsText, $logEventsVerboseText, $printerTeamCity, $printerTestDox, $printerTestDoxSummary, $debug, $withTelemetry, $extensions); + } + /** + * @param non-empty-string $option + */ + private function markProcessed(string $option): void + { + if (!isset($this->processed[$option])) { + $this->processed[$option] = 1; + return; + } + $this->processed[$option]++; + if ($this->processed[$option] === 2) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Option %s cannot be used more than once', $option)); + } + } + /** + * @param non-empty-string $option + */ + private function warnWhenOptionsConflict(?bool $current, string $option, string $opposite): void + { + if ($current === null) { + return; + } + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Options %s and %s cannot be used together', $option, $opposite)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\CliArguments; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Configuration +{ + /** + * @var list + */ + private array $arguments; + private ?string $testFilesFile; + private ?bool $all; + private ?string $atLeastVersion; + private ?bool $backupGlobals; + private ?bool $backupStaticProperties; + private ?bool $beStrictAboutChangesToGlobalState; + private ?string $bootstrap; + private ?string $cacheDirectory; + private ?bool $cacheResult; + private bool $checkPhpConfiguration; + private bool $checkVersion; + private ?string $colors; + private null|int|string $columns; + private ?string $configurationFile; + /** + * @var ?non-empty-list + */ + private ?array $coverageFilter; + private ?string $coverageClover; + private ?string $coverageCobertura; + private ?string $coverageCrap4J; + private ?string $coverageHtml; + private ?string $coverageOpenClover; + private ?string $coveragePhp; + private ?string $coverageText; + private ?bool $coverageTextShowUncoveredFiles; + private ?bool $coverageTextShowOnlySummary; + private ?string $coverageXml; + private ?bool $excludeSourceFromXmlCoverage; + private ?bool $pathCoverage; + private bool $warmCoverageCache; + private ?int $defaultTimeLimit; + private ?bool $disableCodeCoverageIgnore; + private ?bool $disallowTestOutput; + private ?bool $enforceTimeLimit; + /** + * @var ?non-empty-list + */ + private ?array $excludeGroups; + private ?int $executionOrder; + private ?int $executionOrderDefects; + private ?bool $failOnAllIssues; + private ?bool $failOnDeprecation; + private ?bool $failOnPhpunitDeprecation; + private ?bool $failOnPhpunitNotice; + private ?bool $failOnPhpunitWarning; + private ?bool $failOnEmptyTestSuite; + private ?bool $failOnIncomplete; + private ?bool $failOnNotice; + private ?bool $failOnRisky; + private ?bool $failOnSkipped; + private ?bool $failOnWarning; + private ?bool $doNotFailOnDeprecation; + private ?bool $doNotFailOnPhpunitDeprecation; + private ?bool $doNotFailOnPhpunitNotice; + private ?bool $doNotFailOnPhpunitWarning; + private ?bool $doNotFailOnEmptyTestSuite; + private ?bool $doNotFailOnIncomplete; + private ?bool $doNotFailOnNotice; + private ?bool $doNotFailOnRisky; + private ?bool $doNotFailOnSkipped; + private ?bool $doNotFailOnWarning; + private ?bool $stopOnDefect; + private ?bool $stopOnDeprecation; + private ?string $specificDeprecationToStopOn; + private ?bool $stopOnError; + private ?bool $stopOnFailure; + private ?bool $stopOnIncomplete; + private ?bool $stopOnNotice; + private ?bool $stopOnRisky; + private ?bool $stopOnSkipped; + private ?bool $stopOnWarning; + private ?string $filter; + private ?string $excludeFilter; + private ?string $generateBaseline; + private ?string $useBaseline; + private bool $ignoreBaseline; + private bool $generateConfiguration; + private bool $migrateConfiguration; + /** + * @var ?non-empty-list + */ + private ?array $groups; + /** + * @var ?non-empty-list + */ + private ?array $testsCovering; + /** + * @var ?non-empty-list + */ + private ?array $testsUsing; + /** + * @var ?non-empty-list + */ + private ?array $testsRequiringPhpExtension; + private bool $help; + private ?string $includePath; + /** + * @var ?non-empty-array + */ + private ?array $iniSettings; + private ?string $junitLogfile; + private ?string $otrLogfile; + private ?bool $includeGitInformation; + private bool $listGroups; + private bool $listSuites; + private bool $listTestFiles; + private bool $listTests; + private ?string $listTestsXml; + private ?bool $noCoverage; + private ?bool $noExtensions; + private ?bool $noOutput; + private ?bool $noProgress; + private ?bool $noResults; + private ?bool $noLogging; + private ?bool $processIsolation; + private ?int $randomOrderSeed; + private ?bool $reportUselessTests; + private ?bool $resolveDependencies; + private ?bool $reverseList; + private ?bool $stderr; + private ?bool $strictCoverage; + private ?string $teamcityLogfile; + private ?bool $teamCityPrinter; + private ?string $testdoxHtmlFile; + private ?string $testdoxTextFile; + private ?bool $testdoxPrinter; + private ?bool $testdoxPrinterSummary; + /** + * @var ?non-empty-list + */ + private ?array $testSuffixes; + private ?string $testSuite; + private ?string $excludeTestSuite; + private bool $useDefaultConfiguration; + private ?bool $displayDetailsOnAllIssues; + private ?bool $displayDetailsOnIncompleteTests; + private ?bool $displayDetailsOnSkippedTests; + private ?bool $displayDetailsOnTestsThatTriggerDeprecations; + private ?bool $displayDetailsOnPhpunitDeprecations; + private ?bool $displayDetailsOnPhpunitNotices; + private ?bool $displayDetailsOnTestsThatTriggerErrors; + private ?bool $displayDetailsOnTestsThatTriggerNotices; + private ?bool $displayDetailsOnTestsThatTriggerWarnings; + private bool $version; + private ?string $logEventsText; + private ?string $logEventsVerboseText; + private bool $debug; + private bool $withTelemetry; + /** + * @var ?non-empty-list + */ + private ?array $extensions; + /** + * @param list $arguments + * @param ?non-empty-list $excludeGroups + * @param ?non-empty-list $groups + * @param ?non-empty-list $testsCovering + * @param ?non-empty-list $testsUsing + * @param ?non-empty-list $testsRequiringPhpExtension + * @param ?non-empty-array $iniSettings + * @param ?non-empty-list $testSuffixes + * @param ?non-empty-list $coverageFilter + * @param ?non-empty-list $extensions + */ + public function __construct(array $arguments, ?string $testFilesFile, ?bool $all, ?string $atLeastVersion, ?bool $backupGlobals, ?bool $backupStaticProperties, ?bool $beStrictAboutChangesToGlobalState, ?string $bootstrap, ?string $cacheDirectory, ?bool $cacheResult, bool $checkPhpConfiguration, bool $checkVersion, ?string $colors, null|int|string $columns, ?string $configurationFile, ?string $coverageClover, ?string $coverageCobertura, ?string $coverageCrap4J, ?string $coverageHtml, ?string $coverageOpenClover, ?string $coveragePhp, ?string $coverageText, ?bool $coverageTextShowUncoveredFiles, ?bool $coverageTextShowOnlySummary, ?string $coverageXml, ?bool $coverageXmlIncludeSource, ?bool $pathCoverage, bool $warmCoverageCache, ?int $defaultTimeLimit, ?bool $disableCodeCoverageIgnore, ?bool $disallowTestOutput, ?bool $enforceTimeLimit, ?array $excludeGroups, ?int $executionOrder, ?int $executionOrderDefects, ?bool $failOnAllIssues, ?bool $failOnDeprecation, ?bool $failOnPhpunitDeprecation, ?bool $failOnPhpunitNotice, ?bool $failOnPhpunitWarning, ?bool $failOnEmptyTestSuite, ?bool $failOnIncomplete, ?bool $failOnNotice, ?bool $failOnRisky, ?bool $failOnSkipped, ?bool $failOnWarning, ?bool $doNotFailOnDeprecation, ?bool $doNotFailOnPhpunitDeprecation, ?bool $doNotFailOnPhpunitNotice, ?bool $doNotFailOnPhpunitWarning, ?bool $doNotFailOnEmptyTestSuite, ?bool $doNotFailOnIncomplete, ?bool $doNotFailOnNotice, ?bool $doNotFailOnRisky, ?bool $doNotFailOnSkipped, ?bool $doNotFailOnWarning, ?bool $stopOnDefect, ?bool $stopOnDeprecation, ?string $specificDeprecationToStopOn, ?bool $stopOnError, ?bool $stopOnFailure, ?bool $stopOnIncomplete, ?bool $stopOnNotice, ?bool $stopOnRisky, ?bool $stopOnSkipped, ?bool $stopOnWarning, ?string $filter, ?string $excludeFilter, ?string $generateBaseline, ?string $useBaseline, bool $ignoreBaseline, bool $generateConfiguration, bool $migrateConfiguration, ?array $groups, ?array $testsCovering, ?array $testsUsing, ?array $testsRequiringPhpExtension, bool $help, ?string $includePath, ?array $iniSettings, ?string $junitLogfile, ?string $otrLogfile, ?bool $includeGitInformation, bool $listGroups, bool $listSuites, bool $listTestFiles, bool $listTests, ?string $listTestsXml, ?bool $noCoverage, ?bool $noExtensions, ?bool $noOutput, ?bool $noProgress, ?bool $noResults, ?bool $noLogging, ?bool $processIsolation, ?int $randomOrderSeed, ?bool $reportUselessTests, ?bool $resolveDependencies, ?bool $reverseList, ?bool $stderr, ?bool $strictCoverage, ?string $teamcityLogfile, ?string $testdoxHtmlFile, ?string $testdoxTextFile, ?array $testSuffixes, ?string $testSuite, ?string $excludeTestSuite, bool $useDefaultConfiguration, ?bool $displayDetailsOnAllIssues, ?bool $displayDetailsOnIncompleteTests, ?bool $displayDetailsOnSkippedTests, ?bool $displayDetailsOnTestsThatTriggerDeprecations, ?bool $displayDetailsOnPhpunitDeprecations, ?bool $displayDetailsOnPhpunitNotices, ?bool $displayDetailsOnTestsThatTriggerErrors, ?bool $displayDetailsOnTestsThatTriggerNotices, ?bool $displayDetailsOnTestsThatTriggerWarnings, bool $version, ?array $coverageFilter, ?string $logEventsText, ?string $logEventsVerboseText, ?bool $printerTeamCity, ?bool $testdoxPrinter, ?bool $testdoxPrinterSummary, bool $debug, bool $withTelemetry, ?array $extensions) + { + $this->arguments = $arguments; + $this->testFilesFile = $testFilesFile; + $this->all = $all; + $this->atLeastVersion = $atLeastVersion; + $this->backupGlobals = $backupGlobals; + $this->backupStaticProperties = $backupStaticProperties; + $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState; + $this->bootstrap = $bootstrap; + $this->cacheDirectory = $cacheDirectory; + $this->cacheResult = $cacheResult; + $this->checkPhpConfiguration = $checkPhpConfiguration; + $this->checkVersion = $checkVersion; + $this->colors = $colors; + $this->columns = $columns; + $this->configurationFile = $configurationFile; + $this->coverageFilter = $coverageFilter; + $this->coverageClover = $coverageClover; + $this->coverageCobertura = $coverageCobertura; + $this->coverageCrap4J = $coverageCrap4J; + $this->coverageHtml = $coverageHtml; + $this->coverageOpenClover = $coverageOpenClover; + $this->coveragePhp = $coveragePhp; + $this->coverageText = $coverageText; + $this->coverageTextShowUncoveredFiles = $coverageTextShowUncoveredFiles; + $this->coverageTextShowOnlySummary = $coverageTextShowOnlySummary; + $this->coverageXml = $coverageXml; + $this->excludeSourceFromXmlCoverage = $coverageXmlIncludeSource; + $this->pathCoverage = $pathCoverage; + $this->warmCoverageCache = $warmCoverageCache; + $this->defaultTimeLimit = $defaultTimeLimit; + $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore; + $this->disallowTestOutput = $disallowTestOutput; + $this->enforceTimeLimit = $enforceTimeLimit; + $this->excludeGroups = $excludeGroups; + $this->executionOrder = $executionOrder; + $this->executionOrderDefects = $executionOrderDefects; + $this->failOnAllIssues = $failOnAllIssues; + $this->failOnDeprecation = $failOnDeprecation; + $this->failOnPhpunitDeprecation = $failOnPhpunitDeprecation; + $this->failOnPhpunitNotice = $failOnPhpunitNotice; + $this->failOnPhpunitWarning = $failOnPhpunitWarning; + $this->failOnEmptyTestSuite = $failOnEmptyTestSuite; + $this->failOnIncomplete = $failOnIncomplete; + $this->failOnNotice = $failOnNotice; + $this->failOnRisky = $failOnRisky; + $this->failOnSkipped = $failOnSkipped; + $this->failOnWarning = $failOnWarning; + $this->doNotFailOnDeprecation = $doNotFailOnDeprecation; + $this->doNotFailOnPhpunitDeprecation = $doNotFailOnPhpunitDeprecation; + $this->doNotFailOnPhpunitNotice = $doNotFailOnPhpunitNotice; + $this->doNotFailOnPhpunitWarning = $doNotFailOnPhpunitWarning; + $this->doNotFailOnEmptyTestSuite = $doNotFailOnEmptyTestSuite; + $this->doNotFailOnIncomplete = $doNotFailOnIncomplete; + $this->doNotFailOnNotice = $doNotFailOnNotice; + $this->doNotFailOnRisky = $doNotFailOnRisky; + $this->doNotFailOnSkipped = $doNotFailOnSkipped; + $this->doNotFailOnWarning = $doNotFailOnWarning; + $this->stopOnDefect = $stopOnDefect; + $this->stopOnDeprecation = $stopOnDeprecation; + $this->specificDeprecationToStopOn = $specificDeprecationToStopOn; + $this->stopOnError = $stopOnError; + $this->stopOnFailure = $stopOnFailure; + $this->stopOnIncomplete = $stopOnIncomplete; + $this->stopOnNotice = $stopOnNotice; + $this->stopOnRisky = $stopOnRisky; + $this->stopOnSkipped = $stopOnSkipped; + $this->stopOnWarning = $stopOnWarning; + $this->filter = $filter; + $this->excludeFilter = $excludeFilter; + $this->generateBaseline = $generateBaseline; + $this->useBaseline = $useBaseline; + $this->ignoreBaseline = $ignoreBaseline; + $this->generateConfiguration = $generateConfiguration; + $this->migrateConfiguration = $migrateConfiguration; + $this->groups = $groups; + $this->testsCovering = $testsCovering; + $this->testsUsing = $testsUsing; + $this->testsRequiringPhpExtension = $testsRequiringPhpExtension; + $this->help = $help; + $this->includePath = $includePath; + $this->iniSettings = $iniSettings; + $this->junitLogfile = $junitLogfile; + $this->otrLogfile = $otrLogfile; + $this->includeGitInformation = $includeGitInformation; + $this->listGroups = $listGroups; + $this->listSuites = $listSuites; + $this->listTestFiles = $listTestFiles; + $this->listTests = $listTests; + $this->listTestsXml = $listTestsXml; + $this->noCoverage = $noCoverage; + $this->noExtensions = $noExtensions; + $this->noOutput = $noOutput; + $this->noProgress = $noProgress; + $this->noResults = $noResults; + $this->noLogging = $noLogging; + $this->processIsolation = $processIsolation; + $this->randomOrderSeed = $randomOrderSeed; + $this->reportUselessTests = $reportUselessTests; + $this->resolveDependencies = $resolveDependencies; + $this->reverseList = $reverseList; + $this->stderr = $stderr; + $this->strictCoverage = $strictCoverage; + $this->teamcityLogfile = $teamcityLogfile; + $this->testdoxHtmlFile = $testdoxHtmlFile; + $this->testdoxTextFile = $testdoxTextFile; + $this->testSuffixes = $testSuffixes; + $this->testSuite = $testSuite; + $this->excludeTestSuite = $excludeTestSuite; + $this->useDefaultConfiguration = $useDefaultConfiguration; + $this->displayDetailsOnAllIssues = $displayDetailsOnAllIssues; + $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; + $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; + $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; + $this->displayDetailsOnPhpunitDeprecations = $displayDetailsOnPhpunitDeprecations; + $this->displayDetailsOnPhpunitNotices = $displayDetailsOnPhpunitNotices; + $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; + $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; + $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; + $this->version = $version; + $this->logEventsText = $logEventsText; + $this->logEventsVerboseText = $logEventsVerboseText; + $this->teamCityPrinter = $printerTeamCity; + $this->testdoxPrinter = $testdoxPrinter; + $this->testdoxPrinterSummary = $testdoxPrinterSummary; + $this->debug = $debug; + $this->withTelemetry = $withTelemetry; + $this->extensions = $extensions; + } + /** + * @return list + */ + public function arguments(): array + { + return $this->arguments; + } + /** + * @phpstan-assert-if-true !null $this->testFilesFile + */ + public function hasTestFilesFile(): bool + { + return $this->testFilesFile !== null; + } + /** + * @throws Exception + */ + public function testFilesFile(): string + { + if (!$this->hasTestFilesFile()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->testFilesFile; + } + /** + * @phpstan-assert-if-true !null $this->all + */ + public function hasAll(): bool + { + return $this->all !== null; + } + /** + * @throws Exception + */ + public function all(): bool + { + if (!$this->hasAll()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->all; + } + /** + * @phpstan-assert-if-true !null $this->atLeastVersion + */ + public function hasAtLeastVersion(): bool + { + return $this->atLeastVersion !== null; + } + /** + * @throws Exception + */ + public function atLeastVersion(): string + { + if (!$this->hasAtLeastVersion()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->atLeastVersion; + } + /** + * @phpstan-assert-if-true !null $this->backupGlobals + */ + public function hasBackupGlobals(): bool + { + return $this->backupGlobals !== null; + } + /** + * @throws Exception + */ + public function backupGlobals(): bool + { + if (!$this->hasBackupGlobals()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->backupGlobals; + } + /** + * @phpstan-assert-if-true !null $this->backupStaticProperties + */ + public function hasBackupStaticProperties(): bool + { + return $this->backupStaticProperties !== null; + } + /** + * @throws Exception + */ + public function backupStaticProperties(): bool + { + if (!$this->hasBackupStaticProperties()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->backupStaticProperties; + } + /** + * @phpstan-assert-if-true !null $this->beStrictAboutChangesToGlobalState + */ + public function hasBeStrictAboutChangesToGlobalState(): bool + { + return $this->beStrictAboutChangesToGlobalState !== null; + } + /** + * @throws Exception + */ + public function beStrictAboutChangesToGlobalState(): bool + { + if (!$this->hasBeStrictAboutChangesToGlobalState()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->beStrictAboutChangesToGlobalState; + } + /** + * @phpstan-assert-if-true !null $this->bootstrap + */ + public function hasBootstrap(): bool + { + return $this->bootstrap !== null; + } + /** + * @throws Exception + */ + public function bootstrap(): string + { + if (!$this->hasBootstrap()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->bootstrap; + } + /** + * @phpstan-assert-if-true !null $this->cacheDirectory + */ + public function hasCacheDirectory(): bool + { + return $this->cacheDirectory !== null; + } + /** + * @throws Exception + */ + public function cacheDirectory(): string + { + if (!$this->hasCacheDirectory()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->cacheDirectory; + } + /** + * @phpstan-assert-if-true !null $this->cacheResult + */ + public function hasCacheResult(): bool + { + return $this->cacheResult !== null; + } + /** + * @throws Exception + */ + public function cacheResult(): bool + { + if (!$this->hasCacheResult()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->cacheResult; + } + public function checkPhpConfiguration(): bool + { + return $this->checkPhpConfiguration; + } + public function checkVersion(): bool + { + return $this->checkVersion; + } + /** + * @phpstan-assert-if-true !null $this->colors + */ + public function hasColors(): bool + { + return $this->colors !== null; + } + /** + * @throws Exception + */ + public function colors(): string + { + if (!$this->hasColors()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->colors; + } + /** + * @phpstan-assert-if-true !null $this->columns + */ + public function hasColumns(): bool + { + return $this->columns !== null; + } + /** + * @throws Exception + */ + public function columns(): int|string + { + if (!$this->hasColumns()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->columns; + } + /** + * @phpstan-assert-if-true !null $this->configurationFile + */ + public function hasConfigurationFile(): bool + { + return $this->configurationFile !== null; + } + /** + * @throws Exception + */ + public function configurationFile(): string + { + if (!$this->hasConfigurationFile()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->configurationFile; + } + /** + * @phpstan-assert-if-true !null $this->coverageFilter + */ + public function hasCoverageFilter(): bool + { + return $this->coverageFilter !== null; + } + /** + * @throws Exception + * + * @return non-empty-list + */ + public function coverageFilter(): array + { + if (!$this->hasCoverageFilter()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->coverageFilter; + } + /** + * @phpstan-assert-if-true !null $this->coverageClover + */ + public function hasCoverageClover(): bool + { + return $this->coverageClover !== null; + } + /** + * @throws Exception + */ + public function coverageClover(): string + { + if (!$this->hasCoverageClover()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->coverageClover; + } + /** + * @phpstan-assert-if-true !null $this->coverageCobertura + */ + public function hasCoverageCobertura(): bool + { + return $this->coverageCobertura !== null; + } + /** + * @throws Exception + */ + public function coverageCobertura(): string + { + if (!$this->hasCoverageCobertura()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->coverageCobertura; + } + /** + * @phpstan-assert-if-true !null $this->coverageCrap4J + */ + public function hasCoverageCrap4J(): bool + { + return $this->coverageCrap4J !== null; + } + /** + * @throws Exception + */ + public function coverageCrap4J(): string + { + if (!$this->hasCoverageCrap4J()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->coverageCrap4J; + } + /** + * @phpstan-assert-if-true !null $this->coverageHtml + */ + public function hasCoverageHtml(): bool + { + return $this->coverageHtml !== null; + } + /** + * @throws Exception + */ + public function coverageHtml(): string + { + if (!$this->hasCoverageHtml()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->coverageHtml; + } + /** + * @phpstan-assert-if-true !null $this->coverageOpenClover + */ + public function hasCoverageOpenClover(): bool + { + return $this->coverageOpenClover !== null; + } + /** + * @throws Exception + */ + public function coverageOpenClover(): string + { + if (!$this->hasCoverageOpenClover()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->coverageOpenClover; + } + /** + * @phpstan-assert-if-true !null $this->coveragePhp + */ + public function hasCoveragePhp(): bool + { + return $this->coveragePhp !== null; + } + /** + * @throws Exception + */ + public function coveragePhp(): string + { + if (!$this->hasCoveragePhp()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->coveragePhp; + } + /** + * @phpstan-assert-if-true !null $this->coverageText + */ + public function hasCoverageText(): bool + { + return $this->coverageText !== null; + } + /** + * @throws Exception + */ + public function coverageText(): string + { + if (!$this->hasCoverageText()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->coverageText; + } + /** + * @phpstan-assert-if-true !null $this->coverageTextShowUncoveredFiles + */ + public function hasCoverageTextShowUncoveredFiles(): bool + { + return $this->coverageTextShowUncoveredFiles !== null; + } + /** + * @throws Exception + */ + public function coverageTextShowUncoveredFiles(): bool + { + if (!$this->hasCoverageTextShowUncoveredFiles()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->coverageTextShowUncoveredFiles; + } + /** + * @phpstan-assert-if-true !null $this->coverageTextShowOnlySummary + */ + public function hasCoverageTextShowOnlySummary(): bool + { + return $this->coverageTextShowOnlySummary !== null; + } + /** + * @throws Exception + */ + public function coverageTextShowOnlySummary(): bool + { + if (!$this->hasCoverageTextShowOnlySummary()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->coverageTextShowOnlySummary; + } + /** + * @phpstan-assert-if-true !null $this->coverageXml + */ + public function hasCoverageXml(): bool + { + return $this->coverageXml !== null; + } + /** + * @throws Exception + */ + public function coverageXml(): string + { + if (!$this->hasCoverageXml()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->coverageXml; + } + /** + * @phpstan-assert-if-true !null $this->excludeSourceFromXmlCoverage + */ + public function hasExcludeSourceFromXmlCoverage(): bool + { + return $this->excludeSourceFromXmlCoverage !== null; + } + /** + * @throws Exception + */ + public function excludeSourceFromXmlCoverage(): bool + { + if (!$this->hasExcludeSourceFromXmlCoverage()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->excludeSourceFromXmlCoverage; + } + /** + * @phpstan-assert-if-true !null $this->pathCoverage + */ + public function hasPathCoverage(): bool + { + return $this->pathCoverage !== null; + } + /** + * @throws Exception + */ + public function pathCoverage(): bool + { + if (!$this->hasPathCoverage()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->pathCoverage; + } + public function warmCoverageCache(): bool + { + return $this->warmCoverageCache; + } + /** + * @phpstan-assert-if-true !null $this->defaultTimeLimit + */ + public function hasDefaultTimeLimit(): bool + { + return $this->defaultTimeLimit !== null; + } + /** + * @throws Exception + */ + public function defaultTimeLimit(): int + { + if (!$this->hasDefaultTimeLimit()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->defaultTimeLimit; + } + /** + * @phpstan-assert-if-true !null $this->disableCodeCoverageIgnore + */ + public function hasDisableCodeCoverageIgnore(): bool + { + return $this->disableCodeCoverageIgnore !== null; + } + /** + * @throws Exception + */ + public function disableCodeCoverageIgnore(): bool + { + if (!$this->hasDisableCodeCoverageIgnore()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->disableCodeCoverageIgnore; + } + /** + * @phpstan-assert-if-true !null $this->disallowTestOutput + */ + public function hasDisallowTestOutput(): bool + { + return $this->disallowTestOutput !== null; + } + /** + * @throws Exception + */ + public function disallowTestOutput(): bool + { + if (!$this->hasDisallowTestOutput()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->disallowTestOutput; + } + /** + * @phpstan-assert-if-true !null $this->enforceTimeLimit + */ + public function hasEnforceTimeLimit(): bool + { + return $this->enforceTimeLimit !== null; + } + /** + * @throws Exception + */ + public function enforceTimeLimit(): bool + { + if (!$this->hasEnforceTimeLimit()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->enforceTimeLimit; + } + /** + * @phpstan-assert-if-true !null $this->excludeGroups + */ + public function hasExcludeGroups(): bool + { + return $this->excludeGroups !== null; + } + /** + * @throws Exception + * + * @return non-empty-list + */ + public function excludeGroups(): array + { + if (!$this->hasExcludeGroups()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->excludeGroups; + } + /** + * @phpstan-assert-if-true !null $this->executionOrder + */ + public function hasExecutionOrder(): bool + { + return $this->executionOrder !== null; + } + /** + * @throws Exception + */ + public function executionOrder(): int + { + if (!$this->hasExecutionOrder()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->executionOrder; + } + /** + * @phpstan-assert-if-true !null $this->executionOrderDefects + */ + public function hasExecutionOrderDefects(): bool + { + return $this->executionOrderDefects !== null; + } + /** + * @throws Exception + */ + public function executionOrderDefects(): int + { + if (!$this->hasExecutionOrderDefects()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->executionOrderDefects; + } + /** + * @phpstan-assert-if-true !null $this->failOnAllIssues + */ + public function hasFailOnAllIssues(): bool + { + return $this->failOnAllIssues !== null; + } + /** + * @throws Exception + */ + public function failOnAllIssues(): bool + { + if (!$this->hasFailOnAllIssues()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->failOnAllIssues; + } + /** + * @phpstan-assert-if-true !null $this->failOnDeprecation + */ + public function hasFailOnDeprecation(): bool + { + return $this->failOnDeprecation !== null; + } + /** + * @throws Exception + */ + public function failOnDeprecation(): bool + { + if (!$this->hasFailOnDeprecation()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->failOnDeprecation; + } + /** + * @phpstan-assert-if-true !null $this->failOnPhpunitDeprecation + */ + public function hasFailOnPhpunitDeprecation(): bool + { + return $this->failOnPhpunitDeprecation !== null; + } + /** + * @throws Exception + */ + public function failOnPhpunitDeprecation(): bool + { + if (!$this->hasFailOnPhpunitDeprecation()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->failOnPhpunitDeprecation; + } + /** + * @phpstan-assert-if-true !null $this->failOnPhpunitNotice + */ + public function hasFailOnPhpunitNotice(): bool + { + return $this->failOnPhpunitNotice !== null; + } + /** + * @throws Exception + */ + public function failOnPhpunitNotice(): bool + { + if (!$this->hasFailOnPhpunitNotice()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->failOnPhpunitNotice; + } + /** + * @phpstan-assert-if-true !null $this->failOnPhpunitWarning + */ + public function hasFailOnPhpunitWarning(): bool + { + return $this->failOnPhpunitWarning !== null; + } + /** + * @throws Exception + */ + public function failOnPhpunitWarning(): bool + { + if (!$this->hasFailOnPhpunitWarning()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->failOnPhpunitWarning; + } + /** + * @phpstan-assert-if-true !null $this->failOnEmptyTestSuite + */ + public function hasFailOnEmptyTestSuite(): bool + { + return $this->failOnEmptyTestSuite !== null; + } + /** + * @throws Exception + */ + public function failOnEmptyTestSuite(): bool + { + if (!$this->hasFailOnEmptyTestSuite()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->failOnEmptyTestSuite; + } + /** + * @phpstan-assert-if-true !null $this->failOnIncomplete + */ + public function hasFailOnIncomplete(): bool + { + return $this->failOnIncomplete !== null; + } + /** + * @throws Exception + */ + public function failOnIncomplete(): bool + { + if (!$this->hasFailOnIncomplete()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->failOnIncomplete; + } + /** + * @phpstan-assert-if-true !null $this->failOnNotice + */ + public function hasFailOnNotice(): bool + { + return $this->failOnNotice !== null; + } + /** + * @throws Exception + */ + public function failOnNotice(): bool + { + if (!$this->hasFailOnNotice()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->failOnNotice; + } + /** + * @phpstan-assert-if-true !null $this->failOnRisky + */ + public function hasFailOnRisky(): bool + { + return $this->failOnRisky !== null; + } + /** + * @throws Exception + */ + public function failOnRisky(): bool + { + if (!$this->hasFailOnRisky()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->failOnRisky; + } + /** + * @phpstan-assert-if-true !null $this->failOnSkipped + */ + public function hasFailOnSkipped(): bool + { + return $this->failOnSkipped !== null; + } + /** + * @throws Exception + */ + public function failOnSkipped(): bool + { + if (!$this->hasFailOnSkipped()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->failOnSkipped; + } + /** + * @phpstan-assert-if-true !null $this->failOnWarning + */ + public function hasFailOnWarning(): bool + { + return $this->failOnWarning !== null; + } + /** + * @throws Exception + */ + public function failOnWarning(): bool + { + if (!$this->hasFailOnWarning()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->failOnWarning; + } + /** + * @phpstan-assert-if-true !null $this->doNotFailOnDeprecation + */ + public function hasDoNotFailOnDeprecation(): bool + { + return $this->doNotFailOnDeprecation !== null; + } + /** + * @throws Exception + */ + public function doNotFailOnDeprecation(): bool + { + if (!$this->hasDoNotFailOnDeprecation()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->doNotFailOnDeprecation; + } + /** + * @phpstan-assert-if-true !null $this->doNotFailOnPhpunitDeprecation + */ + public function hasDoNotFailOnPhpunitDeprecation(): bool + { + return $this->doNotFailOnPhpunitDeprecation !== null; + } + /** + * @throws Exception + */ + public function doNotFailOnPhpunitDeprecation(): bool + { + if (!$this->hasDoNotFailOnPhpunitDeprecation()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->doNotFailOnPhpunitDeprecation; + } + /** + * @phpstan-assert-if-true !null $this->doNotFailOnPhpunitNotice + */ + public function hasDoNotFailOnPhpunitNotice(): bool + { + return $this->doNotFailOnPhpunitNotice !== null; + } + /** + * @throws Exception + */ + public function doNotFailOnPhpunitNotice(): bool + { + if (!$this->hasDoNotFailOnPhpunitNotice()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->doNotFailOnPhpunitNotice; + } + /** + * @phpstan-assert-if-true !null $this->doNotFailOnPhpunitWarning + */ + public function hasDoNotFailOnPhpunitWarning(): bool + { + return $this->doNotFailOnPhpunitWarning !== null; + } + /** + * @throws Exception + */ + public function doNotFailOnPhpunitWarning(): bool + { + if (!$this->hasDoNotFailOnPhpunitWarning()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->doNotFailOnPhpunitWarning; + } + /** + * @phpstan-assert-if-true !null $this->doNotFailOnEmptyTestSuite + */ + public function hasDoNotFailOnEmptyTestSuite(): bool + { + return $this->doNotFailOnEmptyTestSuite !== null; + } + /** + * @throws Exception + */ + public function doNotFailOnEmptyTestSuite(): bool + { + if (!$this->hasDoNotFailOnEmptyTestSuite()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->doNotFailOnEmptyTestSuite; + } + /** + * @phpstan-assert-if-true !null $this->doNotFailOnIncomplete + */ + public function hasDoNotFailOnIncomplete(): bool + { + return $this->doNotFailOnIncomplete !== null; + } + /** + * @throws Exception + */ + public function doNotFailOnIncomplete(): bool + { + if (!$this->hasDoNotFailOnIncomplete()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->doNotFailOnIncomplete; + } + /** + * @phpstan-assert-if-true !null $this->doNotFailOnNotice + */ + public function hasDoNotFailOnNotice(): bool + { + return $this->doNotFailOnNotice !== null; + } + /** + * @throws Exception + */ + public function doNotFailOnNotice(): bool + { + if (!$this->hasDoNotFailOnNotice()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->doNotFailOnNotice; + } + /** + * @phpstan-assert-if-true !null $this->doNotFailOnRisky + */ + public function hasDoNotFailOnRisky(): bool + { + return $this->doNotFailOnRisky !== null; + } + /** + * @throws Exception + */ + public function doNotFailOnRisky(): bool + { + if (!$this->hasDoNotFailOnRisky()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->doNotFailOnRisky; + } + /** + * @phpstan-assert-if-true !null $this->doNotFailOnSkipped + */ + public function hasDoNotFailOnSkipped(): bool + { + return $this->doNotFailOnSkipped !== null; + } + /** + * @throws Exception + */ + public function doNotFailOnSkipped(): bool + { + if (!$this->hasDoNotFailOnSkipped()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->doNotFailOnSkipped; + } + /** + * @phpstan-assert-if-true !null $this->doNotFailOnWarning + */ + public function hasDoNotFailOnWarning(): bool + { + return $this->doNotFailOnWarning !== null; + } + /** + * @throws Exception + */ + public function doNotFailOnWarning(): bool + { + if (!$this->hasDoNotFailOnWarning()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->doNotFailOnWarning; + } + /** + * @phpstan-assert-if-true !null $this->stopOnDefect + */ + public function hasStopOnDefect(): bool + { + return $this->stopOnDefect !== null; + } + /** + * @throws Exception + */ + public function stopOnDefect(): bool + { + if (!$this->hasStopOnDefect()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->stopOnDefect; + } + /** + * @phpstan-assert-if-true !null $this->stopOnDeprecation + */ + public function hasStopOnDeprecation(): bool + { + return $this->stopOnDeprecation !== null; + } + /** + * @throws Exception + */ + public function stopOnDeprecation(): bool + { + if (!$this->hasStopOnDeprecation()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->stopOnDeprecation; + } + /** + * @phpstan-assert-if-true !null $this->specificDeprecationToStopOn + */ + public function hasSpecificDeprecationToStopOn(): bool + { + return $this->specificDeprecationToStopOn !== null; + } + /** + * @throws Exception + */ + public function specificDeprecationToStopOn(): string + { + if (!$this->hasSpecificDeprecationToStopOn()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->specificDeprecationToStopOn; + } + /** + * @phpstan-assert-if-true !null $this->stopOnError + */ + public function hasStopOnError(): bool + { + return $this->stopOnError !== null; + } + /** + * @throws Exception + */ + public function stopOnError(): bool + { + if (!$this->hasStopOnError()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->stopOnError; + } + /** + * @phpstan-assert-if-true !null $this->stopOnFailure + */ + public function hasStopOnFailure(): bool + { + return $this->stopOnFailure !== null; + } + /** + * @throws Exception + */ + public function stopOnFailure(): bool + { + if (!$this->hasStopOnFailure()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->stopOnFailure; + } + /** + * @phpstan-assert-if-true !null $this->stopOnIncomplete + */ + public function hasStopOnIncomplete(): bool + { + return $this->stopOnIncomplete !== null; + } + /** + * @throws Exception + */ + public function stopOnIncomplete(): bool + { + if (!$this->hasStopOnIncomplete()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->stopOnIncomplete; + } + /** + * @phpstan-assert-if-true !null $this->stopOnNotice + */ + public function hasStopOnNotice(): bool + { + return $this->stopOnNotice !== null; + } + /** + * @throws Exception + */ + public function stopOnNotice(): bool + { + if (!$this->hasStopOnNotice()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->stopOnNotice; + } + /** + * @phpstan-assert-if-true !null $this->stopOnRisky + */ + public function hasStopOnRisky(): bool + { + return $this->stopOnRisky !== null; + } + /** + * @throws Exception + */ + public function stopOnRisky(): bool + { + if (!$this->hasStopOnRisky()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->stopOnRisky; + } + /** + * @phpstan-assert-if-true !null $this->stopOnSkipped + */ + public function hasStopOnSkipped(): bool + { + return $this->stopOnSkipped !== null; + } + /** + * @throws Exception + */ + public function stopOnSkipped(): bool + { + if (!$this->hasStopOnSkipped()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->stopOnSkipped; + } + /** + * @phpstan-assert-if-true !null $this->stopOnWarning + */ + public function hasStopOnWarning(): bool + { + return $this->stopOnWarning !== null; + } + /** + * @throws Exception + */ + public function stopOnWarning(): bool + { + if (!$this->hasStopOnWarning()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->stopOnWarning; + } + /** + * @phpstan-assert-if-true !null $this->excludeFilter + */ + public function hasExcludeFilter(): bool + { + return $this->excludeFilter !== null; + } + /** + * @throws Exception + */ + public function excludeFilter(): string + { + if (!$this->hasExcludeFilter()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->excludeFilter; + } + /** + * @phpstan-assert-if-true !null $this->filter + */ + public function hasFilter(): bool + { + return $this->filter !== null; + } + /** + * @throws Exception + */ + public function filter(): string + { + if (!$this->hasFilter()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->filter; + } + /** + * @phpstan-assert-if-true !null $this->generateBaseline + */ + public function hasGenerateBaseline(): bool + { + return $this->generateBaseline !== null; + } + /** + * @throws Exception + */ + public function generateBaseline(): string + { + if (!$this->hasGenerateBaseline()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->generateBaseline; + } + /** + * @phpstan-assert-if-true !null $this->useBaseline + */ + public function hasUseBaseline(): bool + { + return $this->useBaseline !== null; + } + /** + * @throws Exception + */ + public function useBaseline(): string + { + if (!$this->hasUseBaseline()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->useBaseline; + } + public function ignoreBaseline(): bool + { + return $this->ignoreBaseline; + } + public function generateConfiguration(): bool + { + return $this->generateConfiguration; + } + public function migrateConfiguration(): bool + { + return $this->migrateConfiguration; + } + /** + * @phpstan-assert-if-true !null $this->groups + */ + public function hasGroups(): bool + { + return $this->groups !== null; + } + /** + * @throws Exception + * + * @return non-empty-list + */ + public function groups(): array + { + if (!$this->hasGroups()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->groups; + } + /** + * @phpstan-assert-if-true !null $this->testsCovering + */ + public function hasTestsCovering(): bool + { + return $this->testsCovering !== null; + } + /** + * @throws Exception + * + * @return non-empty-list + */ + public function testsCovering(): array + { + if (!$this->hasTestsCovering()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->testsCovering; + } + /** + * @phpstan-assert-if-true !null $this->testsUsing + */ + public function hasTestsUsing(): bool + { + return $this->testsUsing !== null; + } + /** + * @throws Exception + * + * @return non-empty-list + */ + public function testsUsing(): array + { + if (!$this->hasTestsUsing()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->testsUsing; + } + /** + * @phpstan-assert-if-true !null $this->testsRequiringPhpExtension + */ + public function hasTestsRequiringPhpExtension(): bool + { + return $this->testsRequiringPhpExtension !== null; + } + /** + * @throws Exception + * + * @return non-empty-list + */ + public function testsRequiringPhpExtension(): array + { + if (!$this->hasTestsRequiringPhpExtension()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->testsRequiringPhpExtension; + } + public function help(): bool + { + return $this->help; + } + /** + * @phpstan-assert-if-true !null $this->includePath + */ + public function hasIncludePath(): bool + { + return $this->includePath !== null; + } + /** + * @throws Exception + */ + public function includePath(): string + { + if (!$this->hasIncludePath()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->includePath; + } + /** + * @phpstan-assert-if-true !null $this->iniSettings + */ + public function hasIniSettings(): bool + { + return $this->iniSettings !== null; + } + /** + * @throws Exception + * + * @return non-empty-array + */ + public function iniSettings(): array + { + if (!$this->hasIniSettings()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->iniSettings; + } + /** + * @phpstan-assert-if-true !null $this->junitLogfile + */ + public function hasJunitLogfile(): bool + { + return $this->junitLogfile !== null; + } + /** + * @throws Exception + */ + public function junitLogfile(): string + { + if (!$this->hasJunitLogfile()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->junitLogfile; + } + /** + * @phpstan-assert-if-true !null $this->otrLogfile + */ + public function hasOtrLogfile(): bool + { + return $this->otrLogfile !== null; + } + /** + * @throws Exception + */ + public function otrLogfile(): string + { + if (!$this->hasOtrLogfile()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->otrLogfile; + } + /** + * @phpstan-assert-if-true !null $this->includeGitInformation + */ + public function hasIncludeGitInformation(): bool + { + return $this->includeGitInformation !== null; + } + /** + * @throws Exception + */ + public function includeGitInformation(): bool + { + if (!$this->hasIncludeGitInformation()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->includeGitInformation; + } + public function listGroups(): bool + { + return $this->listGroups; + } + public function listSuites(): bool + { + return $this->listSuites; + } + public function listTestFiles(): bool + { + return $this->listTestFiles; + } + public function listTests(): bool + { + return $this->listTests; + } + /** + * @phpstan-assert-if-true !null $this->listTestsXml + */ + public function hasListTestsXml(): bool + { + return $this->listTestsXml !== null; + } + /** + * @throws Exception + */ + public function listTestsXml(): string + { + if (!$this->hasListTestsXml()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->listTestsXml; + } + /** + * @phpstan-assert-if-true !null $this->noCoverage + */ + public function hasNoCoverage(): bool + { + return $this->noCoverage !== null; + } + /** + * @throws Exception + */ + public function noCoverage(): bool + { + if (!$this->hasNoCoverage()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->noCoverage; + } + /** + * @phpstan-assert-if-true !null $this->noExtensions + */ + public function hasNoExtensions(): bool + { + return $this->noExtensions !== null; + } + /** + * @throws Exception + */ + public function noExtensions(): bool + { + if (!$this->hasNoExtensions()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->noExtensions; + } + /** + * @phpstan-assert-if-true !null $this->noOutput + */ + public function hasNoOutput(): bool + { + return $this->noOutput !== null; + } + /** + * @throws Exception + */ + public function noOutput(): bool + { + if ($this->noOutput === null) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->noOutput; + } + /** + * @phpstan-assert-if-true !null $this->noProgress + */ + public function hasNoProgress(): bool + { + return $this->noProgress !== null; + } + /** + * @throws Exception + */ + public function noProgress(): bool + { + if ($this->noProgress === null) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->noProgress; + } + /** + * @phpstan-assert-if-true !null $this->noResults + */ + public function hasNoResults(): bool + { + return $this->noResults !== null; + } + /** + * @throws Exception + */ + public function noResults(): bool + { + if ($this->noResults === null) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->noResults; + } + /** + * @phpstan-assert-if-true !null $this->noLogging + */ + public function hasNoLogging(): bool + { + return $this->noLogging !== null; + } + /** + * @throws Exception + */ + public function noLogging(): bool + { + if (!$this->hasNoLogging()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->noLogging; + } + /** + * @phpstan-assert-if-true !null $this->processIsolation + */ + public function hasProcessIsolation(): bool + { + return $this->processIsolation !== null; + } + /** + * @throws Exception + */ + public function processIsolation(): bool + { + if (!$this->hasProcessIsolation()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->processIsolation; + } + /** + * @phpstan-assert-if-true !null $this->randomOrderSeed + */ + public function hasRandomOrderSeed(): bool + { + return $this->randomOrderSeed !== null; + } + /** + * @throws Exception + */ + public function randomOrderSeed(): int + { + if (!$this->hasRandomOrderSeed()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->randomOrderSeed; + } + /** + * @phpstan-assert-if-true !null $this->reportUselessTests + */ + public function hasReportUselessTests(): bool + { + return $this->reportUselessTests !== null; + } + /** + * @throws Exception + */ + public function reportUselessTests(): bool + { + if (!$this->hasReportUselessTests()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->reportUselessTests; + } + /** + * @phpstan-assert-if-true !null $this->resolveDependencies + */ + public function hasResolveDependencies(): bool + { + return $this->resolveDependencies !== null; + } + /** + * @throws Exception + */ + public function resolveDependencies(): bool + { + if (!$this->hasResolveDependencies()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->resolveDependencies; + } + /** + * @phpstan-assert-if-true !null $this->reverseList + */ + public function hasReverseList(): bool + { + return $this->reverseList !== null; + } + /** + * @throws Exception + */ + public function reverseList(): bool + { + if (!$this->hasReverseList()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->reverseList; + } + /** + * @phpstan-assert-if-true !null $this->stderr + */ + public function hasStderr(): bool + { + return $this->stderr !== null; + } + /** + * @throws Exception + */ + public function stderr(): bool + { + if (!$this->hasStderr()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->stderr; + } + /** + * @phpstan-assert-if-true !null $this->strictCoverage + */ + public function hasStrictCoverage(): bool + { + return $this->strictCoverage !== null; + } + /** + * @throws Exception + */ + public function strictCoverage(): bool + { + if (!$this->hasStrictCoverage()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->strictCoverage; + } + /** + * @phpstan-assert-if-true !null $this->teamcityLogfile + */ + public function hasTeamcityLogfile(): bool + { + return $this->teamcityLogfile !== null; + } + /** + * @throws Exception + */ + public function teamcityLogfile(): string + { + if (!$this->hasTeamcityLogfile()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->teamcityLogfile; + } + /** + * @phpstan-assert-if-true !null $this->teamCityPrinter + */ + public function hasTeamCityPrinter(): bool + { + return $this->teamCityPrinter !== null; + } + /** + * @throws Exception + */ + public function teamCityPrinter(): bool + { + if (!$this->hasTeamCityPrinter()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->teamCityPrinter; + } + /** + * @phpstan-assert-if-true !null $this->testdoxHtmlFile + */ + public function hasTestdoxHtmlFile(): bool + { + return $this->testdoxHtmlFile !== null; + } + /** + * @throws Exception + */ + public function testdoxHtmlFile(): string + { + if (!$this->hasTestdoxHtmlFile()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->testdoxHtmlFile; + } + /** + * @phpstan-assert-if-true !null $this->testdoxTextFile + */ + public function hasTestdoxTextFile(): bool + { + return $this->testdoxTextFile !== null; + } + /** + * @throws Exception + */ + public function testdoxTextFile(): string + { + if (!$this->hasTestdoxTextFile()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->testdoxTextFile; + } + /** + * @phpstan-assert-if-true !null $this->testdoxPrinter + */ + public function hasTestDoxPrinter(): bool + { + return $this->testdoxPrinter !== null; + } + /** + * @throws Exception + */ + public function testdoxPrinter(): bool + { + if (!$this->hasTestDoxPrinter()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->testdoxPrinter; + } + /** + * @phpstan-assert-if-true !null $this->testdoxPrinterSummary + */ + public function hasTestDoxPrinterSummary(): bool + { + return $this->testdoxPrinterSummary !== null; + } + /** + * @throws Exception + */ + public function testdoxPrinterSummary(): bool + { + if (!$this->hasTestDoxPrinterSummary()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->testdoxPrinterSummary; + } + /** + * @phpstan-assert-if-true !null $this->testSuffixes + */ + public function hasTestSuffixes(): bool + { + return $this->testSuffixes !== null; + } + /** + * @throws Exception + * + * @return non-empty-list + */ + public function testSuffixes(): array + { + if (!$this->hasTestSuffixes()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->testSuffixes; + } + /** + * @phpstan-assert-if-true !null $this->testSuite + */ + public function hasTestSuite(): bool + { + return $this->testSuite !== null; + } + /** + * @throws Exception + */ + public function testSuite(): string + { + if (!$this->hasTestSuite()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->testSuite; + } + /** + * @phpstan-assert-if-true !null $this->excludeTestSuite + */ + public function hasExcludedTestSuite(): bool + { + return $this->excludeTestSuite !== null; + } + /** + * @throws Exception + */ + public function excludedTestSuite(): string + { + if (!$this->hasExcludedTestSuite()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->excludeTestSuite; + } + public function useDefaultConfiguration(): bool + { + return $this->useDefaultConfiguration; + } + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnAllIssues + */ + public function hasDisplayDetailsOnAllIssues(): bool + { + return $this->displayDetailsOnAllIssues !== null; + } + /** + * @throws Exception + */ + public function displayDetailsOnAllIssues(): bool + { + if (!$this->hasDisplayDetailsOnAllIssues()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->displayDetailsOnAllIssues; + } + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnIncompleteTests + */ + public function hasDisplayDetailsOnIncompleteTests(): bool + { + return $this->displayDetailsOnIncompleteTests !== null; + } + /** + * @throws Exception + */ + public function displayDetailsOnIncompleteTests(): bool + { + if (!$this->hasDisplayDetailsOnIncompleteTests()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->displayDetailsOnIncompleteTests; + } + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnSkippedTests + */ + public function hasDisplayDetailsOnSkippedTests(): bool + { + return $this->displayDetailsOnSkippedTests !== null; + } + /** + * @throws Exception + */ + public function displayDetailsOnSkippedTests(): bool + { + if (!$this->hasDisplayDetailsOnSkippedTests()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->displayDetailsOnSkippedTests; + } + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnTestsThatTriggerDeprecations + */ + public function hasDisplayDetailsOnTestsThatTriggerDeprecations(): bool + { + return $this->displayDetailsOnTestsThatTriggerDeprecations !== null; + } + /** + * @throws Exception + */ + public function displayDetailsOnTestsThatTriggerDeprecations(): bool + { + if (!$this->hasDisplayDetailsOnTestsThatTriggerDeprecations()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->displayDetailsOnTestsThatTriggerDeprecations; + } + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnPhpunitDeprecations + */ + public function hasDisplayDetailsOnPhpunitDeprecations(): bool + { + return $this->displayDetailsOnPhpunitDeprecations !== null; + } + /** + * @throws Exception + */ + public function displayDetailsOnPhpunitDeprecations(): bool + { + if (!$this->hasDisplayDetailsOnPhpunitDeprecations()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->displayDetailsOnPhpunitDeprecations; + } + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnPhpunitNotices + */ + public function hasDisplayDetailsOnPhpunitNotices(): bool + { + return $this->displayDetailsOnPhpunitNotices !== null; + } + /** + * @throws Exception + */ + public function displayDetailsOnPhpunitNotices(): bool + { + if (!$this->hasDisplayDetailsOnPhpunitNotices()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->displayDetailsOnPhpunitNotices; + } + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnTestsThatTriggerErrors + */ + public function hasDisplayDetailsOnTestsThatTriggerErrors(): bool + { + return $this->displayDetailsOnTestsThatTriggerErrors !== null; + } + /** + * @throws Exception + */ + public function displayDetailsOnTestsThatTriggerErrors(): bool + { + if (!$this->hasDisplayDetailsOnTestsThatTriggerErrors()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->displayDetailsOnTestsThatTriggerErrors; + } + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnTestsThatTriggerNotices + */ + public function hasDisplayDetailsOnTestsThatTriggerNotices(): bool + { + return $this->displayDetailsOnTestsThatTriggerNotices !== null; + } + /** + * @throws Exception + */ + public function displayDetailsOnTestsThatTriggerNotices(): bool + { + if (!$this->hasDisplayDetailsOnTestsThatTriggerNotices()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->displayDetailsOnTestsThatTriggerNotices; + } + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnTestsThatTriggerWarnings + */ + public function hasDisplayDetailsOnTestsThatTriggerWarnings(): bool + { + return $this->displayDetailsOnTestsThatTriggerWarnings !== null; + } + /** + * @throws Exception + */ + public function displayDetailsOnTestsThatTriggerWarnings(): bool + { + if (!$this->hasDisplayDetailsOnTestsThatTriggerWarnings()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->displayDetailsOnTestsThatTriggerWarnings; + } + public function version(): bool + { + return $this->version; + } + /** + * @phpstan-assert-if-true !null $this->logEventsText + */ + public function hasLogEventsText(): bool + { + return $this->logEventsText !== null; + } + /** + * @throws Exception + */ + public function logEventsText(): string + { + if (!$this->hasLogEventsText()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->logEventsText; + } + /** + * @phpstan-assert-if-true !null $this->logEventsVerboseText + */ + public function hasLogEventsVerboseText(): bool + { + return $this->logEventsVerboseText !== null; + } + /** + * @throws Exception + */ + public function logEventsVerboseText(): string + { + if (!$this->hasLogEventsVerboseText()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->logEventsVerboseText; + } + public function debug(): bool + { + return $this->debug; + } + public function withTelemetry(): bool + { + return $this->withTelemetry; + } + /** + * @phpstan-assert-if-true !null $this->extensions + */ + public function hasExtensions(): bool + { + return $this->extensions !== null; + } + /** + * @throws Exception + * + * @return non-empty-list + */ + public function extensions(): array + { + if (!$this->hasExtensions()) { + throw new \PHPUnit\TextUI\CliArguments\Exception(); + } + return $this->extensions; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\CliArguments; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Exception extends RuntimeException implements \PHPUnit\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\CliArguments; + +use function getcwd; +use function is_dir; +use function is_file; +use function realpath; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class XmlConfigurationFileFinder +{ + public function find(\PHPUnit\TextUI\CliArguments\Configuration $configuration): false|string + { + $useDefaultConfiguration = $configuration->useDefaultConfiguration(); + if ($configuration->hasConfigurationFile()) { + if (is_dir($configuration->configurationFile())) { + $candidate = $this->configurationFileInDirectory($configuration->configurationFile()); + if ($candidate !== \false) { + return $candidate; + } + return \false; + } + return $configuration->configurationFile(); + } + if ($useDefaultConfiguration) { + $directory = getcwd(); + if ($directory !== \false) { + $candidate = $this->configurationFileInDirectory($directory); + if ($candidate !== \false) { + return $candidate; + } + } + } + return \false; + } + private function configurationFileInDirectory(string $directory): false|string + { + $candidates = [$directory . '/phpunit.xml', $directory . '/phpunit.dist.xml', $directory . '/phpunit.xml.dist']; + foreach ($candidates as $candidate) { + if (is_file($candidate)) { + return realpath($candidate); + } + } + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function array_keys; +use function assert; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Filter; +/** + * CLI options and XML configuration are static within a single PHPUnit process. + * It is therefore okay to use a Singleton registry here. + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CodeCoverageFilterRegistry +{ + private static ?self $instance = null; + private ?Filter $filter = null; + private bool $configured = \false; + public static function instance(): self + { + if (self::$instance === null) { + self::$instance = new self(); + } + return self::$instance; + } + /** + * @codeCoverageIgnore + */ + public function get(): Filter + { + assert($this->filter !== null); + return $this->filter; + } + /** + * @codeCoverageIgnore + */ + public function init(\PHPUnit\TextUI\Configuration\Configuration $configuration, bool $force = \false): void + { + if (!$configuration->hasCoverageReport() && !$force) { + return; + } + if ($this->configured && !$force) { + return; + } + $this->filter = new Filter(); + if ($configuration->source()->notEmpty()) { + $this->filter->includeFiles(array_keys((new \PHPUnit\TextUI\Configuration\SourceMapper())->mapForCodeCoverage($configuration->source()))); + $this->configured = \true; + } + } + /** + * @codeCoverageIgnore + */ + public function configured(): bool + { + return $this->configured; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function explode; +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Configuration +{ + public const string COLOR_NEVER = 'never'; + public const string COLOR_AUTO = 'auto'; + public const string COLOR_ALWAYS = 'always'; + public const string COLOR_DEFAULT = self::COLOR_NEVER; + /** + * @var list + */ + private array $cliArguments; + private ?string $testFilesFile; + private ?string $configurationFile; + private ?string $bootstrap; + /** + * @var array + */ + private array $bootstrapForTestSuite; + private bool $cacheResult; + private ?string $cacheDirectory; + private ?string $coverageCacheDirectory; + private \PHPUnit\TextUI\Configuration\Source $source; + private bool $pathCoverage; + private ?string $coverageClover; + private ?string $coverageCobertura; + private ?string $coverageCrap4j; + private int $coverageCrap4jThreshold; + private ?string $coverageHtml; + private int $coverageHtmlLowUpperBound; + private int $coverageHtmlHighLowerBound; + private string $coverageHtmlColorSuccessLow; + private string $coverageHtmlColorSuccessLowDark; + private string $coverageHtmlColorSuccessMedium; + private string $coverageHtmlColorSuccessMediumDark; + private string $coverageHtmlColorSuccessHigh; + private string $coverageHtmlColorSuccessHighDark; + private string $coverageHtmlColorSuccessBar; + private string $coverageHtmlColorSuccessBarDark; + private string $coverageHtmlColorWarning; + private string $coverageHtmlColorWarningDark; + private string $coverageHtmlColorWarningBar; + private string $coverageHtmlColorWarningBarDark; + private string $coverageHtmlColorDanger; + private string $coverageHtmlColorDangerDark; + private string $coverageHtmlColorDangerBar; + private string $coverageHtmlColorDangerBarDark; + private string $coverageHtmlColorBreadcrumbs; + private string $coverageHtmlColorBreadcrumbsDark; + private ?string $coverageHtmlCustomCssFile; + private ?string $coverageOpenClover; + private ?string $coveragePhp; + private ?string $coverageText; + private bool $coverageTextShowUncoveredFiles; + private bool $coverageTextShowOnlySummary; + private ?string $coverageXml; + private bool $coverageXmlIncludeSource; + private string $testResultCacheFile; + private bool $ignoreDeprecatedCodeUnitsFromCodeCoverage; + private bool $disableCodeCoverageIgnore; + private bool $failOnAllIssues; + private bool $failOnDeprecation; + private bool $failOnPhpunitDeprecation; + private bool $failOnPhpunitNotice; + private bool $failOnPhpunitWarning; + private bool $failOnEmptyTestSuite; + private bool $failOnIncomplete; + private bool $failOnNotice; + private bool $failOnRisky; + private bool $failOnSkipped; + private bool $failOnWarning; + private bool $doNotFailOnDeprecation; + private bool $doNotFailOnPhpunitDeprecation; + private bool $doNotFailOnPhpunitNotice; + private bool $doNotFailOnPhpunitWarning; + private bool $doNotFailOnEmptyTestSuite; + private bool $doNotFailOnIncomplete; + private bool $doNotFailOnNotice; + private bool $doNotFailOnRisky; + private bool $doNotFailOnSkipped; + private bool $doNotFailOnWarning; + private bool $stopOnDefect; + private bool $stopOnDeprecation; + private ?string $specificDeprecationToStopOn; + private bool $stopOnError; + private bool $stopOnFailure; + private bool $stopOnIncomplete; + private bool $stopOnNotice; + private bool $stopOnRisky; + private bool $stopOnSkipped; + private bool $stopOnWarning; + private bool $outputToStandardErrorStream; + private int $columns; + private bool $noExtensions; + /** + * @var ?non-empty-string + */ + private ?string $pharExtensionDirectory; + /** + * @var list}> + */ + private array $extensionBootstrappers; + private bool $backupGlobals; + private bool $backupStaticProperties; + private bool $beStrictAboutChangesToGlobalState; + private bool $colors; + private bool $processIsolation; + private bool $enforceTimeLimit; + private int $defaultTimeLimit; + private int $timeoutForSmallTests; + private int $timeoutForMediumTests; + private int $timeoutForLargeTests; + private bool $reportUselessTests; + private bool $strictCoverage; + private bool $disallowTestOutput; + private bool $displayDetailsOnAllIssues; + private bool $displayDetailsOnIncompleteTests; + private bool $displayDetailsOnSkippedTests; + private bool $displayDetailsOnTestsThatTriggerDeprecations; + private bool $displayDetailsOnPhpunitDeprecations; + private bool $displayDetailsOnPhpunitNotices; + private bool $displayDetailsOnTestsThatTriggerErrors; + private bool $displayDetailsOnTestsThatTriggerNotices; + private bool $displayDetailsOnTestsThatTriggerWarnings; + private bool $reverseDefectList; + private bool $requireCoverageMetadata; + private bool $requireSealedMockObjects; + private bool $noProgress; + private bool $noResults; + private bool $noOutput; + private int $executionOrder; + private int $executionOrderDefects; + private bool $resolveDependencies; + private ?string $logfileTeamcity; + private ?string $logfileJunit; + private ?string $logfileOtr; + private bool $includeGitInformation; + private bool $includeGitInformationInOtrLogfile; + private ?string $logfileTestdoxHtml; + private ?string $logfileTestdoxText; + private ?string $logEventsText; + private ?string $logEventsVerboseText; + /** + * @var ?non-empty-list + */ + private ?array $testsCovering; + /** + * @var ?non-empty-list + */ + private ?array $testsUsing; + /** + * @var ?non-empty-list + */ + private ?array $testsRequiringPhpExtension; + private bool $teamCityOutput; + private bool $testDoxOutput; + private bool $testDoxOutputSummary; + private ?string $filter; + private ?string $excludeFilter; + /** + * @var list + */ + private array $groups; + /** + * @var list + */ + private array $excludeGroups; + private int $randomOrderSeed; + private bool $includeUncoveredFiles; + private \PHPUnit\TextUI\Configuration\TestSuiteCollection $testSuite; + private string $includeTestSuite; + private string $excludeTestSuite; + private ?string $defaultTestSuite; + private bool $ignoreTestSelectionInXmlConfiguration; + /** + * @var non-empty-list + */ + private array $testSuffixes; + private \PHPUnit\TextUI\Configuration\Php $php; + private bool $controlGarbageCollector; + private int $numberOfTestsBeforeGarbageCollection; + /** + * @var null|non-empty-string + */ + private ?string $generateBaseline; + private bool $debug; + private bool $withTelemetry; + /** + * @var non-negative-int + */ + private int $shortenArraysForExportThreshold; + /** + * @param list $cliArguments + * @param array $bootstrapForTestSuite + * @param ?non-empty-string $pharExtensionDirectory + * @param list}> $extensionBootstrappers + * @param ?non-empty-list $testsCovering + * @param ?non-empty-list $testsUsing + * @param ?non-empty-list $testsRequiringPhpExtension + * @param list $groups + * @param list $excludeGroups + * @param non-empty-list $testSuffixes + * @param null|non-empty-string $generateBaseline + * @param non-negative-int $shortenArraysForExportThreshold + */ + public function __construct(array $cliArguments, ?string $testFilesFile, ?string $configurationFile, ?string $bootstrap, array $bootstrapForTestSuite, bool $cacheResult, ?string $cacheDirectory, ?string $coverageCacheDirectory, \PHPUnit\TextUI\Configuration\Source $source, string $testResultCacheFile, ?string $coverageClover, ?string $coverageCobertura, ?string $coverageCrap4j, int $coverageCrap4jThreshold, ?string $coverageHtml, int $coverageHtmlLowUpperBound, int $coverageHtmlHighLowerBound, string $coverageHtmlColorSuccessLow, string $coverageHtmlColorSuccessLowDark, string $coverageHtmlColorSuccessMedium, string $coverageHtmlColorSuccessMediumDark, string $coverageHtmlColorSuccessHigh, string $coverageHtmlColorSuccessHighDark, string $coverageHtmlColorSuccessBar, string $coverageHtmlColorSuccessBarDark, string $coverageHtmlColorWarning, string $coverageHtmlColorWarningDark, string $coverageHtmlColorWarningBar, string $coverageHtmlColorWarningBarDark, string $coverageHtmlColorDanger, string $coverageHtmlColorDangerDark, string $coverageHtmlColorDangerBar, string $coverageHtmlColorDangerBarDark, string $coverageHtmlColorBreadcrumbs, string $coverageHtmlColorBreadcrumbsDark, ?string $coverageHtmlCustomCssFile, ?string $coverageOpenClover, ?string $coveragePhp, ?string $coverageText, bool $coverageTextShowUncoveredFiles, bool $coverageTextShowOnlySummary, ?string $coverageXml, bool $coverageXmlIncludeSource, bool $pathCoverage, bool $ignoreDeprecatedCodeUnitsFromCodeCoverage, bool $disableCodeCoverageIgnore, bool $failOnAllIssues, bool $failOnDeprecation, bool $failOnPhpunitDeprecation, bool $failOnPhpunitNotice, bool $failOnPhpunitWarning, bool $failOnEmptyTestSuite, bool $failOnIncomplete, bool $failOnNotice, bool $failOnRisky, bool $failOnSkipped, bool $failOnWarning, bool $doNotFailOnDeprecation, bool $doNotFailOnPhpunitDeprecation, bool $doNotFailOnPhpunitNotice, bool $doNotFailOnPhpunitWarning, bool $doNotFailOnEmptyTestSuite, bool $doNotFailOnIncomplete, bool $doNotFailOnNotice, bool $doNotFailOnRisky, bool $doNotFailOnSkipped, bool $doNotFailOnWarning, bool $stopOnDefect, bool $stopOnDeprecation, ?string $specificDeprecationToStopOn, bool $stopOnError, bool $stopOnFailure, bool $stopOnIncomplete, bool $stopOnNotice, bool $stopOnRisky, bool $stopOnSkipped, bool $stopOnWarning, bool $outputToStandardErrorStream, int $columns, bool $noExtensions, ?string $pharExtensionDirectory, array $extensionBootstrappers, bool $backupGlobals, bool $backupStaticProperties, bool $beStrictAboutChangesToGlobalState, bool $colors, bool $processIsolation, bool $enforceTimeLimit, int $defaultTimeLimit, int $timeoutForSmallTests, int $timeoutForMediumTests, int $timeoutForLargeTests, bool $reportUselessTests, bool $strictCoverage, bool $disallowTestOutput, bool $displayDetailsOnAllIssues, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnPhpunitDeprecations, bool $displayDetailsOnPhpunitNotices, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $reverseDefectList, bool $requireCoverageMetadata, bool $requireSealedMockObjects, bool $noProgress, bool $noResults, bool $noOutput, int $executionOrder, int $executionOrderDefects, bool $resolveDependencies, ?string $logfileTeamcity, ?string $logfileJunit, ?string $logfileOtr, bool $includeGitInformation, bool $includeGitInformationInOtrLogfile, ?string $logfileTestdoxHtml, ?string $logfileTestdoxText, ?string $logEventsText, ?string $logEventsVerboseText, bool $teamCityOutput, bool $testDoxOutput, bool $testDoxOutputSummary, ?array $testsCovering, ?array $testsUsing, ?array $testsRequiringPhpExtension, ?string $filter, ?string $excludeFilter, array $groups, array $excludeGroups, int $randomOrderSeed, bool $includeUncoveredFiles, \PHPUnit\TextUI\Configuration\TestSuiteCollection $testSuite, string $includeTestSuite, string $excludeTestSuite, ?string $defaultTestSuite, bool $ignoreTestSelectionInXmlConfiguration, array $testSuffixes, \PHPUnit\TextUI\Configuration\Php $php, bool $controlGarbageCollector, int $numberOfTestsBeforeGarbageCollection, ?string $generateBaseline, bool $debug, bool $withTelemetry, int $shortenArraysForExportThreshold) + { + $this->cliArguments = $cliArguments; + $this->testFilesFile = $testFilesFile; + $this->configurationFile = $configurationFile; + $this->bootstrap = $bootstrap; + $this->bootstrapForTestSuite = $bootstrapForTestSuite; + $this->cacheResult = $cacheResult; + $this->cacheDirectory = $cacheDirectory; + $this->coverageCacheDirectory = $coverageCacheDirectory; + $this->source = $source; + $this->testResultCacheFile = $testResultCacheFile; + $this->coverageClover = $coverageClover; + $this->coverageCobertura = $coverageCobertura; + $this->coverageCrap4j = $coverageCrap4j; + $this->coverageCrap4jThreshold = $coverageCrap4jThreshold; + $this->coverageHtml = $coverageHtml; + $this->coverageHtmlLowUpperBound = $coverageHtmlLowUpperBound; + $this->coverageHtmlHighLowerBound = $coverageHtmlHighLowerBound; + $this->coverageHtmlColorSuccessLow = $coverageHtmlColorSuccessLow; + $this->coverageHtmlColorSuccessLowDark = $coverageHtmlColorSuccessLowDark; + $this->coverageHtmlColorSuccessMedium = $coverageHtmlColorSuccessMedium; + $this->coverageHtmlColorSuccessMediumDark = $coverageHtmlColorSuccessMediumDark; + $this->coverageHtmlColorSuccessHigh = $coverageHtmlColorSuccessHigh; + $this->coverageHtmlColorSuccessHighDark = $coverageHtmlColorSuccessHighDark; + $this->coverageHtmlColorSuccessBar = $coverageHtmlColorSuccessBar; + $this->coverageHtmlColorSuccessBarDark = $coverageHtmlColorSuccessBarDark; + $this->coverageHtmlColorWarning = $coverageHtmlColorWarning; + $this->coverageHtmlColorWarningDark = $coverageHtmlColorWarningDark; + $this->coverageHtmlColorWarningBar = $coverageHtmlColorWarningBar; + $this->coverageHtmlColorWarningBarDark = $coverageHtmlColorWarningBarDark; + $this->coverageHtmlColorDanger = $coverageHtmlColorDanger; + $this->coverageHtmlColorDangerDark = $coverageHtmlColorDangerDark; + $this->coverageHtmlColorDangerBar = $coverageHtmlColorDangerBar; + $this->coverageHtmlColorDangerBarDark = $coverageHtmlColorDangerBarDark; + $this->coverageHtmlColorBreadcrumbs = $coverageHtmlColorBreadcrumbs; + $this->coverageHtmlColorBreadcrumbsDark = $coverageHtmlColorBreadcrumbsDark; + $this->coverageHtmlCustomCssFile = $coverageHtmlCustomCssFile; + $this->coverageOpenClover = $coverageOpenClover; + $this->coveragePhp = $coveragePhp; + $this->coverageText = $coverageText; + $this->coverageTextShowUncoveredFiles = $coverageTextShowUncoveredFiles; + $this->coverageTextShowOnlySummary = $coverageTextShowOnlySummary; + $this->coverageXml = $coverageXml; + $this->coverageXmlIncludeSource = $coverageXmlIncludeSource; + $this->pathCoverage = $pathCoverage; + $this->ignoreDeprecatedCodeUnitsFromCodeCoverage = $ignoreDeprecatedCodeUnitsFromCodeCoverage; + $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore; + $this->failOnAllIssues = $failOnAllIssues; + $this->failOnDeprecation = $failOnDeprecation; + $this->failOnPhpunitDeprecation = $failOnPhpunitDeprecation; + $this->failOnPhpunitNotice = $failOnPhpunitNotice; + $this->failOnPhpunitWarning = $failOnPhpunitWarning; + $this->failOnEmptyTestSuite = $failOnEmptyTestSuite; + $this->failOnIncomplete = $failOnIncomplete; + $this->failOnNotice = $failOnNotice; + $this->failOnRisky = $failOnRisky; + $this->failOnSkipped = $failOnSkipped; + $this->failOnWarning = $failOnWarning; + $this->doNotFailOnDeprecation = $doNotFailOnDeprecation; + $this->doNotFailOnPhpunitDeprecation = $doNotFailOnPhpunitDeprecation; + $this->doNotFailOnPhpunitNotice = $doNotFailOnPhpunitNotice; + $this->doNotFailOnPhpunitWarning = $doNotFailOnPhpunitWarning; + $this->doNotFailOnEmptyTestSuite = $doNotFailOnEmptyTestSuite; + $this->doNotFailOnIncomplete = $doNotFailOnIncomplete; + $this->doNotFailOnNotice = $doNotFailOnNotice; + $this->doNotFailOnRisky = $doNotFailOnRisky; + $this->doNotFailOnSkipped = $doNotFailOnSkipped; + $this->doNotFailOnWarning = $doNotFailOnWarning; + $this->stopOnDefect = $stopOnDefect; + $this->stopOnDeprecation = $stopOnDeprecation; + $this->specificDeprecationToStopOn = $specificDeprecationToStopOn; + $this->stopOnError = $stopOnError; + $this->stopOnFailure = $stopOnFailure; + $this->stopOnIncomplete = $stopOnIncomplete; + $this->stopOnNotice = $stopOnNotice; + $this->stopOnRisky = $stopOnRisky; + $this->stopOnSkipped = $stopOnSkipped; + $this->stopOnWarning = $stopOnWarning; + $this->outputToStandardErrorStream = $outputToStandardErrorStream; + $this->columns = $columns; + $this->noExtensions = $noExtensions; + $this->pharExtensionDirectory = $pharExtensionDirectory; + $this->extensionBootstrappers = $extensionBootstrappers; + $this->backupGlobals = $backupGlobals; + $this->backupStaticProperties = $backupStaticProperties; + $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState; + $this->colors = $colors; + $this->processIsolation = $processIsolation; + $this->enforceTimeLimit = $enforceTimeLimit; + $this->defaultTimeLimit = $defaultTimeLimit; + $this->timeoutForSmallTests = $timeoutForSmallTests; + $this->timeoutForMediumTests = $timeoutForMediumTests; + $this->timeoutForLargeTests = $timeoutForLargeTests; + $this->reportUselessTests = $reportUselessTests; + $this->strictCoverage = $strictCoverage; + $this->disallowTestOutput = $disallowTestOutput; + $this->displayDetailsOnAllIssues = $displayDetailsOnAllIssues; + $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; + $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; + $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; + $this->displayDetailsOnPhpunitDeprecations = $displayDetailsOnPhpunitDeprecations; + $this->displayDetailsOnPhpunitNotices = $displayDetailsOnPhpunitNotices; + $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; + $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; + $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; + $this->reverseDefectList = $reverseDefectList; + $this->requireCoverageMetadata = $requireCoverageMetadata; + $this->requireSealedMockObjects = $requireSealedMockObjects; + $this->noProgress = $noProgress; + $this->noResults = $noResults; + $this->noOutput = $noOutput; + $this->executionOrder = $executionOrder; + $this->executionOrderDefects = $executionOrderDefects; + $this->resolveDependencies = $resolveDependencies; + $this->logfileTeamcity = $logfileTeamcity; + $this->logfileJunit = $logfileJunit; + $this->logfileOtr = $logfileOtr; + $this->includeGitInformation = $includeGitInformation; + $this->includeGitInformationInOtrLogfile = $includeGitInformationInOtrLogfile; + $this->logfileTestdoxHtml = $logfileTestdoxHtml; + $this->logfileTestdoxText = $logfileTestdoxText; + $this->logEventsText = $logEventsText; + $this->logEventsVerboseText = $logEventsVerboseText; + $this->teamCityOutput = $teamCityOutput; + $this->testDoxOutput = $testDoxOutput; + $this->testDoxOutputSummary = $testDoxOutputSummary; + $this->testsCovering = $testsCovering; + $this->testsUsing = $testsUsing; + $this->testsRequiringPhpExtension = $testsRequiringPhpExtension; + $this->filter = $filter; + $this->excludeFilter = $excludeFilter; + $this->groups = $groups; + $this->excludeGroups = $excludeGroups; + $this->randomOrderSeed = $randomOrderSeed; + $this->includeUncoveredFiles = $includeUncoveredFiles; + $this->testSuite = $testSuite; + $this->includeTestSuite = $includeTestSuite; + $this->excludeTestSuite = $excludeTestSuite; + $this->defaultTestSuite = $defaultTestSuite; + $this->ignoreTestSelectionInXmlConfiguration = $ignoreTestSelectionInXmlConfiguration; + $this->testSuffixes = $testSuffixes; + $this->php = $php; + $this->controlGarbageCollector = $controlGarbageCollector; + $this->numberOfTestsBeforeGarbageCollection = $numberOfTestsBeforeGarbageCollection; + $this->generateBaseline = $generateBaseline; + $this->debug = $debug; + $this->withTelemetry = $withTelemetry; + $this->shortenArraysForExportThreshold = $shortenArraysForExportThreshold; + } + /** + * @phpstan-assert-if-true !empty $this->cliArguments + */ + public function hasCliArguments(): bool + { + return $this->cliArguments !== []; + } + /** + * @return list + */ + public function cliArguments(): array + { + return $this->cliArguments; + } + /** + * @phpstan-assert-if-true !null $this->testFilesFile + */ + public function hasTestFilesFile(): bool + { + return $this->testFilesFile !== null; + } + /** + * @throws NoTestFilesFileException + */ + public function testFilesFile(): string + { + if (!$this->hasTestFilesFile()) { + throw new \PHPUnit\TextUI\Configuration\NoTestFilesFileException(); + } + return $this->testFilesFile; + } + /** + * @phpstan-assert-if-true !null $this->configurationFile + */ + public function hasConfigurationFile(): bool + { + return $this->configurationFile !== null; + } + /** + * @throws NoConfigurationFileException + */ + public function configurationFile(): string + { + if (!$this->hasConfigurationFile()) { + throw new \PHPUnit\TextUI\Configuration\NoConfigurationFileException(); + } + return $this->configurationFile; + } + /** + * @phpstan-assert-if-true !null $this->bootstrap + */ + public function hasBootstrap(): bool + { + return $this->bootstrap !== null; + } + /** + * @throws NoBootstrapException + */ + public function bootstrap(): string + { + if (!$this->hasBootstrap()) { + throw new \PHPUnit\TextUI\Configuration\NoBootstrapException(); + } + return $this->bootstrap; + } + /** + * @return array + */ + public function bootstrapForTestSuite(): array + { + return $this->bootstrapForTestSuite; + } + public function cacheResult(): bool + { + return $this->cacheResult; + } + /** + * @phpstan-assert-if-true !null $this->cacheDirectory + */ + public function hasCacheDirectory(): bool + { + return $this->cacheDirectory !== null; + } + /** + * @throws NoCacheDirectoryException + */ + public function cacheDirectory(): string + { + if (!$this->hasCacheDirectory()) { + throw new \PHPUnit\TextUI\Configuration\NoCacheDirectoryException(); + } + return $this->cacheDirectory; + } + /** + * @phpstan-assert-if-true !null $this->coverageCacheDirectory + */ + public function hasCoverageCacheDirectory(): bool + { + return $this->coverageCacheDirectory !== null; + } + /** + * @throws NoCoverageCacheDirectoryException + */ + public function coverageCacheDirectory(): string + { + if (!$this->hasCoverageCacheDirectory()) { + throw new \PHPUnit\TextUI\Configuration\NoCoverageCacheDirectoryException(); + } + return $this->coverageCacheDirectory; + } + public function source(): \PHPUnit\TextUI\Configuration\Source + { + return $this->source; + } + public function testResultCacheFile(): string + { + return $this->testResultCacheFile; + } + public function ignoreDeprecatedCodeUnitsFromCodeCoverage(): bool + { + return $this->ignoreDeprecatedCodeUnitsFromCodeCoverage; + } + public function disableCodeCoverageIgnore(): bool + { + return $this->disableCodeCoverageIgnore; + } + public function pathCoverage(): bool + { + return $this->pathCoverage; + } + public function hasCoverageReport(): bool + { + return $this->hasCoverageClover() || $this->hasCoverageCobertura() || $this->hasCoverageCrap4j() || $this->hasCoverageHtml() || $this->hasCoverageOpenClover() || $this->hasCoveragePhp() || $this->hasCoverageText() || $this->hasCoverageXml(); + } + /** + * @phpstan-assert-if-true !null $this->coverageClover + */ + public function hasCoverageClover(): bool + { + return $this->coverageClover !== null; + } + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageClover(): string + { + if (!$this->hasCoverageClover()) { + throw new \PHPUnit\TextUI\Configuration\CodeCoverageReportNotConfiguredException(); + } + return $this->coverageClover; + } + /** + * @phpstan-assert-if-true !null $this->coverageCobertura + */ + public function hasCoverageCobertura(): bool + { + return $this->coverageCobertura !== null; + } + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageCobertura(): string + { + if (!$this->hasCoverageCobertura()) { + throw new \PHPUnit\TextUI\Configuration\CodeCoverageReportNotConfiguredException(); + } + return $this->coverageCobertura; + } + /** + * @phpstan-assert-if-true !null $this->coverageCrap4j + */ + public function hasCoverageCrap4j(): bool + { + return $this->coverageCrap4j !== null; + } + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageCrap4j(): string + { + if (!$this->hasCoverageCrap4j()) { + throw new \PHPUnit\TextUI\Configuration\CodeCoverageReportNotConfiguredException(); + } + return $this->coverageCrap4j; + } + public function coverageCrap4jThreshold(): int + { + return $this->coverageCrap4jThreshold; + } + /** + * @phpstan-assert-if-true !null $this->coverageHtml + */ + public function hasCoverageHtml(): bool + { + return $this->coverageHtml !== null; + } + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageHtml(): string + { + if (!$this->hasCoverageHtml()) { + throw new \PHPUnit\TextUI\Configuration\CodeCoverageReportNotConfiguredException(); + } + return $this->coverageHtml; + } + public function coverageHtmlLowUpperBound(): int + { + return $this->coverageHtmlLowUpperBound; + } + public function coverageHtmlHighLowerBound(): int + { + return $this->coverageHtmlHighLowerBound; + } + public function coverageHtmlColorSuccessLow(): string + { + return $this->coverageHtmlColorSuccessLow; + } + public function coverageHtmlColorSuccessLowDark(): string + { + return $this->coverageHtmlColorSuccessLowDark; + } + public function coverageHtmlColorSuccessMedium(): string + { + return $this->coverageHtmlColorSuccessMedium; + } + public function coverageHtmlColorSuccessMediumDark(): string + { + return $this->coverageHtmlColorSuccessMediumDark; + } + public function coverageHtmlColorSuccessHigh(): string + { + return $this->coverageHtmlColorSuccessHigh; + } + public function coverageHtmlColorSuccessHighDark(): string + { + return $this->coverageHtmlColorSuccessHighDark; + } + public function coverageHtmlColorSuccessBar(): string + { + return $this->coverageHtmlColorSuccessBar; + } + public function coverageHtmlColorSuccessBarDark(): string + { + return $this->coverageHtmlColorSuccessBarDark; + } + public function coverageHtmlColorWarning(): string + { + return $this->coverageHtmlColorWarning; + } + public function coverageHtmlColorWarningDark(): string + { + return $this->coverageHtmlColorWarningDark; + } + public function coverageHtmlColorWarningBar(): string + { + return $this->coverageHtmlColorWarningBar; + } + public function coverageHtmlColorWarningBarDark(): string + { + return $this->coverageHtmlColorWarningBarDark; + } + public function coverageHtmlColorDanger(): string + { + return $this->coverageHtmlColorDanger; + } + public function coverageHtmlColorDangerDark(): string + { + return $this->coverageHtmlColorDangerDark; + } + public function coverageHtmlColorDangerBar(): string + { + return $this->coverageHtmlColorDangerBar; + } + public function coverageHtmlColorDangerBarDark(): string + { + return $this->coverageHtmlColorDangerBarDark; + } + public function coverageHtmlColorBreadcrumbs(): string + { + return $this->coverageHtmlColorBreadcrumbs; + } + public function coverageHtmlColorBreadcrumbsDark(): string + { + return $this->coverageHtmlColorBreadcrumbsDark; + } + /** + * @phpstan-assert-if-true !null $this->coverageHtmlCustomCssFile + */ + public function hasCoverageHtmlCustomCssFile(): bool + { + return $this->coverageHtmlCustomCssFile !== null; + } + /** + * @throws NoCustomCssFileException + */ + public function coverageHtmlCustomCssFile(): string + { + if (!$this->hasCoverageHtmlCustomCssFile()) { + throw new \PHPUnit\TextUI\Configuration\NoCustomCssFileException(); + } + return $this->coverageHtmlCustomCssFile; + } + /** + * @phpstan-assert-if-true !null $this->coverageOpenClover + */ + public function hasCoverageOpenClover(): bool + { + return $this->coverageOpenClover !== null; + } + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageOpenClover(): string + { + if (!$this->hasCoverageOpenClover()) { + throw new \PHPUnit\TextUI\Configuration\CodeCoverageReportNotConfiguredException(); + } + return $this->coverageOpenClover; + } + /** + * @phpstan-assert-if-true !null $this->coveragePhp + */ + public function hasCoveragePhp(): bool + { + return $this->coveragePhp !== null; + } + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coveragePhp(): string + { + if (!$this->hasCoveragePhp()) { + throw new \PHPUnit\TextUI\Configuration\CodeCoverageReportNotConfiguredException(); + } + return $this->coveragePhp; + } + /** + * @phpstan-assert-if-true !null $this->coverageText + */ + public function hasCoverageText(): bool + { + return $this->coverageText !== null; + } + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageText(): string + { + if (!$this->hasCoverageText()) { + throw new \PHPUnit\TextUI\Configuration\CodeCoverageReportNotConfiguredException(); + } + return $this->coverageText; + } + public function coverageTextShowUncoveredFiles(): bool + { + return $this->coverageTextShowUncoveredFiles; + } + public function coverageTextShowOnlySummary(): bool + { + return $this->coverageTextShowOnlySummary; + } + /** + * @phpstan-assert-if-true !null $this->coverageXml + */ + public function hasCoverageXml(): bool + { + return $this->coverageXml !== null; + } + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageXml(): string + { + if (!$this->hasCoverageXml()) { + throw new \PHPUnit\TextUI\Configuration\CodeCoverageReportNotConfiguredException(); + } + return $this->coverageXml; + } + public function coverageXmlIncludeSource(): bool + { + return $this->coverageXmlIncludeSource; + } + public function failOnAllIssues(): bool + { + return $this->failOnAllIssues; + } + public function failOnDeprecation(): bool + { + return $this->failOnDeprecation; + } + public function failOnPhpunitDeprecation(): bool + { + return $this->failOnPhpunitDeprecation; + } + public function failOnPhpunitNotice(): bool + { + return $this->failOnPhpunitNotice; + } + public function failOnPhpunitWarning(): bool + { + return $this->failOnPhpunitWarning; + } + public function failOnEmptyTestSuite(): bool + { + return $this->failOnEmptyTestSuite; + } + public function failOnIncomplete(): bool + { + return $this->failOnIncomplete; + } + public function failOnNotice(): bool + { + return $this->failOnNotice; + } + public function failOnRisky(): bool + { + return $this->failOnRisky; + } + public function failOnSkipped(): bool + { + return $this->failOnSkipped; + } + public function failOnWarning(): bool + { + return $this->failOnWarning; + } + public function doNotFailOnDeprecation(): bool + { + return $this->doNotFailOnDeprecation; + } + public function doNotFailOnPhpunitDeprecation(): bool + { + return $this->doNotFailOnPhpunitDeprecation; + } + public function doNotFailOnPhpunitNotice(): bool + { + return $this->doNotFailOnPhpunitNotice; + } + public function doNotFailOnPhpunitWarning(): bool + { + return $this->doNotFailOnPhpunitWarning; + } + public function doNotFailOnEmptyTestSuite(): bool + { + return $this->doNotFailOnEmptyTestSuite; + } + public function doNotFailOnIncomplete(): bool + { + return $this->doNotFailOnIncomplete; + } + public function doNotFailOnNotice(): bool + { + return $this->doNotFailOnNotice; + } + public function doNotFailOnRisky(): bool + { + return $this->doNotFailOnRisky; + } + public function doNotFailOnSkipped(): bool + { + return $this->doNotFailOnSkipped; + } + public function doNotFailOnWarning(): bool + { + return $this->doNotFailOnWarning; + } + public function stopOnDefect(): bool + { + return $this->stopOnDefect; + } + public function stopOnDeprecation(): bool + { + return $this->stopOnDeprecation; + } + /** + * @phpstan-assert-if-true !null $this->specificDeprecationToStopOn + */ + public function hasSpecificDeprecationToStopOn(): bool + { + return $this->specificDeprecationToStopOn !== null; + } + /** + * @throws SpecificDeprecationToStopOnNotConfiguredException + */ + public function specificDeprecationToStopOn(): string + { + if (!$this->hasSpecificDeprecationToStopOn()) { + throw new \PHPUnit\TextUI\Configuration\SpecificDeprecationToStopOnNotConfiguredException(); + } + return $this->specificDeprecationToStopOn; + } + public function stopOnError(): bool + { + return $this->stopOnError; + } + public function stopOnFailure(): bool + { + return $this->stopOnFailure; + } + public function stopOnIncomplete(): bool + { + return $this->stopOnIncomplete; + } + public function stopOnNotice(): bool + { + return $this->stopOnNotice; + } + public function stopOnRisky(): bool + { + return $this->stopOnRisky; + } + public function stopOnSkipped(): bool + { + return $this->stopOnSkipped; + } + public function stopOnWarning(): bool + { + return $this->stopOnWarning; + } + public function outputToStandardErrorStream(): bool + { + return $this->outputToStandardErrorStream; + } + public function columns(): int + { + return $this->columns; + } + public function noExtensions(): bool + { + return $this->noExtensions; + } + /** + * @phpstan-assert-if-true !null $this->pharExtensionDirectory + */ + public function hasPharExtensionDirectory(): bool + { + return $this->pharExtensionDirectory !== null; + } + /** + * @throws NoPharExtensionDirectoryException + * + * @return non-empty-string + */ + public function pharExtensionDirectory(): string + { + if (!$this->hasPharExtensionDirectory()) { + throw new \PHPUnit\TextUI\Configuration\NoPharExtensionDirectoryException(); + } + return $this->pharExtensionDirectory; + } + /** + * @return list}> + */ + public function extensionBootstrappers(): array + { + return $this->extensionBootstrappers; + } + public function backupGlobals(): bool + { + return $this->backupGlobals; + } + public function backupStaticProperties(): bool + { + return $this->backupStaticProperties; + } + public function beStrictAboutChangesToGlobalState(): bool + { + return $this->beStrictAboutChangesToGlobalState; + } + public function colors(): bool + { + return $this->colors; + } + public function processIsolation(): bool + { + return $this->processIsolation; + } + public function enforceTimeLimit(): bool + { + return $this->enforceTimeLimit; + } + public function defaultTimeLimit(): int + { + return $this->defaultTimeLimit; + } + public function timeoutForSmallTests(): int + { + return $this->timeoutForSmallTests; + } + public function timeoutForMediumTests(): int + { + return $this->timeoutForMediumTests; + } + public function timeoutForLargeTests(): int + { + return $this->timeoutForLargeTests; + } + public function reportUselessTests(): bool + { + return $this->reportUselessTests; + } + public function strictCoverage(): bool + { + return $this->strictCoverage; + } + public function disallowTestOutput(): bool + { + return $this->disallowTestOutput; + } + public function displayDetailsOnAllIssues(): bool + { + return $this->displayDetailsOnAllIssues; + } + public function displayDetailsOnIncompleteTests(): bool + { + return $this->displayDetailsOnIncompleteTests; + } + public function displayDetailsOnSkippedTests(): bool + { + return $this->displayDetailsOnSkippedTests; + } + public function displayDetailsOnTestsThatTriggerDeprecations(): bool + { + return $this->displayDetailsOnTestsThatTriggerDeprecations; + } + public function displayDetailsOnPhpunitDeprecations(): bool + { + return $this->displayDetailsOnPhpunitDeprecations; + } + public function displayDetailsOnPhpunitNotices(): bool + { + return $this->displayDetailsOnPhpunitNotices; + } + public function displayDetailsOnTestsThatTriggerErrors(): bool + { + return $this->displayDetailsOnTestsThatTriggerErrors; + } + public function displayDetailsOnTestsThatTriggerNotices(): bool + { + return $this->displayDetailsOnTestsThatTriggerNotices; + } + public function displayDetailsOnTestsThatTriggerWarnings(): bool + { + return $this->displayDetailsOnTestsThatTriggerWarnings; + } + public function reverseDefectList(): bool + { + return $this->reverseDefectList; + } + public function requireCoverageMetadata(): bool + { + return $this->requireCoverageMetadata; + } + public function requireSealedMockObjects(): bool + { + return $this->requireSealedMockObjects; + } + public function noProgress(): bool + { + return $this->noProgress; + } + public function noResults(): bool + { + return $this->noResults; + } + public function noOutput(): bool + { + return $this->noOutput; + } + public function executionOrder(): int + { + return $this->executionOrder; + } + public function executionOrderDefects(): int + { + return $this->executionOrderDefects; + } + public function resolveDependencies(): bool + { + return $this->resolveDependencies; + } + /** + * @phpstan-assert-if-true !null $this->logfileTeamcity + */ + public function hasLogfileTeamcity(): bool + { + return $this->logfileTeamcity !== null; + } + /** + * @throws LoggingNotConfiguredException + */ + public function logfileTeamcity(): string + { + if (!$this->hasLogfileTeamcity()) { + throw new \PHPUnit\TextUI\Configuration\LoggingNotConfiguredException(); + } + return $this->logfileTeamcity; + } + /** + * @phpstan-assert-if-true !null $this->logfileJunit + */ + public function hasLogfileJunit(): bool + { + return $this->logfileJunit !== null; + } + /** + * @throws LoggingNotConfiguredException + */ + public function logfileJunit(): string + { + if (!$this->hasLogfileJunit()) { + throw new \PHPUnit\TextUI\Configuration\LoggingNotConfiguredException(); + } + return $this->logfileJunit; + } + /** + * @phpstan-assert-if-true !null $this->logfileOtr + */ + public function hasLogfileOtr(): bool + { + return $this->logfileOtr !== null; + } + /** + * @throws LoggingNotConfiguredException + */ + public function logfileOtr(): string + { + if (!$this->hasLogfileOtr()) { + throw new \PHPUnit\TextUI\Configuration\LoggingNotConfiguredException(); + } + return $this->logfileOtr; + } + public function includeGitInformationInOtrLogfile(): bool + { + return $this->includeGitInformationInOtrLogfile; + } + public function includeGitInformation(): bool + { + return $this->includeGitInformation; + } + /** + * @phpstan-assert-if-true !null $this->logfileTestdoxHtml + */ + public function hasLogfileTestdoxHtml(): bool + { + return $this->logfileTestdoxHtml !== null; + } + /** + * @throws LoggingNotConfiguredException + */ + public function logfileTestdoxHtml(): string + { + if (!$this->hasLogfileTestdoxHtml()) { + throw new \PHPUnit\TextUI\Configuration\LoggingNotConfiguredException(); + } + return $this->logfileTestdoxHtml; + } + /** + * @phpstan-assert-if-true !null $this->logfileTestdoxText + */ + public function hasLogfileTestdoxText(): bool + { + return $this->logfileTestdoxText !== null; + } + /** + * @throws LoggingNotConfiguredException + */ + public function logfileTestdoxText(): string + { + if (!$this->hasLogfileTestdoxText()) { + throw new \PHPUnit\TextUI\Configuration\LoggingNotConfiguredException(); + } + return $this->logfileTestdoxText; + } + /** + * @phpstan-assert-if-true !null $this->logEventsText + */ + public function hasLogEventsText(): bool + { + return $this->logEventsText !== null; + } + /** + * @throws LoggingNotConfiguredException + */ + public function logEventsText(): string + { + if (!$this->hasLogEventsText()) { + throw new \PHPUnit\TextUI\Configuration\LoggingNotConfiguredException(); + } + return $this->logEventsText; + } + /** + * @phpstan-assert-if-true !null $this->logEventsVerboseText + */ + public function hasLogEventsVerboseText(): bool + { + return $this->logEventsVerboseText !== null; + } + /** + * @throws LoggingNotConfiguredException + */ + public function logEventsVerboseText(): string + { + if (!$this->hasLogEventsVerboseText()) { + throw new \PHPUnit\TextUI\Configuration\LoggingNotConfiguredException(); + } + return $this->logEventsVerboseText; + } + public function outputIsTeamCity(): bool + { + return $this->teamCityOutput; + } + public function outputIsTestDox(): bool + { + return $this->testDoxOutput; + } + public function testDoxOutputWithSummary(): bool + { + return $this->testDoxOutputSummary; + } + /** + * @phpstan-assert-if-true !empty $this->testsCovering + */ + public function hasTestsCovering(): bool + { + return $this->testsCovering !== null; + } + /** + * @throws FilterNotConfiguredException + * + * @return list + */ + public function testsCovering(): array + { + if (!$this->hasTestsCovering()) { + throw new \PHPUnit\TextUI\Configuration\FilterNotConfiguredException(); + } + return $this->testsCovering; + } + /** + * @phpstan-assert-if-true !empty $this->testsUsing + */ + public function hasTestsUsing(): bool + { + return $this->testsUsing !== null; + } + /** + * @throws FilterNotConfiguredException + * + * @return list + */ + public function testsUsing(): array + { + if (!$this->hasTestsUsing()) { + throw new \PHPUnit\TextUI\Configuration\FilterNotConfiguredException(); + } + return $this->testsUsing; + } + /** + * @phpstan-assert-if-true !empty $this->testsRequiringPhpExtension + */ + public function hasTestsRequiringPhpExtension(): bool + { + return $this->testsRequiringPhpExtension !== null; + } + /** + * @throws FilterNotConfiguredException + * + * @return non-empty-list + */ + public function testsRequiringPhpExtension(): array + { + if (!$this->hasTestsRequiringPhpExtension()) { + throw new \PHPUnit\TextUI\Configuration\FilterNotConfiguredException(); + } + return $this->testsRequiringPhpExtension; + } + /** + * @phpstan-assert-if-true !null $this->filter + */ + public function hasFilter(): bool + { + return $this->filter !== null; + } + /** + * @throws FilterNotConfiguredException + */ + public function filter(): string + { + if (!$this->hasFilter()) { + throw new \PHPUnit\TextUI\Configuration\FilterNotConfiguredException(); + } + return $this->filter; + } + /** + * @phpstan-assert-if-true !null $this->excludeFilter + */ + public function hasExcludeFilter(): bool + { + return $this->excludeFilter !== null; + } + /** + * @throws FilterNotConfiguredException + */ + public function excludeFilter(): string + { + if (!$this->hasExcludeFilter()) { + throw new \PHPUnit\TextUI\Configuration\FilterNotConfiguredException(); + } + return $this->excludeFilter; + } + /** + * @phpstan-assert-if-true !empty $this->groups + */ + public function hasGroups(): bool + { + return $this->groups !== []; + } + /** + * @throws FilterNotConfiguredException + * + * @return non-empty-list + */ + public function groups(): array + { + if (!$this->hasGroups()) { + throw new \PHPUnit\TextUI\Configuration\FilterNotConfiguredException(); + } + return $this->groups; + } + /** + * @phpstan-assert-if-true !empty $this->excludeGroups + */ + public function hasExcludeGroups(): bool + { + return $this->excludeGroups !== []; + } + /** + * @throws FilterNotConfiguredException + * + * @return non-empty-list + */ + public function excludeGroups(): array + { + if (!$this->hasExcludeGroups()) { + throw new \PHPUnit\TextUI\Configuration\FilterNotConfiguredException(); + } + return $this->excludeGroups; + } + public function randomOrderSeed(): int + { + return $this->randomOrderSeed; + } + public function includeUncoveredFiles(): bool + { + return $this->includeUncoveredFiles; + } + public function testSuite(): \PHPUnit\TextUI\Configuration\TestSuiteCollection + { + return $this->testSuite; + } + /** + * @return list + */ + public function includeTestSuites(): array + { + if ($this->includeTestSuite === '') { + return []; + } + return explode(',', $this->includeTestSuite); + } + /** + * @return list + */ + public function excludeTestSuites(): array + { + if ($this->excludeTestSuite === '') { + return []; + } + return explode(',', $this->excludeTestSuite); + } + /** + * @phpstan-assert-if-true !null $this->defaultTestSuite + */ + public function hasDefaultTestSuite(): bool + { + return $this->defaultTestSuite !== null; + } + /** + * @throws NoDefaultTestSuiteException + */ + public function defaultTestSuite(): string + { + if (!$this->hasDefaultTestSuite()) { + throw new \PHPUnit\TextUI\Configuration\NoDefaultTestSuiteException(); + } + return $this->defaultTestSuite; + } + public function ignoreTestSelectionInXmlConfiguration(): bool + { + return $this->ignoreTestSelectionInXmlConfiguration; + } + /** + * @return non-empty-list + */ + public function testSuffixes(): array + { + return $this->testSuffixes; + } + public function php(): \PHPUnit\TextUI\Configuration\Php + { + return $this->php; + } + public function controlGarbageCollector(): bool + { + return $this->controlGarbageCollector; + } + public function numberOfTestsBeforeGarbageCollection(): int + { + return $this->numberOfTestsBeforeGarbageCollection; + } + /** + * @phpstan-assert-if-true !null $this->generateBaseline + */ + public function hasGenerateBaseline(): bool + { + return $this->generateBaseline !== null; + } + /** + * @throws NoBaselineException + * + * @return non-empty-string + */ + public function generateBaseline(): string + { + if (!$this->hasGenerateBaseline()) { + throw new \PHPUnit\TextUI\Configuration\NoBaselineException(); + } + return $this->generateBaseline; + } + public function debug(): bool + { + return $this->debug; + } + public function withTelemetry(): bool + { + return $this->withTelemetry; + } + /** + * @return non-negative-int + */ + public function shortenArraysForExportThreshold(): int + { + return $this->shortenArraysForExportThreshold; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class BootstrapScriptDoesNotExistException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ + public function __construct(string $filename) + { + parent::__construct(sprintf('Cannot open bootstrap script "%s"', $filename)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class BootstrapScriptException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\TextUI\Configuration\Exception; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CannotFindSchemaException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CodeCoverageReportNotConfiguredException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ConfigurationCannotBeBuiltException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends \PHPUnit\TextUI\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class FilterNotConfiguredException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class LoggingNotConfiguredException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoBaselineException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoBootstrapException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoCacheDirectoryException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoConfigurationFileException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoCoverageCacheDirectoryException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoCustomCssFileException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoDefaultTestSuiteException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoHtmlCoverageTargetException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoPharExtensionDirectoryException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoTestFilesFileException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SpecificDeprecationToStopOnNotConfiguredException extends RuntimeException implements \PHPUnit\TextUI\Configuration\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const DIRECTORY_SEPARATOR; +use const PATH_SEPARATOR; +use function array_diff; +use function array_key_exists; +use function array_values; +use function assert; +use function dirname; +use function explode; +use function is_int; +use function realpath; +use function sprintf; +use function time; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; +use PHPUnit\TextUI\CliArguments\Exception; +use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; +use PHPUnit\TextUI\XmlConfiguration\LoadedFromFileConfiguration; +use PHPUnit\TextUI\XmlConfiguration\SchemaDetector; +use PHPUnit\Util\Filesystem; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html\Colors; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Thresholds; +use PHPUnitPHAR\SebastianBergmann\Environment\Console; +use PHPUnitPHAR\SebastianBergmann\Invoker\Invoker; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Merger +{ + /** + * @throws \PHPUnit\TextUI\XmlConfiguration\Exception + * @throws Exception + * @throws NoCustomCssFileException + */ + public function merge(CliConfiguration $cliConfiguration, XmlConfiguration $xmlConfiguration): \PHPUnit\TextUI\Configuration\Configuration + { + $testFilesFile = null; + if ($cliConfiguration->hasTestFilesFile()) { + $testFilesFile = $cliConfiguration->testFilesFile(); + } + $configurationFile = null; + if ($xmlConfiguration->wasLoadedFromFile()) { + assert($xmlConfiguration instanceof LoadedFromFileConfiguration); + $configurationFile = $xmlConfiguration->filename(); + } + $bootstrap = null; + if ($cliConfiguration->hasBootstrap()) { + $bootstrap = $cliConfiguration->bootstrap(); + } elseif ($xmlConfiguration->phpunit()->hasBootstrap()) { + $bootstrap = $xmlConfiguration->phpunit()->bootstrap(); + } + if ($cliConfiguration->hasCacheResult()) { + $cacheResult = $cliConfiguration->cacheResult(); + } else { + $cacheResult = $xmlConfiguration->phpunit()->cacheResult(); + } + $cacheDirectory = null; + $coverageCacheDirectory = null; + if ($cliConfiguration->hasCacheDirectory() && Filesystem::createDirectory($cliConfiguration->cacheDirectory())) { + $cacheDirectory = realpath($cliConfiguration->cacheDirectory()); + } elseif ($xmlConfiguration->phpunit()->hasCacheDirectory() && Filesystem::createDirectory($xmlConfiguration->phpunit()->cacheDirectory())) { + $cacheDirectory = realpath($xmlConfiguration->phpunit()->cacheDirectory()); + } + if ($cacheDirectory !== null) { + $coverageCacheDirectory = $cacheDirectory . DIRECTORY_SEPARATOR . 'code-coverage'; + $testResultCacheFile = $cacheDirectory . DIRECTORY_SEPARATOR . 'test-results'; + } + if (!isset($testResultCacheFile)) { + if ($xmlConfiguration->wasLoadedFromFile()) { + $testResultCacheFile = dirname(realpath($xmlConfiguration->filename())) . DIRECTORY_SEPARATOR . '.phpunit.result.cache'; + } else { + $candidate = realpath($_SERVER['PHP_SELF']); + if ($candidate) { + $testResultCacheFile = dirname($candidate) . DIRECTORY_SEPARATOR . '.phpunit.result.cache'; + } else { + $testResultCacheFile = '.phpunit.result.cache'; + } + } + } + if ($cliConfiguration->hasDisableCodeCoverageIgnore()) { + $disableCodeCoverageIgnore = $cliConfiguration->disableCodeCoverageIgnore(); + } else { + $disableCodeCoverageIgnore = $xmlConfiguration->codeCoverage()->disableCodeCoverageIgnore(); + } + if ($cliConfiguration->hasFailOnAllIssues()) { + $failOnAllIssues = $cliConfiguration->failOnAllIssues(); + } else { + $failOnAllIssues = $xmlConfiguration->phpunit()->failOnAllIssues(); + } + if ($cliConfiguration->hasFailOnDeprecation()) { + $failOnDeprecation = $cliConfiguration->failOnDeprecation(); + } else { + $failOnDeprecation = $xmlConfiguration->phpunit()->failOnDeprecation(); + } + if ($cliConfiguration->hasFailOnPhpunitDeprecation()) { + $failOnPhpunitDeprecation = $cliConfiguration->failOnPhpunitDeprecation(); + } else { + $failOnPhpunitDeprecation = $xmlConfiguration->phpunit()->failOnPhpunitDeprecation(); + } + if ($cliConfiguration->hasFailOnPhpunitNotice()) { + $failOnPhpunitNotice = $cliConfiguration->failOnPhpunitNotice(); + } else { + $failOnPhpunitNotice = $xmlConfiguration->phpunit()->failOnPhpunitNotice(); + } + if ($cliConfiguration->hasFailOnPhpunitWarning()) { + $failOnPhpunitWarning = $cliConfiguration->failOnPhpunitWarning(); + } else { + $failOnPhpunitWarning = $xmlConfiguration->phpunit()->failOnPhpunitWarning(); + } + if ($cliConfiguration->hasFailOnEmptyTestSuite()) { + $failOnEmptyTestSuite = $cliConfiguration->failOnEmptyTestSuite(); + } elseif ($xmlConfiguration->phpunit()->hasFailOnEmptyTestSuite()) { + $failOnEmptyTestSuite = $xmlConfiguration->phpunit()->failOnEmptyTestSuite(); + } else { + $failOnEmptyTestSuite = $this->hasExplicitTestSelection($cliConfiguration); + } + if ($cliConfiguration->hasFailOnIncomplete()) { + $failOnIncomplete = $cliConfiguration->failOnIncomplete(); + } else { + $failOnIncomplete = $xmlConfiguration->phpunit()->failOnIncomplete(); + } + if ($cliConfiguration->hasFailOnNotice()) { + $failOnNotice = $cliConfiguration->failOnNotice(); + } else { + $failOnNotice = $xmlConfiguration->phpunit()->failOnNotice(); + } + if ($cliConfiguration->hasFailOnRisky()) { + $failOnRisky = $cliConfiguration->failOnRisky(); + } else { + $failOnRisky = $xmlConfiguration->phpunit()->failOnRisky(); + } + if ($cliConfiguration->hasFailOnSkipped()) { + $failOnSkipped = $cliConfiguration->failOnSkipped(); + } else { + $failOnSkipped = $xmlConfiguration->phpunit()->failOnSkipped(); + } + if ($cliConfiguration->hasFailOnWarning()) { + $failOnWarning = $cliConfiguration->failOnWarning(); + } else { + $failOnWarning = $xmlConfiguration->phpunit()->failOnWarning(); + } + $doNotFailOnDeprecation = \false; + if ($cliConfiguration->hasDoNotFailOnDeprecation()) { + $doNotFailOnDeprecation = $cliConfiguration->doNotFailOnDeprecation(); + } + $doNotFailOnPhpunitDeprecation = \false; + if ($cliConfiguration->hasDoNotFailOnPhpunitDeprecation()) { + $doNotFailOnPhpunitDeprecation = $cliConfiguration->doNotFailOnPhpunitDeprecation(); + } + $doNotFailOnPhpunitNotice = \false; + if ($cliConfiguration->hasDoNotFailOnPhpunitNotice()) { + $doNotFailOnPhpunitNotice = $cliConfiguration->doNotFailOnPhpunitNotice(); + } + $doNotFailOnPhpunitWarning = \false; + if ($cliConfiguration->hasDoNotFailOnPhpunitWarning()) { + $doNotFailOnPhpunitWarning = $cliConfiguration->doNotFailOnPhpunitWarning(); + } + $doNotFailOnEmptyTestSuite = \false; + if ($cliConfiguration->hasDoNotFailOnEmptyTestSuite()) { + $doNotFailOnEmptyTestSuite = $cliConfiguration->doNotFailOnEmptyTestSuite(); + } + $doNotFailOnIncomplete = \false; + if ($cliConfiguration->hasDoNotFailOnIncomplete()) { + $doNotFailOnIncomplete = $cliConfiguration->doNotFailOnIncomplete(); + } + $doNotFailOnNotice = \false; + if ($cliConfiguration->hasDoNotFailOnNotice()) { + $doNotFailOnNotice = $cliConfiguration->doNotFailOnNotice(); + } + $doNotFailOnRisky = \false; + if ($cliConfiguration->hasDoNotFailOnRisky()) { + $doNotFailOnRisky = $cliConfiguration->doNotFailOnRisky(); + } + $doNotFailOnSkipped = \false; + if ($cliConfiguration->hasDoNotFailOnSkipped()) { + $doNotFailOnSkipped = $cliConfiguration->doNotFailOnSkipped(); + } + $doNotFailOnWarning = \false; + if ($cliConfiguration->hasDoNotFailOnWarning()) { + $doNotFailOnWarning = $cliConfiguration->doNotFailOnWarning(); + } + if ($cliConfiguration->hasStopOnDefect()) { + $stopOnDefect = $cliConfiguration->stopOnDefect(); + } else { + $stopOnDefect = $xmlConfiguration->phpunit()->stopOnDefect(); + } + if ($cliConfiguration->hasStopOnDeprecation()) { + $stopOnDeprecation = $cliConfiguration->stopOnDeprecation(); + } else { + $stopOnDeprecation = $xmlConfiguration->phpunit()->stopOnDeprecation(); + } + $specificDeprecationToStopOn = null; + if ($cliConfiguration->hasSpecificDeprecationToStopOn()) { + $specificDeprecationToStopOn = $cliConfiguration->specificDeprecationToStopOn(); + } + if ($cliConfiguration->hasStopOnError()) { + $stopOnError = $cliConfiguration->stopOnError(); + } else { + $stopOnError = $xmlConfiguration->phpunit()->stopOnError(); + } + if ($cliConfiguration->hasStopOnFailure()) { + $stopOnFailure = $cliConfiguration->stopOnFailure(); + } else { + $stopOnFailure = $xmlConfiguration->phpunit()->stopOnFailure(); + } + if ($cliConfiguration->hasStopOnIncomplete()) { + $stopOnIncomplete = $cliConfiguration->stopOnIncomplete(); + } else { + $stopOnIncomplete = $xmlConfiguration->phpunit()->stopOnIncomplete(); + } + if ($cliConfiguration->hasStopOnNotice()) { + $stopOnNotice = $cliConfiguration->stopOnNotice(); + } else { + $stopOnNotice = $xmlConfiguration->phpunit()->stopOnNotice(); + } + if ($cliConfiguration->hasStopOnRisky()) { + $stopOnRisky = $cliConfiguration->stopOnRisky(); + } else { + $stopOnRisky = $xmlConfiguration->phpunit()->stopOnRisky(); + } + if ($cliConfiguration->hasStopOnSkipped()) { + $stopOnSkipped = $cliConfiguration->stopOnSkipped(); + } else { + $stopOnSkipped = $xmlConfiguration->phpunit()->stopOnSkipped(); + } + if ($cliConfiguration->hasStopOnWarning()) { + $stopOnWarning = $cliConfiguration->stopOnWarning(); + } else { + $stopOnWarning = $xmlConfiguration->phpunit()->stopOnWarning(); + } + if ($cliConfiguration->hasStderr() && $cliConfiguration->stderr()) { + $outputToStandardErrorStream = \true; + } else { + $outputToStandardErrorStream = $xmlConfiguration->phpunit()->stderr(); + } + if ($cliConfiguration->hasColumns()) { + $columns = $cliConfiguration->columns(); + } else { + $columns = $xmlConfiguration->phpunit()->columns(); + } + if ($columns === 'max') { + $columns = (new Console())->getNumberOfColumns(); + } + if ($columns < 16) { + $columns = 16; + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning('Less than 16 columns requested, number of columns set to 16'); + } + assert(is_int($columns)); + $noExtensions = \false; + if ($cliConfiguration->hasNoExtensions() && $cliConfiguration->noExtensions()) { + $noExtensions = \true; + } + $pharExtensionDirectory = null; + if ($xmlConfiguration->phpunit()->hasExtensionsDirectory()) { + $pharExtensionDirectory = $xmlConfiguration->phpunit()->extensionsDirectory(); + } + $extensionBootstrappers = []; + if ($cliConfiguration->hasExtensions()) { + foreach ($cliConfiguration->extensions() as $extension) { + if (array_key_exists($extension, $extensionBootstrappers)) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Extension "%s" is configured more than once on the command line', $extension)); + } + $extensionBootstrappers[$extension] = ['className' => $extension, 'parameters' => []]; + } + } + foreach ($xmlConfiguration->extensions() as $extension) { + if (array_key_exists($extension->className(), $extensionBootstrappers)) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Extension "%s" is configured more than once', $extension->className())); + } + $extensionBootstrappers[$extension->className()] = ['className' => $extension->className(), 'parameters' => $extension->parameters()]; + } + if ($cliConfiguration->hasPathCoverage() && $cliConfiguration->pathCoverage()) { + $pathCoverage = $cliConfiguration->pathCoverage(); + } else { + $pathCoverage = $xmlConfiguration->codeCoverage()->pathCoverage(); + } + $defaultColors = Colors::default(); + $defaultThresholds = Thresholds::default(); + $coverageClover = null; + $coverageCobertura = null; + $coverageCrap4j = null; + $coverageCrap4jThreshold = 30; + $coverageHtml = null; + $coverageHtmlLowUpperBound = $defaultThresholds->lowUpperBound(); + $coverageHtmlHighLowerBound = $defaultThresholds->highLowerBound(); + $coverageHtmlColorSuccessLow = $defaultColors->successLow(); + $coverageHtmlColorSuccessLowDark = $defaultColors->successLowDark(); + $coverageHtmlColorSuccessMedium = $defaultColors->successMedium(); + $coverageHtmlColorSuccessMediumDark = $defaultColors->successMediumDark(); + $coverageHtmlColorSuccessHigh = $defaultColors->successHigh(); + $coverageHtmlColorSuccessHighDark = $defaultColors->successHighDark(); + $coverageHtmlColorSuccessBar = $defaultColors->successBar(); + $coverageHtmlColorSuccessBarDark = $defaultColors->successBarDark(); + $coverageHtmlColorWarning = $defaultColors->warning(); + $coverageHtmlColorWarningDark = $defaultColors->warningDark(); + $coverageHtmlColorWarningBar = $defaultColors->warningBar(); + $coverageHtmlColorWarningBarDark = $defaultColors->warningBarDark(); + $coverageHtmlColorDanger = $defaultColors->danger(); + $coverageHtmlColorDangerDark = $defaultColors->dangerDark(); + $coverageHtmlColorDangerBar = $defaultColors->dangerBar(); + $coverageHtmlColorDangerBarDark = $defaultColors->dangerBarDark(); + $coverageHtmlColorBreadcrumbs = $defaultColors->breadcrumbs(); + $coverageHtmlColorBreadcrumbsDark = $defaultColors->breadcrumbsDark(); + $coverageHtmlCustomCssFile = null; + $coverageOpenClover = null; + $coveragePhp = null; + $coverageText = null; + $coverageTextShowUncoveredFiles = \false; + $coverageTextShowOnlySummary = \false; + $coverageXml = null; + $coverageXmlIncludeSource = \true; + $coverageFromXmlConfiguration = \true; + if ($cliConfiguration->hasNoCoverage() && $cliConfiguration->noCoverage()) { + $coverageFromXmlConfiguration = \false; + } + if ($cliConfiguration->hasCoverageClover()) { + $coverageClover = $cliConfiguration->coverageClover(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasClover()) { + $coverageClover = $xmlConfiguration->codeCoverage()->clover()->target()->path(); + } + if ($cliConfiguration->hasCoverageCobertura()) { + $coverageCobertura = $cliConfiguration->coverageCobertura(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasCobertura()) { + $coverageCobertura = $xmlConfiguration->codeCoverage()->cobertura()->target()->path(); + } + if ($xmlConfiguration->codeCoverage()->hasCrap4j()) { + $coverageCrap4jThreshold = $xmlConfiguration->codeCoverage()->crap4j()->threshold(); + } + if ($cliConfiguration->hasCoverageCrap4J()) { + $coverageCrap4j = $cliConfiguration->coverageCrap4J(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasCrap4j()) { + $coverageCrap4j = $xmlConfiguration->codeCoverage()->crap4j()->target()->path(); + } + if ($xmlConfiguration->codeCoverage()->hasHtml()) { + $coverageHtmlHighLowerBound = $xmlConfiguration->codeCoverage()->html()->highLowerBound(); + $coverageHtmlLowUpperBound = $xmlConfiguration->codeCoverage()->html()->lowUpperBound(); + if ($coverageHtmlLowUpperBound > $coverageHtmlHighLowerBound) { + $coverageHtmlLowUpperBound = $defaultThresholds->lowUpperBound(); + $coverageHtmlHighLowerBound = $defaultThresholds->highLowerBound(); + } + $coverageHtmlColorSuccessLow = $xmlConfiguration->codeCoverage()->html()->colorSuccessLow(); + $coverageHtmlColorSuccessLowDark = $xmlConfiguration->codeCoverage()->html()->colorSuccessLowDark(); + $coverageHtmlColorSuccessMedium = $xmlConfiguration->codeCoverage()->html()->colorSuccessMedium(); + $coverageHtmlColorSuccessMediumDark = $xmlConfiguration->codeCoverage()->html()->colorSuccessMediumDark(); + $coverageHtmlColorSuccessHigh = $xmlConfiguration->codeCoverage()->html()->colorSuccessHigh(); + $coverageHtmlColorSuccessHighDark = $xmlConfiguration->codeCoverage()->html()->colorSuccessHighDark(); + $coverageHtmlColorSuccessBar = $xmlConfiguration->codeCoverage()->html()->colorSuccessBar(); + $coverageHtmlColorSuccessBarDark = $xmlConfiguration->codeCoverage()->html()->colorSuccessBarDark(); + $coverageHtmlColorWarning = $xmlConfiguration->codeCoverage()->html()->colorWarning(); + $coverageHtmlColorWarningDark = $xmlConfiguration->codeCoverage()->html()->colorWarningDark(); + $coverageHtmlColorWarningBar = $xmlConfiguration->codeCoverage()->html()->colorWarningBar(); + $coverageHtmlColorWarningBarDark = $xmlConfiguration->codeCoverage()->html()->colorWarningBarDark(); + $coverageHtmlColorDanger = $xmlConfiguration->codeCoverage()->html()->colorDanger(); + $coverageHtmlColorDangerDark = $xmlConfiguration->codeCoverage()->html()->colorDangerDark(); + $coverageHtmlColorDangerBar = $xmlConfiguration->codeCoverage()->html()->colorDangerBar(); + $coverageHtmlColorDangerBarDark = $xmlConfiguration->codeCoverage()->html()->colorDangerBarDark(); + $coverageHtmlColorBreadcrumbs = $xmlConfiguration->codeCoverage()->html()->colorBreadcrumbs(); + $coverageHtmlColorBreadcrumbsDark = $xmlConfiguration->codeCoverage()->html()->colorBreadcrumbsDark(); + if ($xmlConfiguration->codeCoverage()->html()->hasCustomCssFile()) { + $coverageHtmlCustomCssFile = $xmlConfiguration->codeCoverage()->html()->customCssFile(); + } + } + if ($cliConfiguration->hasCoverageHtml()) { + $coverageHtml = $cliConfiguration->coverageHtml(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasHtml() && $xmlConfiguration->codeCoverage()->html()->hasTarget()) { + $coverageHtml = $xmlConfiguration->codeCoverage()->html()->target()->path(); + } + if ($cliConfiguration->hasCoverageOpenClover()) { + $coverageOpenClover = $cliConfiguration->coverageOpenClover(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasOpenClover()) { + $coverageOpenClover = $xmlConfiguration->codeCoverage()->openClover()->target()->path(); + } + if ($cliConfiguration->hasCoveragePhp()) { + $coveragePhp = $cliConfiguration->coveragePhp(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasPhp()) { + $coveragePhp = $xmlConfiguration->codeCoverage()->php()->target()->path(); + } + if ($xmlConfiguration->codeCoverage()->hasText()) { + $coverageTextShowUncoveredFiles = $xmlConfiguration->codeCoverage()->text()->showUncoveredFiles(); + $coverageTextShowOnlySummary = $xmlConfiguration->codeCoverage()->text()->showOnlySummary(); + } + if ($cliConfiguration->hasCoverageTextShowUncoveredFiles()) { + $coverageTextShowUncoveredFiles = $cliConfiguration->coverageTextShowUncoveredFiles(); + } + if ($cliConfiguration->hasCoverageTextShowOnlySummary()) { + $coverageTextShowOnlySummary = $cliConfiguration->coverageTextShowOnlySummary(); + } + if ($cliConfiguration->hasCoverageText()) { + $coverageText = $cliConfiguration->coverageText(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasText()) { + $coverageText = $xmlConfiguration->codeCoverage()->text()->target()->path(); + } + if ($cliConfiguration->hasCoverageXml()) { + $coverageXml = $cliConfiguration->coverageXml(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasXml()) { + $coverageXml = $xmlConfiguration->codeCoverage()->xml()->target()->path(); + } + if ($cliConfiguration->hasExcludeSourceFromXmlCoverage()) { + $coverageXmlIncludeSource = !$cliConfiguration->excludeSourceFromXmlCoverage(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasXml()) { + $coverageXmlIncludeSource = $xmlConfiguration->codeCoverage()->xml()->includeSource(); + } + if ($cliConfiguration->hasBackupGlobals()) { + $backupGlobals = $cliConfiguration->backupGlobals(); + } else { + $backupGlobals = $xmlConfiguration->phpunit()->backupGlobals(); + } + if ($cliConfiguration->hasBackupStaticProperties()) { + $backupStaticProperties = $cliConfiguration->backupStaticProperties(); + } else { + $backupStaticProperties = $xmlConfiguration->phpunit()->backupStaticProperties(); + } + if ($cliConfiguration->hasBeStrictAboutChangesToGlobalState()) { + $beStrictAboutChangesToGlobalState = $cliConfiguration->beStrictAboutChangesToGlobalState(); + } else { + $beStrictAboutChangesToGlobalState = $xmlConfiguration->phpunit()->beStrictAboutChangesToGlobalState(); + } + if ($cliConfiguration->hasProcessIsolation()) { + $processIsolation = $cliConfiguration->processIsolation(); + } else { + $processIsolation = $xmlConfiguration->phpunit()->processIsolation(); + } + if ($cliConfiguration->hasEnforceTimeLimit()) { + $enforceTimeLimit = $cliConfiguration->enforceTimeLimit(); + } else { + $enforceTimeLimit = $xmlConfiguration->phpunit()->enforceTimeLimit(); + } + if ($enforceTimeLimit && !(new Invoker())->canInvokeWithTimeout()) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning('The pcntl extension is required for enforcing time limits'); + } + if ($cliConfiguration->hasDefaultTimeLimit()) { + $defaultTimeLimit = $cliConfiguration->defaultTimeLimit(); + } else { + $defaultTimeLimit = $xmlConfiguration->phpunit()->defaultTimeLimit(); + } + $timeoutForSmallTests = $xmlConfiguration->phpunit()->timeoutForSmallTests(); + $timeoutForMediumTests = $xmlConfiguration->phpunit()->timeoutForMediumTests(); + $timeoutForLargeTests = $xmlConfiguration->phpunit()->timeoutForLargeTests(); + if ($cliConfiguration->hasReportUselessTests()) { + $reportUselessTests = $cliConfiguration->reportUselessTests(); + } else { + $reportUselessTests = $xmlConfiguration->phpunit()->beStrictAboutTestsThatDoNotTestAnything(); + } + if ($cliConfiguration->hasStrictCoverage()) { + $strictCoverage = $cliConfiguration->strictCoverage(); + } else { + $strictCoverage = $xmlConfiguration->phpunit()->beStrictAboutCoverageMetadata(); + } + if ($cliConfiguration->hasDisallowTestOutput()) { + $disallowTestOutput = $cliConfiguration->disallowTestOutput(); + } else { + $disallowTestOutput = $xmlConfiguration->phpunit()->beStrictAboutOutputDuringTests(); + } + if ($cliConfiguration->hasDisplayDetailsOnAllIssues()) { + $displayDetailsOnAllIssues = $cliConfiguration->displayDetailsOnAllIssues(); + } else { + $displayDetailsOnAllIssues = $xmlConfiguration->phpunit()->displayDetailsOnAllIssues(); + } + if ($cliConfiguration->hasDisplayDetailsOnIncompleteTests()) { + $displayDetailsOnIncompleteTests = $cliConfiguration->displayDetailsOnIncompleteTests(); + } else { + $displayDetailsOnIncompleteTests = $xmlConfiguration->phpunit()->displayDetailsOnIncompleteTests(); + } + if ($cliConfiguration->hasDisplayDetailsOnSkippedTests()) { + $displayDetailsOnSkippedTests = $cliConfiguration->displayDetailsOnSkippedTests(); + } else { + $displayDetailsOnSkippedTests = $xmlConfiguration->phpunit()->displayDetailsOnSkippedTests(); + } + if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerDeprecations()) { + $displayDetailsOnTestsThatTriggerDeprecations = $cliConfiguration->displayDetailsOnTestsThatTriggerDeprecations(); + } else { + $displayDetailsOnTestsThatTriggerDeprecations = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerDeprecations(); + } + if ($cliConfiguration->hasDisplayDetailsOnPhpunitDeprecations()) { + $displayDetailsOnPhpunitDeprecations = $cliConfiguration->displayDetailsOnPhpunitDeprecations(); + } else { + $displayDetailsOnPhpunitDeprecations = $xmlConfiguration->phpunit()->displayDetailsOnPhpunitDeprecations(); + } + if ($cliConfiguration->hasDisplayDetailsOnPhpunitNotices()) { + $displayDetailsOnPhpunitNotices = $cliConfiguration->displayDetailsOnPhpunitNotices(); + } else { + $displayDetailsOnPhpunitNotices = $xmlConfiguration->phpunit()->displayDetailsOnPhpunitNotices(); + } + if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerErrors()) { + $displayDetailsOnTestsThatTriggerErrors = $cliConfiguration->displayDetailsOnTestsThatTriggerErrors(); + } else { + $displayDetailsOnTestsThatTriggerErrors = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerErrors(); + } + if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerNotices()) { + $displayDetailsOnTestsThatTriggerNotices = $cliConfiguration->displayDetailsOnTestsThatTriggerNotices(); + } else { + $displayDetailsOnTestsThatTriggerNotices = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerNotices(); + } + if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerWarnings()) { + $displayDetailsOnTestsThatTriggerWarnings = $cliConfiguration->displayDetailsOnTestsThatTriggerWarnings(); + } else { + $displayDetailsOnTestsThatTriggerWarnings = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerWarnings(); + } + if ($cliConfiguration->hasReverseList()) { + $reverseDefectList = $cliConfiguration->reverseList(); + } else { + $reverseDefectList = $xmlConfiguration->phpunit()->reverseDefectList(); + } + $requireCoverageMetadata = $xmlConfiguration->phpunit()->requireCoverageMetadata(); + $requireSealedMockObjects = $xmlConfiguration->phpunit()->requireSealedMockObjects(); + if ($cliConfiguration->hasExecutionOrder()) { + $executionOrder = $cliConfiguration->executionOrder(); + } else { + $executionOrder = $xmlConfiguration->phpunit()->executionOrder(); + } + $executionOrderDefects = TestSuiteSorter::ORDER_DEFAULT; + if ($cliConfiguration->hasExecutionOrderDefects()) { + $executionOrderDefects = $cliConfiguration->executionOrderDefects(); + } elseif ($xmlConfiguration->phpunit()->defectsFirst()) { + $executionOrderDefects = TestSuiteSorter::ORDER_DEFECTS_FIRST; + } + if ($cliConfiguration->hasResolveDependencies()) { + $resolveDependencies = $cliConfiguration->resolveDependencies(); + } else { + $resolveDependencies = $xmlConfiguration->phpunit()->resolveDependencies(); + } + $colors = \false; + $colorsSupported = (new Console())->hasColorSupport(); + if ($cliConfiguration->hasColors()) { + if ($cliConfiguration->colors() === \PHPUnit\TextUI\Configuration\Configuration::COLOR_ALWAYS) { + $colors = \true; + } elseif ($colorsSupported && $cliConfiguration->colors() === \PHPUnit\TextUI\Configuration\Configuration::COLOR_AUTO) { + $colors = \true; + } + } elseif ($xmlConfiguration->phpunit()->colors() === \PHPUnit\TextUI\Configuration\Configuration::COLOR_ALWAYS) { + $colors = \true; + } elseif ($colorsSupported && $xmlConfiguration->phpunit()->colors() === \PHPUnit\TextUI\Configuration\Configuration::COLOR_AUTO) { + $colors = \true; + } + $logfileTeamcity = null; + $logfileJunit = null; + $logfileOtr = null; + $logfileTestdoxHtml = null; + $logfileTestdoxText = null; + $loggingFromXmlConfiguration = \true; + if ($cliConfiguration->hasNoLogging() && $cliConfiguration->noLogging()) { + $loggingFromXmlConfiguration = \false; + } + if ($cliConfiguration->hasTeamcityLogfile()) { + $logfileTeamcity = $cliConfiguration->teamcityLogfile(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasTeamCity()) { + $logfileTeamcity = $xmlConfiguration->logging()->teamCity()->target()->path(); + } + if ($cliConfiguration->hasJunitLogfile()) { + $logfileJunit = $cliConfiguration->junitLogfile(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasJunit()) { + $logfileJunit = $xmlConfiguration->logging()->junit()->target()->path(); + } + if ($cliConfiguration->hasOtrLogfile()) { + $logfileOtr = $cliConfiguration->otrLogfile(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasOtr()) { + $logfileOtr = $xmlConfiguration->logging()->otr()->target()->path(); + } + $includeGitInformation = \false; + $includeGitInformationInOtrLogfile = \false; + if ($cliConfiguration->hasIncludeGitInformation()) { + $includeGitInformation = $cliConfiguration->includeGitInformation(); + $includeGitInformationInOtrLogfile = $cliConfiguration->includeGitInformation(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasOtr()) { + $includeGitInformationInOtrLogfile = $xmlConfiguration->logging()->otr()->includeGitInformation(); + } + if ($cliConfiguration->hasTestdoxHtmlFile()) { + $logfileTestdoxHtml = $cliConfiguration->testdoxHtmlFile(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasTestDoxHtml()) { + $logfileTestdoxHtml = $xmlConfiguration->logging()->testDoxHtml()->target()->path(); + } + if ($cliConfiguration->hasTestdoxTextFile()) { + $logfileTestdoxText = $cliConfiguration->testdoxTextFile(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasTestDoxText()) { + $logfileTestdoxText = $xmlConfiguration->logging()->testDoxText()->target()->path(); + } + $logEventsText = null; + if ($cliConfiguration->hasLogEventsText()) { + $logEventsText = $cliConfiguration->logEventsText(); + } + $logEventsVerboseText = null; + if ($cliConfiguration->hasLogEventsVerboseText()) { + $logEventsVerboseText = $cliConfiguration->logEventsVerboseText(); + } + $teamCityOutput = \false; + if ($cliConfiguration->hasTeamCityPrinter() && $cliConfiguration->teamCityPrinter()) { + $teamCityOutput = \true; + } + if ($cliConfiguration->hasTestDoxPrinter() && $cliConfiguration->testdoxPrinter()) { + $testDoxOutput = \true; + } else { + $testDoxOutput = $xmlConfiguration->phpunit()->testdoxPrinter(); + } + if ($cliConfiguration->hasTestDoxPrinterSummary() && $cliConfiguration->testdoxPrinterSummary()) { + $testDoxOutputSummary = \true; + } else { + $testDoxOutputSummary = $xmlConfiguration->phpunit()->testdoxPrinterSummary(); + } + $noProgress = \false; + if ($cliConfiguration->hasNoProgress() && $cliConfiguration->noProgress()) { + $noProgress = \true; + } + $noResults = \false; + if ($cliConfiguration->hasNoResults() && $cliConfiguration->noResults()) { + $noResults = \true; + } + $noOutput = \false; + if ($cliConfiguration->hasNoOutput() && $cliConfiguration->noOutput()) { + $noOutput = \true; + } + $testsCovering = null; + if ($cliConfiguration->hasTestsCovering()) { + $testsCovering = $cliConfiguration->testsCovering(); + } + $testsUsing = null; + if ($cliConfiguration->hasTestsUsing()) { + $testsUsing = $cliConfiguration->testsUsing(); + } + $testsRequiringPhpExtension = null; + if ($cliConfiguration->hasTestsRequiringPhpExtension()) { + $testsRequiringPhpExtension = $cliConfiguration->testsRequiringPhpExtension(); + } + $filter = null; + if ($cliConfiguration->hasFilter()) { + $filter = $cliConfiguration->filter(); + } + $excludeFilter = null; + if ($cliConfiguration->hasExcludeFilter()) { + $excludeFilter = $cliConfiguration->excludeFilter(); + } + $ignoreTestSelectionInXmlConfiguration = \false; + if ($cliConfiguration->hasAll()) { + $ignoreTestSelectionInXmlConfiguration = \true; + } + $groups = []; + if ($cliConfiguration->hasGroups()) { + $groups = $cliConfiguration->groups(); + } elseif (!$ignoreTestSelectionInXmlConfiguration) { + $groups = $xmlConfiguration->groups()->include()->asArrayOfStrings(); + } + $excludeGroups = []; + if ($cliConfiguration->hasExcludeGroups()) { + $excludeGroups = $cliConfiguration->excludeGroups(); + } elseif (!$ignoreTestSelectionInXmlConfiguration) { + $excludeGroups = $xmlConfiguration->groups()->exclude()->asArrayOfStrings(); + } + $excludeGroups = array_diff($excludeGroups, $groups); + if ($cliConfiguration->hasRandomOrderSeed()) { + $randomOrderSeed = $cliConfiguration->randomOrderSeed(); + } else { + $randomOrderSeed = time(); + } + if ($xmlConfiguration->wasLoadedFromFile() && $xmlConfiguration->hasValidationErrors()) { + if ((new SchemaDetector())->detect($xmlConfiguration->filename())->detected()) { + EventFacade::emitter()->testRunnerTriggeredPhpunitDeprecation('Your XML configuration validates against a deprecated schema. Migrate your XML configuration using "--migrate-configuration"!'); + } else { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning("Test results may not be as expected because the XML configuration file did not pass validation:\n" . $xmlConfiguration->validationErrors()); + } + } + $includeUncoveredFiles = $xmlConfiguration->codeCoverage()->includeUncoveredFiles(); + $includePaths = []; + if ($cliConfiguration->hasIncludePath()) { + foreach (explode(PATH_SEPARATOR, $cliConfiguration->includePath()) as $includePath) { + $includePaths[] = new \PHPUnit\TextUI\Configuration\Directory($includePath); + } + } + foreach ($xmlConfiguration->php()->includePaths() as $includePath) { + $includePaths[] = $includePath; + } + $iniSettings = []; + if ($cliConfiguration->hasIniSettings()) { + foreach ($cliConfiguration->iniSettings() as $name => $value) { + $iniSettings[] = new \PHPUnit\TextUI\Configuration\IniSetting($name, $value); + } + } + foreach ($xmlConfiguration->php()->iniSettings() as $iniSetting) { + $iniSettings[] = $iniSetting; + } + $includeTestSuite = ''; + if ($cliConfiguration->hasTestSuite()) { + $includeTestSuite = $cliConfiguration->testSuite(); + } elseif ($xmlConfiguration->phpunit()->hasDefaultTestSuite()) { + $includeTestSuite = $xmlConfiguration->phpunit()->defaultTestSuite(); + } + $excludeTestSuite = ''; + if ($cliConfiguration->hasExcludedTestSuite()) { + $excludeTestSuite = $cliConfiguration->excludedTestSuite(); + } + $testSuffixes = ['Test.php', '.phpt']; + if ($cliConfiguration->hasTestSuffixes()) { + $testSuffixes = $cliConfiguration->testSuffixes(); + } + $sourceIncludeDirectories = []; + if ($cliConfiguration->hasCoverageFilter()) { + foreach ($cliConfiguration->coverageFilter() as $directory) { + $sourceIncludeDirectories[] = new \PHPUnit\TextUI\Configuration\FilterDirectory($directory, '', '.php'); + } + } + foreach ($xmlConfiguration->source()->includeDirectories() as $directory) { + $sourceIncludeDirectories[] = $directory; + } + $sourceIncludeFiles = $xmlConfiguration->source()->includeFiles(); + $sourceExcludeDirectories = $xmlConfiguration->source()->excludeDirectories(); + $sourceExcludeFiles = $xmlConfiguration->source()->excludeFiles(); + $useBaseline = null; + $generateBaseline = null; + if (!$cliConfiguration->hasGenerateBaseline()) { + if ($cliConfiguration->hasUseBaseline()) { + $useBaseline = $cliConfiguration->useBaseline(); + } elseif ($xmlConfiguration->source()->hasBaseline()) { + $useBaseline = $xmlConfiguration->source()->baseline(); + } + } else { + $generateBaseline = $cliConfiguration->generateBaseline(); + } + assert($useBaseline !== ''); + assert($generateBaseline !== ''); + if ($failOnAllIssues) { + $displayDetailsOnAllIssues = \true; + } + if ($failOnDeprecation && !$doNotFailOnDeprecation) { + $displayDetailsOnTestsThatTriggerDeprecations = \true; + } + if ($failOnPhpunitDeprecation && !$doNotFailOnPhpunitDeprecation) { + $displayDetailsOnPhpunitDeprecations = \true; + } + if ($failOnPhpunitNotice && !$doNotFailOnPhpunitNotice) { + $displayDetailsOnPhpunitNotices = \true; + } + if ($failOnNotice && !$doNotFailOnNotice) { + $displayDetailsOnTestsThatTriggerNotices = \true; + } + if ($failOnWarning && !$doNotFailOnWarning) { + $displayDetailsOnTestsThatTriggerWarnings = \true; + } + if ($failOnIncomplete && !$doNotFailOnIncomplete) { + $displayDetailsOnIncompleteTests = \true; + } + if ($failOnSkipped && !$doNotFailOnSkipped) { + $displayDetailsOnSkippedTests = \true; + } + $issueTriggerIdentificationNeeded = $xmlConfiguration->source()->ignoreSelfDeprecations() || $xmlConfiguration->source()->ignoreDirectDeprecations() || $xmlConfiguration->source()->ignoreIndirectDeprecations(); + if ($issueTriggerIdentificationNeeded && !$xmlConfiguration->source()->identifyIssueTrigger()) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning('The identification of issue triggers is disabled. However, ignoring self-deprecations, direct deprecations, or indirect deprecations is requested.'); + } + return new \PHPUnit\TextUI\Configuration\Configuration($cliConfiguration->arguments(), $testFilesFile, $configurationFile, $bootstrap, $xmlConfiguration->phpunit()->bootstrapForTestSuite(), $cacheResult, $cacheDirectory, $coverageCacheDirectory, new \PHPUnit\TextUI\Configuration\Source($useBaseline, $cliConfiguration->ignoreBaseline(), \PHPUnit\TextUI\Configuration\FilterDirectoryCollection::fromArray($sourceIncludeDirectories), $sourceIncludeFiles, $sourceExcludeDirectories, $sourceExcludeFiles, $xmlConfiguration->source()->restrictNotices(), $xmlConfiguration->source()->restrictWarnings(), $xmlConfiguration->source()->ignoreSuppressionOfDeprecations(), $xmlConfiguration->source()->ignoreSuppressionOfPhpDeprecations(), $xmlConfiguration->source()->ignoreSuppressionOfErrors(), $xmlConfiguration->source()->ignoreSuppressionOfNotices(), $xmlConfiguration->source()->ignoreSuppressionOfPhpNotices(), $xmlConfiguration->source()->ignoreSuppressionOfWarnings(), $xmlConfiguration->source()->ignoreSuppressionOfPhpWarnings(), $xmlConfiguration->source()->deprecationTriggers(), $xmlConfiguration->source()->ignoreSelfDeprecations(), $xmlConfiguration->source()->ignoreDirectDeprecations(), $xmlConfiguration->source()->ignoreIndirectDeprecations(), $xmlConfiguration->source()->identifyIssueTrigger(), $xmlConfiguration->source()->issueTriggerResolvers()), $testResultCacheFile, $coverageClover, $coverageCobertura, $coverageCrap4j, $coverageCrap4jThreshold, $coverageHtml, $coverageHtmlLowUpperBound, $coverageHtmlHighLowerBound, $coverageHtmlColorSuccessLow, $coverageHtmlColorSuccessLowDark, $coverageHtmlColorSuccessMedium, $coverageHtmlColorSuccessMediumDark, $coverageHtmlColorSuccessHigh, $coverageHtmlColorSuccessHighDark, $coverageHtmlColorSuccessBar, $coverageHtmlColorSuccessBarDark, $coverageHtmlColorWarning, $coverageHtmlColorWarningDark, $coverageHtmlColorWarningBar, $coverageHtmlColorWarningBarDark, $coverageHtmlColorDanger, $coverageHtmlColorDangerDark, $coverageHtmlColorDangerBar, $coverageHtmlColorDangerBarDark, $coverageHtmlColorBreadcrumbs, $coverageHtmlColorBreadcrumbsDark, $coverageHtmlCustomCssFile, $coverageOpenClover, $coveragePhp, $coverageText, $coverageTextShowUncoveredFiles, $coverageTextShowOnlySummary, $coverageXml, $coverageXmlIncludeSource, $pathCoverage, $xmlConfiguration->codeCoverage()->ignoreDeprecatedCodeUnits(), $disableCodeCoverageIgnore, $failOnAllIssues, $failOnDeprecation, $failOnPhpunitDeprecation, $failOnPhpunitNotice, $failOnPhpunitWarning, $failOnEmptyTestSuite, $failOnIncomplete, $failOnNotice, $failOnRisky, $failOnSkipped, $failOnWarning, $doNotFailOnDeprecation, $doNotFailOnPhpunitDeprecation, $doNotFailOnPhpunitNotice, $doNotFailOnPhpunitWarning, $doNotFailOnEmptyTestSuite, $doNotFailOnIncomplete, $doNotFailOnNotice, $doNotFailOnRisky, $doNotFailOnSkipped, $doNotFailOnWarning, $stopOnDefect, $stopOnDeprecation, $specificDeprecationToStopOn, $stopOnError, $stopOnFailure, $stopOnIncomplete, $stopOnNotice, $stopOnRisky, $stopOnSkipped, $stopOnWarning, $outputToStandardErrorStream, $columns, $noExtensions, $pharExtensionDirectory, array_values($extensionBootstrappers), $backupGlobals, $backupStaticProperties, $beStrictAboutChangesToGlobalState, $colors, $processIsolation, $enforceTimeLimit, $defaultTimeLimit, $timeoutForSmallTests, $timeoutForMediumTests, $timeoutForLargeTests, $reportUselessTests, $strictCoverage, $disallowTestOutput, $displayDetailsOnAllIssues, $displayDetailsOnIncompleteTests, $displayDetailsOnSkippedTests, $displayDetailsOnTestsThatTriggerDeprecations, $displayDetailsOnPhpunitDeprecations, $displayDetailsOnPhpunitNotices, $displayDetailsOnTestsThatTriggerErrors, $displayDetailsOnTestsThatTriggerNotices, $displayDetailsOnTestsThatTriggerWarnings, $reverseDefectList, $requireCoverageMetadata, $requireSealedMockObjects, $noProgress, $noResults, $noOutput, $executionOrder, $executionOrderDefects, $resolveDependencies, $logfileTeamcity, $logfileJunit, $logfileOtr, $includeGitInformation, $includeGitInformationInOtrLogfile, $logfileTestdoxHtml, $logfileTestdoxText, $logEventsText, $logEventsVerboseText, $teamCityOutput, $testDoxOutput, $testDoxOutputSummary, $testsCovering, $testsUsing, $testsRequiringPhpExtension, $filter, $excludeFilter, $groups, $excludeGroups, $randomOrderSeed, $includeUncoveredFiles, $xmlConfiguration->testSuite(), $includeTestSuite, $excludeTestSuite, $xmlConfiguration->phpunit()->hasDefaultTestSuite() ? $xmlConfiguration->phpunit()->defaultTestSuite() : null, $ignoreTestSelectionInXmlConfiguration, $testSuffixes, new \PHPUnit\TextUI\Configuration\Php(\PHPUnit\TextUI\Configuration\DirectoryCollection::fromArray($includePaths), \PHPUnit\TextUI\Configuration\IniSettingCollection::fromArray($iniSettings), $xmlConfiguration->php()->constants(), $xmlConfiguration->php()->globalVariables(), $xmlConfiguration->php()->envVariables(), $xmlConfiguration->php()->postVariables(), $xmlConfiguration->php()->getVariables(), $xmlConfiguration->php()->cookieVariables(), $xmlConfiguration->php()->serverVariables(), $xmlConfiguration->php()->filesVariables(), $xmlConfiguration->php()->requestVariables()), $xmlConfiguration->phpunit()->controlGarbageCollector(), $xmlConfiguration->phpunit()->numberOfTestsBeforeGarbageCollection(), $generateBaseline, $cliConfiguration->debug(), $cliConfiguration->withTelemetry(), $xmlConfiguration->phpunit()->shortenArraysForExportThreshold()); + } + private function hasExplicitTestSelection(CliConfiguration $cliConfiguration): bool + { + if ($cliConfiguration->hasFilter()) { + return \true; + } + if ($cliConfiguration->hasExcludeFilter()) { + return \true; + } + if ($cliConfiguration->hasGroups()) { + return \true; + } + if ($cliConfiguration->hasExcludeGroups()) { + return \true; + } + if ($cliConfiguration->hasTestSuite()) { + return \true; + } + if ($cliConfiguration->hasExcludedTestSuite()) { + return \true; + } + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const PATH_SEPARATOR; +use function constant; +use function define; +use function defined; +use function getenv; +use function implode; +use function ini_get; +use function ini_set; +use function putenv; +use function restore_error_handler; +use function set_error_handler; +use function sprintf; +use PHPUnit\Event\Facade as EventFacade; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpHandler +{ + public function handle(\PHPUnit\TextUI\Configuration\Php $configuration): void + { + $this->handleIncludePaths($configuration->includePaths()); + $this->handleIniSettings($configuration->iniSettings()); + $this->handleConstants($configuration->constants()); + $this->handleGlobalVariables($configuration->globalVariables()); + $this->handleServerVariables($configuration->serverVariables()); + $this->handleEnvVariables($configuration->envVariables()); + $this->handleVariables('_POST', $configuration->postVariables()); + $this->handleVariables('_GET', $configuration->getVariables()); + $this->handleVariables('_COOKIE', $configuration->cookieVariables()); + $this->handleVariables('_FILES', $configuration->filesVariables()); + $this->handleVariables('_REQUEST', $configuration->requestVariables()); + } + private function handleIncludePaths(\PHPUnit\TextUI\Configuration\DirectoryCollection $includePaths): void + { + if (!$includePaths->isEmpty()) { + $includePathsAsStrings = []; + foreach ($includePaths as $includePath) { + $includePathsAsStrings[] = $includePath->path(); + } + ini_set('include_path', implode(PATH_SEPARATOR, $includePathsAsStrings) . PATH_SEPARATOR . ini_get('include_path')); + } + } + private function handleIniSettings(\PHPUnit\TextUI\Configuration\IniSettingCollection $iniSettings): void + { + foreach ($iniSettings as $iniSetting) { + $value = $iniSetting->value(); + if (defined($value)) { + $value = (string) constant($value); + } + $error = ''; + set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) use (&$error): true { + $error = $errstr; + return \true; + }); + $success = ini_set($iniSetting->name(), $value); + restore_error_handler(); + if ($success === \false) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Failed to set "%s=%s": %s', $iniSetting->name(), $value, $error)); + } + } + } + private function handleConstants(\PHPUnit\TextUI\Configuration\ConstantCollection $constants): void + { + foreach ($constants as $constant) { + if (!defined($constant->name())) { + define($constant->name(), $constant->value()); + } + } + } + private function handleGlobalVariables(\PHPUnit\TextUI\Configuration\VariableCollection $variables): void + { + foreach ($variables as $variable) { + $GLOBALS[$variable->name()] = $variable->value(); + } + } + private function handleServerVariables(\PHPUnit\TextUI\Configuration\VariableCollection $variables): void + { + foreach ($variables as $variable) { + $_SERVER[$variable->name()] = $variable->value(); + } + } + private function handleVariables(string $target, \PHPUnit\TextUI\Configuration\VariableCollection $variables): void + { + foreach ($variables as $variable) { + $GLOBALS[$target][$variable->name()] = $variable->value(); + } + } + private function handleEnvVariables(\PHPUnit\TextUI\Configuration\VariableCollection $variables): void + { + foreach ($variables as $variable) { + $name = $variable->name(); + $value = $variable->value(); + $force = $variable->force(); + if ($force || getenv($name) === \false) { + putenv("{$name}={$value}"); + } + $value = getenv($name); + if ($force || !isset($_ENV[$name])) { + $_ENV[$name] = $value; + } + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function assert; +use function file_get_contents; +use function file_put_contents; +use function serialize; +use function unserialize; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; +use PHPUnit\TextUI\CliArguments\Exception; +use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; +use PHPUnit\Util\VersionComparisonOperator; +/** + * CLI options and XML configuration are static within a single PHPUnit process. + * It is therefore okay to use a Singleton registry here. + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Registry +{ + private static ?\PHPUnit\TextUI\Configuration\Configuration $instance = null; + public static function saveTo(string $path): bool + { + $result = file_put_contents($path, serialize(self::get())); + if ($result) { + return \true; + } + // @codeCoverageIgnoreStart + return \false; + // @codeCoverageIgnoreEnd + } + /** + * This method is used by the "run test(s) in separate process" templates. + * + * @noinspection PhpUnused + * + * @codeCoverageIgnore + */ + public static function loadFrom(string $path): void + { + $buffer = file_get_contents($path); + assert($buffer !== \false); + self::$instance = unserialize($buffer, ['allowed_classes' => [\PHPUnit\TextUI\Configuration\Configuration::class, \PHPUnit\TextUI\Configuration\Php::class, \PHPUnit\TextUI\Configuration\ConstantCollection::class, \PHPUnit\TextUI\Configuration\Constant::class, \PHPUnit\TextUI\Configuration\IniSettingCollection::class, \PHPUnit\TextUI\Configuration\IniSetting::class, \PHPUnit\TextUI\Configuration\VariableCollection::class, \PHPUnit\TextUI\Configuration\Variable::class, \PHPUnit\TextUI\Configuration\DirectoryCollection::class, \PHPUnit\TextUI\Configuration\Directory::class, \PHPUnit\TextUI\Configuration\FileCollection::class, \PHPUnit\TextUI\Configuration\File::class, \PHPUnit\TextUI\Configuration\FilterDirectoryCollection::class, \PHPUnit\TextUI\Configuration\FilterDirectory::class, \PHPUnit\TextUI\Configuration\FilterFileCollection::class, \PHPUnit\TextUI\Configuration\FilterFile::class, \PHPUnit\TextUI\Configuration\TestDirectoryCollection::class, \PHPUnit\TextUI\Configuration\TestDirectory::class, \PHPUnit\TextUI\Configuration\TestFileCollection::class, \PHPUnit\TextUI\Configuration\TestFile::class, \PHPUnit\TextUI\Configuration\TestSuiteCollection::class, \PHPUnit\TextUI\Configuration\TestSuite::class, VersionComparisonOperator::class, \PHPUnit\TextUI\Configuration\Source::class]]); + } + public static function get(): \PHPUnit\TextUI\Configuration\Configuration + { + assert(self::$instance instanceof \PHPUnit\TextUI\Configuration\Configuration); + return self::$instance; + } + /** + * @throws \PHPUnit\TextUI\XmlConfiguration\Exception + * @throws Exception + * @throws NoCustomCssFileException + */ + public static function init(CliConfiguration $cliConfiguration, XmlConfiguration $xmlConfiguration): \PHPUnit\TextUI\Configuration\Configuration + { + self::$instance = (new \PHPUnit\TextUI\Configuration\Merger())->merge($cliConfiguration, $xmlConfiguration); + EventFacade::emitter()->testRunnerConfigured(self::$instance); + return self::$instance; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SourceFilter +{ + private static ?self $instance = null; + /** + * @var array + */ + private readonly array $map; + public static function instance(): self + { + if (self::$instance === null) { + self::$instance = new self((new \PHPUnit\TextUI\Configuration\SourceMapper())->map(\PHPUnit\TextUI\Configuration\Registry::get()->source())); + } + return self::$instance; + } + /** + * @param array $map + */ + public function __construct(array $map) + { + $this->map = $map; + } + /** + * @param non-empty-string $path + */ + public function includes(string $path): bool + { + return isset($this->map[$path]); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const DIRECTORY_SEPARATOR; +use function file_get_contents; +use function file_put_contents; +use function is_array; +use function preg_match; +use function realpath; +use function serialize; +use function str_replace; +use function unserialize; +use PHPUnitPHAR\SebastianBergmann\FileIterator\Facade as FileIteratorFacade; +use SplObjectStorage; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SourceMapper +{ + /** + * @var ?SplObjectStorage> + */ + private static ?SplObjectStorage $files = null; + public static function saveTo(string $path, \PHPUnit\TextUI\Configuration\Source $source): bool + { + $map = (new self())->map($source); + return file_put_contents($path, serialize($map)) !== \false; + } + /** + * @codeCoverageIgnore + */ + public static function loadFrom(string $path, \PHPUnit\TextUI\Configuration\Source $source): void + { + $content = file_get_contents($path); + if ($content === \false) { + return; + } + $map = unserialize($content, ['allowed_classes' => \false]); + if (!is_array($map)) { + return; + } + if (self::$files === null) { + self::$files = new SplObjectStorage(); + } + /** @phpstan-ignore offsetAssign.valueType */ + self::$files[$source] = $map; + } + /** + * @return array + */ + public function map(\PHPUnit\TextUI\Configuration\Source $source): array + { + if (self::$files === null) { + self::$files = new SplObjectStorage(); + } + if (isset(self::$files[$source])) { + return self::$files[$source]; + } + $files = []; + $directories = $this->aggregateDirectories($source->includeDirectories()); + foreach ($directories as $path => [$prefixes, $suffixes]) { + $basePath = realpath($path); + foreach ((new FileIteratorFacade())->getFilesAsArray($path, $suffixes, $prefixes) as $file) { + $file = realpath($file); + if (!$file) { + continue; + } + if ($this->isInHiddenDirectory($file, $basePath)) { + continue; + } + $files[$file] = \true; + } + } + foreach ($source->includeFiles() as $file) { + $file = realpath($file->path()); + if (!$file) { + continue; + } + $files[$file] = \true; + } + $directories = $this->aggregateDirectories($source->excludeDirectories()); + foreach ($directories as $path => [$prefixes, $suffixes]) { + foreach ((new FileIteratorFacade())->getFilesAsArray($path, $suffixes, $prefixes) as $file) { + $file = realpath($file); + if (!$file) { + continue; + } + if (!isset($files[$file])) { + continue; + } + unset($files[$file]); + } + } + foreach ($source->excludeFiles() as $file) { + $file = realpath($file->path()); + if (!$file) { + continue; + } + if (!isset($files[$file])) { + continue; + } + unset($files[$file]); + } + self::$files[$source] = $files; + return $files; + } + /** + * @return array + */ + public function mapForCodeCoverage(\PHPUnit\TextUI\Configuration\Source $source): array + { + $files = $this->map($source); + foreach ($source->includeDirectories() as $directory) { + if ($directory->includeInCodeCoverage()) { + continue; + } + foreach ((new FileIteratorFacade())->getFilesAsArray($directory->path(), $directory->suffix(), $directory->prefix()) as $file) { + $file = realpath($file); + if (!$file) { + continue; + } + unset($files[$file]); + } + } + foreach ($source->includeFiles() as $file) { + if ($file->includeInCodeCoverage()) { + continue; + } + $path = realpath($file->path()); + if (!$path) { + continue; + } + unset($files[$path]); + } + return $files; + } + private function isInHiddenDirectory(string $path, false|string $basePath): bool + { + $relativePath = str_replace((string) $basePath, '', $path); + $separator = DIRECTORY_SEPARATOR === '\\' ? '\\\\' : '/'; + return preg_match('=' . $separator . '\.[^' . $separator . ']*' . $separator . '=', $relativePath) === 1; + } + /** + * @return array,list}> + */ + private function aggregateDirectories(\PHPUnit\TextUI\Configuration\FilterDirectoryCollection $directories): array + { + $aggregated = []; + foreach ($directories as $directory) { + if (!isset($aggregated[$directory->path()])) { + $aggregated[$directory->path()] = [0 => [], 1 => []]; + } + $prefix = $directory->prefix(); + if ($prefix !== '') { + $aggregated[$directory->path()][0][] = $prefix; + } + $suffix = $directory->suffix(); + if ($suffix !== '') { + $aggregated[$directory->path()][1][] = $suffix; + } + } + return $aggregated; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const DIRECTORY_SEPARATOR; +use const PHP_EOL; +use function assert; +use function count; +use function dirname; +use function file; +use function is_dir; +use function is_file; +use function realpath; +use function str_ends_with; +use function trim; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Exception; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\TestSuiteLoader; +use PHPUnit\TextUI\RuntimeException; +use PHPUnit\TextUI\TestDirectoryNotFoundException; +use PHPUnit\TextUI\TestFileNotFoundException; +use PHPUnit\TextUI\XmlConfiguration\TestSuiteMapper; +use PHPUnitPHAR\SebastianBergmann\FileIterator\Facade as FileIteratorFacade; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteBuilder +{ + /** + * @throws \PHPUnit\Framework\Exception + * @throws RuntimeException + * @throws TestDirectoryNotFoundException + * @throws TestFileNotFoundException + */ + public function build(\PHPUnit\TextUI\Configuration\Configuration $configuration): TestSuite + { + if ($configuration->hasCliArguments() || $configuration->hasTestFilesFile()) { + $arguments = []; + if ($configuration->hasCliArguments()) { + foreach ($configuration->cliArguments() as $cliArgument) { + $argument = realpath($cliArgument); + if (!$argument) { + throw new TestFileNotFoundException($cliArgument); + } + $arguments[] = $argument; + } + } + if ($configuration->hasTestFilesFile()) { + if (!is_file($configuration->testFilesFile())) { + throw new RuntimeException('Cannot read from ' . $configuration->testFilesFile()); + } + $directory = dirname($configuration->testFilesFile()) . DIRECTORY_SEPARATOR; + foreach (file($configuration->testFilesFile()) as $file) { + $file = trim($file); + $argument = realpath($file); + if (!$argument) { + $argument = realpath($directory . $file); + } + if (!$argument) { + throw new TestFileNotFoundException($file); + } + $arguments[] = $argument; + } + } + if (count($arguments) === 1) { + $testSuite = $this->testSuiteFromPath($arguments[0], $configuration->testSuffixes()); + } else { + $testSuite = $this->testSuiteFromPathList($arguments, $configuration->testSuffixes()); + } + } + if (!isset($testSuite)) { + $xmlConfigurationFile = $configuration->hasConfigurationFile() ? $configuration->configurationFile() : 'Root Test Suite'; + assert($xmlConfigurationFile !== ''); + $testSuite = (new TestSuiteMapper())->map($xmlConfigurationFile, $configuration->testSuite(), $configuration->ignoreTestSelectionInXmlConfiguration() ? [] : $configuration->includeTestSuites(), $configuration->ignoreTestSelectionInXmlConfiguration() ? [] : $configuration->excludeTestSuites()); + } + EventFacade::emitter()->testSuiteLoaded(\PHPUnit\Event\TestSuite\TestSuiteBuilder::from($testSuite)); + return $testSuite; + } + /** + * @param non-empty-string $path + * @param list $suffixes + * + * @throws \PHPUnit\Framework\Exception + */ + private function testSuiteFromPath(string $path, array $suffixes, ?TestSuite $suite = null): TestSuite + { + if (str_ends_with($path, '.phpt') && is_file($path)) { + if ($suite === null) { + $suite = TestSuite::empty($path); + } + $suite->addTestFile($path); + return $suite; + } + if (is_dir($path)) { + $files = (new FileIteratorFacade())->getFilesAsArray($path, $suffixes); + if ($suite === null) { + $suite = TestSuite::empty('CLI Arguments'); + } + $suite->addTestFiles($files); + return $suite; + } + try { + $testClass = (new TestSuiteLoader())->load($path); + } catch (Exception $e) { + print $e->getMessage() . PHP_EOL; + exit(1); + } + if ($suite === null) { + return TestSuite::fromClassReflector($testClass); + } + $suite->addTestSuite($testClass); + return $suite; + } + /** + * @param list $paths + * @param list $suffixes + * + * @throws \PHPUnit\Framework\Exception + */ + private function testSuiteFromPathList(array $paths, array $suffixes): TestSuite + { + $suite = TestSuite::empty('CLI Arguments'); + foreach ($paths as $path) { + $this->testSuiteFromPath($path, $suffixes, $suite); + } + return $suite; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Constant +{ + private string $name; + private bool|string $value; + public function __construct(string $name, bool|string $value) + { + $this->name = $name; + $this->value = $value; + } + public function name(): string + { + return $this->name; + } + public function value(): bool|string + { + return $this->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class ConstantCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $constants; + /** + * @param list $constants + */ + public static function fromArray(array $constants): self + { + return new self(...$constants); + } + private function __construct(\PHPUnit\TextUI\Configuration\Constant ...$constants) + { + $this->constants = $constants; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->constants; + } + public function count(): int + { + return count($this->constants); + } + public function getIterator(): \PHPUnit\TextUI\Configuration\ConstantCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\ConstantCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class ConstantCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $constants; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\ConstantCollection $constants) + { + $this->constants = $constants->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->constants[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\Constant + { + return $this->constants[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Directory +{ + private string $path; + public function __construct(string $path) + { + $this->path = $path; + } + public function path(): string + { + return $this->path; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class DirectoryCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $directories; + /** + * @param list $directories + */ + public static function fromArray(array $directories): self + { + return new self(...$directories); + } + private function __construct(\PHPUnit\TextUI\Configuration\Directory ...$directories) + { + $this->directories = $directories; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->directories; + } + public function count(): int + { + return count($this->directories); + } + public function getIterator(): \PHPUnit\TextUI\Configuration\DirectoryCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\DirectoryCollectionIterator($this); + } + public function isEmpty(): bool + { + return $this->count() === 0; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class DirectoryCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $directories; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\DirectoryCollection $directories) + { + $this->directories = $directories->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->directories[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\Directory + { + return $this->directories[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class ExtensionBootstrap +{ + /** + * @var non-empty-string + */ + private string $className; + /** + * @var array + */ + private array $parameters; + /** + * @param non-empty-string $className + * @param array $parameters + */ + public function __construct(string $className, array $parameters) + { + $this->className = $className; + $this->parameters = $parameters; + } + /** + * @return non-empty-string + */ + public function className(): string + { + return $this->className; + } + /** + * @return array + */ + public function parameters(): array + { + return $this->parameters; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use IteratorAggregate; +/** + * @template-implements IteratorAggregate + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class ExtensionBootstrapCollection implements IteratorAggregate +{ + /** + * @var list + */ + private array $extensionBootstraps; + /** + * @param list $extensionBootstraps + */ + public static function fromArray(array $extensionBootstraps): self + { + return new self(...$extensionBootstraps); + } + private function __construct(\PHPUnit\TextUI\Configuration\ExtensionBootstrap ...$extensionBootstraps) + { + $this->extensionBootstraps = $extensionBootstraps; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->extensionBootstraps; + } + public function getIterator(): \PHPUnit\TextUI\Configuration\ExtensionBootstrapCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\ExtensionBootstrapCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class ExtensionBootstrapCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $extensionBootstraps; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection $extensionBootstraps) + { + $this->extensionBootstraps = $extensionBootstraps->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->extensionBootstraps[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\ExtensionBootstrap + { + return $this->extensionBootstraps[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class File +{ + /** + * @var non-empty-string + */ + private string $path; + /** + * @param non-empty-string $path + */ + public function __construct(string $path) + { + $this->path = $path; + } + /** + * @return non-empty-string + */ + public function path(): string + { + return $this->path; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class FileCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $files; + /** + * @param list $files + */ + public static function fromArray(array $files): self + { + return new self(...$files); + } + private function __construct(\PHPUnit\TextUI\Configuration\File ...$files) + { + $this->files = $files; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->files; + } + public function count(): int + { + return count($this->files); + } + public function notEmpty(): bool + { + return $this->files !== []; + } + public function getIterator(): \PHPUnit\TextUI\Configuration\FileCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\FileCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class FileCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $files; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\FileCollection $files) + { + $this->files = $files->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->files[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\File + { + return $this->files[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class FilterDirectory +{ + /** + * @var non-empty-string + */ + private string $path; + private string $prefix; + private string $suffix; + private bool $includeInCodeCoverage; + /** + * @param non-empty-string $path + */ + public function __construct(string $path, string $prefix, string $suffix, bool $includeInCodeCoverage = \true) + { + $this->path = $path; + $this->prefix = $prefix; + $this->suffix = $suffix; + $this->includeInCodeCoverage = $includeInCodeCoverage; + } + /** + * @return non-empty-string + */ + public function path(): string + { + return $this->path; + } + public function prefix(): string + { + return $this->prefix; + } + public function suffix(): string + { + return $this->suffix; + } + public function includeInCodeCoverage(): bool + { + return $this->includeInCodeCoverage; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class FilterDirectoryCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $directories; + /** + * @param list $directories + */ + public static function fromArray(array $directories): self + { + return new self(...$directories); + } + private function __construct(\PHPUnit\TextUI\Configuration\FilterDirectory ...$directories) + { + $this->directories = $directories; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->directories; + } + public function count(): int + { + return count($this->directories); + } + public function notEmpty(): bool + { + return $this->directories !== []; + } + public function getIterator(): \PHPUnit\TextUI\Configuration\FilterDirectoryCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\FilterDirectoryCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class FilterDirectoryCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $directories; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\FilterDirectoryCollection $directories) + { + $this->directories = $directories->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->directories[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\FilterDirectory + { + return $this->directories[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class FilterFile +{ + /** + * @var non-empty-string + */ + private string $path; + private bool $includeInCodeCoverage; + /** + * @param non-empty-string $path + */ + public function __construct(string $path, bool $includeInCodeCoverage = \true) + { + $this->path = $path; + $this->includeInCodeCoverage = $includeInCodeCoverage; + } + /** + * @return non-empty-string + */ + public function path(): string + { + return $this->path; + } + public function includeInCodeCoverage(): bool + { + return $this->includeInCodeCoverage; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class FilterFileCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $files; + /** + * @param list $files + */ + public static function fromArray(array $files): self + { + return new self(...$files); + } + private function __construct(\PHPUnit\TextUI\Configuration\FilterFile ...$files) + { + $this->files = $files; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->files; + } + public function count(): int + { + return count($this->files); + } + public function notEmpty(): bool + { + return $this->files !== []; + } + public function getIterator(): \PHPUnit\TextUI\Configuration\FilterFileCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\FilterFileCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class FilterFileCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $files; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\FilterFileCollection $files) + { + $this->files = $files->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->files[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\FilterFile + { + return $this->files[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Group +{ + private string $name; + public function __construct(string $name) + { + $this->name = $name; + } + public function name(): string + { + return $this->name; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class GroupCollection implements IteratorAggregate +{ + /** + * @var list + */ + private array $groups; + /** + * @param list $groups + */ + public static function fromArray(array $groups): self + { + return new self(...$groups); + } + private function __construct(\PHPUnit\TextUI\Configuration\Group ...$groups) + { + $this->groups = $groups; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->groups; + } + /** + * @return list + */ + public function asArrayOfStrings(): array + { + $result = []; + foreach ($this->groups as $group) { + $result[] = $group->name(); + } + return $result; + } + public function isEmpty(): bool + { + return $this->groups === []; + } + public function getIterator(): \PHPUnit\TextUI\Configuration\GroupCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\GroupCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class GroupCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $groups; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\GroupCollection $groups) + { + $this->groups = $groups->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->groups[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\Group + { + return $this->groups[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class IniSetting +{ + private string $name; + private string $value; + public function __construct(string $name, string $value) + { + $this->name = $name; + $this->value = $value; + } + public function name(): string + { + return $this->name; + } + public function value(): string + { + return $this->value; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class IniSettingCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $iniSettings; + /** + * @param list $iniSettings + */ + public static function fromArray(array $iniSettings): self + { + return new self(...$iniSettings); + } + private function __construct(\PHPUnit\TextUI\Configuration\IniSetting ...$iniSettings) + { + $this->iniSettings = $iniSettings; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->iniSettings; + } + public function count(): int + { + return count($this->iniSettings); + } + public function getIterator(): \PHPUnit\TextUI\Configuration\IniSettingCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\IniSettingCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class IniSettingCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $iniSettings; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\IniSettingCollection $iniSettings) + { + $this->iniSettings = $iniSettings->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->iniSettings[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\IniSetting + { + return $this->iniSettings[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Php +{ + private \PHPUnit\TextUI\Configuration\DirectoryCollection $includePaths; + private \PHPUnit\TextUI\Configuration\IniSettingCollection $iniSettings; + private \PHPUnit\TextUI\Configuration\ConstantCollection $constants; + private \PHPUnit\TextUI\Configuration\VariableCollection $globalVariables; + private \PHPUnit\TextUI\Configuration\VariableCollection $envVariables; + private \PHPUnit\TextUI\Configuration\VariableCollection $postVariables; + private \PHPUnit\TextUI\Configuration\VariableCollection $getVariables; + private \PHPUnit\TextUI\Configuration\VariableCollection $cookieVariables; + private \PHPUnit\TextUI\Configuration\VariableCollection $serverVariables; + private \PHPUnit\TextUI\Configuration\VariableCollection $filesVariables; + private \PHPUnit\TextUI\Configuration\VariableCollection $requestVariables; + public function __construct(\PHPUnit\TextUI\Configuration\DirectoryCollection $includePaths, \PHPUnit\TextUI\Configuration\IniSettingCollection $iniSettings, \PHPUnit\TextUI\Configuration\ConstantCollection $constants, \PHPUnit\TextUI\Configuration\VariableCollection $globalVariables, \PHPUnit\TextUI\Configuration\VariableCollection $envVariables, \PHPUnit\TextUI\Configuration\VariableCollection $postVariables, \PHPUnit\TextUI\Configuration\VariableCollection $getVariables, \PHPUnit\TextUI\Configuration\VariableCollection $cookieVariables, \PHPUnit\TextUI\Configuration\VariableCollection $serverVariables, \PHPUnit\TextUI\Configuration\VariableCollection $filesVariables, \PHPUnit\TextUI\Configuration\VariableCollection $requestVariables) + { + $this->includePaths = $includePaths; + $this->iniSettings = $iniSettings; + $this->constants = $constants; + $this->globalVariables = $globalVariables; + $this->envVariables = $envVariables; + $this->postVariables = $postVariables; + $this->getVariables = $getVariables; + $this->cookieVariables = $cookieVariables; + $this->serverVariables = $serverVariables; + $this->filesVariables = $filesVariables; + $this->requestVariables = $requestVariables; + } + public function includePaths(): \PHPUnit\TextUI\Configuration\DirectoryCollection + { + return $this->includePaths; + } + public function iniSettings(): \PHPUnit\TextUI\Configuration\IniSettingCollection + { + return $this->iniSettings; + } + public function constants(): \PHPUnit\TextUI\Configuration\ConstantCollection + { + return $this->constants; + } + public function globalVariables(): \PHPUnit\TextUI\Configuration\VariableCollection + { + return $this->globalVariables; + } + public function envVariables(): \PHPUnit\TextUI\Configuration\VariableCollection + { + return $this->envVariables; + } + public function postVariables(): \PHPUnit\TextUI\Configuration\VariableCollection + { + return $this->postVariables; + } + public function getVariables(): \PHPUnit\TextUI\Configuration\VariableCollection + { + return $this->getVariables; + } + public function cookieVariables(): \PHPUnit\TextUI\Configuration\VariableCollection + { + return $this->cookieVariables; + } + public function serverVariables(): \PHPUnit\TextUI\Configuration\VariableCollection + { + return $this->serverVariables; + } + public function filesVariables(): \PHPUnit\TextUI\Configuration\VariableCollection + { + return $this->filesVariables; + } + public function requestVariables(): \PHPUnit\TextUI\Configuration\VariableCollection + { + return $this->requestVariables; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Source +{ + /** + * @var non-empty-string + */ + private ?string $baseline; + private bool $ignoreBaseline; + private \PHPUnit\TextUI\Configuration\FilterDirectoryCollection $includeDirectories; + private \PHPUnit\TextUI\Configuration\FilterFileCollection $includeFiles; + private \PHPUnit\TextUI\Configuration\FilterDirectoryCollection $excludeDirectories; + private \PHPUnit\TextUI\Configuration\FilterFileCollection $excludeFiles; + private bool $restrictNotices; + private bool $restrictWarnings; + private bool $ignoreSuppressionOfDeprecations; + private bool $ignoreSuppressionOfPhpDeprecations; + private bool $ignoreSuppressionOfErrors; + private bool $ignoreSuppressionOfNotices; + private bool $ignoreSuppressionOfPhpNotices; + private bool $ignoreSuppressionOfWarnings; + private bool $ignoreSuppressionOfPhpWarnings; + private bool $ignoreSelfDeprecations; + private bool $ignoreDirectDeprecations; + private bool $ignoreIndirectDeprecations; + private bool $identifyIssueTrigger; + /** + * @var array{functions: list, methods: list, ignoreUndefinedTriggers: bool} + */ + private array $deprecationTriggers; + /** + * @var list + */ + private array $issueTriggerResolvers; + /** + * @param ?non-empty-string $baseline + * @param array{functions: list, methods: list, ignoreUndefinedTriggers: bool} $deprecationTriggers + * @param list $issueTriggerResolvers + */ + public function __construct(?string $baseline, bool $ignoreBaseline, \PHPUnit\TextUI\Configuration\FilterDirectoryCollection $includeDirectories, \PHPUnit\TextUI\Configuration\FilterFileCollection $includeFiles, \PHPUnit\TextUI\Configuration\FilterDirectoryCollection $excludeDirectories, \PHPUnit\TextUI\Configuration\FilterFileCollection $excludeFiles, bool $restrictNotices, bool $restrictWarnings, bool $ignoreSuppressionOfDeprecations, bool $ignoreSuppressionOfPhpDeprecations, bool $ignoreSuppressionOfErrors, bool $ignoreSuppressionOfNotices, bool $ignoreSuppressionOfPhpNotices, bool $ignoreSuppressionOfWarnings, bool $ignoreSuppressionOfPhpWarnings, array $deprecationTriggers, bool $ignoreSelfDeprecations, bool $ignoreDirectDeprecations, bool $ignoreIndirectDeprecations, bool $identifyIssueTrigger, array $issueTriggerResolvers = []) + { + $this->baseline = $baseline; + $this->ignoreBaseline = $ignoreBaseline; + $this->includeDirectories = $includeDirectories; + $this->includeFiles = $includeFiles; + $this->excludeDirectories = $excludeDirectories; + $this->excludeFiles = $excludeFiles; + $this->restrictNotices = $restrictNotices; + $this->restrictWarnings = $restrictWarnings; + $this->ignoreSuppressionOfDeprecations = $ignoreSuppressionOfDeprecations; + $this->ignoreSuppressionOfPhpDeprecations = $ignoreSuppressionOfPhpDeprecations; + $this->ignoreSuppressionOfErrors = $ignoreSuppressionOfErrors; + $this->ignoreSuppressionOfNotices = $ignoreSuppressionOfNotices; + $this->ignoreSuppressionOfPhpNotices = $ignoreSuppressionOfPhpNotices; + $this->ignoreSuppressionOfWarnings = $ignoreSuppressionOfWarnings; + $this->ignoreSuppressionOfPhpWarnings = $ignoreSuppressionOfPhpWarnings; + $this->deprecationTriggers = $deprecationTriggers; + $this->ignoreSelfDeprecations = $ignoreSelfDeprecations; + $this->ignoreDirectDeprecations = $ignoreDirectDeprecations; + $this->ignoreIndirectDeprecations = $ignoreIndirectDeprecations; + $this->identifyIssueTrigger = $identifyIssueTrigger; + $this->issueTriggerResolvers = $issueTriggerResolvers; + } + /** + * @phpstan-assert-if-true !null $this->baseline + */ + public function useBaseline(): bool + { + return $this->hasBaseline() && !$this->ignoreBaseline; + } + /** + * @phpstan-assert-if-true !null $this->baseline + */ + public function hasBaseline(): bool + { + return $this->baseline !== null; + } + /** + * @throws NoBaselineException + * + * @return non-empty-string + */ + public function baseline(): string + { + if (!$this->hasBaseline()) { + throw new \PHPUnit\TextUI\Configuration\NoBaselineException(); + } + return $this->baseline; + } + public function includeDirectories(): \PHPUnit\TextUI\Configuration\FilterDirectoryCollection + { + return $this->includeDirectories; + } + public function includeFiles(): \PHPUnit\TextUI\Configuration\FilterFileCollection + { + return $this->includeFiles; + } + public function excludeDirectories(): \PHPUnit\TextUI\Configuration\FilterDirectoryCollection + { + return $this->excludeDirectories; + } + public function excludeFiles(): \PHPUnit\TextUI\Configuration\FilterFileCollection + { + return $this->excludeFiles; + } + public function notEmpty(): bool + { + return $this->includeDirectories->notEmpty() || $this->includeFiles->notEmpty(); + } + public function restrictNotices(): bool + { + return $this->restrictNotices; + } + public function restrictWarnings(): bool + { + return $this->restrictWarnings; + } + public function ignoreSuppressionOfDeprecations(): bool + { + return $this->ignoreSuppressionOfDeprecations; + } + public function ignoreSuppressionOfPhpDeprecations(): bool + { + return $this->ignoreSuppressionOfPhpDeprecations; + } + public function ignoreSuppressionOfErrors(): bool + { + return $this->ignoreSuppressionOfErrors; + } + public function ignoreSuppressionOfNotices(): bool + { + return $this->ignoreSuppressionOfNotices; + } + public function ignoreSuppressionOfPhpNotices(): bool + { + return $this->ignoreSuppressionOfPhpNotices; + } + public function ignoreSuppressionOfWarnings(): bool + { + return $this->ignoreSuppressionOfWarnings; + } + public function ignoreSuppressionOfPhpWarnings(): bool + { + return $this->ignoreSuppressionOfPhpWarnings; + } + /** + * @return array{functions: list, methods: list, ignoreUndefinedTriggers: bool} + */ + public function deprecationTriggers(): array + { + return $this->deprecationTriggers; + } + public function ignoreSelfDeprecations(): bool + { + return $this->ignoreSelfDeprecations; + } + public function ignoreDirectDeprecations(): bool + { + return $this->ignoreDirectDeprecations; + } + public function ignoreIndirectDeprecations(): bool + { + return $this->ignoreIndirectDeprecations; + } + public function identifyIssueTrigger(): bool + { + return $this->identifyIssueTrigger; + } + /** + * @return list + */ + public function issueTriggerResolvers(): array + { + return $this->issueTriggerResolvers; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Util\VersionComparisonOperator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class TestDirectory +{ + /** + * @var non-empty-string + */ + private string $path; + private string $prefix; + private string $suffix; + private string $phpVersion; + private VersionComparisonOperator $phpVersionOperator; + /** + * @var list + */ + private array $groups; + /** + * @param non-empty-string $path + * @param list $groups + */ + public function __construct(string $path, string $prefix, string $suffix, string $phpVersion, VersionComparisonOperator $phpVersionOperator, array $groups) + { + $this->path = $path; + $this->prefix = $prefix; + $this->suffix = $suffix; + $this->phpVersion = $phpVersion; + $this->phpVersionOperator = $phpVersionOperator; + $this->groups = $groups; + } + /** + * @return non-empty-string + */ + public function path(): string + { + return $this->path; + } + public function prefix(): string + { + return $this->prefix; + } + public function suffix(): string + { + return $this->suffix; + } + public function phpVersion(): string + { + return $this->phpVersion; + } + public function phpVersionOperator(): VersionComparisonOperator + { + return $this->phpVersionOperator; + } + /** + * @return list + */ + public function groups(): array + { + return $this->groups; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class TestDirectoryCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $directories; + /** + * @param list $directories + */ + public static function fromArray(array $directories): self + { + return new self(...$directories); + } + private function __construct(\PHPUnit\TextUI\Configuration\TestDirectory ...$directories) + { + $this->directories = $directories; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->directories; + } + public function count(): int + { + return count($this->directories); + } + public function getIterator(): \PHPUnit\TextUI\Configuration\TestDirectoryCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\TestDirectoryCollectionIterator($this); + } + public function isEmpty(): bool + { + return $this->count() === 0; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class TestDirectoryCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $directories; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\TestDirectoryCollection $directories) + { + $this->directories = $directories->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->directories[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\TestDirectory + { + return $this->directories[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Util\VersionComparisonOperator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class TestFile +{ + /** + * @var non-empty-string + */ + private string $path; + private string $phpVersion; + private VersionComparisonOperator $phpVersionOperator; + /** + * @var list + */ + private array $groups; + /** + * @param non-empty-string $path + * @param list $groups + */ + public function __construct(string $path, string $phpVersion, VersionComparisonOperator $phpVersionOperator, array $groups) + { + $this->path = $path; + $this->phpVersion = $phpVersion; + $this->phpVersionOperator = $phpVersionOperator; + $this->groups = $groups; + } + /** + * @return non-empty-string + */ + public function path(): string + { + return $this->path; + } + public function phpVersion(): string + { + return $this->phpVersion; + } + public function phpVersionOperator(): VersionComparisonOperator + { + return $this->phpVersionOperator; + } + /** + * @return list + */ + public function groups(): array + { + return $this->groups; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class TestFileCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $files; + /** + * @param list $files + */ + public static function fromArray(array $files): self + { + return new self(...$files); + } + private function __construct(\PHPUnit\TextUI\Configuration\TestFile ...$files) + { + $this->files = $files; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->files; + } + public function count(): int + { + return count($this->files); + } + public function getIterator(): \PHPUnit\TextUI\Configuration\TestFileCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\TestFileCollectionIterator($this); + } + public function isEmpty(): bool + { + return $this->count() === 0; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class TestFileCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $files; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\TestFileCollection $files) + { + $this->files = $files->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->files[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\TestFile + { + return $this->files[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class TestSuite +{ + /** + * @var non-empty-string + */ + private string $name; + private \PHPUnit\TextUI\Configuration\TestDirectoryCollection $directories; + private \PHPUnit\TextUI\Configuration\TestFileCollection $files; + private \PHPUnit\TextUI\Configuration\FileCollection $exclude; + /** + * @param non-empty-string $name + */ + public function __construct(string $name, \PHPUnit\TextUI\Configuration\TestDirectoryCollection $directories, \PHPUnit\TextUI\Configuration\TestFileCollection $files, \PHPUnit\TextUI\Configuration\FileCollection $exclude) + { + $this->name = $name; + $this->directories = $directories; + $this->files = $files; + $this->exclude = $exclude; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + public function directories(): \PHPUnit\TextUI\Configuration\TestDirectoryCollection + { + return $this->directories; + } + public function files(): \PHPUnit\TextUI\Configuration\TestFileCollection + { + return $this->files; + } + public function exclude(): \PHPUnit\TextUI\Configuration\FileCollection + { + return $this->exclude; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class TestSuiteCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $testSuites; + /** + * @param list $testSuites + */ + public static function fromArray(array $testSuites): self + { + return new self(...$testSuites); + } + private function __construct(\PHPUnit\TextUI\Configuration\TestSuite ...$testSuites) + { + $this->testSuites = $testSuites; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->testSuites; + } + public function count(): int + { + return count($this->testSuites); + } + public function getIterator(): \PHPUnit\TextUI\Configuration\TestSuiteCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\TestSuiteCollectionIterator($this); + } + public function isEmpty(): bool + { + return $this->count() === 0; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class TestSuiteCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $testSuites; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\TestSuiteCollection $testSuites) + { + $this->testSuites = $testSuites->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->testSuites[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\TestSuite + { + return $this->testSuites[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Variable +{ + private string $name; + private mixed $value; + private bool $force; + public function __construct(string $name, mixed $value, bool $force) + { + $this->name = $name; + $this->value = $value; + $this->force = $force; + } + public function name(): string + { + return $this->name; + } + public function value(): mixed + { + return $this->value; + } + public function force(): bool + { + return $this->force; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class VariableCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $variables; + /** + * @param list $variables + */ + public static function fromArray(array $variables): self + { + return new self(...$variables); + } + private function __construct(\PHPUnit\TextUI\Configuration\Variable ...$variables) + { + $this->variables = $variables; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->variables; + } + public function count(): int + { + return count($this->variables); + } + public function getIterator(): \PHPUnit\TextUI\Configuration\VariableCollectionIterator + { + return new \PHPUnit\TextUI\Configuration\VariableCollectionIterator($this); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use Iterator; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class VariableCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $variables; + /** + * @var non-negative-int + */ + private int $position = 0; + public function __construct(\PHPUnit\TextUI\Configuration\VariableCollection $variables) + { + $this->variables = $variables->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->variables[$this->position]); + } + /** + * @return non-negative-int + */ + public function key(): int + { + return $this->position; + } + public function current(): \PHPUnit\TextUI\Configuration\Variable + { + return $this->variables[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage; + +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Clover; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Cobertura; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Crap4j; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Html; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\OpenClover; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Php; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Text; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Xml; +use PHPUnit\TextUI\XmlConfiguration\Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class CodeCoverage +{ + private bool $pathCoverage; + private bool $includeUncoveredFiles; + private bool $ignoreDeprecatedCodeUnits; + private bool $disableCodeCoverageIgnore; + private ?Clover $clover; + private ?Cobertura $cobertura; + private ?Crap4j $crap4j; + private ?Html $html; + private ?OpenClover $openClover; + private ?Php $php; + private ?Text $text; + private ?Xml $xml; + public function __construct(bool $pathCoverage, bool $includeUncoveredFiles, bool $ignoreDeprecatedCodeUnits, bool $disableCodeCoverageIgnore, ?Clover $clover, ?Cobertura $cobertura, ?Crap4j $crap4j, ?Html $html, ?OpenClover $openClover, ?Php $php, ?Text $text, ?Xml $xml) + { + $this->pathCoverage = $pathCoverage; + $this->includeUncoveredFiles = $includeUncoveredFiles; + $this->ignoreDeprecatedCodeUnits = $ignoreDeprecatedCodeUnits; + $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore; + $this->clover = $clover; + $this->cobertura = $cobertura; + $this->crap4j = $crap4j; + $this->html = $html; + $this->openClover = $openClover; + $this->php = $php; + $this->text = $text; + $this->xml = $xml; + } + public function pathCoverage(): bool + { + return $this->pathCoverage; + } + public function includeUncoveredFiles(): bool + { + return $this->includeUncoveredFiles; + } + public function ignoreDeprecatedCodeUnits(): bool + { + return $this->ignoreDeprecatedCodeUnits; + } + public function disableCodeCoverageIgnore(): bool + { + return $this->disableCodeCoverageIgnore; + } + /** + * @phpstan-assert-if-true !null $this->clover + */ + public function hasClover(): bool + { + return $this->clover !== null; + } + /** + * @throws Exception + */ + public function clover(): Clover + { + if (!$this->hasClover()) { + throw new Exception('Code Coverage report "Clover XML" has not been configured'); + } + return $this->clover; + } + /** + * @phpstan-assert-if-true !null $this->cobertura + */ + public function hasCobertura(): bool + { + return $this->cobertura !== null; + } + /** + * @throws Exception + */ + public function cobertura(): Cobertura + { + if (!$this->hasCobertura()) { + throw new Exception('Code Coverage report "Cobertura XML" has not been configured'); + } + return $this->cobertura; + } + /** + * @phpstan-assert-if-true !null $this->crap4j + */ + public function hasCrap4j(): bool + { + return $this->crap4j !== null; + } + /** + * @throws Exception + */ + public function crap4j(): Crap4j + { + if (!$this->hasCrap4j()) { + throw new Exception('Code Coverage report "Crap4J" has not been configured'); + } + return $this->crap4j; + } + /** + * @phpstan-assert-if-true !null $this->html + */ + public function hasHtml(): bool + { + return $this->html !== null; + } + /** + * @throws Exception + */ + public function html(): Html + { + if (!$this->hasHtml()) { + throw new Exception('Code Coverage report "HTML" has not been configured'); + } + return $this->html; + } + /** + * @phpstan-assert-if-true !null $this->openClover + */ + public function hasOpenClover(): bool + { + return $this->openClover !== null; + } + /** + * @throws Exception + */ + public function openClover(): OpenClover + { + if (!$this->hasOpenClover()) { + throw new Exception('Code Coverage report "OpenClover XML" has not been configured'); + } + return $this->openClover; + } + /** + * @phpstan-assert-if-true !null $this->php + */ + public function hasPhp(): bool + { + return $this->php !== null; + } + /** + * @throws Exception + */ + public function php(): Php + { + if (!$this->hasPhp()) { + throw new Exception('Code Coverage report "PHP" has not been configured'); + } + return $this->php; + } + /** + * @phpstan-assert-if-true !null $this->text + */ + public function hasText(): bool + { + return $this->text !== null; + } + /** + * @throws Exception + */ + public function text(): Text + { + if (!$this->hasText()) { + throw new Exception('Code Coverage report "Text" has not been configured'); + } + return $this->text; + } + /** + * @phpstan-assert-if-true !null $this->xml + */ + public function hasXml(): bool + { + return $this->xml !== null; + } + /** + * @throws Exception + */ + public function xml(): Xml + { + if (!$this->hasXml()) { + throw new Exception('Code Coverage report "XML" has not been configured'); + } + return $this->xml; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Clover +{ + private File $target; + public function __construct(File $target) + { + $this->target = $target; + } + public function target(): File + { + return $this->target; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Cobertura +{ + private File $target; + public function __construct(File $target) + { + $this->target = $target; + } + public function target(): File + { + return $this->target; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Crap4j +{ + private File $target; + private int $threshold; + public function __construct(File $target, int $threshold) + { + $this->target = $target; + $this->threshold = $threshold; + } + public function target(): File + { + return $this->target; + } + public function threshold(): int + { + return $this->threshold; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\Directory; +use PHPUnit\TextUI\Configuration\NoCustomCssFileException; +use PHPUnit\TextUI\Configuration\NoHtmlCoverageTargetException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Html +{ + private ?Directory $target; + private int $lowUpperBound; + private int $highLowerBound; + private string $colorSuccessLow; + private string $colorSuccessLowDark; + private string $colorSuccessMedium; + private string $colorSuccessMediumDark; + private string $colorSuccessHigh; + private string $colorSuccessHighDark; + private string $colorSuccessBar; + private string $colorSuccessBarDark; + private string $colorWarning; + private string $colorWarningDark; + private string $colorWarningBar; + private string $colorWarningBarDark; + private string $colorDanger; + private string $colorDangerDark; + private string $colorDangerBar; + private string $colorDangerBarDark; + private string $colorBreadcrumbs; + private string $colorBreadcrumbsDark; + private ?string $customCssFile; + public function __construct(?Directory $target, int $lowUpperBound, int $highLowerBound, string $colorSuccessLow, string $colorSuccessLowDark, string $colorSuccessMedium, string $colorSuccessMediumDark, string $colorSuccessHigh, string $colorSuccessHighDark, string $colorSuccessBar, string $colorSuccessBarDark, string $colorWarning, string $colorWarningDark, string $colorWarningBar, string $colorWarningBarDark, string $colorDanger, string $colorDangerDark, string $colorDangerBar, string $colorDangerBarDark, string $colorBreadcrumbs, string $colorBreadcrumbsDark, ?string $customCssFile) + { + $this->target = $target; + $this->lowUpperBound = $lowUpperBound; + $this->highLowerBound = $highLowerBound; + $this->colorSuccessLow = $colorSuccessLow; + $this->colorSuccessLowDark = $colorSuccessLowDark; + $this->colorSuccessMedium = $colorSuccessMedium; + $this->colorSuccessMediumDark = $colorSuccessMediumDark; + $this->colorSuccessHigh = $colorSuccessHigh; + $this->colorSuccessHighDark = $colorSuccessHighDark; + $this->colorSuccessBar = $colorSuccessBar; + $this->colorSuccessBarDark = $colorSuccessBarDark; + $this->colorWarning = $colorWarning; + $this->colorWarningDark = $colorWarningDark; + $this->colorWarningBar = $colorWarningBar; + $this->colorWarningBarDark = $colorWarningBarDark; + $this->colorDanger = $colorDanger; + $this->colorDangerDark = $colorDangerDark; + $this->colorDangerBar = $colorDangerBar; + $this->colorDangerBarDark = $colorDangerBarDark; + $this->colorBreadcrumbs = $colorBreadcrumbs; + $this->colorBreadcrumbsDark = $colorBreadcrumbsDark; + $this->customCssFile = $customCssFile; + } + /** + * @phpstan-assert-if-true !null $this->target + */ + public function hasTarget(): bool + { + return $this->target !== null; + } + /** + * @throws NoHtmlCoverageTargetException + */ + public function target(): Directory + { + if (!$this->hasTarget()) { + throw new NoHtmlCoverageTargetException(); + } + return $this->target; + } + public function lowUpperBound(): int + { + return $this->lowUpperBound; + } + public function highLowerBound(): int + { + return $this->highLowerBound; + } + public function colorSuccessLow(): string + { + return $this->colorSuccessLow; + } + public function colorSuccessLowDark(): string + { + return $this->colorSuccessLowDark; + } + public function colorSuccessMedium(): string + { + return $this->colorSuccessMedium; + } + public function colorSuccessMediumDark(): string + { + return $this->colorSuccessMediumDark; + } + public function colorSuccessHigh(): string + { + return $this->colorSuccessHigh; + } + public function colorSuccessHighDark(): string + { + return $this->colorSuccessHighDark; + } + public function colorSuccessBar(): string + { + return $this->colorSuccessBar; + } + public function colorSuccessBarDark(): string + { + return $this->colorSuccessBarDark; + } + public function colorWarning(): string + { + return $this->colorWarning; + } + public function colorWarningDark(): string + { + return $this->colorWarningDark; + } + public function colorWarningBar(): string + { + return $this->colorWarningBar; + } + public function colorWarningBarDark(): string + { + return $this->colorWarningBarDark; + } + public function colorDanger(): string + { + return $this->colorDanger; + } + public function colorDangerDark(): string + { + return $this->colorDangerDark; + } + public function colorDangerBar(): string + { + return $this->colorDangerBar; + } + public function colorDangerBarDark(): string + { + return $this->colorDangerBarDark; + } + public function colorBreadcrumbs(): string + { + return $this->colorBreadcrumbs; + } + public function colorBreadcrumbsDark(): string + { + return $this->colorBreadcrumbsDark; + } + /** + * @phpstan-assert-if-true !null $this->customCssFile + */ + public function hasCustomCssFile(): bool + { + return $this->customCssFile !== null; + } + /** + * @throws NoCustomCssFileException + */ + public function customCssFile(): string + { + if (!$this->hasCustomCssFile()) { + throw new NoCustomCssFileException(); + } + return $this->customCssFile; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class OpenClover +{ + private File $target; + public function __construct(File $target) + { + $this->target = $target; + } + public function target(): File + { + return $this->target; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Php +{ + private File $target; + public function __construct(File $target) + { + $this->target = $target; + } + public function target(): File + { + return $this->target; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Text +{ + private File $target; + private bool $showUncoveredFiles; + private bool $showOnlySummary; + public function __construct(File $target, bool $showUncoveredFiles, bool $showOnlySummary) + { + $this->target = $target; + $this->showUncoveredFiles = $showUncoveredFiles; + $this->showOnlySummary = $showOnlySummary; + } + public function target(): File + { + return $this->target; + } + public function showUncoveredFiles(): bool + { + return $this->showUncoveredFiles; + } + public function showOnlySummary(): bool + { + return $this->showOnlySummary; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\Directory; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Xml +{ + private Directory $target; + private bool $includeSource; + public function __construct(Directory $target, bool $includeSource) + { + $this->target = $target; + $this->includeSource = $includeSource; + } + public function target(): Directory + { + return $this->target; + } + public function includeSource(): bool + { + return $this->includeSource; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; +use PHPUnit\TextUI\Configuration\Php; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\TestSuiteCollection; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; +use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +abstract readonly class Configuration +{ + private ExtensionBootstrapCollection $extensions; + private Source $source; + private CodeCoverage $codeCoverage; + private \PHPUnit\TextUI\XmlConfiguration\Groups $groups; + private Logging $logging; + private Php $php; + private \PHPUnit\TextUI\XmlConfiguration\PHPUnit $phpunit; + private TestSuiteCollection $testSuite; + public function __construct(ExtensionBootstrapCollection $extensions, Source $source, CodeCoverage $codeCoverage, \PHPUnit\TextUI\XmlConfiguration\Groups $groups, Logging $logging, Php $php, \PHPUnit\TextUI\XmlConfiguration\PHPUnit $phpunit, TestSuiteCollection $testSuite) + { + $this->extensions = $extensions; + $this->source = $source; + $this->codeCoverage = $codeCoverage; + $this->groups = $groups; + $this->logging = $logging; + $this->php = $php; + $this->phpunit = $phpunit; + $this->testSuite = $testSuite; + } + public function extensions(): ExtensionBootstrapCollection + { + return $this->extensions; + } + public function source(): Source + { + return $this->source; + } + public function codeCoverage(): CodeCoverage + { + return $this->codeCoverage; + } + public function groups(): \PHPUnit\TextUI\XmlConfiguration\Groups + { + return $this->groups; + } + public function logging(): Logging + { + return $this->logging; + } + public function php(): Php + { + return $this->php; + } + public function phpunit(): \PHPUnit\TextUI\XmlConfiguration\PHPUnit + { + return $this->phpunit; + } + public function testSuite(): TestSuiteCollection + { + return $this->testSuite; + } + /** + * @phpstan-assert-if-true DefaultConfiguration $this + */ + public function isDefault(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true LoadedFromFileConfiguration $this + */ + public function wasLoadedFromFile(): bool + { + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\TextUI\Configuration\ConstantCollection; +use PHPUnit\TextUI\Configuration\DirectoryCollection; +use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; +use PHPUnit\TextUI\Configuration\FilterDirectoryCollection; +use PHPUnit\TextUI\Configuration\FilterFileCollection; +use PHPUnit\TextUI\Configuration\GroupCollection; +use PHPUnit\TextUI\Configuration\IniSettingCollection; +use PHPUnit\TextUI\Configuration\Php; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\TestSuiteCollection; +use PHPUnit\TextUI\Configuration\VariableCollection; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; +use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class DefaultConfiguration extends \PHPUnit\TextUI\XmlConfiguration\Configuration +{ + public static function create(): self + { + return new self(ExtensionBootstrapCollection::fromArray([]), new Source(null, \false, FilterDirectoryCollection::fromArray([]), FilterFileCollection::fromArray([]), FilterDirectoryCollection::fromArray([]), FilterFileCollection::fromArray([]), \false, \false, \false, \false, \false, \false, \false, \false, \false, ['functions' => [], 'methods' => [], 'ignoreUndefinedTriggers' => \false], \false, \false, \false, \true), new CodeCoverage(\false, \true, \false, \false, null, null, null, null, null, null, null, null), new \PHPUnit\TextUI\XmlConfiguration\Groups(GroupCollection::fromArray([]), GroupCollection::fromArray([])), new Logging(null, null, null, null, null), new Php(DirectoryCollection::fromArray([]), IniSettingCollection::fromArray([]), ConstantCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([]), VariableCollection::fromArray([])), new \PHPUnit\TextUI\XmlConfiguration\PHPUnit(null, \true, 80, \PHPUnit\TextUI\Configuration\Configuration::COLOR_DEFAULT, \false, \false, \false, \false, \false, \false, \false, \false, \false, \false, \false, \false, \false, null, [], \false, \false, \false, \false, \false, \true, \false, \false, \false, \false, \false, \false, \false, \false, \false, \false, \false, \false, \false, \false, \false, \false, null, \false, \false, \true, \false, \false, 1, 1, 10, 60, null, TestSuiteSorter::ORDER_DEFAULT, \true, \false, \false, \false, \false, \false, \false, 100, 10), TestSuiteCollection::fromArray([])); + } + public function isDefault(): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Exception extends RuntimeException implements \PHPUnit\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function str_replace; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Generator +{ + /** + * @var string + */ + private const string TEMPLATE = <<<'EOT' + + + + + {tests_directory} + + + + + + {src_directory} + + + + +EOT; + public function generateDefaultConfiguration(string $schemaLocation, string $bootstrapScript, string $testsDirectory, string $srcDirectory, string $cacheDirectory): string + { + return str_replace(['{schema_location}', '{bootstrap_script}', '{tests_directory}', '{src_directory}', '{cache_directory}'], [$schemaLocation, $bootstrapScript, $testsDirectory, $srcDirectory, $cacheDirectory], self::TEMPLATE); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\TextUI\Configuration\GroupCollection; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Groups +{ + private GroupCollection $include; + private GroupCollection $exclude; + public function __construct(GroupCollection $include, GroupCollection $exclude) + { + $this->include = $include; + $this->exclude = $exclude; + } + public function hasInclude(): bool + { + return !$this->include->isEmpty(); + } + public function include(): GroupCollection + { + return $this->include; + } + public function hasExclude(): bool + { + return !$this->exclude->isEmpty(); + } + public function exclude(): GroupCollection + { + return $this->exclude; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; +use PHPUnit\TextUI\Configuration\Php; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\TestSuiteCollection; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; +use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class LoadedFromFileConfiguration extends \PHPUnit\TextUI\XmlConfiguration\Configuration +{ + /** + * @var non-empty-string + */ + private string $filename; + private \PHPUnit\TextUI\XmlConfiguration\ValidationResult $validationResult; + /** + * @param non-empty-string $filename + */ + public function __construct(string $filename, \PHPUnit\TextUI\XmlConfiguration\ValidationResult $validationResult, ExtensionBootstrapCollection $extensions, Source $source, CodeCoverage $codeCoverage, \PHPUnit\TextUI\XmlConfiguration\Groups $groups, Logging $logging, Php $php, \PHPUnit\TextUI\XmlConfiguration\PHPUnit $phpunit, TestSuiteCollection $testSuite) + { + $this->filename = $filename; + $this->validationResult = $validationResult; + parent::__construct($extensions, $source, $codeCoverage, $groups, $logging, $php, $phpunit, $testSuite); + } + /** + * @return non-empty-string + */ + public function filename(): string + { + return $this->filename; + } + public function hasValidationErrors(): bool + { + return $this->validationResult->hasValidationErrors(); + } + public function validationErrors(): string + { + return $this->validationResult->asString(); + } + public function wasLoadedFromFile(): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use const DIRECTORY_SEPARATOR; +use const PHP_EOL; +use const PHP_VERSION; +use function assert; +use function defined; +use function dirname; +use function explode; +use function is_numeric; +use function preg_match; +use function realpath; +use function sprintf; +use function str_contains; +use function str_starts_with; +use function strlen; +use function strtolower; +use function substr; +use function trim; +use DOMDocument; +use DOMElement; +use DOMNode; +use DOMNodeList; +use DOMXPath; +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\Runner\Version; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\Constant; +use PHPUnit\TextUI\Configuration\ConstantCollection; +use PHPUnit\TextUI\Configuration\Directory; +use PHPUnit\TextUI\Configuration\DirectoryCollection; +use PHPUnit\TextUI\Configuration\ExtensionBootstrap; +use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; +use PHPUnit\TextUI\Configuration\File; +use PHPUnit\TextUI\Configuration\FileCollection; +use PHPUnit\TextUI\Configuration\FilterDirectory; +use PHPUnit\TextUI\Configuration\FilterDirectoryCollection; +use PHPUnit\TextUI\Configuration\FilterFile; +use PHPUnit\TextUI\Configuration\FilterFileCollection; +use PHPUnit\TextUI\Configuration\Group; +use PHPUnit\TextUI\Configuration\GroupCollection; +use PHPUnit\TextUI\Configuration\IniSetting; +use PHPUnit\TextUI\Configuration\IniSettingCollection; +use PHPUnit\TextUI\Configuration\Php; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\TestDirectory; +use PHPUnit\TextUI\Configuration\TestDirectoryCollection; +use PHPUnit\TextUI\Configuration\TestFile; +use PHPUnit\TextUI\Configuration\TestFileCollection; +use PHPUnit\TextUI\Configuration\TestSuite as TestSuiteConfiguration; +use PHPUnit\TextUI\Configuration\TestSuiteCollection; +use PHPUnit\TextUI\Configuration\Variable; +use PHPUnit\TextUI\Configuration\VariableCollection; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Clover; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Cobertura; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Crap4j; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Html as CodeCoverageHtml; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\OpenClover; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Php as CodeCoveragePhp; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Text as CodeCoverageText; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Xml as CodeCoverageXml; +use PHPUnit\TextUI\XmlConfiguration\Logging\Junit; +use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; +use PHPUnit\TextUI\XmlConfiguration\Logging\Otr; +use PHPUnit\TextUI\XmlConfiguration\Logging\TeamCity; +use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Html as TestDoxHtml; +use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Text as TestDoxText; +use PHPUnit\Util\VersionComparisonOperator; +use PHPUnit\Util\Xml\Loader as XmlLoader; +use PHPUnit\Util\Xml\XmlException; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html\Colors; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Thresholds; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Loader +{ + /** + * @throws Exception + */ + public function load(string $filename): \PHPUnit\TextUI\XmlConfiguration\LoadedFromFileConfiguration + { + try { + $document = (new XmlLoader())->loadFile($filename); + } catch (XmlException $e) { + throw new \PHPUnit\TextUI\XmlConfiguration\Exception($e->getMessage(), $e->getCode(), $e); + } + $xpath = new DOMXPath($document); + try { + $xsdFilename = (new \PHPUnit\TextUI\XmlConfiguration\SchemaFinder())->find(Version::series()); + } catch (\PHPUnit\TextUI\XmlConfiguration\CannotFindSchemaException $e) { + throw new \PHPUnit\TextUI\XmlConfiguration\Exception($e->getMessage(), $e->getCode(), $e); + } + $configurationFileRealpath = realpath($filename); + assert($configurationFileRealpath !== \false && $configurationFileRealpath !== ''); + $validationResult = (new \PHPUnit\TextUI\XmlConfiguration\Validator())->validate($document, $xsdFilename); + if ($validationResult->hasValidationErrors()) { + $this->ensureConfigurationValidatesAgainstAtLeastOneSchema($document, $configurationFileRealpath, $validationResult); + } + try { + return new \PHPUnit\TextUI\XmlConfiguration\LoadedFromFileConfiguration($configurationFileRealpath, $validationResult, $this->extensions($xpath), $this->source($configurationFileRealpath, $xpath), $this->codeCoverage($configurationFileRealpath, $xpath), $this->groups($xpath), $this->logging($configurationFileRealpath, $xpath), $this->php($configurationFileRealpath, $xpath), $this->phpunit($configurationFileRealpath, $document, $xpath), $this->testSuite($configurationFileRealpath, $xpath)); + } catch (Throwable $t) { + $message = sprintf('Cannot load XML configuration file %s', $configurationFileRealpath); + if ($validationResult->hasValidationErrors()) { + $message .= ' because it has validation errors:' . PHP_EOL . $validationResult->asString(); + } + throw new \PHPUnit\TextUI\XmlConfiguration\Exception($message, previous: $t); + } + } + private function logging(string $filename, DOMXPath $xpath): Logging + { + $junit = null; + $element = $this->element($xpath, 'logging/junit'); + if ($element !== null) { + $junit = new Junit(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); + } + $otr = null; + $element = $this->element($xpath, 'logging/otr'); + if ($element !== null) { + $otr = new Otr(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile'))), $this->parseBooleanAttribute($element, 'includeGitInformation', \false)); + } + $teamCity = null; + $element = $this->element($xpath, 'logging/teamcity'); + if ($element !== null) { + $teamCity = new TeamCity(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); + } + $testDoxHtml = null; + $element = $this->element($xpath, 'logging/testdoxHtml'); + if ($element !== null) { + $testDoxHtml = new TestDoxHtml(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); + } + $testDoxText = null; + $element = $this->element($xpath, 'logging/testdoxText'); + if ($element !== null) { + $testDoxText = new TestDoxText(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); + } + return new Logging($junit, $otr, $teamCity, $testDoxHtml, $testDoxText); + } + private function extensions(DOMXPath $xpath): ExtensionBootstrapCollection + { + $extensionBootstrappers = []; + $bootstrapNodes = $xpath->query('extensions/bootstrap'); + assert($bootstrapNodes instanceof DOMNodeList); + foreach ($bootstrapNodes as $bootstrap) { + assert($bootstrap instanceof DOMElement); + $parameters = []; + $parameterNodes = $xpath->query('parameter', $bootstrap); + assert($parameterNodes instanceof DOMNodeList); + foreach ($parameterNodes as $parameter) { + assert($parameter instanceof DOMElement); + $parameters[$parameter->getAttribute('name')] = $parameter->getAttribute('value'); + } + $className = $bootstrap->getAttribute('class'); + assert($className !== ''); + $extensionBootstrappers[] = new ExtensionBootstrap($className, $parameters); + } + return ExtensionBootstrapCollection::fromArray($extensionBootstrappers); + } + /** + * @return non-empty-string + */ + private function toAbsolutePath(string $filename, string $path): string + { + $path = trim($path); + if (str_starts_with($path, '/')) { + return $path; + } + // Matches the following on Windows: + // - \\NetworkComputer\Path + // - \\.\D: + // - \\.\c: + // - C:\Windows + // - C:\windows + // - C:/windows + // - c:/windows + if (defined('PHP_WINDOWS_VERSION_BUILD') && $path !== '' && ($path[0] === '\\' || strlen($path) >= 3 && preg_match('#^[A-Z]:[/\\\\]#i', substr($path, 0, 3)))) { + return $path; + } + if (str_contains($path, '://')) { + return $path; + } + return dirname($filename) . DIRECTORY_SEPARATOR . $path; + } + private function source(string $filename, DOMXPath $xpath): Source + { + $baseline = null; + $restrictNotices = \false; + $restrictWarnings = \false; + $ignoreSuppressionOfDeprecations = \false; + $ignoreSuppressionOfPhpDeprecations = \false; + $ignoreSuppressionOfErrors = \false; + $ignoreSuppressionOfNotices = \false; + $ignoreSuppressionOfPhpNotices = \false; + $ignoreSuppressionOfWarnings = \false; + $ignoreSuppressionOfPhpWarnings = \false; + $ignoreSelfDeprecations = \false; + $ignoreDirectDeprecations = \false; + $ignoreIndirectDeprecations = \false; + $identifyIssueTrigger = \true; + $element = $this->element($xpath, 'source'); + if ($element !== null) { + $baseline = $this->parseStringAttribute($element, 'baseline'); + if ($baseline !== null) { + $baseline = $this->toAbsolutePath($filename, $baseline); + } + $restrictNotices = $this->parseBooleanAttribute($element, 'restrictNotices', \false); + $restrictWarnings = $this->parseBooleanAttribute($element, 'restrictWarnings', \false); + $ignoreSuppressionOfDeprecations = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfDeprecations', \false); + $ignoreSuppressionOfPhpDeprecations = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfPhpDeprecations', \false); + $ignoreSuppressionOfErrors = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfErrors', \false); + $ignoreSuppressionOfNotices = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfNotices', \false); + $ignoreSuppressionOfPhpNotices = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfPhpNotices', \false); + $ignoreSuppressionOfWarnings = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfWarnings', \false); + $ignoreSuppressionOfPhpWarnings = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfPhpWarnings', \false); + $ignoreSelfDeprecations = $this->parseBooleanAttribute($element, 'ignoreSelfDeprecations', \false); + $ignoreDirectDeprecations = $this->parseBooleanAttribute($element, 'ignoreDirectDeprecations', \false); + $ignoreIndirectDeprecations = $this->parseBooleanAttribute($element, 'ignoreIndirectDeprecations', \false); + $identifyIssueTrigger = $this->parseBooleanAttribute($element, 'identifyIssueTrigger', \true); + } + $deprecationTriggerElement = $this->element($xpath, 'source/deprecationTrigger'); + $deprecationTriggers = ['functions' => [], 'methods' => [], 'ignoreUndefinedTriggers' => $deprecationTriggerElement !== null && $this->parseBooleanAttribute($deprecationTriggerElement, 'ignoreUndefinedTriggers', \false)]; + $functionNodes = $xpath->query('source/deprecationTrigger/function'); + assert($functionNodes instanceof DOMNodeList); + foreach ($functionNodes as $functionNode) { + assert($functionNode instanceof DOMElement); + $deprecationTriggers['functions'][] = $functionNode->textContent; + } + $methodNodes = $xpath->query('source/deprecationTrigger/method'); + assert($methodNodes instanceof DOMNodeList); + foreach ($methodNodes as $methodNode) { + assert($methodNode instanceof DOMElement); + $deprecationTriggers['methods'][] = $methodNode->textContent; + } + $issueTriggerResolvers = []; + $issueTriggerResolverNodes = $xpath->query('source/issueTriggerResolvers/issueTriggerResolver'); + assert($issueTriggerResolverNodes instanceof DOMNodeList); + foreach ($issueTriggerResolverNodes as $node) { + assert($node instanceof DOMElement); + $issueTriggerResolvers[] = $node->getAttribute('className'); + } + return new Source($baseline, \false, $this->readFilterDirectories($filename, $xpath, 'source/include/directory'), $this->readFilterFiles($filename, $xpath, 'source/include/file'), $this->readFilterDirectories($filename, $xpath, 'source/exclude/directory'), $this->readFilterFiles($filename, $xpath, 'source/exclude/file'), $restrictNotices, $restrictWarnings, $ignoreSuppressionOfDeprecations, $ignoreSuppressionOfPhpDeprecations, $ignoreSuppressionOfErrors, $ignoreSuppressionOfNotices, $ignoreSuppressionOfPhpNotices, $ignoreSuppressionOfWarnings, $ignoreSuppressionOfPhpWarnings, $deprecationTriggers, $ignoreSelfDeprecations, $ignoreDirectDeprecations, $ignoreIndirectDeprecations, $identifyIssueTrigger, $issueTriggerResolvers); + } + private function codeCoverage(string $filename, DOMXPath $xpath): CodeCoverage + { + $pathCoverage = \false; + $includeUncoveredFiles = \true; + $ignoreDeprecatedCodeUnits = \false; + $disableCodeCoverageIgnore = \false; + $element = $this->element($xpath, 'coverage'); + if ($element !== null) { + $pathCoverage = $this->parseBooleanAttribute($element, 'pathCoverage', \false); + $includeUncoveredFiles = $this->parseBooleanAttribute($element, 'includeUncoveredFiles', \true); + $ignoreDeprecatedCodeUnits = $this->parseBooleanAttribute($element, 'ignoreDeprecatedCodeUnits', \false); + $disableCodeCoverageIgnore = $this->parseBooleanAttribute($element, 'disableCodeCoverageIgnore', \false); + } + $clover = null; + $element = $this->element($xpath, 'coverage/report/clover'); + if ($element !== null) { + $clover = new Clover(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); + } + $cobertura = null; + $element = $this->element($xpath, 'coverage/report/cobertura'); + if ($element !== null) { + $cobertura = new Cobertura(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); + } + $crap4j = null; + $element = $this->element($xpath, 'coverage/report/crap4j'); + if ($element !== null) { + $crap4j = new Crap4j(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile'))), $this->parseIntegerAttribute($element, 'threshold', 30)); + } + $html = null; + $element = $this->element($xpath, 'coverage/report/html'); + if ($element !== null) { + $defaultColors = Colors::default(); + $defaultThresholds = Thresholds::default(); + $outputDirectory = $this->parseStringAttribute($element, 'outputDirectory'); + if ($outputDirectory !== null) { + $outputDirectory = new Directory($this->toAbsolutePath($filename, $outputDirectory)); + } + $html = new CodeCoverageHtml($outputDirectory, $this->parseIntegerAttribute($element, 'lowUpperBound', $defaultThresholds->lowUpperBound()), $this->parseIntegerAttribute($element, 'highLowerBound', $defaultThresholds->highLowerBound()), $this->parseStringAttributeWithDefault($element, 'colorSuccessLow', $defaultColors->successLow()), $this->parseStringAttributeWithDefault($element, 'colorSuccessLowDark', $defaultColors->successLowDark()), $this->parseStringAttributeWithDefault($element, 'colorSuccessMedium', $defaultColors->successMedium()), $this->parseStringAttributeWithDefault($element, 'colorSuccessMediumDark', $defaultColors->successMediumDark()), $this->parseStringAttributeWithDefault($element, 'colorSuccessHigh', $defaultColors->successHigh()), $this->parseStringAttributeWithDefault($element, 'colorSuccessHighDark', $defaultColors->successHighDark()), $this->parseStringAttributeWithDefault($element, 'colorSuccessBar', $defaultColors->successBar()), $this->parseStringAttributeWithDefault($element, 'colorSuccessBarDark', $defaultColors->successBarDark()), $this->parseStringAttributeWithDefault($element, 'colorWarning', $defaultColors->warning()), $this->parseStringAttributeWithDefault($element, 'colorWarningDark', $defaultColors->warningDark()), $this->parseStringAttributeWithDefault($element, 'colorWarningBar', $defaultColors->warningBar()), $this->parseStringAttributeWithDefault($element, 'colorWarningBarDark', $defaultColors->warningBarDark()), $this->parseStringAttributeWithDefault($element, 'colorDanger', $defaultColors->danger()), $this->parseStringAttributeWithDefault($element, 'colorDangerDark', $defaultColors->dangerDark()), $this->parseStringAttributeWithDefault($element, 'colorDangerBar', $defaultColors->dangerBar()), $this->parseStringAttributeWithDefault($element, 'colorDangerBarDark', $defaultColors->dangerBarDark()), $this->parseStringAttributeWithDefault($element, 'colorBreadcrumbs', $defaultColors->breadcrumbs()), $this->parseStringAttributeWithDefault($element, 'colorBreadcrumbsDark', $defaultColors->breadcrumbsDark()), $this->parseStringAttribute($element, 'customCssFile')); + } + $openClover = null; + $element = $this->element($xpath, 'coverage/report/openclover'); + if ($element !== null) { + $openClover = new OpenClover(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); + } + $php = null; + $element = $this->element($xpath, 'coverage/report/php'); + if ($element !== null) { + $php = new CodeCoveragePhp(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); + } + $text = null; + $element = $this->element($xpath, 'coverage/report/text'); + if ($element !== null) { + $text = new CodeCoverageText(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile'))), $this->parseBooleanAttribute($element, 'showUncoveredFiles', \false), $this->parseBooleanAttribute($element, 'showOnlySummary', \false)); + } + $xml = null; + $element = $this->element($xpath, 'coverage/report/xml'); + if ($element !== null) { + $xml = new CodeCoverageXml(new Directory($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputDirectory'))), $this->parseBooleanAttribute($element, 'includeSource', \true)); + } + return new CodeCoverage($pathCoverage, $includeUncoveredFiles, $ignoreDeprecatedCodeUnits, $disableCodeCoverageIgnore, $clover, $cobertura, $crap4j, $html, $openClover, $php, $text, $xml); + } + private function booleanFromString(string $value, bool $default): bool + { + if (strtolower($value) === 'false') { + return \false; + } + if (strtolower($value) === 'true') { + return \true; + } + return $default; + } + private function valueFromString(string $value): bool|string + { + if (strtolower($value) === 'false') { + return \false; + } + if (strtolower($value) === 'true') { + return \true; + } + return $value; + } + private function readFilterDirectories(string $filename, DOMXPath $xpath, string $query): FilterDirectoryCollection + { + $directories = []; + $directoryNodes = $xpath->query($query); + assert($directoryNodes instanceof DOMNodeList); + foreach ($directoryNodes as $directoryNode) { + assert($directoryNode instanceof DOMElement); + $directoryPath = $directoryNode->textContent; + if ($directoryPath === '') { + continue; + } + $directories[] = new FilterDirectory($this->toAbsolutePath($filename, $directoryPath), $directoryNode->hasAttribute('prefix') ? $directoryNode->getAttribute('prefix') : '', $directoryNode->hasAttribute('suffix') ? $directoryNode->getAttribute('suffix') : '.php', !$directoryNode->hasAttribute('includeInCodeCoverage') || $directoryNode->getAttribute('includeInCodeCoverage') !== 'false'); + } + return FilterDirectoryCollection::fromArray($directories); + } + private function readFilterFiles(string $filename, DOMXPath $xpath, string $query): FilterFileCollection + { + $files = []; + $fileNodes = $xpath->query($query); + assert($fileNodes instanceof DOMNodeList); + foreach ($fileNodes as $fileNode) { + assert($fileNode instanceof DOMElement); + $filePath = $fileNode->textContent; + if ($filePath !== '') { + $files[] = new FilterFile($this->toAbsolutePath($filename, $filePath), !$fileNode->hasAttribute('includeInCodeCoverage') || $fileNode->getAttribute('includeInCodeCoverage') !== 'false'); + } + } + return FilterFileCollection::fromArray($files); + } + private function groups(DOMXPath $xpath): \PHPUnit\TextUI\XmlConfiguration\Groups + { + $include = []; + $exclude = []; + $groupNodes = $xpath->query('groups/include/group'); + assert($groupNodes instanceof DOMNodeList); + foreach ($groupNodes as $groupNode) { + assert($groupNode instanceof DOMNode); + $include[] = new Group($groupNode->textContent); + } + $groupNodes = $xpath->query('groups/exclude/group'); + assert($groupNodes instanceof DOMNodeList); + foreach ($groupNodes as $groupNode) { + assert($groupNode instanceof DOMNode); + $exclude[] = new Group($groupNode->textContent); + } + return new \PHPUnit\TextUI\XmlConfiguration\Groups(GroupCollection::fromArray($include), GroupCollection::fromArray($exclude)); + } + private function parseBooleanAttribute(DOMElement $element, string $attribute, bool $default): bool + { + if (!$element->hasAttribute($attribute)) { + return $default; + } + return $this->booleanFromString($element->getAttribute($attribute), \false); + } + private function parseIntegerAttribute(DOMElement $element, string $attribute, int $default): int + { + if (!$element->hasAttribute($attribute)) { + return $default; + } + return $this->parseInteger($element->getAttribute($attribute), $default); + } + private function parseStringAttribute(DOMElement $element, string $attribute): ?string + { + if (!$element->hasAttribute($attribute)) { + return null; + } + return $element->getAttribute($attribute); + } + private function parseStringAttributeWithDefault(DOMElement $element, string $attribute, string $default): string + { + if (!$element->hasAttribute($attribute)) { + return $default; + } + return $element->getAttribute($attribute); + } + private function parseInteger(string $value, int $default): int + { + if (is_numeric($value)) { + return (int) $value; + } + return $default; + } + private function php(string $filename, DOMXPath $xpath): Php + { + $includePaths = []; + $includePathNodes = $xpath->query('php/includePath'); + assert($includePathNodes instanceof DOMNodeList); + foreach ($includePathNodes as $includePath) { + assert($includePath instanceof DOMNode); + $path = $includePath->textContent; + if ($path !== '') { + $includePaths[] = new Directory($this->toAbsolutePath($filename, $path)); + } + } + $iniSettings = []; + $iniNodes = $xpath->query('php/ini'); + assert($iniNodes instanceof DOMNodeList); + foreach ($iniNodes as $ini) { + assert($ini instanceof DOMElement); + $iniSettings[] = new IniSetting($ini->getAttribute('name'), $ini->getAttribute('value')); + } + $constants = []; + $constNodes = $xpath->query('php/const'); + assert($constNodes instanceof DOMNodeList); + foreach ($constNodes as $constNode) { + assert($constNode instanceof DOMElement); + $value = $constNode->getAttribute('value'); + $constants[] = new Constant($constNode->getAttribute('name'), $this->valueFromString($value)); + } + $variables = ['var' => [], 'env' => [], 'post' => [], 'get' => [], 'cookie' => [], 'server' => [], 'files' => [], 'request' => []]; + foreach (['var', 'env', 'post', 'get', 'cookie', 'server', 'files', 'request'] as $array) { + $varNodes = $xpath->query('php/' . $array); + assert($varNodes instanceof DOMNodeList); + foreach ($varNodes as $var) { + assert($var instanceof DOMElement); + $name = $var->getAttribute('name'); + $value = $var->getAttribute('value'); + $force = \false; + $verbatim = \false; + if ($var->hasAttribute('force')) { + $force = $this->booleanFromString($var->getAttribute('force'), \false); + } + if ($var->hasAttribute('verbatim')) { + $verbatim = $this->booleanFromString($var->getAttribute('verbatim'), \false); + } + if (!$verbatim) { + $value = $this->valueFromString($value); + } + $variables[$array][] = new Variable($name, $value, $force); + } + } + return new Php(DirectoryCollection::fromArray($includePaths), IniSettingCollection::fromArray($iniSettings), ConstantCollection::fromArray($constants), VariableCollection::fromArray($variables['var']), VariableCollection::fromArray($variables['env']), VariableCollection::fromArray($variables['post']), VariableCollection::fromArray($variables['get']), VariableCollection::fromArray($variables['cookie']), VariableCollection::fromArray($variables['server']), VariableCollection::fromArray($variables['files']), VariableCollection::fromArray($variables['request'])); + } + private function phpunit(string $filename, DOMDocument $document, DOMXPath $xpath): \PHPUnit\TextUI\XmlConfiguration\PHPUnit + { + $executionOrder = TestSuiteSorter::ORDER_DEFAULT; + $defectsFirst = \false; + $resolveDependencies = $this->parseBooleanAttribute($document->documentElement, 'resolveDependencies', \true); + if ($document->documentElement->hasAttribute('executionOrder')) { + foreach (explode(',', $document->documentElement->getAttribute('executionOrder')) as $order) { + switch ($order) { + case 'default': + $executionOrder = TestSuiteSorter::ORDER_DEFAULT; + $defectsFirst = \false; + $resolveDependencies = \true; + break; + case 'depends': + $resolveDependencies = \true; + break; + case 'no-depends': + $resolveDependencies = \false; + break; + case 'defects': + $defectsFirst = \true; + break; + case 'duration': + $executionOrder = TestSuiteSorter::ORDER_DURATION; + break; + case 'random': + $executionOrder = TestSuiteSorter::ORDER_RANDOMIZED; + break; + case 'reverse': + $executionOrder = TestSuiteSorter::ORDER_REVERSED; + break; + case 'size': + $executionOrder = TestSuiteSorter::ORDER_SIZE; + break; + } + } + } + $cacheDirectory = $this->parseStringAttribute($document->documentElement, 'cacheDirectory'); + if ($cacheDirectory !== null) { + $cacheDirectory = $this->toAbsolutePath($filename, $cacheDirectory); + } + $bootstrap = $this->parseStringAttribute($document->documentElement, 'bootstrap'); + if ($bootstrap !== null) { + $bootstrap = $this->toAbsolutePath($filename, $bootstrap); + } + $extensionsDirectory = $this->parseStringAttribute($document->documentElement, 'extensionsDirectory'); + if ($extensionsDirectory !== null) { + $extensionsDirectory = $this->toAbsolutePath($filename, $extensionsDirectory); + } + $backupStaticProperties = \false; + if ($document->documentElement->hasAttribute('backupStaticProperties')) { + $backupStaticProperties = $this->parseBooleanAttribute($document->documentElement, 'backupStaticProperties', \false); + } + $requireCoverageMetadata = \false; + if ($document->documentElement->hasAttribute('requireCoverageMetadata')) { + $requireCoverageMetadata = $this->parseBooleanAttribute($document->documentElement, 'requireCoverageMetadata', \false); + } + $requireSealedMockObjects = \false; + if ($document->documentElement->hasAttribute('requireSealedMockObjects')) { + $requireSealedMockObjects = $this->parseBooleanAttribute($document->documentElement, 'requireSealedMockObjects', \false); + } + $beStrictAboutCoverageMetadata = \false; + if ($document->documentElement->hasAttribute('beStrictAboutCoverageMetadata')) { + $beStrictAboutCoverageMetadata = $this->parseBooleanAttribute($document->documentElement, 'beStrictAboutCoverageMetadata', \false); + } + $shortenArraysForExportThreshold = $this->parseIntegerAttribute($document->documentElement, 'shortenArraysForExportThreshold', 10); + if ($shortenArraysForExportThreshold < 0) { + $shortenArraysForExportThreshold = 0; + } + return new \PHPUnit\TextUI\XmlConfiguration\PHPUnit($cacheDirectory, $this->parseBooleanAttribute($document->documentElement, 'cacheResult', \true), $this->parseColumns($document), $this->parseColors($document), $this->parseBooleanAttribute($document->documentElement, 'stderr', \false), $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnAllIssues', \false), $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnIncompleteTests', \false), $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnSkippedTests', \false), $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerDeprecations', \false), $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnPhpunitDeprecations', \false), $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnPhpunitNotices', \false), $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerErrors', \false), $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerNotices', \false), $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerWarnings', \false), $this->parseBooleanAttribute($document->documentElement, 'reverseDefectList', \false), $requireCoverageMetadata, $requireSealedMockObjects, $bootstrap, $this->bootstrapForTestSuite($filename, $xpath), $this->parseBooleanAttribute($document->documentElement, 'processIsolation', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnAllIssues', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnDeprecation', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnPhpunitDeprecation', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnPhpunitNotice', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnPhpunitWarning', \true), $this->parseBooleanAttribute($document->documentElement, 'failOnEmptyTestSuite', \false), $document->documentElement->hasAttribute('failOnEmptyTestSuite'), $this->parseBooleanAttribute($document->documentElement, 'failOnIncomplete', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnNotice', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnRisky', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnSkipped', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnWarning', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnDefect', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnDeprecation', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnError', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnFailure', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnIncomplete', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnNotice', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnRisky', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnSkipped', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnWarning', \false), $extensionsDirectory, $this->parseBooleanAttribute($document->documentElement, 'beStrictAboutChangesToGlobalState', \false), $this->parseBooleanAttribute($document->documentElement, 'beStrictAboutOutputDuringTests', \false), $this->parseBooleanAttribute($document->documentElement, 'beStrictAboutTestsThatDoNotTestAnything', \true), $beStrictAboutCoverageMetadata, $this->parseBooleanAttribute($document->documentElement, 'enforceTimeLimit', \false), $this->parseIntegerAttribute($document->documentElement, 'defaultTimeLimit', 1), $this->parseIntegerAttribute($document->documentElement, 'timeoutForSmallTests', 1), $this->parseIntegerAttribute($document->documentElement, 'timeoutForMediumTests', 10), $this->parseIntegerAttribute($document->documentElement, 'timeoutForLargeTests', 60), $this->parseStringAttribute($document->documentElement, 'defaultTestSuite'), $executionOrder, $resolveDependencies, $defectsFirst, $this->parseBooleanAttribute($document->documentElement, 'backupGlobals', \false), $backupStaticProperties, $this->parseBooleanAttribute($document->documentElement, 'testdox', \false), $this->parseBooleanAttribute($document->documentElement, 'testdoxSummary', \false), $this->parseBooleanAttribute($document->documentElement, 'controlGarbageCollector', \false), $this->parseIntegerAttribute($document->documentElement, 'numberOfTestsBeforeGarbageCollection', 100), $shortenArraysForExportThreshold); + } + private function parseColors(DOMDocument $document): string + { + $colors = Configuration::COLOR_DEFAULT; + if ($document->documentElement->hasAttribute('colors')) { + if ($this->booleanFromString($document->documentElement->getAttribute('colors'), \false)) { + $colors = Configuration::COLOR_ALWAYS; + } else { + $colors = Configuration::COLOR_NEVER; + } + } + return $colors; + } + private function parseColumns(DOMDocument $document): int|string + { + $columns = 80; + if ($document->documentElement->hasAttribute('columns')) { + $columns = $document->documentElement->getAttribute('columns'); + if ($columns !== 'max') { + $columns = $this->parseInteger($columns, 80); + } + } + return $columns; + } + /** + * @return array + */ + private function bootstrapForTestSuite(string $filename, DOMXPath $xpath): array + { + $bootstrapForTestSuite = []; + foreach ($this->parseTestSuiteElements($xpath) as $element) { + if (!$element->hasAttribute('bootstrap')) { + continue; + } + $name = $element->getAttribute('name'); + $bootstrap = $element->getAttribute('bootstrap'); + assert($name !== ''); + assert($bootstrap !== ''); + $bootstrapForTestSuite[$name] = $this->toAbsolutePath($filename, $bootstrap); + } + return $bootstrapForTestSuite; + } + private function testSuite(string $filename, DOMXPath $xpath): TestSuiteCollection + { + $testSuites = []; + foreach ($this->parseTestSuiteElements($xpath) as $element) { + $exclude = []; + foreach ($element->getElementsByTagName('exclude') as $excludeNode) { + $excludeFile = $excludeNode->textContent; + if ($excludeFile !== '') { + $exclude[] = new File($this->toAbsolutePath($filename, $excludeFile)); + } + } + $directories = []; + foreach ($element->getElementsByTagName('directory') as $directoryNode) { + assert($directoryNode instanceof DOMElement); + $directory = $directoryNode->textContent; + if ($directory === '') { + continue; + } + $prefix = ''; + if ($directoryNode->hasAttribute('prefix')) { + $prefix = $directoryNode->getAttribute('prefix'); + } + $suffix = 'Test.php'; + if ($directoryNode->hasAttribute('suffix')) { + $suffix = $directoryNode->getAttribute('suffix'); + } + $phpVersion = PHP_VERSION; + if ($directoryNode->hasAttribute('phpVersion')) { + $phpVersion = $directoryNode->getAttribute('phpVersion'); + } + $phpVersionOperator = new VersionComparisonOperator('>='); + if ($directoryNode->hasAttribute('phpVersionOperator')) { + $phpVersionOperator = new VersionComparisonOperator($directoryNode->getAttribute('phpVersionOperator')); + } + $groups = []; + if ($directoryNode->hasAttribute('groups')) { + foreach (explode(',', $directoryNode->getAttribute('groups')) as $group) { + $group = trim($group); + if ($group === '') { + continue; + } + $groups[] = $group; + } + } + $directories[] = new TestDirectory($this->toAbsolutePath($filename, $directory), $prefix, $suffix, $phpVersion, $phpVersionOperator, $groups); + } + $files = []; + foreach ($element->getElementsByTagName('file') as $fileNode) { + assert($fileNode instanceof DOMElement); + $file = $fileNode->textContent; + if ($file === '') { + continue; + } + $phpVersion = PHP_VERSION; + if ($fileNode->hasAttribute('phpVersion')) { + $phpVersion = $fileNode->getAttribute('phpVersion'); + } + $phpVersionOperator = new VersionComparisonOperator('>='); + if ($fileNode->hasAttribute('phpVersionOperator')) { + $phpVersionOperator = new VersionComparisonOperator($fileNode->getAttribute('phpVersionOperator')); + } + $groups = []; + if ($fileNode->hasAttribute('groups')) { + foreach (explode(',', $fileNode->getAttribute('groups')) as $group) { + $group = trim($group); + if ($group === '') { + continue; + } + $groups[] = $group; + } + } + $files[] = new TestFile($this->toAbsolutePath($filename, $file), $phpVersion, $phpVersionOperator, $groups); + } + $name = $element->getAttribute('name'); + assert($name !== ''); + $testSuites[] = new TestSuiteConfiguration($name, TestDirectoryCollection::fromArray($directories), TestFileCollection::fromArray($files), FileCollection::fromArray($exclude)); + } + return TestSuiteCollection::fromArray($testSuites); + } + /** + * @return list + */ + private function parseTestSuiteElements(DOMXPath $xpath): array + { + $elements = []; + $testSuiteNodes = $xpath->query('testsuites/testsuite'); + assert($testSuiteNodes instanceof DOMNodeList); + if ($testSuiteNodes->length === 0) { + $testSuiteNodes = $xpath->query('testsuite'); + assert($testSuiteNodes instanceof DOMNodeList); + } + if ($testSuiteNodes->length === 1) { + $element = $testSuiteNodes->item(0); + assert($element instanceof DOMElement); + $elements[] = $element; + } else { + foreach ($testSuiteNodes as $testSuiteNode) { + assert($testSuiteNode instanceof DOMElement); + $elements[] = $testSuiteNode; + } + } + return $elements; + } + private function element(DOMXPath $xpath, string $element): ?DOMElement + { + $nodes = $xpath->query($element); + assert($nodes instanceof DOMNodeList); + if ($nodes->length === 1) { + $node = $nodes->item(0); + assert($node instanceof DOMElement); + return $node; + } + return null; + } + /** + * @throws Exception + */ + private function ensureConfigurationValidatesAgainstAtLeastOneSchema(DOMDocument $document, string $configurationFile, \PHPUnit\TextUI\XmlConfiguration\ValidationResult $validationResult): void + { + if ($document->documentElement->localName === 'phpunit') { + return; + } + $schemaFinder = new \PHPUnit\TextUI\XmlConfiguration\SchemaFinder(); + $validator = new \PHPUnit\TextUI\XmlConfiguration\Validator(); + foreach ($schemaFinder->available() as $version) { + try { + $xsdFilename = $schemaFinder->find($version); + } catch (\PHPUnit\TextUI\XmlConfiguration\CannotFindSchemaException) { + continue; + } + if (!$validator->validate($document, $xsdFilename)->hasValidationErrors()) { + return; + } + } + throw new \PHPUnit\TextUI\XmlConfiguration\Exception(sprintf('XML configuration file %s does not validate against any supported PHPUnit schema:' . PHP_EOL . '%s', $configurationFile, $validationResult->asString())); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging; + +use PHPUnit\TextUI\Configuration\File; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Junit +{ + private File $target; + public function __construct(File $target) + { + $this->target = $target; + } + public function target(): File + { + return $this->target; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging; + +use PHPUnit\TextUI\XmlConfiguration\Exception; +use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Html as TestDoxHtml; +use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Text as TestDoxText; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Logging +{ + private ?\PHPUnit\TextUI\XmlConfiguration\Logging\Junit $junit; + private ?\PHPUnit\TextUI\XmlConfiguration\Logging\Otr $otr; + private ?\PHPUnit\TextUI\XmlConfiguration\Logging\TeamCity $teamCity; + private ?TestDoxHtml $testDoxHtml; + private ?TestDoxText $testDoxText; + public function __construct(?\PHPUnit\TextUI\XmlConfiguration\Logging\Junit $junit, ?\PHPUnit\TextUI\XmlConfiguration\Logging\Otr $otr, ?\PHPUnit\TextUI\XmlConfiguration\Logging\TeamCity $teamCity, ?TestDoxHtml $testDoxHtml, ?TestDoxText $testDoxText) + { + $this->junit = $junit; + $this->otr = $otr; + $this->teamCity = $teamCity; + $this->testDoxHtml = $testDoxHtml; + $this->testDoxText = $testDoxText; + } + public function hasJunit(): bool + { + return $this->junit !== null; + } + /** + * @throws Exception + */ + public function junit(): \PHPUnit\TextUI\XmlConfiguration\Logging\Junit + { + if ($this->junit === null) { + throw new Exception('Logger "JUnit XML" is not configured'); + } + return $this->junit; + } + public function hasOtr(): bool + { + return $this->otr !== null; + } + /** + * @throws Exception + */ + public function otr(): \PHPUnit\TextUI\XmlConfiguration\Logging\Otr + { + if ($this->otr === null) { + throw new Exception('Logger "Open Test Reporting XML" is not configured'); + } + return $this->otr; + } + public function hasTeamCity(): bool + { + return $this->teamCity !== null; + } + /** + * @throws Exception + */ + public function teamCity(): \PHPUnit\TextUI\XmlConfiguration\Logging\TeamCity + { + if ($this->teamCity === null) { + throw new Exception('Logger "Team City" is not configured'); + } + return $this->teamCity; + } + public function hasTestDoxHtml(): bool + { + return $this->testDoxHtml !== null; + } + /** + * @throws Exception + */ + public function testDoxHtml(): TestDoxHtml + { + if ($this->testDoxHtml === null) { + throw new Exception('Logger "TestDox HTML" is not configured'); + } + return $this->testDoxHtml; + } + public function hasTestDoxText(): bool + { + return $this->testDoxText !== null; + } + /** + * @throws Exception + */ + public function testDoxText(): TestDoxText + { + if ($this->testDoxText === null) { + throw new Exception('Logger "TestDox Text" is not configured'); + } + return $this->testDoxText; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging; + +use PHPUnit\TextUI\Configuration\File; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Otr +{ + private File $target; + private bool $includeGitInformation; + public function __construct(File $target, bool $includeGitInformation) + { + $this->target = $target; + $this->includeGitInformation = $includeGitInformation; + } + public function target(): File + { + return $this->target; + } + public function includeGitInformation(): bool + { + return $this->includeGitInformation; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging; + +use PHPUnit\TextUI\Configuration\File; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class TeamCity +{ + private File $target; + public function __construct(File $target) + { + $this->target = $target; + } + public function target(): File + { + return $this->target; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging\TestDox; + +use PHPUnit\TextUI\Configuration\File; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Html +{ + private File $target; + public function __construct(File $target) + { + $this->target = $target; + } + public function target(): File + { + return $this->target; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging\TestDox; + +use PHPUnit\TextUI\Configuration\File; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Text +{ + private File $target; + public function __construct(File $target) + { + $this->target = $target; + } + public function target(): File + { + return $this->target; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function version_compare; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MigrationBuilder +{ + /** + * @var non-empty-array> + */ + private const array AVAILABLE_MIGRATIONS = ['8.5' => [\PHPUnit\TextUI\XmlConfiguration\RemoveLogTypes::class], '9.2' => [\PHPUnit\TextUI\XmlConfiguration\RemoveCacheTokensAttribute::class, \PHPUnit\TextUI\XmlConfiguration\IntroduceCoverageElement::class, \PHPUnit\TextUI\XmlConfiguration\MoveAttributesFromRootToCoverage::class, \PHPUnit\TextUI\XmlConfiguration\MoveAttributesFromFilterWhitelistToCoverage::class, \PHPUnit\TextUI\XmlConfiguration\MoveWhitelistIncludesToCoverage::class, \PHPUnit\TextUI\XmlConfiguration\MoveWhitelistExcludesToCoverage::class, \PHPUnit\TextUI\XmlConfiguration\RemoveEmptyFilter::class, \PHPUnit\TextUI\XmlConfiguration\CoverageCloverToReport::class, \PHPUnit\TextUI\XmlConfiguration\CoverageCrap4jToReport::class, \PHPUnit\TextUI\XmlConfiguration\CoverageHtmlToReport::class, \PHPUnit\TextUI\XmlConfiguration\CoveragePhpToReport::class, \PHPUnit\TextUI\XmlConfiguration\CoverageTextToReport::class, \PHPUnit\TextUI\XmlConfiguration\CoverageXmlToReport::class, \PHPUnit\TextUI\XmlConfiguration\ConvertLogTypes::class], '9.6' => [\PHPUnit\TextUI\XmlConfiguration\RemoveListeners::class, \PHPUnit\TextUI\XmlConfiguration\RemoveTestSuiteLoaderAttributes::class, \PHPUnit\TextUI\XmlConfiguration\RemoveCacheResultFileAttribute::class, \PHPUnit\TextUI\XmlConfiguration\RemoveCoverageElementCacheDirectoryAttribute::class, \PHPUnit\TextUI\XmlConfiguration\RemoveCoverageElementProcessUncoveredFilesAttribute::class, \PHPUnit\TextUI\XmlConfiguration\IntroduceCacheDirectoryAttribute::class, \PHPUnit\TextUI\XmlConfiguration\RenameBackupStaticAttributesAttribute::class, \PHPUnit\TextUI\XmlConfiguration\RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute::class, \PHPUnit\TextUI\XmlConfiguration\RemoveBeStrictAboutTodoAnnotatedTestsAttribute::class, \PHPUnit\TextUI\XmlConfiguration\RemovePrinterAttributes::class, \PHPUnit\TextUI\XmlConfiguration\RemoveVerboseAttribute::class, \PHPUnit\TextUI\XmlConfiguration\RenameForceCoversAnnotationAttribute::class, \PHPUnit\TextUI\XmlConfiguration\RenameBeStrictAboutCoversAnnotationAttribute::class, \PHPUnit\TextUI\XmlConfiguration\RemoveConversionToExceptionsAttributes::class, \PHPUnit\TextUI\XmlConfiguration\RemoveNoInteractionAttribute::class, \PHPUnit\TextUI\XmlConfiguration\RemoveLoggingElements::class, \PHPUnit\TextUI\XmlConfiguration\RemoveTestDoxGroupsElement::class], '10.0' => [\PHPUnit\TextUI\XmlConfiguration\MoveCoverageDirectoriesToSource::class], '10.4' => [\PHPUnit\TextUI\XmlConfiguration\RemoveBeStrictAboutTodoAnnotatedTestsAttribute::class], '10.5' => [\PHPUnit\TextUI\XmlConfiguration\RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute::class], '11.0' => [\PHPUnit\TextUI\XmlConfiguration\ReplaceRestrictDeprecationsWithIgnoreDeprecations::class], '11.1' => [\PHPUnit\TextUI\XmlConfiguration\RemoveCacheResultFileAttribute::class, \PHPUnit\TextUI\XmlConfiguration\RemoveCoverageElementCacheDirectoryAttribute::class], '11.2' => [\PHPUnit\TextUI\XmlConfiguration\RemoveBeStrictAboutTodoAnnotatedTestsAttribute::class]]; + /** + * @return non-empty-list + */ + public function build(string $fromVersion): array + { + $stack = [new \PHPUnit\TextUI\XmlConfiguration\UpdateSchemaLocation()]; + foreach (self::AVAILABLE_MIGRATIONS as $version => $migrations) { + if (version_compare($version, $fromVersion, '<')) { + continue; + } + foreach ($migrations as $migration) { + $stack[] = new $migration(); + } + } + return $stack; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\Exception; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MigrationException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ConvertLogTypes implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $logging = $document->getElementsByTagName('logging')->item(0); + if (!$logging instanceof DOMElement) { + return; + } + $types = ['junit' => 'junit', 'teamcity' => 'teamcity', 'testdox-html' => 'testdoxHtml', 'testdox-text' => 'testdoxText', 'testdox-xml' => 'testdoxXml', 'plain' => 'text']; + $logNodes = []; + foreach ($logging->getElementsByTagName('log') as $logNode) { + if (!isset($types[$logNode->getAttribute('type')])) { + continue; + } + $logNodes[] = $logNode; + } + foreach ($logNodes as $oldNode) { + $newLogNode = $document->createElement($types[$oldNode->getAttribute('type')]); + $newLogNode->setAttribute('outputFile', $oldNode->getAttribute('target')); + $logging->replaceChild($newLogNode, $oldNode); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoverageCloverToReport extends \PHPUnit\TextUI\XmlConfiguration\LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-clover'; + } + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $clover = $logNode->ownerDocument->createElement('clover'); + $clover->setAttribute('outputFile', $logNode->getAttribute('target')); + return $clover; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoverageCrap4jToReport extends \PHPUnit\TextUI\XmlConfiguration\LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-crap4j'; + } + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $crap4j = $logNode->ownerDocument->createElement('crap4j'); + $crap4j->setAttribute('outputFile', $logNode->getAttribute('target')); + $this->migrateAttributes($logNode, $crap4j, ['threshold']); + return $crap4j; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoverageHtmlToReport extends \PHPUnit\TextUI\XmlConfiguration\LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-html'; + } + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $html = $logNode->ownerDocument->createElement('html'); + $html->setAttribute('outputDirectory', $logNode->getAttribute('target')); + $this->migrateAttributes($logNode, $html, ['lowUpperBound', 'highLowerBound']); + return $html; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoveragePhpToReport extends \PHPUnit\TextUI\XmlConfiguration\LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-php'; + } + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $php = $logNode->ownerDocument->createElement('php'); + $php->setAttribute('outputFile', $logNode->getAttribute('target')); + return $php; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoverageTextToReport extends \PHPUnit\TextUI\XmlConfiguration\LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-text'; + } + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $text = $logNode->ownerDocument->createElement('text'); + $text->setAttribute('outputFile', $logNode->getAttribute('target')); + $this->migrateAttributes($logNode, $text, ['showUncoveredFiles', 'showOnlySummary']); + return $text; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoverageXmlToReport extends \PHPUnit\TextUI\XmlConfiguration\LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-xml'; + } + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $xml = $logNode->ownerDocument->createElement('xml'); + $xml->setAttribute('outputDirectory', $logNode->getAttribute('target')); + return $xml; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IntroduceCacheDirectoryAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('cacheDirectory')) { + return; + } + $root->setAttribute('cacheDirectory', '.phpunit.cache'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IntroduceCoverageElement implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $coverage = $document->createElement('coverage'); + $document->documentElement->insertBefore($coverage, $document->documentElement->firstChild); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use function sprintf; +use DOMDocument; +use DOMElement; +use DOMXPath; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class LogToReportMigration implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $coverage = $document->getElementsByTagName('coverage')->item(0); + if (!$coverage instanceof DOMElement) { + throw new \PHPUnit\TextUI\XmlConfiguration\MigrationException('Unexpected state - No coverage element'); + } + $logNode = $this->findLogNode($document); + if ($logNode === null) { + return; + } + $reportChild = $this->toReportFormat($logNode); + $report = $coverage->getElementsByTagName('report')->item(0); + if ($report === null) { + $report = $coverage->appendChild($document->createElement('report')); + } + $report->appendChild($reportChild); + $logNode->parentNode->removeChild($logNode); + } + /** + * @param list $attributes + */ + protected function migrateAttributes(DOMElement $src, DOMElement $dest, array $attributes): void + { + foreach ($attributes as $attr) { + if (!$src->hasAttribute($attr)) { + continue; + } + $dest->setAttribute($attr, $src->getAttribute($attr)); + $src->removeAttribute($attr); + } + } + abstract protected function forType(): string; + abstract protected function toReportFormat(DOMElement $logNode): DOMElement; + private function findLogNode(DOMDocument $document): ?DOMElement + { + $xpath = new DOMXPath($document); + $logNode = $xpath->query(sprintf('//logging/log[@type="%s"]', $this->forType())); + assert($logNode !== \false); + $logNode = $logNode->item(0); + if (!$logNode instanceof DOMElement) { + return null; + } + return $logNode; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Migration +{ + public function migrate(DOMDocument $document): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MoveAttributesFromFilterWhitelistToCoverage implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $whitelist = $document->getElementsByTagName('whitelist')->item(0); + if ($whitelist === null) { + return; + } + $coverage = $document->getElementsByTagName('coverage')->item(0); + if (!$coverage instanceof DOMElement) { + throw new \PHPUnit\TextUI\XmlConfiguration\MigrationException('Unexpected state - No coverage element'); + } + $map = ['addUncoveredFilesFromWhitelist' => 'includeUncoveredFiles', 'processUncoveredFilesFromWhitelist' => 'processUncoveredFiles']; + foreach ($map as $old => $new) { + if (!$whitelist->hasAttribute($old)) { + continue; + } + $coverage->setAttribute($new, $whitelist->getAttribute($old)); + $whitelist->removeAttribute($old); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MoveAttributesFromRootToCoverage implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $map = ['disableCodeCoverageIgnore' => 'disableCodeCoverageIgnore', 'ignoreDeprecatedCodeUnitsFromCodeCoverage' => 'ignoreDeprecatedCodeUnits']; + $root = $document->documentElement; + assert($root instanceof DOMElement); + $coverage = $document->getElementsByTagName('coverage')->item(0); + if (!$coverage instanceof DOMElement) { + throw new \PHPUnit\TextUI\XmlConfiguration\MigrationException('Unexpected state - No coverage element'); + } + foreach ($map as $old => $new) { + if (!$root->hasAttribute($old)) { + continue; + } + $coverage->setAttribute($new, $root->getAttribute($old)); + $root->removeAttribute($old); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +use DOMXPath; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MoveCoverageDirectoriesToSource implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $source = $document->getElementsByTagName('source')->item(0); + if ($source !== null) { + return; + } + $coverage = $document->getElementsByTagName('coverage')->item(0); + if ($coverage === null) { + return; + } + $root = $document->documentElement; + assert($root instanceof DOMElement); + $source = $document->createElement('source'); + $root->appendChild($source); + $xpath = new DOMXPath($document); + foreach (['include', 'exclude'] as $element) { + $nodes = $xpath->query('//coverage/' . $element); + assert($nodes !== \false); + foreach (\PHPUnit\TextUI\XmlConfiguration\SnapshotNodeList::fromNodeList($nodes) as $node) { + $source->appendChild($node); + } + } + if ($coverage->childElementCount !== 0) { + return; + } + assert($coverage->parentNode !== null); + $coverage->parentNode->removeChild($coverage); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use function in_array; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MoveWhitelistExcludesToCoverage implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $whitelist = $document->getElementsByTagName('whitelist')->item(0); + if ($whitelist === null) { + return; + } + $excludeNodes = \PHPUnit\TextUI\XmlConfiguration\SnapshotNodeList::fromNodeList($whitelist->getElementsByTagName('exclude')); + if ($excludeNodes->count() === 0) { + return; + } + $coverage = $document->getElementsByTagName('coverage')->item(0); + if (!$coverage instanceof DOMElement) { + throw new \PHPUnit\TextUI\XmlConfiguration\MigrationException('Unexpected state - No coverage element'); + } + $targetExclude = $coverage->getElementsByTagName('exclude')->item(0); + if ($targetExclude === null) { + $targetExclude = $coverage->appendChild($document->createElement('exclude')); + } + foreach ($excludeNodes as $excludeNode) { + assert($excludeNode instanceof DOMElement); + foreach (\PHPUnit\TextUI\XmlConfiguration\SnapshotNodeList::fromNodeList($excludeNode->childNodes) as $child) { + if (!$child instanceof DOMElement || !in_array($child->nodeName, ['directory', 'file'], \true)) { + continue; + } + $targetExclude->appendChild($child); + } + if ($excludeNode->getElementsByTagName('*')->count() !== 0) { + throw new \PHPUnit\TextUI\XmlConfiguration\MigrationException('Dangling child elements in exclude found.'); + } + $whitelist->removeChild($excludeNode); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MoveWhitelistIncludesToCoverage implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $whitelist = $document->getElementsByTagName('whitelist')->item(0); + if ($whitelist === null) { + return; + } + $coverage = $document->getElementsByTagName('coverage')->item(0); + if (!$coverage instanceof DOMElement) { + throw new \PHPUnit\TextUI\XmlConfiguration\MigrationException('Unexpected state - No coverage element'); + } + $include = $document->createElement('include'); + $coverage->appendChild($include); + foreach (\PHPUnit\TextUI\XmlConfiguration\SnapshotNodeList::fromNodeList($whitelist->childNodes) as $child) { + if (!$child instanceof DOMElement) { + continue; + } + if (!($child->nodeName === 'directory' || $child->nodeName === 'file')) { + continue; + } + $include->appendChild($child); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('beStrictAboutResourceUsageDuringSmallTests')) { + $root->removeAttribute('beStrictAboutResourceUsageDuringSmallTests'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveBeStrictAboutTodoAnnotatedTestsAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('beStrictAboutTodoAnnotatedTests')) { + $root->removeAttribute('beStrictAboutTodoAnnotatedTests'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveCacheResultFileAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('cacheResultFile')) { + $root->removeAttribute('cacheResultFile'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveCacheTokensAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('cacheTokens')) { + $root->removeAttribute('cacheTokens'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveConversionToExceptionsAttributes implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('convertDeprecationsToExceptions')) { + $root->removeAttribute('convertDeprecationsToExceptions'); + } + if ($root->hasAttribute('convertErrorsToExceptions')) { + $root->removeAttribute('convertErrorsToExceptions'); + } + if ($root->hasAttribute('convertNoticesToExceptions')) { + $root->removeAttribute('convertNoticesToExceptions'); + } + if ($root->hasAttribute('convertWarningsToExceptions')) { + $root->removeAttribute('convertWarningsToExceptions'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveCoverageElementCacheDirectoryAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $node = $document->getElementsByTagName('coverage')->item(0); + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + if ($node->hasAttribute('cacheDirectory')) { + $node->removeAttribute('cacheDirectory'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveCoverageElementProcessUncoveredFilesAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $node = $document->getElementsByTagName('coverage')->item(0); + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + if ($node->hasAttribute('processUncoveredFiles')) { + $node->removeAttribute('processUncoveredFiles'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function sprintf; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveEmptyFilter implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $whitelist = $document->getElementsByTagName('whitelist')->item(0); + if ($whitelist instanceof DOMElement) { + $this->ensureEmpty($whitelist); + $whitelist->parentNode->removeChild($whitelist); + } + $filter = $document->getElementsByTagName('filter')->item(0); + if ($filter instanceof DOMElement) { + $this->ensureEmpty($filter); + $filter->parentNode->removeChild($filter); + } + } + /** + * @throws MigrationException + */ + private function ensureEmpty(DOMElement $element): void + { + if ($element->attributes->length > 0) { + throw new \PHPUnit\TextUI\XmlConfiguration\MigrationException(sprintf('%s element has unexpected attributes', $element->nodeName)); + } + if ($element->getElementsByTagName('*')->length > 0) { + throw new \PHPUnit\TextUI\XmlConfiguration\MigrationException(sprintf('%s element has unexpected children', $element->nodeName)); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveListeners implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $node = $document->getElementsByTagName('listeners')->item(0); + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + $node->parentNode->removeChild($node); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveLogTypes implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $logging = $document->getElementsByTagName('logging')->item(0); + if (!$logging instanceof DOMElement) { + return; + } + foreach (\PHPUnit\TextUI\XmlConfiguration\SnapshotNodeList::fromNodeList($logging->getElementsByTagName('log')) as $logNode) { + assert($logNode instanceof DOMElement); + switch ($logNode->getAttribute('type')) { + case 'json': + case 'tap': + $logging->removeChild($logNode); + } + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +use DOMXPath; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveLoggingElements implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $this->removeTestDoxElement($document); + $this->removeTextElement($document); + } + private function removeTestDoxElement(DOMDocument $document): void + { + $nodes = (new DOMXPath($document))->query('logging/testdoxXml'); + assert($nodes !== \false); + $node = $nodes->item(0); + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + $node->parentNode->removeChild($node); + } + private function removeTextElement(DOMDocument $document): void + { + $nodes = (new DOMXPath($document))->query('logging/text'); + assert($nodes !== \false); + $node = $nodes->item(0); + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + $node->parentNode->removeChild($node); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveNoInteractionAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('noInteraction')) { + $root->removeAttribute('noInteraction'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemovePrinterAttributes implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('printerClass')) { + $root->removeAttribute('printerClass'); + } + if ($root->hasAttribute('printerFile')) { + $root->removeAttribute('printerFile'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('registerMockObjectsFromTestArgumentsRecursively')) { + $root->removeAttribute('registerMockObjectsFromTestArgumentsRecursively'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveTestDoxGroupsElement implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $node = $document->getElementsByTagName('testdoxGroups')->item(0); + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + $node->parentNode->removeChild($node); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveTestSuiteLoaderAttributes implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('testSuiteLoaderClass')) { + $root->removeAttribute('testSuiteLoaderClass'); + } + if ($root->hasAttribute('testSuiteLoaderFile')) { + $root->removeAttribute('testSuiteLoaderFile'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveVerboseAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('verbose')) { + $root->removeAttribute('verbose'); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RenameBackupStaticAttributesAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('backupStaticProperties')) { + return; + } + if (!$root->hasAttribute('backupStaticAttributes')) { + return; + } + $root->setAttribute('backupStaticProperties', $root->getAttribute('backupStaticAttributes')); + $root->removeAttribute('backupStaticAttributes'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RenameBeStrictAboutCoversAnnotationAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('beStrictAboutCoverageMetadata')) { + return; + } + if (!$root->hasAttribute('beStrictAboutCoversAnnotation')) { + return; + } + $root->setAttribute('beStrictAboutCoverageMetadata', $root->getAttribute('beStrictAboutCoversAnnotation')); + $root->removeAttribute('beStrictAboutCoversAnnotation'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RenameForceCoversAnnotationAttribute implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + if ($root->hasAttribute('requireCoverageMetadata')) { + return; + } + if (!$root->hasAttribute('forceCoversAnnotation')) { + return; + } + $root->setAttribute('requireCoverageMetadata', $root->getAttribute('forceCoversAnnotation')); + $root->removeAttribute('forceCoversAnnotation'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ReplaceRestrictDeprecationsWithIgnoreDeprecations implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $source = $document->getElementsByTagName('source')->item(0); + if ($source === null) { + return; + } + assert($source instanceof DOMElement); + if (!$source->hasAttribute('restrictDeprecations')) { + return; + } + $restrictDeprecations = $source->getAttribute('restrictDeprecations') === 'true'; + $source->removeAttribute('restrictDeprecations'); + if (!$restrictDeprecations || $source->hasAttribute('ignoreIndirectDeprecations')) { + return; + } + $source->setAttribute('ignoreIndirectDeprecations', 'true'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use function str_contains; +use DOMDocument; +use DOMElement; +use PHPUnit\Runner\Version; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UpdateSchemaLocation implements \PHPUnit\TextUI\XmlConfiguration\Migration +{ + private const string NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema-instance'; + private const string LOCAL_NAME_SCHEMA_LOCATION = 'noNamespaceSchemaLocation'; + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + $existingSchemaLocation = $root->getAttributeNS(self::NAMESPACE_URI, self::LOCAL_NAME_SCHEMA_LOCATION); + if (str_contains($existingSchemaLocation, '://') === \false) { + // If the current schema location is a relative path, don't update it + return; + } + $root->setAttributeNS(self::NAMESPACE_URI, 'xsi:' . self::LOCAL_NAME_SCHEMA_LOCATION, 'https://schema.phpunit.de/' . Version::series() . '/phpunit.xsd'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use function str_contains; +use DOMDocument; +use DOMElement; +use PHPUnit\Runner\Version; +use PHPUnit\Util\Xml\Loader as XmlLoader; +use PHPUnit\Util\Xml\XmlException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Migrator +{ + /** + * @throws Exception + * @throws MigrationException + * @throws XmlException + */ + public function migrate(string $filename): string + { + $origin = (new \PHPUnit\TextUI\XmlConfiguration\SchemaDetector())->detect($filename); + if (!$origin->detected()) { + throw new \PHPUnit\TextUI\XmlConfiguration\Exception('The file does not validate against any known schema'); + } + $configurationDocument = (new XmlLoader())->loadFile($filename); + if ($origin->version() === Version::series()) { + if (!$this->schemaLocationNeedsUpdate($configurationDocument)) { + throw new \PHPUnit\TextUI\XmlConfiguration\Exception('The file does not need to be migrated'); + } + (new \PHPUnit\TextUI\XmlConfiguration\UpdateSchemaLocation())->migrate($configurationDocument); + } else { + foreach ((new \PHPUnit\TextUI\XmlConfiguration\MigrationBuilder())->build($origin->version()) as $migration) { + $migration->migrate($configurationDocument); + } + } + $configurationDocument->formatOutput = \true; + $configurationDocument->preserveWhiteSpace = \false; + $xml = $configurationDocument->saveXML(); + assert($xml !== \false); + return $xml; + } + private function schemaLocationNeedsUpdate(DOMDocument $document): bool + { + $root = $document->documentElement; + assert($root instanceof DOMElement); + $schemaLocation = $root->getAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'noNamespaceSchemaLocation'); + if (!str_contains($schemaLocation, '://')) { + return \false; + } + return $schemaLocation !== 'https://schema.phpunit.de/' . Version::series() . '/phpunit.xsd'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function count; +use ArrayIterator; +use Countable; +use DOMNode; +use DOMNodeList; +use IteratorAggregate; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @template-implements IteratorAggregate + */ +final class SnapshotNodeList implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $nodes = []; + /** + * @param DOMNodeList $list + */ + public static function fromNodeList(DOMNodeList $list): self + { + $snapshot = new self(); + foreach ($list as $node) { + $snapshot->nodes[] = $node; + } + return $snapshot; + } + public function count(): int + { + return count($this->nodes); + } + /** + * @return ArrayIterator + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->nodes); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class PHPUnit +{ + private ?string $cacheDirectory; + private bool $cacheResult; + private int|string $columns; + private string $colors; + private bool $stderr; + private bool $displayDetailsOnAllIssues; + private bool $displayDetailsOnIncompleteTests; + private bool $displayDetailsOnSkippedTests; + private bool $displayDetailsOnTestsThatTriggerDeprecations; + private bool $displayDetailsOnPhpunitDeprecations; + private bool $displayDetailsOnPhpunitNotices; + private bool $displayDetailsOnTestsThatTriggerErrors; + private bool $displayDetailsOnTestsThatTriggerNotices; + private bool $displayDetailsOnTestsThatTriggerWarnings; + private bool $reverseDefectList; + private bool $requireCoverageMetadata; + private bool $requireSealedMockObjects; + private ?string $bootstrap; + /** + * @var array + */ + private array $bootstrapForTestSuite; + private bool $processIsolation; + private bool $failOnAllIssues; + private bool $failOnDeprecation; + private bool $failOnPhpunitDeprecation; + private bool $failOnPhpunitNotice; + private bool $failOnPhpunitWarning; + private bool $failOnEmptyTestSuite; + private bool $hasFailOnEmptyTestSuite; + private bool $failOnIncomplete; + private bool $failOnNotice; + private bool $failOnRisky; + private bool $failOnSkipped; + private bool $failOnWarning; + private bool $stopOnDefect; + private bool $stopOnDeprecation; + private bool $stopOnError; + private bool $stopOnFailure; + private bool $stopOnIncomplete; + private bool $stopOnNotice; + private bool $stopOnRisky; + private bool $stopOnSkipped; + private bool $stopOnWarning; + /** + * @var ?non-empty-string + */ + private ?string $extensionsDirectory; + private bool $beStrictAboutChangesToGlobalState; + private bool $beStrictAboutOutputDuringTests; + private bool $beStrictAboutTestsThatDoNotTestAnything; + private bool $beStrictAboutCoverageMetadata; + private bool $enforceTimeLimit; + private int $defaultTimeLimit; + private int $timeoutForSmallTests; + private int $timeoutForMediumTests; + private int $timeoutForLargeTests; + private ?string $defaultTestSuite; + private int $executionOrder; + private bool $resolveDependencies; + private bool $defectsFirst; + private bool $backupGlobals; + private bool $backupStaticProperties; + private bool $testdoxPrinter; + private bool $testdoxPrinterSummary; + private bool $controlGarbageCollector; + private int $numberOfTestsBeforeGarbageCollection; + /** + * @var non-negative-int + */ + private int $shortenArraysForExportThreshold; + /** + * @param array $bootstrapForTestSuite + * @param ?non-empty-string $extensionsDirectory + * @param non-negative-int $shortenArraysForExportThreshold + */ + public function __construct(?string $cacheDirectory, bool $cacheResult, int|string $columns, string $colors, bool $stderr, bool $displayDetailsOnAllIssues, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnPhpunitDeprecations, bool $displayDetailsOnPhpunitNotices, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $reverseDefectList, bool $requireCoverageMetadata, bool $requireSealedMockObjects, ?string $bootstrap, array $bootstrapForTestSuite, bool $processIsolation, bool $failOnAllIssues, bool $failOnDeprecation, bool $failOnPhpunitDeprecation, bool $failOnPhpunitNotice, bool $failOnPhpunitWarning, bool $failOnEmptyTestSuite, bool $hasFailOnEmptyTestSuite, bool $failOnIncomplete, bool $failOnNotice, bool $failOnRisky, bool $failOnSkipped, bool $failOnWarning, bool $stopOnDefect, bool $stopOnDeprecation, bool $stopOnError, bool $stopOnFailure, bool $stopOnIncomplete, bool $stopOnNotice, bool $stopOnRisky, bool $stopOnSkipped, bool $stopOnWarning, ?string $extensionsDirectory, bool $beStrictAboutChangesToGlobalState, bool $beStrictAboutOutputDuringTests, bool $beStrictAboutTestsThatDoNotTestAnything, bool $beStrictAboutCoverageMetadata, bool $enforceTimeLimit, int $defaultTimeLimit, int $timeoutForSmallTests, int $timeoutForMediumTests, int $timeoutForLargeTests, ?string $defaultTestSuite, int $executionOrder, bool $resolveDependencies, bool $defectsFirst, bool $backupGlobals, bool $backupStaticProperties, bool $testdoxPrinter, bool $testdoxPrinterSummary, bool $controlGarbageCollector, int $numberOfTestsBeforeGarbageCollection, int $shortenArraysForExportThreshold) + { + $this->cacheDirectory = $cacheDirectory; + $this->cacheResult = $cacheResult; + $this->columns = $columns; + $this->colors = $colors; + $this->stderr = $stderr; + $this->displayDetailsOnAllIssues = $displayDetailsOnAllIssues; + $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; + $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; + $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; + $this->displayDetailsOnPhpunitDeprecations = $displayDetailsOnPhpunitDeprecations; + $this->displayDetailsOnPhpunitNotices = $displayDetailsOnPhpunitNotices; + $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; + $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; + $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; + $this->reverseDefectList = $reverseDefectList; + $this->requireCoverageMetadata = $requireCoverageMetadata; + $this->requireSealedMockObjects = $requireSealedMockObjects; + $this->bootstrap = $bootstrap; + $this->bootstrapForTestSuite = $bootstrapForTestSuite; + $this->processIsolation = $processIsolation; + $this->failOnAllIssues = $failOnAllIssues; + $this->failOnDeprecation = $failOnDeprecation; + $this->failOnPhpunitDeprecation = $failOnPhpunitDeprecation; + $this->failOnPhpunitNotice = $failOnPhpunitNotice; + $this->failOnPhpunitWarning = $failOnPhpunitWarning; + $this->failOnEmptyTestSuite = $failOnEmptyTestSuite; + $this->hasFailOnEmptyTestSuite = $hasFailOnEmptyTestSuite; + $this->failOnIncomplete = $failOnIncomplete; + $this->failOnNotice = $failOnNotice; + $this->failOnRisky = $failOnRisky; + $this->failOnSkipped = $failOnSkipped; + $this->failOnWarning = $failOnWarning; + $this->stopOnDefect = $stopOnDefect; + $this->stopOnDeprecation = $stopOnDeprecation; + $this->stopOnError = $stopOnError; + $this->stopOnFailure = $stopOnFailure; + $this->stopOnIncomplete = $stopOnIncomplete; + $this->stopOnNotice = $stopOnNotice; + $this->stopOnRisky = $stopOnRisky; + $this->stopOnSkipped = $stopOnSkipped; + $this->stopOnWarning = $stopOnWarning; + $this->extensionsDirectory = $extensionsDirectory; + $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState; + $this->beStrictAboutOutputDuringTests = $beStrictAboutOutputDuringTests; + $this->beStrictAboutTestsThatDoNotTestAnything = $beStrictAboutTestsThatDoNotTestAnything; + $this->beStrictAboutCoverageMetadata = $beStrictAboutCoverageMetadata; + $this->enforceTimeLimit = $enforceTimeLimit; + $this->defaultTimeLimit = $defaultTimeLimit; + $this->timeoutForSmallTests = $timeoutForSmallTests; + $this->timeoutForMediumTests = $timeoutForMediumTests; + $this->timeoutForLargeTests = $timeoutForLargeTests; + $this->defaultTestSuite = $defaultTestSuite; + $this->executionOrder = $executionOrder; + $this->resolveDependencies = $resolveDependencies; + $this->defectsFirst = $defectsFirst; + $this->backupGlobals = $backupGlobals; + $this->backupStaticProperties = $backupStaticProperties; + $this->testdoxPrinter = $testdoxPrinter; + $this->testdoxPrinterSummary = $testdoxPrinterSummary; + $this->controlGarbageCollector = $controlGarbageCollector; + $this->numberOfTestsBeforeGarbageCollection = $numberOfTestsBeforeGarbageCollection; + $this->shortenArraysForExportThreshold = $shortenArraysForExportThreshold; + } + /** + * @phpstan-assert-if-true !null $this->cacheDirectory + */ + public function hasCacheDirectory(): bool + { + return $this->cacheDirectory !== null; + } + /** + * @throws Exception + */ + public function cacheDirectory(): string + { + if (!$this->hasCacheDirectory()) { + throw new \PHPUnit\TextUI\XmlConfiguration\Exception('Cache directory is not configured'); + } + return $this->cacheDirectory; + } + public function cacheResult(): bool + { + return $this->cacheResult; + } + public function columns(): int|string + { + return $this->columns; + } + public function colors(): string + { + return $this->colors; + } + public function stderr(): bool + { + return $this->stderr; + } + public function displayDetailsOnAllIssues(): bool + { + return $this->displayDetailsOnAllIssues; + } + public function displayDetailsOnIncompleteTests(): bool + { + return $this->displayDetailsOnIncompleteTests; + } + public function displayDetailsOnSkippedTests(): bool + { + return $this->displayDetailsOnSkippedTests; + } + public function displayDetailsOnTestsThatTriggerDeprecations(): bool + { + return $this->displayDetailsOnTestsThatTriggerDeprecations; + } + public function displayDetailsOnPhpunitDeprecations(): bool + { + return $this->displayDetailsOnPhpunitDeprecations; + } + public function displayDetailsOnPhpunitNotices(): bool + { + return $this->displayDetailsOnPhpunitNotices; + } + public function displayDetailsOnTestsThatTriggerErrors(): bool + { + return $this->displayDetailsOnTestsThatTriggerErrors; + } + public function displayDetailsOnTestsThatTriggerNotices(): bool + { + return $this->displayDetailsOnTestsThatTriggerNotices; + } + public function displayDetailsOnTestsThatTriggerWarnings(): bool + { + return $this->displayDetailsOnTestsThatTriggerWarnings; + } + public function reverseDefectList(): bool + { + return $this->reverseDefectList; + } + public function requireCoverageMetadata(): bool + { + return $this->requireCoverageMetadata; + } + public function requireSealedMockObjects(): bool + { + return $this->requireSealedMockObjects; + } + /** + * @phpstan-assert-if-true !null $this->bootstrap + */ + public function hasBootstrap(): bool + { + return $this->bootstrap !== null; + } + /** + * @throws Exception + */ + public function bootstrap(): string + { + if (!$this->hasBootstrap()) { + throw new \PHPUnit\TextUI\XmlConfiguration\Exception('Bootstrap script is not configured'); + } + return $this->bootstrap; + } + /** + * @return array + */ + public function bootstrapForTestSuite(): array + { + return $this->bootstrapForTestSuite; + } + public function processIsolation(): bool + { + return $this->processIsolation; + } + public function failOnAllIssues(): bool + { + return $this->failOnAllIssues; + } + public function failOnDeprecation(): bool + { + return $this->failOnDeprecation; + } + public function failOnPhpunitDeprecation(): bool + { + return $this->failOnPhpunitDeprecation; + } + public function failOnPhpunitNotice(): bool + { + return $this->failOnPhpunitNotice; + } + public function failOnPhpunitWarning(): bool + { + return $this->failOnPhpunitWarning; + } + public function failOnEmptyTestSuite(): bool + { + return $this->failOnEmptyTestSuite; + } + public function hasFailOnEmptyTestSuite(): bool + { + return $this->hasFailOnEmptyTestSuite; + } + public function failOnIncomplete(): bool + { + return $this->failOnIncomplete; + } + public function failOnNotice(): bool + { + return $this->failOnNotice; + } + public function failOnRisky(): bool + { + return $this->failOnRisky; + } + public function failOnSkipped(): bool + { + return $this->failOnSkipped; + } + public function failOnWarning(): bool + { + return $this->failOnWarning; + } + public function stopOnDefect(): bool + { + return $this->stopOnDefect; + } + public function stopOnDeprecation(): bool + { + return $this->stopOnDeprecation; + } + public function stopOnError(): bool + { + return $this->stopOnError; + } + public function stopOnFailure(): bool + { + return $this->stopOnFailure; + } + public function stopOnIncomplete(): bool + { + return $this->stopOnIncomplete; + } + public function stopOnNotice(): bool + { + return $this->stopOnNotice; + } + public function stopOnRisky(): bool + { + return $this->stopOnRisky; + } + public function stopOnSkipped(): bool + { + return $this->stopOnSkipped; + } + public function stopOnWarning(): bool + { + return $this->stopOnWarning; + } + /** + * @phpstan-assert-if-true !null $this->extensionsDirectory + */ + public function hasExtensionsDirectory(): bool + { + return $this->extensionsDirectory !== null; + } + /** + * @throws Exception + * + * @return non-empty-string + */ + public function extensionsDirectory(): string + { + if (!$this->hasExtensionsDirectory()) { + throw new \PHPUnit\TextUI\XmlConfiguration\Exception('Extensions directory is not configured'); + } + return $this->extensionsDirectory; + } + public function beStrictAboutChangesToGlobalState(): bool + { + return $this->beStrictAboutChangesToGlobalState; + } + public function beStrictAboutOutputDuringTests(): bool + { + return $this->beStrictAboutOutputDuringTests; + } + public function beStrictAboutTestsThatDoNotTestAnything(): bool + { + return $this->beStrictAboutTestsThatDoNotTestAnything; + } + public function beStrictAboutCoverageMetadata(): bool + { + return $this->beStrictAboutCoverageMetadata; + } + public function enforceTimeLimit(): bool + { + return $this->enforceTimeLimit; + } + public function defaultTimeLimit(): int + { + return $this->defaultTimeLimit; + } + public function timeoutForSmallTests(): int + { + return $this->timeoutForSmallTests; + } + public function timeoutForMediumTests(): int + { + return $this->timeoutForMediumTests; + } + public function timeoutForLargeTests(): int + { + return $this->timeoutForLargeTests; + } + /** + * @phpstan-assert-if-true !null $this->defaultTestSuite + */ + public function hasDefaultTestSuite(): bool + { + return $this->defaultTestSuite !== null; + } + /** + * @throws Exception + */ + public function defaultTestSuite(): string + { + if (!$this->hasDefaultTestSuite()) { + throw new \PHPUnit\TextUI\XmlConfiguration\Exception('Default test suite is not configured'); + } + return $this->defaultTestSuite; + } + public function executionOrder(): int + { + return $this->executionOrder; + } + public function resolveDependencies(): bool + { + return $this->resolveDependencies; + } + public function defectsFirst(): bool + { + return $this->defectsFirst; + } + public function backupGlobals(): bool + { + return $this->backupGlobals; + } + public function backupStaticProperties(): bool + { + return $this->backupStaticProperties; + } + public function testdoxPrinter(): bool + { + return $this->testdoxPrinter; + } + public function testdoxPrinterSummary(): bool + { + return $this->testdoxPrinterSummary; + } + public function controlGarbageCollector(): bool + { + return $this->controlGarbageCollector; + } + public function numberOfTestsBeforeGarbageCollection(): int + { + return $this->numberOfTestsBeforeGarbageCollection; + } + /** + * @return non-negative-int + */ + public function shortenArraysForExportThreshold(): int + { + return $this->shortenArraysForExportThreshold; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class FailedSchemaDetectionResult extends \PHPUnit\TextUI\XmlConfiguration\SchemaDetectionResult +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\Util\Xml\XmlException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +abstract readonly class SchemaDetectionResult +{ + /** + * @phpstan-assert-if-true SuccessfulSchemaDetectionResult $this + */ + public function detected(): bool + { + return \false; + } + /** + * @throws XmlException + */ + public function version(): string + { + throw new XmlException('No supported schema was detected'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\Util\Xml\Loader; +use PHPUnit\Util\Xml\XmlException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class SchemaDetector +{ + /** + * @throws XmlException + */ + public function detect(string $filename): \PHPUnit\TextUI\XmlConfiguration\SchemaDetectionResult + { + $document = (new Loader())->loadFile($filename); + $schemaFinder = new \PHPUnit\TextUI\XmlConfiguration\SchemaFinder(); + foreach ($schemaFinder->available() as $candidate) { + $schema = (new \PHPUnit\TextUI\XmlConfiguration\SchemaFinder())->find($candidate); + if (!(new \PHPUnit\TextUI\XmlConfiguration\Validator())->validate($document, $schema)->hasValidationErrors()) { + return new \PHPUnit\TextUI\XmlConfiguration\SuccessfulSchemaDetectionResult($candidate); + } + } + return new \PHPUnit\TextUI\XmlConfiguration\FailedSchemaDetectionResult(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class SuccessfulSchemaDetectionResult extends \PHPUnit\TextUI\XmlConfiguration\SchemaDetectionResult +{ + /** + * @var non-empty-string + */ + private string $version; + /** + * @param non-empty-string $version + */ + public function __construct(string $version) + { + $this->version = $version; + } + public function detected(): bool + { + return \true; + } + /** + * @throws void + * + * @return non-empty-string + */ + public function version(): string + { + return $this->version; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use function defined; +use function is_file; +use function rsort; +use function sprintf; +use DirectoryIterator; +use PHPUnit\Runner\Version; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class SchemaFinder +{ + /** + * @return non-empty-list + */ + public function available(): array + { + $result = [Version::series()]; + foreach (new DirectoryIterator($this->path() . 'schema') as $file) { + if ($file->isDot()) { + continue; + } + $version = $file->getBasename('.xsd'); + assert($version !== ''); + $result[] = $version; + } + rsort($result); + return $result; + } + /** + * @throws CannotFindSchemaException + */ + public function find(string $version): string + { + if ($version === Version::series()) { + $filename = $this->path() . 'phpunit.xsd'; + } else { + $filename = $this->path() . 'schema/' . $version . '.xsd'; + } + if (!is_file($filename)) { + throw new \PHPUnit\TextUI\XmlConfiguration\CannotFindSchemaException(sprintf('Schema for PHPUnit %s is not available', $version)); + } + return $filename; + } + private function path(): string + { + if (defined('__PHPUNIT_PHAR_ROOT__')) { + return __PHPUNIT_PHAR_ROOT__ . '/'; + } + return __DIR__ . '/../../../../'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use const PHP_VERSION; +use function in_array; +use function is_dir; +use function is_file; +use function sprintf; +use function str_contains; +use function version_compare; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\Exception as FrameworkException; +use PHPUnit\Framework\TestSuite as TestSuiteObject; +use PHPUnit\TextUI\Configuration\TestSuiteCollection; +use PHPUnit\TextUI\RuntimeException; +use PHPUnit\TextUI\TestDirectoryNotFoundException; +use PHPUnit\TextUI\TestFileNotFoundException; +use PHPUnitPHAR\SebastianBergmann\FileIterator\Facade; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteMapper +{ + /** + * @param non-empty-string $xmlConfigurationFile + * @param list $includeTestSuites + * @param list $excludeTestSuites + * + * @throws RuntimeException + * @throws TestDirectoryNotFoundException + * @throws TestFileNotFoundException + */ + public function map(string $xmlConfigurationFile, TestSuiteCollection $configuredTestSuites, array $includeTestSuites, array $excludeTestSuites): TestSuiteObject + { + try { + $result = TestSuiteObject::empty($xmlConfigurationFile); + $processed = []; + foreach ($configuredTestSuites as $configuredTestSuite) { + if ($includeTestSuites !== [] && !in_array($configuredTestSuite->name(), $includeTestSuites, \true)) { + continue; + } + if ($excludeTestSuites !== [] && in_array($configuredTestSuite->name(), $excludeTestSuites, \true)) { + continue; + } + $testSuiteName = $configuredTestSuite->name(); + $exclude = []; + foreach ($configuredTestSuite->exclude()->asArray() as $file) { + $exclude[] = $file->path(); + } + $testSuite = TestSuiteObject::empty($configuredTestSuite->name()); + $empty = \true; + foreach ($configuredTestSuite->directories() as $directory) { + if (!str_contains($directory->path(), '*') && !is_dir($directory->path())) { + throw new TestDirectoryNotFoundException($directory->path()); + } + if (!version_compare(PHP_VERSION, $directory->phpVersion(), $directory->phpVersionOperator()->asString())) { + continue; + } + $files = (new Facade())->getFilesAsArray($directory->path(), $directory->suffix(), $directory->prefix(), $exclude); + $groups = $directory->groups(); + foreach ($files as $file) { + if (isset($processed[$file])) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot add file %s to test suite "%s" as it was already added to test suite "%s"', $file, $testSuiteName, $processed[$file])); + continue; + } + $processed[$file] = $testSuiteName; + $empty = \false; + $testSuite->addTestFile($file, $groups); + } + } + foreach ($configuredTestSuite->files() as $file) { + if (!is_file($file->path())) { + throw new TestFileNotFoundException($file->path()); + } + if (!version_compare(PHP_VERSION, $file->phpVersion(), $file->phpVersionOperator()->asString())) { + continue; + } + if (isset($processed[$file->path()])) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Cannot add file %s to test suite "%s" as it was already added to test suite "%s"', $file->path(), $testSuiteName, $processed[$file->path()])); + continue; + } + $processed[$file->path()] = $testSuiteName; + $empty = \false; + $testSuite->addTestFile($file->path(), $file->groups()); + } + if (!$empty) { + $result->addTest($testSuite); + } + } + return $result; + } catch (FrameworkException $e) { + throw new RuntimeException($e->getMessage(), $e->getCode(), $e); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use const PHP_EOL; +use function sprintf; +use function trim; +use LibXMLError; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class ValidationResult +{ + /** + * @var array> + */ + private array $validationErrors; + /** + * @param array $errors + */ + public static function fromArray(array $errors): self + { + $validationErrors = []; + foreach ($errors as $error) { + if (!isset($validationErrors[$error->line])) { + $validationErrors[$error->line] = []; + } + $validationErrors[$error->line][] = trim($error->message); + } + return new self($validationErrors); + } + /** + * @param array> $validationErrors + */ + private function __construct(array $validationErrors) + { + $this->validationErrors = $validationErrors; + } + public function hasValidationErrors(): bool + { + return $this->validationErrors !== []; + } + public function asString(): string + { + $buffer = ''; + foreach ($this->validationErrors as $line => $validationErrorsOnLine) { + $buffer .= sprintf(PHP_EOL . ' Line %d:' . PHP_EOL, $line); + foreach ($validationErrorsOnLine as $validationError) { + $buffer .= sprintf(' - %s' . PHP_EOL, $validationError); + } + } + return $buffer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use function file_get_contents; +use function libxml_clear_errors; +use function libxml_get_errors; +use function libxml_use_internal_errors; +use DOMDocument; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Validator +{ + public function validate(DOMDocument $document, string $xsdFilename): \PHPUnit\TextUI\XmlConfiguration\ValidationResult + { + $buffer = file_get_contents($xsdFilename); + assert($buffer !== \false); + $originalErrorHandling = libxml_use_internal_errors(\true); + $document->schemaValidateSource($buffer); + $errors = libxml_get_errors(); + libxml_clear_errors(); + libxml_use_internal_errors($originalErrorHandling); + return \PHPUnit\TextUI\XmlConfiguration\ValidationResult::fromArray($errors); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CannotOpenSocketException extends RuntimeException implements \PHPUnit\TextUI\Exception +{ + public function __construct(string $hostname, int $port) + { + parent::__construct(sprintf('Cannot open socket %s:%d', $hostname, $port)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidSocketException extends RuntimeException implements \PHPUnit\TextUI\Exception +{ + public function __construct(string $socket) + { + parent::__construct(sprintf('"%s" does not match "socket://hostname:port" format', $socket)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class RuntimeException extends \RuntimeException implements \PHPUnit\TextUI\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestDirectoryNotFoundException extends RuntimeException implements \PHPUnit\TextUI\Exception +{ + public function __construct(string $path) + { + parent::__construct(sprintf('Test directory "%s" not found', $path)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestFileNotFoundException extends RuntimeException implements \PHPUnit\TextUI\Exception +{ + public function __construct(string $path) + { + parent::__construct(sprintf('Test file "%s" not found', $path)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use const PHP_EOL; +use function count; +use function defined; +use function explode; +use function max; +use function preg_replace_callback; +use function str_pad; +use function str_repeat; +use function strlen; +use function wordwrap; +use PHPUnit\Util\Color; +use PHPUnitPHAR\SebastianBergmann\Environment\Console; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Help +{ + private const string LEFT_MARGIN = ' '; + private int $lengthOfLongestOptionName = 0; + private readonly int $columnsAvailableForDescription; + private bool $hasColor; + public function __construct(?int $width = null, ?bool $withColor = null) + { + if ($width === null) { + $width = (new Console())->getNumberOfColumns(); + } + if ($withColor === null) { + $this->hasColor = (new Console())->hasColorSupport(); + } else { + $this->hasColor = $withColor; + } + foreach ($this->elements() as $options) { + foreach ($options as $option) { + if (isset($option['arg'])) { + $this->lengthOfLongestOptionName = max($this->lengthOfLongestOptionName, strlen($option['arg'])); + } + } + } + $this->columnsAvailableForDescription = $width - $this->lengthOfLongestOptionName - 4; + } + public function generate(): string + { + if ($this->hasColor) { + return $this->writeWithColor(); + } + return $this->writeWithoutColor(); + } + private function writeWithoutColor(): string + { + $buffer = ''; + foreach ($this->elements() as $section => $options) { + $buffer .= "{$section}:" . PHP_EOL; + if ($section !== 'Usage') { + $buffer .= PHP_EOL; + } + foreach ($options as $option) { + if (isset($option['spacer'])) { + $buffer .= PHP_EOL; + } + if (isset($option['text'])) { + $buffer .= self::LEFT_MARGIN . $option['text'] . PHP_EOL; + } + if (isset($option['arg'])) { + $arg = str_pad($option['arg'], $this->lengthOfLongestOptionName); + $buffer .= self::LEFT_MARGIN . $arg . ' ' . $option['desc'] . PHP_EOL; + } + } + $buffer .= PHP_EOL; + } + return $buffer; + } + private function writeWithColor(): string + { + $buffer = ''; + foreach ($this->elements() as $section => $options) { + $buffer .= Color::colorize('fg-yellow', "{$section}:") . PHP_EOL; + if ($section !== 'Usage') { + $buffer .= PHP_EOL; + } + foreach ($options as $option) { + if (isset($option['spacer'])) { + $buffer .= PHP_EOL; + } + if (isset($option['text'])) { + $buffer .= self::LEFT_MARGIN . $option['text'] . PHP_EOL; + } + if (isset($option['arg'])) { + $arg = Color::colorize('fg-green', str_pad($option['arg'], $this->lengthOfLongestOptionName)); + $arg = preg_replace_callback('/(<[^>]+>)/', static fn(array $matches) => Color::colorize('fg-cyan', $matches[0]), $arg); + $desc = explode(PHP_EOL, wordwrap($option['desc'], $this->columnsAvailableForDescription, PHP_EOL)); + $buffer .= self::LEFT_MARGIN . $arg . ' ' . $desc[0] . PHP_EOL; + for ($i = 1; $i < count($desc); $i++) { + $buffer .= str_repeat(' ', $this->lengthOfLongestOptionName + 3) . $desc[$i] . PHP_EOL; + } + } + } + $buffer .= PHP_EOL; + } + return $buffer; + } + /** + * @return array> + */ + private function elements(): array + { + $elements = ['Usage' => [['text' => 'phpunit [options] ...']], 'Configuration' => [['arg' => '--bootstrap ', 'desc' => 'A PHP script that is included before the tests run'], ['arg' => '-c|--configuration ', 'desc' => 'Read configuration from XML file'], ['arg' => '--no-configuration', 'desc' => 'Ignore default configuration file (phpunit.xml)'], ['arg' => '--extension ', 'desc' => 'Register test runner extension with bootstrap '], ['arg' => '--no-extensions', 'desc' => 'Do not register test runner extensions'], ['arg' => '--include-path ', 'desc' => 'Prepend PHP\'s include_path with given path(s)'], ['arg' => '-d ', 'desc' => 'Sets a php.ini value'], ['arg' => '--cache-directory ', 'desc' => 'Specify cache directory'], ['arg' => '--generate-configuration', 'desc' => 'Generate configuration file with suggested settings'], ['arg' => '--migrate-configuration', 'desc' => 'Migrate configuration file to current format'], ['arg' => '--generate-baseline ', 'desc' => 'Generate baseline for issues'], ['arg' => '--use-baseline ', 'desc' => 'Use baseline to ignore issues'], ['arg' => '--ignore-baseline', 'desc' => 'Do not use baseline to ignore issues']], 'Selection' => [['arg' => '--all', 'desc' => 'Ignore test selection from XML configuration file'], ['arg' => '--list-suites', 'desc' => 'List available test suites'], ['arg' => '--testsuite ', 'desc' => 'Only run tests from the specified test suite(s)'], ['arg' => '--exclude-testsuite ', 'desc' => 'Exclude tests from the specified test suite(s)'], ['arg' => '--list-groups', 'desc' => 'List available test groups'], ['arg' => '--group ', 'desc' => 'Only run tests from the specified group(s)'], ['arg' => '--exclude-group ', 'desc' => 'Exclude tests from the specified group(s)'], ['arg' => '--covers ', 'desc' => 'Only run tests that intend to cover '], ['arg' => '--uses ', 'desc' => 'Only run tests that intend to use '], ['arg' => '--requires-php-extension ', 'desc' => 'Only run tests that require PHP extension '], ['arg' => '--list-test-files', 'desc' => 'List available test files'], ['arg' => '--list-tests', 'desc' => 'List available tests'], ['arg' => '--list-tests-xml ', 'desc' => 'List available tests in XML format'], ['arg' => '--filter ', 'desc' => 'Filter which tests to run'], ['arg' => '--exclude-filter ', 'desc' => 'Exclude tests for the specified filter pattern'], ['arg' => '--test-suffix ', 'desc' => 'Only search for test in files with specified suffix(es). Default: Test.php,.phpt'], ['arg' => '--test-files-file ', 'desc' => 'Only run test files listed in file (one file by line)']], 'Execution' => [['arg' => '--process-isolation', 'desc' => 'Run each test in a separate PHP process'], ['arg' => '--globals-backup', 'desc' => 'Backup and restore $GLOBALS for each test'], ['arg' => '--static-backup', 'desc' => 'Backup and restore static properties for each test'], ['spacer' => ''], ['arg' => '--strict-coverage', 'desc' => 'Be strict about code coverage metadata'], ['arg' => '--strict-global-state', 'desc' => 'Be strict about changes to global state'], ['arg' => '--disallow-test-output', 'desc' => 'Be strict about output during tests'], ['arg' => '--enforce-time-limit', 'desc' => 'Enforce time limit based on test size'], ['arg' => '--default-time-limit ', 'desc' => 'Timeout in seconds for tests that have no declared size'], ['arg' => '--do-not-report-useless-tests', 'desc' => 'Do not report tests that do not test anything'], ['spacer' => ''], ['arg' => '--stop-on-defect', 'desc' => 'Stop after first error, failure, warning, or risky test'], ['arg' => '--stop-on-error', 'desc' => 'Stop after first error'], ['arg' => '--stop-on-failure', 'desc' => 'Stop after first failure'], ['arg' => '--stop-on-warning', 'desc' => 'Stop after first warning'], ['arg' => '--stop-on-risky', 'desc' => 'Stop after first risky test'], ['arg' => '--stop-on-deprecation', 'desc' => 'Stop after first test that triggered a deprecation'], ['arg' => '--stop-on-notice', 'desc' => 'Stop after first test that triggered a notice'], ['arg' => '--stop-on-skipped', 'desc' => 'Stop after first skipped test'], ['arg' => '--stop-on-incomplete', 'desc' => 'Stop after first incomplete test'], ['spacer' => ''], ['arg' => '--fail-on-empty-test-suite', 'desc' => 'Signal failure using shell exit code when no tests were run'], ['arg' => '--fail-on-warning', 'desc' => 'Signal failure using shell exit code when a warning was triggered'], ['arg' => '--fail-on-risky', 'desc' => 'Signal failure using shell exit code when a test was considered risky'], ['arg' => '--fail-on-deprecation', 'desc' => 'Signal failure using shell exit code when a deprecation was triggered'], ['arg' => '--fail-on-phpunit-deprecation', 'desc' => 'Signal failure using shell exit code when a PHPUnit deprecation was triggered'], ['arg' => '--fail-on-phpunit-notice', 'desc' => 'Signal failure using shell exit code when a PHPUnit notice was triggered'], ['arg' => '--fail-on-phpunit-warning', 'desc' => 'Signal failure using shell exit code when a PHPUnit warning was triggered'], ['arg' => '--fail-on-notice', 'desc' => 'Signal failure using shell exit code when a notice was triggered'], ['arg' => '--fail-on-skipped', 'desc' => 'Signal failure using shell exit code when a test was skipped'], ['arg' => '--fail-on-incomplete', 'desc' => 'Signal failure using shell exit code when a test was marked incomplete'], ['arg' => '--fail-on-all-issues', 'desc' => 'Signal failure using shell exit code when an issue is triggered'], ['spacer' => ''], ['arg' => '--do-not-fail-on-empty-test-suite', 'desc' => 'Do not signal failure using shell exit code when no tests were run'], ['arg' => '--do-not-fail-on-warning', 'desc' => 'Do not signal failure using shell exit code when a warning was triggered'], ['arg' => '--do-not-fail-on-risky', 'desc' => 'Do not signal failure using shell exit code when a test was considered risky'], ['arg' => '--do-not-fail-on-deprecation', 'desc' => 'Do not signal failure using shell exit code when a deprecation was triggered'], ['arg' => '--do-not-fail-on-phpunit-deprecation', 'desc' => 'Do not signal failure using shell exit code when a PHPUnit deprecation was triggered'], ['arg' => '--do-not-fail-on-phpunit-notice', 'desc' => 'Do not signal failure using shell exit code when a PHPUnit notice was triggered'], ['arg' => '--do-not-fail-on-phpunit-warning', 'desc' => 'Do not signal failure using shell exit code when a PHPUnit warning was triggered'], ['arg' => '--do-not-fail-on-notice', 'desc' => 'Do not signal failure using shell exit code when a notice was triggered'], ['arg' => '--do-not-fail-on-skipped', 'desc' => 'Do not signal failure using shell exit code when a test was skipped'], ['arg' => '--do-not-fail-on-incomplete', 'desc' => 'Do not signal failure using shell exit code when a test was marked incomplete'], ['spacer' => ''], ['arg' => '--cache-result', 'desc' => 'Write test results to cache file'], ['arg' => '--do-not-cache-result', 'desc' => 'Do not write test results to cache file'], ['spacer' => ''], ['arg' => '--order-by ', 'desc' => 'Run tests in order: default|defects|depends|duration|no-depends|random|reverse|size'], ['arg' => '--resolve-dependencies', 'desc' => 'Alias for "--order-by depends"'], ['arg' => '--ignore-dependencies', 'desc' => 'Alias for "--order-by no-depends"'], ['arg' => '--random-order', 'desc' => 'Alias for "--order-by random"'], ['arg' => '--random-order-seed ', 'desc' => 'Use the specified random seed when running tests in random order'], ['arg' => '--reverse-order', 'desc' => 'Alias for "--order-by reverse"']], 'Reporting' => [['arg' => '--colors=', 'desc' => 'Use colors in output ("never", "auto" or "always")'], ['arg' => '--columns ', 'desc' => 'Number of columns to use for progress output'], ['arg' => '--columns max', 'desc' => 'Use maximum number of columns for progress output'], ['arg' => '--stderr', 'desc' => 'Write to STDERR instead of STDOUT'], ['spacer' => ''], ['arg' => '--no-progress', 'desc' => 'Disable output of test execution progress'], ['arg' => '--no-results', 'desc' => 'Disable output of test results'], ['arg' => '--no-output', 'desc' => 'Disable all output'], ['spacer' => ''], ['arg' => '--display-incomplete', 'desc' => 'Display details for incomplete tests'], ['arg' => '--display-skipped', 'desc' => 'Display details for skipped tests'], ['arg' => '--display-deprecations', 'desc' => 'Display details for deprecations triggered by tests'], ['arg' => '--display-phpunit-deprecations', 'desc' => 'Display details for PHPUnit deprecations'], ['arg' => '--display-phpunit-notices', 'desc' => 'Display details for PHPUnit notices'], ['arg' => '--display-errors', 'desc' => 'Display details for errors triggered by tests'], ['arg' => '--display-notices', 'desc' => 'Display details for notices triggered by tests'], ['arg' => '--display-warnings', 'desc' => 'Display details for warnings triggered by tests'], ['arg' => '--display-all-issues', 'desc' => 'Display details for all issues that are triggered'], ['arg' => '--reverse-list', 'desc' => 'Print defects in reverse order'], ['spacer' => ''], ['arg' => '--teamcity', 'desc' => 'Replace default progress and result output with TeamCity format'], ['arg' => '--testdox', 'desc' => 'Replace default result output with TestDox format'], ['arg' => '--testdox-summary', 'desc' => 'Repeat TestDox output for tests with errors, failures, or issues'], ['spacer' => ''], ['arg' => '--debug', 'desc' => 'Replace default progress and result output with debugging information'], ['arg' => '--with-telemetry', 'desc' => 'Include telemetry information in debugging information output']], 'Logging' => [['arg' => '--log-junit ', 'desc' => 'Write test results in JUnit XML format to file'], ['arg' => '--log-otr ', 'desc' => 'Write test results in Open Test Reporting XML format to file'], ['arg' => '--log-teamcity ', 'desc' => 'Write test results in TeamCity format to file'], ['arg' => '--testdox-html ', 'desc' => 'Write test results in TestDox format (HTML) to file'], ['arg' => '--testdox-text ', 'desc' => 'Write test results in TestDox format (plain text) to file'], ['arg' => '--log-events-text ', 'desc' => 'Stream events as plain text to file'], ['arg' => '--log-events-verbose-text ', 'desc' => 'Stream events as plain text with extended information to file'], ['arg' => '--include-git-information', 'desc' => 'Include Git information in supported formats'], ['arg' => '--no-logging', 'desc' => 'Ignore logging configured in the XML configuration file']], 'Code Coverage' => [['arg' => '--coverage-clover ', 'desc' => 'Write code coverage report in Clover XML format to file'], ['arg' => '--coverage-openclover ', 'desc' => 'Write code coverage report in OpenClover XML format to file'], ['arg' => '--coverage-cobertura ', 'desc' => 'Write code coverage report in Cobertura XML format to file'], ['arg' => '--coverage-crap4j ', 'desc' => 'Write code coverage report in Crap4J XML format to file'], ['arg' => '--coverage-html ', 'desc' => 'Write code coverage report in HTML format to directory'], ['arg' => '--coverage-php ', 'desc' => 'Write serialized code coverage data to file'], ['arg' => '--coverage-text=', 'desc' => 'Write code coverage report in text format to file [default: standard output]'], ['arg' => '--only-summary-for-coverage-text', 'desc' => 'Option for code coverage report in text format: only show summary'], ['arg' => '--show-uncovered-for-coverage-text', 'desc' => 'Option for code coverage report in text format: show uncovered files'], ['arg' => '--coverage-xml ', 'desc' => 'Write code coverage report in XML format to directory'], ['arg' => '--exclude-source-from-xml-coverage', 'desc' => 'Exclude element from code coverage report in XML format'], ['arg' => '--warm-coverage-cache', 'desc' => 'Warm static analysis cache'], ['arg' => '--coverage-filter ', 'desc' => 'Include in code coverage reporting'], ['arg' => '--path-coverage', 'desc' => 'Report path coverage in addition to line coverage'], ['arg' => '--disable-coverage-ignore', 'desc' => 'Disable metadata for ignoring code coverage'], ['arg' => '--no-coverage', 'desc' => 'Ignore code coverage reporting configured in the XML configuration file']]]; + if (defined('__PHPUNIT_PHAR__')) { + $elements['PHAR'] = [['arg' => '--manifest', 'desc' => 'Print Software Bill of Materials (SBOM) in plain-text format'], ['arg' => '--sbom', 'desc' => 'Print Software Bill of Materials (SBOM) in CycloneDX XML format'], ['arg' => '--composer-lock', 'desc' => 'Print composer.lock file used to build the PHAR']]; + } + $elements['Miscellaneous'] = [['arg' => '-h|--help', 'desc' => 'Prints this usage information'], ['arg' => '--version', 'desc' => 'Prints the version and exits'], ['arg' => '--atleast-version ', 'desc' => 'Checks that version is greater than and exits'], ['arg' => '--check-version', 'desc' => 'Checks whether PHPUnit is the latest version and exits'], ['arg' => '--check-php-configuration', 'desc' => 'Checks whether PHP configuration follows best practices']]; + return $elements; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use function floor; +use function sprintf; +use function str_repeat; +use function strlen; +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\TestRunner\ChildProcessErrored; +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Framework\TestStatus\TestStatus; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\SourceFilter; +use PHPUnit\TextUI\Output\Printer; +use PHPUnit\Util\Color; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ProgressPrinter +{ + private readonly Printer $printer; + private readonly bool $colors; + private readonly int $numberOfColumns; + private readonly Source $source; + private int $column = 0; + private int $numberOfTests = 0; + private int $numberOfTestsWidth = 0; + private int $maxColumn = 0; + private int $numberOfTestsRun = 0; + private ?TestStatus $status = null; + private bool $prepared = \false; + private bool $childProcessErrored = \false; + public function __construct(Printer $printer, Facade $facade, bool $colors, int $numberOfColumns, Source $source) + { + $this->printer = $printer; + $this->colors = $colors; + $this->numberOfColumns = $numberOfColumns; + $this->source = $source; + $this->registerSubscribers($facade); + } + public function testRunnerExecutionStarted(ExecutionStarted $event): void + { + $this->numberOfTestsRun = 0; + $this->numberOfTests = $event->testSuite()->count(); + $this->numberOfTestsWidth = strlen((string) $this->numberOfTests); + $this->column = 0; + $this->maxColumn = $this->numberOfColumns - strlen(' / (XXX%)') - 2 * $this->numberOfTestsWidth; + } + public function beforeTestClassMethodErrored(): void + { + $this->printProgressForError(); + $this->updateTestStatus(TestStatus::error()); + } + public function testPrepared(): void + { + $this->prepared = \true; + } + public function testSkipped(): void + { + if (!$this->prepared) { + $this->printProgressForSkipped(); + } else { + $this->updateTestStatus(TestStatus::skipped()); + } + } + public function testSuiteSkipped(int $countTests): void + { + for ($i = 0; $i < $countTests; $i++) { + $this->testSkipped(); + } + } + public function testMarkedIncomplete(): void + { + $this->updateTestStatus(TestStatus::incomplete()); + } + public function testTriggeredNotice(NoticeTriggered $event): void + { + if ($event->ignoredByBaseline()) { + return; + } + if ($this->source->restrictNotices() && !SourceFilter::instance()->includes($event->file())) { + return; + } + if (!$this->source->ignoreSuppressionOfNotices() && $event->wasSuppressed()) { + return; + } + $this->updateTestStatus(TestStatus::notice()); + } + public function testTriggeredPhpNotice(PhpNoticeTriggered $event): void + { + if ($event->ignoredByBaseline()) { + return; + } + if ($this->source->restrictNotices() && !SourceFilter::instance()->includes($event->file())) { + return; + } + if (!$this->source->ignoreSuppressionOfPhpNotices() && $event->wasSuppressed()) { + return; + } + $this->updateTestStatus(TestStatus::notice()); + } + public function testTriggeredDeprecation(DeprecationTriggered $event): void + { + if ($event->ignoredByBaseline() || $event->ignoredByTest()) { + return; + } + if ($this->source->ignoreSelfDeprecations() && $event->trigger()->isSelf()) { + return; + } + if ($this->source->ignoreDirectDeprecations() && $event->trigger()->isDirect()) { + return; + } + if ($this->source->ignoreIndirectDeprecations() && $event->trigger()->isIndirect()) { + return; + } + if (!$this->source->ignoreSuppressionOfDeprecations() && $event->wasSuppressed()) { + return; + } + $this->updateTestStatus(TestStatus::deprecation()); + } + public function testTriggeredPhpDeprecation(PhpDeprecationTriggered $event): void + { + if ($event->ignoredByBaseline() || $event->ignoredByTest()) { + return; + } + if ($this->source->ignoreSelfDeprecations() && $event->trigger()->isSelf()) { + return; + } + if ($this->source->ignoreDirectDeprecations() && $event->trigger()->isDirect()) { + return; + } + if ($this->source->ignoreIndirectDeprecations() && $event->trigger()->isIndirect()) { + return; + } + if (!$this->source->ignoreSuppressionOfPhpDeprecations() && $event->wasSuppressed()) { + return; + } + $this->updateTestStatus(TestStatus::deprecation()); + } + public function testTriggeredPhpunitDeprecation(): void + { + $this->updateTestStatus(TestStatus::deprecation()); + } + public function testTriggeredPhpunitNotice(): void + { + $this->updateTestStatus(TestStatus::notice()); + } + public function testConsideredRisky(): void + { + $this->updateTestStatus(TestStatus::risky()); + } + public function testTriggeredWarning(WarningTriggered $event): void + { + if ($event->ignoredByBaseline()) { + return; + } + if ($this->source->restrictWarnings() && !SourceFilter::instance()->includes($event->file())) { + return; + } + if (!$this->source->ignoreSuppressionOfWarnings() && $event->wasSuppressed()) { + return; + } + $this->updateTestStatus(TestStatus::warning()); + } + public function testTriggeredPhpWarning(PhpWarningTriggered $event): void + { + if ($event->ignoredByBaseline()) { + return; + } + if ($this->source->restrictWarnings() && !SourceFilter::instance()->includes($event->file())) { + return; + } + if (!$this->source->ignoreSuppressionOfPhpWarnings() && $event->wasSuppressed()) { + return; + } + $this->updateTestStatus(TestStatus::warning()); + } + public function testTriggeredPhpunitWarning(PhpunitWarningTriggered $event): void + { + if ($event->ignoredByTest()) { + return; + } + $this->updateTestStatus(TestStatus::warning()); + } + public function testTriggeredError(ErrorTriggered $event): void + { + if (!$this->source->ignoreSuppressionOfErrors() && $event->wasSuppressed()) { + return; + } + $this->updateTestStatus(TestStatus::error()); + } + public function testFailed(): void + { + $this->updateTestStatus(TestStatus::failure()); + } + public function testErrored(Errored $event): void + { + if ($this->childProcessErrored) { + $this->updateTestStatus(TestStatus::error()); + return; + } + if (!$this->prepared) { + $this->printProgressForError(); + } else { + $this->updateTestStatus(TestStatus::error()); + } + } + public function testFinished(): void + { + if ($this->status === null) { + $this->printProgressForSuccess(); + } elseif ($this->status->isSkipped()) { + $this->printProgressForSkipped(); + } elseif ($this->status->isIncomplete()) { + $this->printProgressForIncomplete(); + } elseif ($this->status->isRisky()) { + $this->printProgressForRisky(); + } elseif ($this->status->isNotice()) { + $this->printProgressForNotice(); + } elseif ($this->status->isDeprecation()) { + $this->printProgressForDeprecation(); + } elseif ($this->status->isWarning()) { + $this->printProgressForWarning(); + } elseif ($this->status->isFailure()) { + $this->printProgressForFailure(); + } else { + $this->printProgressForError(); + } + $this->status = null; + $this->prepared = \false; + $this->childProcessErrored = \false; + } + public function childProcessErrored(ChildProcessErrored $event): void + { + $this->childProcessErrored = \true; + } + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers(new \PHPUnit\TextUI\Output\Default\ProgressPrinter\BeforeTestClassMethodErroredSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestConsideredRiskySubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestErroredSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestFailedSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestFinishedSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestMarkedIncompleteSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestPreparedSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestRunnerExecutionStartedSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestSkippedSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestSuiteSkippedSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestTriggeredDeprecationSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestTriggeredNoticeSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestTriggeredPhpDeprecationSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestTriggeredPhpNoticeSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestTriggeredPhpunitDeprecationSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestTriggeredPhpunitNoticeSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestTriggeredPhpunitWarningSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestTriggeredPhpWarningSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\TestTriggeredWarningSubscriber($this), new \PHPUnit\TextUI\Output\Default\ProgressPrinter\ChildProcessErroredSubscriber($this)); + } + private function updateTestStatus(TestStatus $status): void + { + if ($this->status !== null && $this->status->isMoreImportantThan($status)) { + return; + } + $this->status = $status; + } + private function printProgressForSuccess(): void + { + $this->printProgress('.'); + } + private function printProgressForSkipped(): void + { + $this->printProgressWithColor('fg-cyan, bold', 'S'); + } + private function printProgressForIncomplete(): void + { + $this->printProgressWithColor('fg-yellow, bold', 'I'); + } + private function printProgressForNotice(): void + { + $this->printProgressWithColor('fg-yellow, bold', 'N'); + } + private function printProgressForDeprecation(): void + { + $this->printProgressWithColor('fg-yellow, bold', 'D'); + } + private function printProgressForRisky(): void + { + $this->printProgressWithColor('fg-yellow, bold', 'R'); + } + private function printProgressForWarning(): void + { + $this->printProgressWithColor('fg-yellow, bold', 'W'); + } + private function printProgressForFailure(): void + { + $this->printProgressWithColor('bg-red, fg-white', 'F'); + } + private function printProgressForError(): void + { + $this->printProgressWithColor('fg-red, bold', 'E'); + } + private function printProgressWithColor(string $color, string $progress): void + { + if ($this->colors) { + $progress = Color::colorizeTextBox($color, $progress); + } + $this->printProgress($progress); + } + private function printProgress(string $progress): void + { + $this->printer->print($progress); + $this->column++; + $this->numberOfTestsRun++; + if ($this->column === $this->maxColumn || $this->numberOfTestsRun === $this->numberOfTests) { + if ($this->numberOfTestsRun === $this->numberOfTests) { + $this->printer->print(str_repeat(' ', $this->maxColumn - $this->column)); + } + $this->printer->print(sprintf(' %' . $this->numberOfTestsWidth . 'd / %' . $this->numberOfTestsWidth . 'd (%3s%%)', $this->numberOfTestsRun, $this->numberOfTests, floor($this->numberOfTestsRun / $this->numberOfTests * 100))); + if ($this->column === $this->maxColumn) { + $this->column = 0; + $this->printer->print("\n"); + } + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestClassMethodErroredSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements BeforeFirstTestMethodErroredSubscriber +{ + public function notify(BeforeFirstTestMethodErrored $event): void + { + $this->printer()->beforeTestClassMethodErrored(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\TestRunner\ChildProcessErrored; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessErroredSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements \PHPUnit\Event\TestRunner\ChildProcessErroredSubscriber +{ + public function notify(ChildProcessErrored $event): void + { + $this->printer()->childProcessErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private \PHPUnit\TextUI\Output\Default\ProgressPrinter\ProgressPrinter $printer; + public function __construct(\PHPUnit\TextUI\Output\Default\ProgressPrinter\ProgressPrinter $printer) + { + $this->printer = $printer; + } + protected function printer(): \PHPUnit\TextUI\Output\Default\ProgressPrinter\ProgressPrinter + { + return $this->printer; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\ConsideredRiskySubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestConsideredRiskySubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements ConsideredRiskySubscriber +{ + public function notify(ConsideredRisky $event): void + { + $this->printer()->testConsideredRisky(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements ErroredSubscriber +{ + public function notify(Errored $event): void + { + $this->printer()->testErrored($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements FailedSubscriber +{ + public function notify(Failed $event): void + { + $this->printer()->testFailed(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->printer()->testFinished(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements MarkedIncompleteSubscriber +{ + public function notify(MarkedIncomplete $event): void + { + $this->printer()->testMarkedIncomplete(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->printer()->testPrepared(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerExecutionStartedSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements ExecutionStartedSubscriber +{ + public function notify(ExecutionStarted $event): void + { + $this->printer()->testRunnerExecutionStarted($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements SkippedSubscriber +{ + public function notify(Skipped $event): void + { + $this->printer()->testSkipped(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\TestSuite\Skipped; +use PHPUnit\Event\TestSuite\SkippedSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteSkippedSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements SkippedSubscriber +{ + public function notify(Skipped $event): void + { + $this->printer()->testSuiteSkipped($event->testSuite()->count()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredDeprecationSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements DeprecationTriggeredSubscriber +{ + public function notify(DeprecationTriggered $event): void + { + $this->printer()->testTriggeredDeprecation($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\ErrorTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredErrorSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements ErrorTriggeredSubscriber +{ + public function notify(ErrorTriggered $event): void + { + $this->printer()->testTriggeredError($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\NoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredNoticeSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements NoticeTriggeredSubscriber +{ + public function notify(NoticeTriggered $event): void + { + $this->printer()->testTriggeredNotice($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpDeprecationSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements PhpDeprecationTriggeredSubscriber +{ + public function notify(PhpDeprecationTriggered $event): void + { + $this->printer()->testTriggeredPhpDeprecation($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpNoticeSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements PhpNoticeTriggeredSubscriber +{ + public function notify(PhpNoticeTriggered $event): void + { + $this->printer()->testTriggeredPhpNotice($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpWarningSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements PhpWarningTriggeredSubscriber +{ + public function notify(PhpWarningTriggered $event): void + { + $this->printer()->testTriggeredPhpWarning($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitDeprecationSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements PhpunitDeprecationTriggeredSubscriber +{ + public function notify(PhpunitDeprecationTriggered $event): void + { + $this->printer()->testTriggeredPhpunitDeprecation(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitNoticeSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements PhpunitNoticeTriggeredSubscriber +{ + public function notify(PhpunitNoticeTriggered $event): void + { + $this->printer()->testTriggeredPhpunitNotice(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitWarningSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements PhpunitWarningTriggeredSubscriber +{ + public function notify(PhpunitWarningTriggered $event): void + { + $this->printer()->testTriggeredPhpunitWarning($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\Test\WarningTriggeredSubscriber; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredWarningSubscriber extends \PHPUnit\TextUI\Output\Default\ProgressPrinter\Subscriber implements WarningTriggeredSubscriber +{ + public function notify(WarningTriggered $event): void + { + $this->printer()->testTriggeredWarning($event); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default; + +use const PHP_EOL; +use function array_keys; +use function array_merge; +use function array_reverse; +use function array_unique; +use function assert; +use function count; +use function explode; +use function ksort; +use function range; +use function sprintf; +use function str_starts_with; +use function strlen; +use function substr; +use function trim; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\AfterLastTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\TestRunner\TestResult\Issues\Issue; +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\TextUI\Output\Printer; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ResultPrinter +{ + private readonly Printer $printer; + private readonly bool $displayPhpunitDeprecations; + private readonly bool $displayPhpunitErrors; + private readonly bool $displayPhpunitNotices; + private readonly bool $displayPhpunitWarnings; + private readonly bool $displayTestsWithErrors; + private readonly bool $displayTestsWithFailedAssertions; + private readonly bool $displayRiskyTests; + private readonly bool $displayDetailsOnIncompleteTests; + private readonly bool $displayDetailsOnSkippedTests; + private readonly bool $displayDetailsOnTestsThatTriggerDeprecations; + private readonly bool $displayDetailsOnTestsThatTriggerErrors; + private readonly bool $displayDetailsOnTestsThatTriggerNotices; + private readonly bool $displayDetailsOnTestsThatTriggerWarnings; + private readonly bool $displayDefectsInReverseOrder; + private bool $listPrinted = \false; + public function __construct(Printer $printer, bool $displayPhpunitDeprecations, bool $displayPhpunitErrors, bool $displayPhpunitNotices, bool $displayPhpunitWarnings, bool $displayTestsWithErrors, bool $displayTestsWithFailedAssertions, bool $displayRiskyTests, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $displayDefectsInReverseOrder) + { + $this->printer = $printer; + $this->displayPhpunitDeprecations = $displayPhpunitDeprecations; + $this->displayPhpunitErrors = $displayPhpunitErrors; + $this->displayPhpunitNotices = $displayPhpunitNotices; + $this->displayPhpunitWarnings = $displayPhpunitWarnings; + $this->displayTestsWithErrors = $displayTestsWithErrors; + $this->displayTestsWithFailedAssertions = $displayTestsWithFailedAssertions; + $this->displayRiskyTests = $displayRiskyTests; + $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; + $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; + $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; + $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; + $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; + $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; + $this->displayDefectsInReverseOrder = $displayDefectsInReverseOrder; + } + public function print(TestResult $result, bool $stackTraceForDeprecations = \false): void + { + if ($this->displayPhpunitErrors) { + $this->printPhpunitErrors($result); + } + if ($this->displayPhpunitWarnings) { + $this->printTestRunnerWarnings($result); + } + if ($this->displayPhpunitDeprecations) { + $this->printTestRunnerDeprecations($result); + } + if ($this->displayPhpunitNotices) { + $this->printTestRunnerNotices($result); + } + if ($this->displayTestsWithErrors) { + $this->printTestsWithErrors($result); + } + if ($this->displayTestsWithFailedAssertions) { + $this->printTestsWithFailedAssertions($result); + } + if ($this->displayPhpunitWarnings) { + $this->printDetailsOnTestsThatTriggeredPhpunitWarnings($result); + } + if ($this->displayPhpunitDeprecations) { + $this->printDetailsOnTestsThatTriggeredPhpunitDeprecations($result); + } + if ($this->displayRiskyTests) { + $this->printRiskyTests($result); + } + if ($this->displayPhpunitNotices) { + $this->printDetailsOnTestsThatTriggeredPhpunitNotices($result); + } + if ($this->displayDetailsOnIncompleteTests) { + $this->printIncompleteTests($result); + } + if ($this->displayDetailsOnSkippedTests) { + $this->printSkippedTestSuites($result); + $this->printSkippedTests($result); + } + if ($this->displayDetailsOnTestsThatTriggerErrors) { + $this->printIssueList('error', $result->errors()); + } + if ($this->displayDetailsOnTestsThatTriggerWarnings) { + $this->printIssueList('PHP warning', $result->phpWarnings()); + $this->printIssueList('warning', $result->warnings()); + } + if ($this->displayDetailsOnTestsThatTriggerNotices) { + $this->printIssueList('PHP notice', $result->phpNotices()); + $this->printIssueList('notice', $result->notices()); + } + if ($this->displayDetailsOnTestsThatTriggerDeprecations) { + $this->printIssueList('PHP deprecation', $result->phpDeprecations()); + $this->printIssueList('deprecation', $result->deprecations(), $stackTraceForDeprecations); + } + } + private function printPhpunitErrors(TestResult $result): void + { + if (!$result->hasTestTriggeredPhpunitErrorEvents()) { + return; + } + $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitErrorEvents()); + $this->printListHeaderWithNumber($elements['numberOfTestsWithIssues'], 'PHPUnit error'); + $this->printList($elements['elements']); + } + private function printDetailsOnTestsThatTriggeredPhpunitDeprecations(TestResult $result): void + { + if (!$result->hasTestTriggeredPhpunitDeprecationEvents()) { + return; + } + $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitDeprecationEvents()); + $this->printListHeaderWithNumberOfTestsAndNumberOfIssues($elements['numberOfTestsWithIssues'], $elements['numberOfIssues'], 'PHPUnit deprecation'); + $this->printList($elements['elements']); + } + private function printDetailsOnTestsThatTriggeredPhpunitNotices(TestResult $result): void + { + if (!$result->hasTestTriggeredPhpunitNoticeEvents()) { + return; + } + $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitNoticeEvents()); + $this->printListHeaderWithNumberOfTestsAndNumberOfIssues($elements['numberOfTestsWithIssues'], $elements['numberOfIssues'], 'PHPUnit notice'); + $this->printList($elements['elements']); + } + private function printTestRunnerNotices(TestResult $result): void + { + if (!$result->hasTestRunnerTriggeredNoticeEvents()) { + return; + } + $elements = []; + $messages = []; + foreach ($result->testRunnerTriggeredNoticeEvents() as $event) { + if (isset($messages[$event->message()])) { + continue; + } + $elements[] = ['title' => $event->message(), 'body' => '']; + $messages[$event->message()] = \true; + } + $this->printListHeaderWithNumber(count($elements), 'PHPUnit test runner notice'); + $this->printList($elements); + } + private function printTestRunnerWarnings(TestResult $result): void + { + if (!$result->hasTestRunnerTriggeredWarningEvents()) { + return; + } + $elements = []; + $messages = []; + foreach ($result->testRunnerTriggeredWarningEvents() as $event) { + if (isset($messages[$event->message()])) { + continue; + } + $elements[] = ['title' => $event->message(), 'body' => '']; + $messages[$event->message()] = \true; + } + $this->printListHeaderWithNumber(count($elements), 'PHPUnit test runner warning'); + $this->printList($elements); + } + private function printTestRunnerDeprecations(TestResult $result): void + { + if (!$result->hasTestRunnerTriggeredDeprecationEvents()) { + return; + } + $elements = []; + foreach ($result->testRunnerTriggeredDeprecationEvents() as $event) { + $elements[] = ['title' => $event->message(), 'body' => '']; + } + $this->printListHeaderWithNumber(count($elements), 'PHPUnit test runner deprecation'); + $this->printList($elements); + } + private function printDetailsOnTestsThatTriggeredPhpunitWarnings(TestResult $result): void + { + if (!$result->hasTestTriggeredPhpunitWarningEvents()) { + return; + } + $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitWarningEvents()); + $this->printListHeaderWithNumberOfTestsAndNumberOfIssues($elements['numberOfTestsWithIssues'], $elements['numberOfIssues'], 'PHPUnit warning'); + $this->printList($elements['elements']); + } + private function printTestsWithErrors(TestResult $result): void + { + if (!$result->hasTestErroredEvents()) { + return; + } + $elements = []; + foreach ($result->testErroredEvents() as $event) { + if ($event instanceof AfterLastTestMethodErrored || $event instanceof BeforeFirstTestMethodErrored) { + $title = $event->testClassName(); + } else { + $title = $this->name($event->test()); + } + $elements[] = ['title' => $title, 'body' => $event->throwable()->asString()]; + } + $this->printListHeaderWithNumber(count($elements), 'error'); + $this->printList($elements); + } + private function printTestsWithFailedAssertions(TestResult $result): void + { + if (!$result->hasTestFailedEvents()) { + return; + } + $elements = []; + foreach ($result->testFailedEvents() as $event) { + if ($event instanceof AfterLastTestMethodFailed || $event instanceof BeforeFirstTestMethodFailed) { + $title = $event->testClassName(); + } else { + $title = $this->name($event->test()); + } + $body = $event->throwable()->asString(); + if (str_starts_with($body, 'AssertionError: ')) { + $body = substr($body, strlen('AssertionError: ')); + } + $elements[] = ['title' => $title, 'body' => $body]; + } + $this->printListHeaderWithNumber(count($elements), 'failure'); + $this->printList($elements); + } + private function printRiskyTests(TestResult $result): void + { + if (!$result->hasTestConsideredRiskyEvents()) { + return; + } + $elements = $this->mapTestsWithIssuesEventsToElements($result->testConsideredRiskyEvents()); + $this->printListHeaderWithNumber($elements['numberOfTestsWithIssues'], 'risky test'); + $this->printList($elements['elements']); + } + private function printIncompleteTests(TestResult $result): void + { + if (!$result->hasTestMarkedIncompleteEvents()) { + return; + } + $elements = []; + foreach ($result->testMarkedIncompleteEvents() as $event) { + $elements[] = ['title' => $this->name($event->test()), 'body' => $event->throwable()->asString()]; + } + $this->printListHeaderWithNumber(count($elements), 'incomplete test'); + $this->printList($elements); + } + private function printSkippedTestSuites(TestResult $result): void + { + if (!$result->hasTestSuiteSkippedEvents()) { + return; + } + $elements = []; + foreach ($result->testSuiteSkippedEvents() as $event) { + $elements[] = ['title' => $event->testSuite()->name(), 'body' => $event->message()]; + } + $this->printListHeaderWithNumber(count($elements), 'skipped test suite'); + $this->printList($elements); + } + private function printSkippedTests(TestResult $result): void + { + if (!$result->hasTestSkippedEvents()) { + return; + } + $elements = []; + foreach ($result->testSkippedEvents() as $event) { + $elements[] = ['title' => $this->name($event->test()), 'body' => $event->message()]; + } + $this->printListHeaderWithNumber(count($elements), 'skipped test'); + $this->printList($elements); + } + /** + * @param non-empty-string $type + * @param list $issues + */ + private function printIssueList(string $type, array $issues, bool $stackTrace = \false): void + { + if ($issues === []) { + return; + } + $numberOfUniqueIssues = count($issues); + $triggeringTests = []; + foreach ($issues as $issue) { + $triggeringTests = array_merge($triggeringTests, array_keys($issue->triggeringTests())); + } + $numberOfTests = count(array_unique($triggeringTests)); + unset($triggeringTests); + $this->printListHeader(sprintf('%d test%s triggered %d %s%s:' . PHP_EOL . PHP_EOL, $numberOfTests, $numberOfTests !== 1 ? 's' : '', $numberOfUniqueIssues, $type, $numberOfUniqueIssues !== 1 ? 's' : '')); + $i = 1; + foreach ($issues as $issue) { + $title = sprintf('%s:%d', $issue->file(), $issue->line()); + $body = trim($issue->description()) . PHP_EOL . PHP_EOL; + if ($stackTrace && $issue->hasStackTrace()) { + $body .= trim($issue->stackTrace()) . PHP_EOL . PHP_EOL; + } + if (!$issue->triggeredInTest()) { + $body .= 'Triggered by:'; + $triggeringTests = $issue->triggeringTests(); + ksort($triggeringTests); + foreach ($triggeringTests as $triggeringTest) { + $body .= PHP_EOL . PHP_EOL . '* ' . $triggeringTest['test']->id(); + if ($triggeringTest['count'] > 1) { + $body .= sprintf(' (%d times)', $triggeringTest['count']); + } + if ($triggeringTest['test']->isTestMethod()) { + $body .= PHP_EOL . ' ' . $triggeringTest['test']->file() . ':' . $triggeringTest['test']->line(); + } + } + } + $this->printIssueListElement($i++, $title, $body); + $this->printer->print(PHP_EOL); + } + } + private function printListHeaderWithNumberOfTestsAndNumberOfIssues(int $numberOfTestsWithIssues, int $numberOfIssues, string $type): void + { + $this->printListHeader(sprintf("%d test%s triggered %d %s%s:\n\n", $numberOfTestsWithIssues, $numberOfTestsWithIssues !== 1 ? 's' : '', $numberOfIssues, $type, $numberOfIssues !== 1 ? 's' : '')); + } + private function printListHeaderWithNumber(int $number, string $type): void + { + $this->printListHeader(sprintf("There %s %d %s%s:\n\n", $number === 1 ? 'was' : 'were', $number, $type, $number === 1 ? '' : 's')); + } + private function printListHeader(string $header): void + { + if ($this->listPrinted) { + $this->printer->print("--\n\n"); + } + $this->listPrinted = \true; + $this->printer->print($header); + } + /** + * @param list $elements + */ + private function printList(array $elements): void + { + $i = 1; + if ($this->displayDefectsInReverseOrder) { + $elements = array_reverse($elements); + } + foreach ($elements as $element) { + $this->printListElement($i++, $element['title'], $element['body']); + } + $this->printer->print("\n"); + } + private function printListElement(int $number, string $title, string $body): void + { + $body = trim($body); + $this->printer->print(sprintf("%s%d) %s\n%s%s", $number > 1 ? "\n" : '', $number, $title, $body, $body !== '' ? "\n" : '')); + } + private function printIssueListElement(int $number, string $title, string $body): void + { + $body = trim($body); + $this->printer->print(sprintf("%d) %s\n%s%s", $number, $title, $body, $body !== '' ? "\n" : '')); + } + private function name(Test $test): string + { + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + if (!$test->testData()->hasDataFromDataProvider()) { + return $test->nameWithClass(); + } + return $test->className() . '::' . $test->methodName() . $test->testData()->dataFromDataProvider()->dataAsStringForResultOutput(); + } + return $test->name(); + } + /** + * @param array> $events + * + * @return array{numberOfTestsWithIssues: int, numberOfIssues: int, elements: list} + */ + private function mapTestsWithIssuesEventsToElements(array $events): array + { + $elements = []; + $issues = 0; + foreach ($events as $reasons) { + $test = $reasons[0]->test(); + $testLocation = $this->testLocation($test); + $title = $this->name($test); + $body = ''; + $first = \true; + $single = count($reasons) === 1; + foreach ($reasons as $reason) { + if ($first) { + $first = \false; + } else { + $body .= PHP_EOL; + } + $body .= $this->reasonMessage($reason, $single); + $body .= $this->reasonLocation($reason, $single); + $issues++; + } + if ($testLocation !== '') { + $body .= $testLocation; + } + $elements[] = ['title' => $title, 'body' => $body]; + } + return ['numberOfTestsWithIssues' => count($events), 'numberOfIssues' => $issues, 'elements' => $elements]; + } + private function testLocation(Test $test): string + { + if (!$test->isTestMethod()) { + return ''; + } + assert($test instanceof TestMethod); + return sprintf('%s%s:%d%s', PHP_EOL, $test->file(), $test->line(), PHP_EOL); + } + private function reasonMessage(ConsideredRisky|DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpunitDeprecationTriggered|PhpunitErrorTriggered|PhpunitNoticeTriggered|PhpunitWarningTriggered|PhpWarningTriggered|WarningTriggered $reason, bool $single): string + { + $message = trim($reason->message()); + if ($single) { + return $message . PHP_EOL; + } + $lines = explode(PHP_EOL, $message); + $buffer = '* ' . $lines[0] . PHP_EOL; + if (count($lines) > 1) { + foreach (range(1, count($lines) - 1) as $line) { + $buffer .= ' ' . $lines[$line] . PHP_EOL; + } + } + return $buffer; + } + private function reasonLocation(ConsideredRisky|DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpunitDeprecationTriggered|PhpunitErrorTriggered|PhpunitNoticeTriggered|PhpunitWarningTriggered|PhpWarningTriggered|WarningTriggered $reason, bool $single): string + { + if (!$reason instanceof DeprecationTriggered && !$reason instanceof PhpDeprecationTriggered && !$reason instanceof ErrorTriggered && !$reason instanceof NoticeTriggered && !$reason instanceof PhpNoticeTriggered && !$reason instanceof WarningTriggered && !$reason instanceof PhpWarningTriggered) { + return ''; + } + return sprintf('%s%s:%d%s', $single ? '' : ' ', $reason->file(), $reason->line(), PHP_EOL); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default; + +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\PrintedUnexpectedOutput; +use PHPUnit\Event\Test\PrintedUnexpectedOutputSubscriber; +use PHPUnit\TextUI\Output\Printer; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UnexpectedOutputPrinter implements PrintedUnexpectedOutputSubscriber +{ + private Printer $printer; + public function __construct(Printer $printer, Facade $facade) + { + $this->printer = $printer; + $facade->registerSubscriber($this); + } + public function notify(PrintedUnexpectedOutput $event): void + { + $this->printer->print($event->output()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output; + +use const PHP_EOL; +use function assert; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Logging\TeamCity\TeamCityLogger; +use PHPUnit\Logging\TestDox\TestResultCollection; +use PHPUnit\Runner\DirectoryDoesNotExistException; +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\TextUI\CannotOpenSocketException; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\InvalidSocketException; +use PHPUnit\TextUI\Output\Default\ProgressPrinter\ProgressPrinter as DefaultProgressPrinter; +use PHPUnit\TextUI\Output\Default\ResultPrinter as DefaultResultPrinter; +use PHPUnit\TextUI\Output\Default\UnexpectedOutputPrinter; +use PHPUnit\TextUI\Output\TestDox\ResultPrinter as TestDoxResultPrinter; +use PHPUnitPHAR\SebastianBergmann\Timer\Duration; +use PHPUnitPHAR\SebastianBergmann\Timer\ResourceUsageFormatter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Facade +{ + private static ?\PHPUnit\TextUI\Output\Printer $printer = null; + private static ?DefaultResultPrinter $defaultResultPrinter = null; + private static ?TestDoxResultPrinter $testDoxResultPrinter = null; + private static ?\PHPUnit\TextUI\Output\SummaryPrinter $summaryPrinter = null; + private static bool $defaultProgressPrinter = \false; + public static function init(Configuration $configuration, bool $extensionReplacesProgressOutput, bool $extensionReplacesResultOutput): \PHPUnit\TextUI\Output\Printer + { + self::createPrinter($configuration); + assert(self::$printer !== null); + if ($configuration->debug()) { + return self::$printer; + } + self::createUnexpectedOutputPrinter(); + if (!$extensionReplacesProgressOutput) { + self::createProgressPrinter($configuration); + } + if (!$extensionReplacesResultOutput) { + self::createResultPrinter($configuration); + self::createSummaryPrinter($configuration); + } + if ($configuration->outputIsTeamCity()) { + new TeamCityLogger(\PHPUnit\TextUI\Output\DefaultPrinter::standardOutput(), EventFacade::instance()); + } + assert(self::$printer !== null); + return self::$printer; + } + /** + * @param ?array $testDoxResult + */ + public static function printResult(TestResult $result, ?array $testDoxResult, Duration $duration, bool $stackTraceForDeprecations): void + { + assert(self::$printer !== null); + if ($result->numberOfTestsRun() > 0) { + if (self::$defaultProgressPrinter) { + self::$printer->print(PHP_EOL . PHP_EOL); + } + self::$printer->print((new ResourceUsageFormatter())->resourceUsage($duration) . PHP_EOL . PHP_EOL); + } + if (self::$testDoxResultPrinter !== null && $testDoxResult !== null) { + self::$testDoxResultPrinter->print($result, $testDoxResult); + } + if (self::$defaultResultPrinter !== null) { + self::$defaultResultPrinter->print($result, $stackTraceForDeprecations); + } + if (self::$summaryPrinter !== null) { + self::$summaryPrinter->print($result); + } + } + /** + * @throws CannotOpenSocketException + * @throws DirectoryDoesNotExistException + * @throws InvalidSocketException + */ + public static function printerFor(string $target): \PHPUnit\TextUI\Output\Printer + { + if ($target === 'php://stdout') { + if (self::$printer !== null && !self::$printer instanceof \PHPUnit\TextUI\Output\NullPrinter) { + return self::$printer; + } + return \PHPUnit\TextUI\Output\DefaultPrinter::standardOutput(); + } + return \PHPUnit\TextUI\Output\DefaultPrinter::from($target); + } + private static function createPrinter(Configuration $configuration): void + { + $printerNeeded = \false; + if ($configuration->debug()) { + $printerNeeded = \true; + } + if ($configuration->outputIsTeamCity()) { + $printerNeeded = \true; + } + if ($configuration->outputIsTestDox()) { + $printerNeeded = \true; + } + if (!$configuration->noOutput() && !$configuration->noProgress()) { + $printerNeeded = \true; + } + if (!$configuration->noOutput() && !$configuration->noResults()) { + $printerNeeded = \true; + } + if ($printerNeeded) { + if ($configuration->outputToStandardErrorStream()) { + self::$printer = \PHPUnit\TextUI\Output\DefaultPrinter::standardError(); + return; + } + self::$printer = \PHPUnit\TextUI\Output\DefaultPrinter::standardOutput(); + return; + } + self::$printer = new \PHPUnit\TextUI\Output\NullPrinter(); + } + private static function createProgressPrinter(Configuration $configuration): void + { + assert(self::$printer !== null); + if (!self::useDefaultProgressPrinter($configuration)) { + return; + } + new DefaultProgressPrinter(self::$printer, EventFacade::instance(), $configuration->colors(), $configuration->columns(), $configuration->source()); + self::$defaultProgressPrinter = \true; + } + private static function useDefaultProgressPrinter(Configuration $configuration): bool + { + if ($configuration->noOutput()) { + return \false; + } + if ($configuration->noProgress()) { + return \false; + } + if ($configuration->outputIsTeamCity()) { + return \false; + } + return \true; + } + private static function createResultPrinter(Configuration $configuration): void + { + assert(self::$printer !== null); + if ($configuration->outputIsTestDox()) { + self::$defaultResultPrinter = new DefaultResultPrinter(self::$printer, $configuration->displayDetailsOnPhpunitDeprecations() || $configuration->displayDetailsOnAllIssues(), \true, $configuration->displayDetailsOnPhpunitNotices() || $configuration->displayDetailsOnAllIssues(), \true, \false, \false, \true, \false, \false, $configuration->displayDetailsOnTestsThatTriggerDeprecations() || $configuration->displayDetailsOnAllIssues(), $configuration->displayDetailsOnTestsThatTriggerErrors() || $configuration->displayDetailsOnAllIssues(), $configuration->displayDetailsOnTestsThatTriggerNotices() || $configuration->displayDetailsOnAllIssues(), $configuration->displayDetailsOnTestsThatTriggerWarnings() || $configuration->displayDetailsOnAllIssues(), $configuration->reverseDefectList()); + } + if ($configuration->outputIsTestDox()) { + self::$testDoxResultPrinter = new TestDoxResultPrinter(self::$printer, $configuration->colors(), $configuration->columns(), $configuration->testDoxOutputWithSummary()); + } + if ($configuration->noOutput() || $configuration->noResults()) { + return; + } + if (self::$defaultResultPrinter !== null) { + return; + } + self::$defaultResultPrinter = new DefaultResultPrinter(self::$printer, $configuration->displayDetailsOnPhpunitDeprecations() || $configuration->displayDetailsOnAllIssues(), \true, $configuration->displayDetailsOnPhpunitNotices() || $configuration->displayDetailsOnAllIssues(), \true, \true, \true, \true, $configuration->displayDetailsOnIncompleteTests() || $configuration->displayDetailsOnAllIssues(), $configuration->displayDetailsOnSkippedTests() || $configuration->displayDetailsOnAllIssues(), $configuration->displayDetailsOnTestsThatTriggerDeprecations() || $configuration->displayDetailsOnAllIssues(), $configuration->displayDetailsOnTestsThatTriggerErrors() || $configuration->displayDetailsOnAllIssues(), $configuration->displayDetailsOnTestsThatTriggerNotices() || $configuration->displayDetailsOnAllIssues(), $configuration->displayDetailsOnTestsThatTriggerWarnings() || $configuration->displayDetailsOnAllIssues(), $configuration->reverseDefectList()); + } + private static function createSummaryPrinter(Configuration $configuration): void + { + assert(self::$printer !== null); + if (($configuration->noOutput() || $configuration->noResults()) && !($configuration->outputIsTeamCity() || $configuration->outputIsTestDox())) { + return; + } + self::$summaryPrinter = new \PHPUnit\TextUI\Output\SummaryPrinter(self::$printer, $configuration->colors()); + } + private static function createUnexpectedOutputPrinter(): void + { + assert(self::$printer !== null); + new UnexpectedOutputPrinter(self::$printer, EventFacade::instance()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output; + +use function assert; +use function count; +use function dirname; +use function explode; +use function fclose; +use function fopen; +use function fsockopen; +use function fwrite; +use function str_replace; +use function str_starts_with; +use PHPUnit\Runner\DirectoryDoesNotExistException; +use PHPUnit\TextUI\CannotOpenSocketException; +use PHPUnit\TextUI\InvalidSocketException; +use PHPUnit\Util\Filesystem; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DefaultPrinter implements \PHPUnit\TextUI\Output\Printer +{ + /** + * @var closed-resource|resource + */ + private $stream; + private readonly bool $isPhpStream; + private bool $isOpen; + /** + * @throws CannotOpenSocketException + * @throws DirectoryDoesNotExistException + * @throws InvalidSocketException + */ + public static function from(string $out): self + { + return new self($out); + } + /** + * @throws CannotOpenSocketException + * @throws DirectoryDoesNotExistException + * @throws InvalidSocketException + */ + public static function standardOutput(): self + { + return new self('php://stdout'); + } + /** + * @throws CannotOpenSocketException + * @throws DirectoryDoesNotExistException + * @throws InvalidSocketException + */ + public static function standardError(): self + { + return new self('php://stderr'); + } + /** + * @throws CannotOpenSocketException + * @throws DirectoryDoesNotExistException + * @throws InvalidSocketException + */ + private function __construct(string $out) + { + $this->isPhpStream = str_starts_with($out, 'php://'); + if (str_starts_with($out, 'socket://')) { + $tmp = explode(':', str_replace('socket://', '', $out)); + if (count($tmp) !== 2) { + throw new InvalidSocketException($out); + } + $stream = @fsockopen($tmp[0], (int) $tmp[1]); + if ($stream === \false) { + throw new CannotOpenSocketException($tmp[0], (int) $tmp[1]); + } + $this->stream = $stream; + $this->isOpen = \true; + return; + } + if (!$this->isPhpStream && !Filesystem::createDirectory(dirname($out))) { + throw new DirectoryDoesNotExistException(dirname($out)); + } + $stream = fopen($out, 'wb'); + assert($stream !== \false); + $this->stream = $stream; + $this->isOpen = \true; + } + public function print(string $buffer): void + { + assert($this->isOpen); + fwrite($this->stream, $buffer); + } + public function flush(): void + { + if ($this->isOpen && $this->isPhpStream) { + fclose($this->stream); + $this->isOpen = \false; + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class NullPrinter implements \PHPUnit\TextUI\Output\Printer +{ + public function print(string $buffer): void + { + } + public function flush(): void + { + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Printer +{ + public function print(string $buffer): void; + public function flush(): void; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\Util\Color; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SummaryPrinter +{ + private readonly \PHPUnit\TextUI\Output\Printer $printer; + private readonly bool $colors; + private bool $countPrinted = \false; + public function __construct(\PHPUnit\TextUI\Output\Printer $printer, bool $colors) + { + $this->printer = $printer; + $this->colors = $colors; + } + public function print(TestResult $result): void + { + if ($result->numberOfTestsRun() === 0) { + $this->printWithColor('fg-black, bg-yellow', 'No tests executed!'); + return; + } + if ($result->wasSuccessful() && !$result->hasIssues() && !$result->hasTestSuiteSkippedEvents() && !$result->hasTestSkippedEvents()) { + $this->printWithColor('fg-black, bg-green', sprintf('OK (%d test%s, %d assertion%s)', $result->numberOfTestsRun(), $result->numberOfTestsRun() === 1 ? '' : 's', $result->numberOfAssertions(), $result->numberOfAssertions() === 1 ? '' : 's')); + $this->printNumberOfIssuesIgnoredByBaseline($result); + return; + } + if ($result->wasSuccessful()) { + if ($result->hasIssues()) { + $color = 'fg-black, bg-yellow'; + $this->printWithColor($color, 'OK, but there were issues!'); + } else { + $color = 'fg-black, bg-green'; + $this->printWithColor($color, 'OK, but some tests were skipped!'); + } + } else { + $color = 'fg-white, bg-red'; + if ($result->hasTestErroredEvents() || $result->hasTestTriggeredPhpunitErrorEvents()) { + $this->printWithColor('fg-white, bg-red', 'ERRORS!'); + } else { + $this->printWithColor('fg-white, bg-red', 'FAILURES!'); + } + } + $this->printCountString($result->numberOfTestsRun(), 'Tests', $color, \true); + $this->printCountString($result->numberOfAssertions(), 'Assertions', $color, \true); + $this->printCountString($result->numberOfErrors(), 'Errors', $color); + $this->printCountString($result->numberOfTestFailedEvents(), 'Failures', $color); + $this->printCountString($result->numberOfPhpunitWarnings(), 'PHPUnit Warnings', $color); + $this->printCountString($result->numberOfWarnings(), 'Warnings', $color); + $this->printCountString($result->numberOfPhpOrUserDeprecations(), 'Deprecations', $color); + $this->printCountString($result->numberOfPhpunitDeprecations(), 'PHPUnit Deprecations', $color); + $this->printCountString($result->numberOfPhpunitNotices(), 'PHPUnit Notices', $color); + $this->printCountString($result->numberOfNotices(), 'Notices', $color); + $this->printCountString($result->numberOfTestSkippedByTestSuiteSkippedEvents() + $result->numberOfTestSkippedEvents(), 'Skipped', $color); + $this->printCountString($result->numberOfTestMarkedIncompleteEvents(), 'Incomplete', $color); + $this->printCountString($result->numberOfTestsWithTestConsideredRiskyEvents(), 'Risky', $color); + $this->printWithColor($color, '.'); + $this->printNumberOfIssuesIgnoredByBaseline($result); + } + private function printCountString(int $count, string $name, string $color, bool $always = \false): void + { + if ($always || $count > 0) { + $this->printWithColor($color, sprintf('%s%s: %d', $this->countPrinted ? ', ' : '', $name, $count), \false); + $this->countPrinted = \true; + } + } + private function printWithColor(string $color, string $buffer, bool $lf = \true): void + { + if ($this->colors) { + $buffer = Color::colorizeTextBox($color, $buffer); + } + $this->printer->print($buffer); + if ($lf) { + $this->printer->print(PHP_EOL); + } + } + private function printNumberOfIssuesIgnoredByBaseline(TestResult $result): void + { + if ($result->hasIssuesIgnoredByBaseline()) { + $this->printer->print(sprintf('%s%d issue%s %s ignored by baseline.%s', PHP_EOL, $result->numberOfIssuesIgnoredByBaseline(), $result->numberOfIssuesIgnoredByBaseline() > 1 ? 's' : '', $result->numberOfIssuesIgnoredByBaseline() > 1 ? 'were' : 'was', PHP_EOL)); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\TestDox; + +use const PHP_EOL; +use function array_map; +use function explode; +use function implode; +use function preg_match; +use function preg_split; +use function rtrim; +use function sprintf; +use function str_starts_with; +use function trim; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Framework\TestStatus\TestStatus; +use PHPUnit\Logging\TestDox\TestResult as TestDoxTestResult; +use PHPUnit\Logging\TestDox\TestResultCollection; +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\TextUI\Output\Printer; +use PHPUnit\Util\Color; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ResultPrinter +{ + private Printer $printer; + private bool $colors; + private int $columns; + private bool $printSummary; + public function __construct(Printer $printer, bool $colors, int $columns, bool $printSummary) + { + $this->printer = $printer; + $this->colors = $colors; + $this->columns = $columns; + $this->printSummary = $printSummary; + } + /** + * @param array $tests + */ + public function print(TestResult $result, array $tests): void + { + $this->doPrint($tests, \false); + if ($this->printSummary) { + $this->printer->print('Summary of tests with errors, failures, or issues:' . PHP_EOL . PHP_EOL); + $this->doPrint($tests, \true); + } + $beforeFirstTestMethodErrored = []; + $afterLastTestMethodErrored = []; + foreach ($result->testErroredEvents() as $error) { + if ($error instanceof BeforeFirstTestMethodErrored) { + $beforeFirstTestMethodErrored[$error->calledMethod()->className() . '::' . $error->calledMethod()->methodName()] = $error; + } + if ($error instanceof AfterLastTestMethodErrored) { + $afterLastTestMethodErrored[$error->calledMethod()->className() . '::' . $error->calledMethod()->methodName()] = $error; + } + } + $this->printBeforeClassOrAfterClassErrors('before-first-test', $beforeFirstTestMethodErrored); + $this->printBeforeClassOrAfterClassErrors('after-last-test', $afterLastTestMethodErrored); + } + /** + * @param array $tests + */ + private function doPrint(array $tests, bool $onlySummary): void + { + foreach ($tests as $_tests) { + $print = \true; + if ($onlySummary) { + $found = \false; + foreach ($_tests as $test) { + if ($test->status()->isSuccess()) { + continue; + } + $found = \true; + break; + } + if (!$found) { + $print = \false; + } + } + if (!$print) { + continue; + } + $this->printPrettifiedClassName($_tests->asArray()[0]->test()->testDox()->prettifiedClassName()); + foreach ($_tests as $test) { + if ($onlySummary && $test->status()->isSuccess()) { + continue; + } + $this->printTestResult($test); + } + $this->printer->print(PHP_EOL); + } + } + private function printPrettifiedClassName(string $prettifiedClassName): void + { + $buffer = $prettifiedClassName; + if ($this->colors) { + $buffer = Color::colorizeTextBox('underlined', $buffer); + } + $this->printer->print($buffer . PHP_EOL); + } + private function printTestResult(TestDoxTestResult $test): void + { + $this->printTestResultHeader($test); + $this->printTestResultBody($test); + } + private function printTestResultHeader(TestDoxTestResult $test): void + { + $buffer = ' ' . $this->symbolFor($test->status()) . ' '; + if ($this->colors) { + $this->printer->print(Color::colorizeTextBox($this->colorFor($test->status()), $buffer)); + } else { + $this->printer->print($buffer); + } + $this->printer->print($test->test()->testDox()->prettifiedMethodName($this->colors) . PHP_EOL); + } + private function printTestResultBody(TestDoxTestResult $test): void + { + if ($test->status()->isSuccess()) { + return; + } + if (!$test->hasThrowable()) { + return; + } + $this->printTestResultBodyStart($test); + $this->printThrowable($test->status(), $test->throwable()); + $this->printTestResultBodyEnd($test); + } + private function printTestResultBodyStart(TestDoxTestResult $test): void + { + $this->printer->print($this->prefixLines($this->prefixFor('start', $test->status()), '')); + $this->printer->print(PHP_EOL); + } + private function printTestResultBodyEnd(TestDoxTestResult $test): void + { + $this->printer->print(PHP_EOL); + $this->printer->print($this->prefixLines($this->prefixFor('last', $test->status()), '')); + $this->printer->print(PHP_EOL); + } + private function printThrowable(TestStatus $status, Throwable $throwable): void + { + $message = trim($throwable->description()); + $stackTrace = $this->formatStackTrace($throwable->stackTrace()); + $diff = ''; + if ($message !== '' && $this->colors) { + ['message' => $message, 'diff' => $diff] = $this->colorizeMessageAndDiff($message, $this->messageColorFor($status)); + } + if ($message !== '') { + $this->printer->print($this->prefixLines($this->prefixFor('message', $status), $message)); + $this->printer->print(PHP_EOL); + } + if ($diff !== '') { + $this->printer->print($this->prefixLines($this->prefixFor('diff', $status), $diff)); + $this->printer->print(PHP_EOL); + } + if ($stackTrace !== '') { + if ($message !== '' || $diff !== '') { + $tracePrefix = $this->prefixFor('default', $status); + } else { + $tracePrefix = $this->prefixFor('trace', $status); + } + $this->printer->print($this->prefixLines($tracePrefix, PHP_EOL . $stackTrace)); + } + if ($throwable->hasPrevious()) { + $this->printer->print(PHP_EOL); + $this->printer->print($this->prefixLines($this->prefixFor('default', $status), ' ')); + $this->printer->print(PHP_EOL); + $this->printer->print($this->prefixLines($this->prefixFor('default', $status), 'Caused by:')); + $this->printer->print(PHP_EOL); + $this->printThrowable($status, $throwable->previous()); + } + } + /** + * @return array{message: string, diff: string} + */ + private function colorizeMessageAndDiff(string $buffer, string $style): array + { + $lines = []; + if ($buffer !== '') { + $lines = array_map(rtrim(...), explode(PHP_EOL, $buffer)); + } + $message = []; + $diff = []; + $insideDiff = \false; + foreach ($lines as $line) { + if ($line === '--- Expected') { + $insideDiff = \true; + } + if (!$insideDiff) { + $message[] = $line; + } else { + if (str_starts_with($line, '-')) { + $line = Color::colorize('fg-red', Color::visualizeWhitespace($line, \true)); + } elseif (str_starts_with($line, '+')) { + $line = Color::colorize('fg-green', Color::visualizeWhitespace($line, \true)); + } elseif ($line === '@@ @@') { + $line = Color::colorize('fg-cyan', $line); + } + $diff[] = $line; + } + } + $message = implode(PHP_EOL, $message); + $diff = implode(PHP_EOL, $diff); + if ($message !== '') { + // Testdox output has a left-margin of 5; keep right-margin to prevent terminal scrolling + $message = Color::colorizeTextBox($style, $message, $this->columns - 7); + } + return ['message' => $message, 'diff' => $diff]; + } + private function formatStackTrace(string $stackTrace): string + { + if (!$this->colors) { + return rtrim($stackTrace); + } + $lines = []; + $previousPath = ''; + foreach (explode(PHP_EOL, $stackTrace) as $line) { + if (preg_match('/^(.*):(\d+)$/', $line, $matches) > 0) { + $lines[] = Color::colorizePath($matches[1], $previousPath) . Color::dim(':') . Color::colorize('fg-blue', $matches[2]) . "\n"; + $previousPath = $matches[1]; + continue; + } + $lines[] = $line; + $previousPath = ''; + } + return rtrim(implode('', $lines)); + } + private function prefixLines(string $prefix, string $message): string + { + $lines = preg_split('/\r\n|\r|\n/', $message); + if ($lines === \false) { + $lines = []; + } + return implode(PHP_EOL, array_map(static fn(string $line) => ' ' . $prefix . ($line !== '' ? ' ' . $line : ''), $lines)); + } + /** + * @param 'default'|'diff'|'last'|'message'|'start'|'trace' $type + */ + private function prefixFor(string $type, TestStatus $status): string + { + if (!$this->colors) { + return '│'; + } + return Color::colorize($this->colorFor($status), match ($type) { + 'default' => '│', + 'start' => 'â”', + 'message' => '├', + 'diff' => '┊', + 'trace' => '╵', + 'last' => 'â”´', + }); + } + private function colorFor(TestStatus $status): string + { + if ($status->isSuccess()) { + return 'fg-green'; + } + if ($status->isError()) { + return 'fg-yellow'; + } + if ($status->isFailure()) { + return 'fg-red'; + } + if ($status->isSkipped()) { + return 'fg-cyan'; + } + if ($status->isIncomplete() || $status->isDeprecation() || $status->isNotice() || $status->isRisky() || $status->isWarning()) { + return 'fg-yellow'; + } + return 'fg-blue'; + } + private function messageColorFor(TestStatus $status): string + { + if ($status->isSuccess()) { + return ''; + } + if ($status->isError()) { + return 'bg-yellow,fg-black'; + } + if ($status->isFailure()) { + return 'bg-red,fg-white'; + } + if ($status->isSkipped()) { + return 'fg-cyan'; + } + if ($status->isIncomplete() || $status->isDeprecation() || $status->isNotice() || $status->isRisky() || $status->isWarning()) { + return 'fg-yellow'; + } + return 'fg-white,bg-blue'; + } + private function symbolFor(TestStatus $status): string + { + if ($status->isSuccess()) { + return '✔'; + } + if ($status->isError() || $status->isFailure()) { + return '✘'; + } + if ($status->isSkipped()) { + return '↩'; + } + if ($status->isDeprecation() || $status->isNotice() || $status->isRisky() || $status->isWarning()) { + return 'âš '; + } + if ($status->isIncomplete()) { + return '∅'; + } + return '?'; + } + /** + * @param 'after-last-test'|'before-first-test' $type + * @param array $errors + */ + private function printBeforeClassOrAfterClassErrors(string $type, array $errors): void + { + if ($errors === []) { + return; + } + $this->printer->print(sprintf('These %s methods errored:' . PHP_EOL . PHP_EOL, $type)); + $index = 0; + foreach ($errors as $method => $error) { + $this->printer->print(sprintf('%d) %s' . PHP_EOL, ++$index, $method)); + $this->printer->print(trim($error->throwable()->description()) . PHP_EOL . PHP_EOL); + $this->printer->print($this->formatStackTrace($error->throwable()->stackTrace()) . PHP_EOL); + } + $this->printer->print(PHP_EOL); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\TextUI\Configuration\Configuration; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ShellExitCodeCalculator +{ + private const int SUCCESS_EXIT = 0; + private const int FAILURE_EXIT = 1; + private const int EXCEPTION_EXIT = 2; + public function calculate(Configuration $configuration, TestResult $result): int + { + $failOnDeprecation = \false; + $failOnPhpunitDeprecation = \false; + $failOnPhpunitNotice = \false; + $failOnPhpunitWarning = \false; + $failOnEmptyTestSuite = \false; + $failOnIncomplete = \false; + $failOnNotice = \false; + $failOnRisky = \false; + $failOnSkipped = \false; + $failOnWarning = \false; + if ($configuration->failOnAllIssues()) { + $failOnDeprecation = \true; + $failOnPhpunitDeprecation = \true; + $failOnPhpunitNotice = \true; + $failOnPhpunitWarning = \true; + $failOnEmptyTestSuite = \true; + $failOnIncomplete = \true; + $failOnNotice = \true; + $failOnRisky = \true; + $failOnSkipped = \true; + $failOnWarning = \true; + } + if ($configuration->failOnDeprecation()) { + $failOnDeprecation = \true; + } + if ($configuration->doNotFailOnDeprecation()) { + $failOnDeprecation = \false; + } + if ($configuration->failOnPhpunitDeprecation()) { + $failOnPhpunitDeprecation = \true; + } + if ($configuration->doNotFailOnPhpunitDeprecation()) { + $failOnPhpunitDeprecation = \false; + } + if ($configuration->failOnPhpunitNotice()) { + $failOnPhpunitNotice = \true; + } + if ($configuration->doNotFailOnPhpunitNotice()) { + $failOnPhpunitNotice = \false; + } + if ($configuration->failOnPhpunitWarning()) { + $failOnPhpunitWarning = \true; + } + if ($configuration->doNotFailOnPhpunitWarning()) { + $failOnPhpunitWarning = \false; + } + if ($configuration->failOnEmptyTestSuite()) { + $failOnEmptyTestSuite = \true; + } + if ($configuration->doNotFailOnEmptyTestSuite()) { + $failOnEmptyTestSuite = \false; + } + if ($configuration->failOnIncomplete()) { + $failOnIncomplete = \true; + } + if ($configuration->doNotFailOnIncomplete()) { + $failOnIncomplete = \false; + } + if ($configuration->failOnNotice()) { + $failOnNotice = \true; + } + if ($configuration->doNotFailOnNotice()) { + $failOnNotice = \false; + } + if ($configuration->failOnRisky()) { + $failOnRisky = \true; + } + if ($configuration->doNotFailOnRisky()) { + $failOnRisky = \false; + } + if ($configuration->failOnSkipped()) { + $failOnSkipped = \true; + } + if ($configuration->doNotFailOnSkipped()) { + $failOnSkipped = \false; + } + if ($configuration->failOnWarning()) { + $failOnWarning = \true; + } + if ($configuration->doNotFailOnWarning()) { + $failOnWarning = \false; + } + $returnCode = self::FAILURE_EXIT; + if ($result->wasSuccessful()) { + $returnCode = self::SUCCESS_EXIT; + } + if ($failOnEmptyTestSuite && !$result->hasTests()) { + $returnCode = self::FAILURE_EXIT; + } + if ($failOnDeprecation && $result->hasPhpOrUserDeprecations()) { + $returnCode = self::FAILURE_EXIT; + } + if ($failOnPhpunitDeprecation && $result->hasPhpunitDeprecations()) { + $returnCode = self::FAILURE_EXIT; + } + if ($failOnPhpunitNotice && $result->hasPhpunitNotices()) { + $returnCode = self::FAILURE_EXIT; + } + if ($failOnPhpunitWarning && $result->hasPhpunitWarnings()) { + $returnCode = self::FAILURE_EXIT; + } + if ($failOnIncomplete && $result->hasIncompleteTests()) { + $returnCode = self::FAILURE_EXIT; + } + if ($failOnNotice && $result->hasNotices()) { + $returnCode = self::FAILURE_EXIT; + } + if ($failOnRisky && $result->hasRiskyTests()) { + $returnCode = self::FAILURE_EXIT; + } + if ($failOnSkipped && $result->hasSkippedTests()) { + $returnCode = self::FAILURE_EXIT; + } + if ($failOnWarning && $result->hasWarnings()) { + $returnCode = self::FAILURE_EXIT; + } + if ($result->hasErrors()) { + $returnCode = self::EXCEPTION_EXIT; + } + return $returnCode; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function mt_srand; +use PHPUnit\Event; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\ResultCache\ResultCache; +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\TextUI\Configuration\Configuration; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestRunner +{ + /** + * @throws RuntimeException + */ + public function run(Configuration $configuration, ResultCache $resultCache, TestSuite $suite): void + { + try { + Event\Facade::emitter()->testRunnerStarted(); + if ($configuration->executionOrder() === TestSuiteSorter::ORDER_RANDOMIZED) { + mt_srand($configuration->randomOrderSeed()); + } + if ($configuration->executionOrder() !== TestSuiteSorter::ORDER_DEFAULT || $configuration->executionOrderDefects() !== TestSuiteSorter::ORDER_DEFAULT || $configuration->resolveDependencies()) { + $resultCache->load(); + (new TestSuiteSorter($resultCache))->reorderTestsInSuite($suite, $configuration->executionOrder(), $configuration->resolveDependencies(), $configuration->executionOrderDefects()); + Event\Facade::emitter()->testSuiteSorted($configuration->executionOrder(), $configuration->executionOrderDefects(), $configuration->resolveDependencies()); + } + (new \PHPUnit\TextUI\TestSuiteFilterProcessor())->process($configuration, $suite); + Event\Facade::emitter()->testRunnerExecutionStarted(Event\TestSuite\TestSuiteBuilder::from($suite)); + $suite->run(); + Event\Facade::emitter()->testRunnerExecutionFinished(); + Event\Facade::emitter()->testRunnerFinished(); + } catch (Throwable $t) { + throw new \PHPUnit\TextUI\RuntimeException($t->getMessage(), (int) $t->getCode(), $t); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function array_map; +use PHPUnit\Event; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\Filter\Factory; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\FilterNotConfiguredException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFilterProcessor +{ + /** + * @throws Event\RuntimeException + * @throws FilterNotConfiguredException + */ + public function process(Configuration $configuration, TestSuite $suite): void + { + $factory = new Factory(); + if (!$configuration->hasFilter() && !$configuration->hasGroups() && !$configuration->hasExcludeGroups() && !$configuration->hasExcludeFilter() && !$configuration->hasTestsCovering() && !$configuration->hasTestsUsing() && !$configuration->hasTestsRequiringPhpExtension()) { + return; + } + if ($configuration->hasExcludeGroups()) { + $factory->addExcludeGroupFilter($configuration->excludeGroups()); + } + if ($configuration->hasGroups()) { + $factory->addIncludeGroupFilter($configuration->groups()); + } + if ($configuration->hasTestsCovering()) { + $factory->addIncludeGroupFilter(array_map(static fn(string $name): string => '__phpunit_covers_' . $name, $configuration->testsCovering())); + } + if ($configuration->hasTestsUsing()) { + $factory->addIncludeGroupFilter(array_map(static fn(string $name): string => '__phpunit_uses_' . $name, $configuration->testsUsing())); + } + if ($configuration->hasTestsRequiringPhpExtension()) { + $factory->addIncludeGroupFilter(array_map(static fn(string $name): string => '__phpunit_requires_php_extension' . $name, $configuration->testsRequiringPhpExtension())); + } + if ($configuration->hasExcludeFilter()) { + $factory->addExcludeNameFilter($configuration->excludeFilter()); + } + if ($configuration->hasFilter()) { + $factory->addIncludeNameFilter($configuration->filter()); + } + $suite->injectFilter($factory); + Event\Facade::emitter()->testSuiteFiltered(Event\TestSuite\TestSuiteBuilder::from($suite)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const DIRECTORY_SEPARATOR; +use const PHP_EOL; +use function array_key_exists; +use function array_map; +use function array_walk; +use function assert; +use function count; +use function explode; +use function implode; +use function max; +use function min; +use function preg_replace; +use function preg_replace_callback; +use function preg_split; +use function sprintf; +use function str_pad; +use function strlen; +use function strtr; +use function trim; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Color +{ + /** + * @var non-empty-array + */ + private const array WHITESPACE_MAP = [' ' => '·', "\t" => '⇥']; + /** + * @var non-empty-array + */ + private const array WHITESPACE_EOL_MAP = [' ' => '·', "\t" => '⇥', "\n" => '↵', "\r" => '⟵']; + /** + * @var non-empty-array + */ + private const array ANSI_CODES = ['reset' => '0', 'bold' => '1', 'dim' => '2', 'dim-reset' => '22', 'underlined' => '4', 'fg-default' => '39', 'fg-black' => '30', 'fg-red' => '31', 'fg-green' => '32', 'fg-yellow' => '33', 'fg-blue' => '34', 'fg-magenta' => '35', 'fg-cyan' => '36', 'fg-white' => '37', 'bg-default' => '49', 'bg-black' => '40', 'bg-red' => '41', 'bg-green' => '42', 'bg-yellow' => '43', 'bg-blue' => '44', 'bg-magenta' => '45', 'bg-cyan' => '46', 'bg-white' => '47']; + /** + * @param non-empty-string $color + */ + public static function colorize(string $color, string $buffer): string + { + if (trim($buffer) === '') { + return $buffer; + } + if (array_key_exists($color, self::ANSI_CODES)) { + return self::optimizeColor(sprintf("\x1b[%sm%s\x1b[0m", self::ANSI_CODES[$color], $buffer)); + } + $styles = []; + foreach (explode(',', $color) as $code) { + $code = trim($code); + if (array_key_exists($code, self::ANSI_CODES)) { + $styles[] = self::ANSI_CODES[$code]; + } + } + if ($styles === []) { + return $buffer; + } + return self::optimizeColor(sprintf("\x1b[%sm%s\x1b[0m", implode(';', $styles), $buffer)); + } + /** + * @param non-empty-string $color + * @param ?non-negative-int $columns + */ + public static function colorizeTextBox(string $color, string $buffer, ?int $columns = null): string + { + $lines = preg_split('/\r\n|\r|\n/', $buffer); + $maxBoxWidth = max(array_map(strlen(...), $lines)); + if ($columns !== null) { + $maxBoxWidth = min($maxBoxWidth, $columns); + } + array_walk($lines, static function (string &$line) use ($color, $maxBoxWidth): void { + $line = self::colorize($color, str_pad($line, $maxBoxWidth)); + }); + return implode(PHP_EOL, $lines); + } + /** + * @param non-empty-string $path + * @param ?non-empty-string $previousPath + */ + public static function colorizePath(string $path, ?string $previousPath = null, bool $colorizeFilename = \false): string + { + if ($previousPath === null) { + $previousPath = ''; + } + $path = explode(DIRECTORY_SEPARATOR, $path); + $previousPath = explode(DIRECTORY_SEPARATOR, $previousPath); + for ($i = 0; $i < min(count($path), count($previousPath)); $i++) { + if ($path[$i] === $previousPath[$i]) { + $path[$i] = self::dim($path[$i]); + } + } + if ($colorizeFilename) { + $last = count($path) - 1; + $path[$last] = preg_replace_callback('/([\-_.]+|phpt$)/', static fn(array $matches) => self::dim($matches[0]), $path[$last]); + } + return self::optimizeColor(implode(self::dim(DIRECTORY_SEPARATOR), $path)); + } + public static function dim(string $buffer): string + { + if (trim($buffer) === '') { + return $buffer; + } + return "\x1b[2m{$buffer}\x1b[22m"; + } + public static function visualizeWhitespace(string $buffer, bool $visualizeEOL = \false): string + { + $replaceMap = $visualizeEOL ? self::WHITESPACE_EOL_MAP : self::WHITESPACE_MAP; + $result = preg_replace_callback('/\s+/', static fn(array $matches) => self::dim(strtr($matches[0], $replaceMap)), $buffer); + assert($result !== null); + return $result; + } + private static function optimizeColor(string $buffer): string + { + $result = preg_replace(["/\x1b\\[22m\x1b\\[2m/", "/\x1b\\[([^m]*)m\x1b\\[([1-9][0-9;]*)m/", "/(\x1b\\[[^m]*m)+(\x1b\\[0m)/"], ['', "\x1b[\$1;\$2m", '$2'], $buffer); + assert($result !== null); + return $result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidDirectoryException extends RuntimeException implements \PHPUnit\Util\Exception +{ + public function __construct(string $directory) + { + parent::__construct(sprintf('"%s" is not a directory', $directory)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidJsonException extends RuntimeException implements \PHPUnit\Util\Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function sprintf; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidVersionOperatorException extends RuntimeException implements \PHPUnit\Util\Exception +{ + public function __construct(string $operator) + { + parent::__construct(sprintf('"%s" is not a valid version_compare() operator', $operator)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +use PHPUnit\Util\Exception; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class PhpProcessException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\Xml; + +use PHPUnit\Util\Exception; +use RuntimeException; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class XmlException extends RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const PHP_OS_FAMILY; +use function array_any; +use function assert; +use function class_exists; +use function defined; +use function dirname; +use function is_dir; +use function realpath; +use function str_starts_with; +use function sys_get_temp_dir; +use PHPUnitPHAR\Composer\Autoload\ClassLoader; +use PHPUnitPHAR\DeepCopy\DeepCopy; +use PHPUnitPHAR\PharIo\Manifest\Manifest; +use PHPUnitPHAR\PharIo\Version\Version as PharIoVersion; +use PHPUnitPHAR\PhpParser\Parser; +use PHPUnit\Framework\TestCase; +use ReflectionClass; +use PHPUnitPHAR\SebastianBergmann\CliParser\Parser as CliParser; +use PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage; +use PHPUnitPHAR\SebastianBergmann\Comparator\Comparator; +use PHPUnitPHAR\SebastianBergmann\Complexity\Calculator; +use PHPUnitPHAR\SebastianBergmann\Diff\Diff; +use PHPUnitPHAR\SebastianBergmann\Environment\Runtime; +use PHPUnitPHAR\SebastianBergmann\Exporter\Exporter; +use PHPUnitPHAR\SebastianBergmann\FileIterator\Facade as FileIteratorFacade; +use PHPUnitPHAR\SebastianBergmann\GlobalState\Snapshot; +use PHPUnitPHAR\SebastianBergmann\Invoker\Invoker; +use PHPUnitPHAR\SebastianBergmann\LinesOfCode\Counter; +use PHPUnitPHAR\SebastianBergmann\ObjectEnumerator\Enumerator; +use PHPUnitPHAR\SebastianBergmann\ObjectReflector\ObjectReflector; +use PHPUnitPHAR\SebastianBergmann\RecursionContext\Context; +use PHPUnitPHAR\SebastianBergmann\Template\Template; +use PHPUnitPHAR\SebastianBergmann\Timer\Timer; +use PHPUnitPHAR\SebastianBergmann\Type\TypeName; +use PHPUnitPHAR\SebastianBergmann\Version; +use PHPUnitPHAR\staabm\SideEffectsDetector\SideEffectsDetector; +use PHPUnitPHAR\TheSeer\Tokenizer\Tokenizer; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ExcludeList +{ + /** + * @var non-empty-array + */ + private const array EXCLUDED_CLASS_NAMES = [ + // composer + ClassLoader::class => 1, + // myclabs/deepcopy + DeepCopy::class => 1, + // nikic/php-parser + Parser::class => 1, + // phar-io/manifest + Manifest::class => 1, + // phar-io/version + PharIoVersion::class => 1, + // phpunit/phpunit + TestCase::class => 2, + // phpunit/php-code-coverage + CodeCoverage::class => 1, + // phpunit/php-file-iterator + FileIteratorFacade::class => 1, + // phpunit/php-invoker + Invoker::class => 1, + // phpunit/php-text-template + Template::class => 1, + // phpunit/php-timer + Timer::class => 1, + // sebastian/cli-parser + CliParser::class => 1, + // sebastian/comparator + Comparator::class => 1, + // sebastian/complexity + Calculator::class => 1, + // sebastian/diff + Diff::class => 1, + // sebastian/environment + Runtime::class => 1, + // sebastian/exporter + Exporter::class => 1, + // sebastian/global-state + Snapshot::class => 1, + // sebastian/lines-of-code + Counter::class => 1, + // sebastian/object-enumerator + Enumerator::class => 1, + // sebastian/object-reflector + ObjectReflector::class => 1, + // sebastian/recursion-context + Context::class => 1, + // sebastian/type + TypeName::class => 1, + // sebastian/version + Version::class => 1, + // staabm/side-effects-detector + SideEffectsDetector::class => 1, + // theseer/tokenizer + Tokenizer::class => 1, + ]; + /** + * @var list + */ + private static array $directories = []; + private static bool $initialized = \false; + private readonly bool $enabled; + /** + * @param non-empty-string $directory + * + * @throws InvalidDirectoryException + */ + public static function addDirectory(string $directory): void + { + if (!is_dir($directory)) { + throw new \PHPUnit\Util\InvalidDirectoryException($directory); + } + $directory = realpath($directory); + assert($directory !== \false); + self::$directories[] = $directory; + } + public function __construct(?bool $enabled = null) + { + if ($enabled === null) { + $enabled = !defined('PHPUNIT_TESTSUITE'); + } + $this->enabled = $enabled; + } + /** + * @return list + */ + public function getExcludedDirectories(): array + { + self::initialize(); + return self::$directories; + } + public function isExcluded(string $file): bool + { + if (!$this->enabled) { + return \false; + } + self::initialize(); + return array_any(self::$directories, static fn(string $directory) => str_starts_with($file, $directory)); + } + private static function initialize(): void + { + if (self::$initialized) { + return; + } + foreach (self::EXCLUDED_CLASS_NAMES as $className => $parent) { + if (!class_exists($className)) { + continue; + } + $directory = (new ReflectionClass($className))->getFileName(); + for ($i = 0; $i < $parent; $i++) { + $directory = dirname($directory); + } + self::$directories[] = $directory; + } + /** + * Hide process isolation workaround on Windows: + * tempnam() prefix is limited to first 3 characters. + * + * @see https://php.net/manual/en/function.tempnam.php + */ + if (PHP_OS_FAMILY === 'Windows') { + // @codeCoverageIgnoreStart + self::$directories[] = sys_get_temp_dir() . '\PHP'; + // @codeCoverageIgnoreEnd + } + self::$initialized = \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use PHPUnitPHAR\SebastianBergmann\Exporter\Exporter as OriginalExporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class Exporter +{ + private static ?OriginalExporter $exporter = null; + public static function export(mixed $value): string + { + return \PHPUnit\Util\Sanitizer::sanitizeBidirectionalControlCharacters(self::exporter()->export($value)); + } + /** + * @param array $data + */ + public static function shortenedRecursiveExport(array $data): string + { + return \PHPUnit\Util\Sanitizer::sanitizeBidirectionalControlCharacters(self::exporter()->shortenedRecursiveExport($data)); + } + public static function shortenedExport(mixed $value): string + { + return \PHPUnit\Util\Sanitizer::sanitizeBidirectionalControlCharacters(self::exporter()->shortenedExport($value)); + } + private static function exporter(): OriginalExporter + { + if (self::$exporter !== null) { + return self::$exporter; + } + self::$exporter = new OriginalExporter(ConfigurationRegistry::get()->shortenArraysForExportThreshold()); + return self::$exporter; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const DIRECTORY_SEPARATOR; +use function basename; +use function dirname; +use function is_dir; +use function mkdir; +use function realpath; +use function str_starts_with; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Filesystem +{ + public static function createDirectory(string $directory): bool + { + return !(!is_dir($directory) && !@mkdir($directory, 0777, \true) && !is_dir($directory)); + } + /** + * @param non-empty-string $path + * + * @return false|non-empty-string + */ + public static function resolveStreamOrFile(string $path): false|string + { + if (str_starts_with($path, 'php://') || str_starts_with($path, 'socket://')) { + return $path; + } + $directory = dirname($path); + if (is_dir($directory)) { + return realpath($directory) . DIRECTORY_SEPARATOR . basename($path); + } + return \false; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function array_any; +use function array_unshift; +use function defined; +use function in_array; +use function is_array; +use function is_file; +use function realpath; +use function sprintf; +use function str_starts_with; +use PHPUnit\Framework\Exception; +use PHPUnit\Framework\PhptAssertionFailedError; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Filter +{ + /** + * @throws Exception + */ + public static function stackTraceFromThrowableAsString(Throwable $t, bool $unwrap = \true): string + { + if ($t instanceof PhptAssertionFailedError) { + $stackTrace = $t->syntheticTrace(); + $file = $t->syntheticFile(); + $line = $t->syntheticLine(); + } elseif ($t instanceof Exception) { + $stackTrace = $t->getSerializableTrace(); + $file = $t->getFile(); + $line = $t->getLine(); + } else { + if ($unwrap && $t->getPrevious() !== null) { + $t = $t->getPrevious(); + } + $stackTrace = $t->getTrace(); + $file = $t->getFile(); + $line = $t->getLine(); + } + if (!self::frameExists($stackTrace, $file, $line)) { + array_unshift($stackTrace, ['file' => $file, 'line' => $line]); + } + return self::stackTraceAsString($stackTrace); + } + /** + * @param list $frames + */ + private static function stackTraceAsString(array $frames): string + { + $buffer = ''; + $prefix = defined('__PHPUNIT_PHAR_ROOT__') ? __PHPUNIT_PHAR_ROOT__ : \false; + $excludeList = new \PHPUnit\Util\ExcludeList(); + foreach ($frames as $frame) { + if (self::shouldPrintFrame($frame, $prefix, $excludeList)) { + $buffer .= sprintf("%s:%s\n", $frame['file'], $frame['line'] ?? '?'); + } + } + return $buffer; + } + /** + * @param array{file?: non-empty-string} $frame + */ + private static function shouldPrintFrame(array $frame, false|string $prefix, \PHPUnit\Util\ExcludeList $excludeList): bool + { + if (!isset($frame['file'])) { + return \false; + } + $file = $frame['file']; + $fileIsNotPrefixed = $prefix === \false || !str_starts_with($file, $prefix); + // @see https://github.com/sebastianbergmann/phpunit/issues/4033 + if (isset($GLOBALS['_SERVER']['SCRIPT_NAME'])) { + $script = realpath($GLOBALS['_SERVER']['SCRIPT_NAME']); + } else { + // @codeCoverageIgnoreStart + $script = ''; + // @codeCoverageIgnoreEnd + } + return $fileIsNotPrefixed && $file !== $script && self::fileIsExcluded($file, $excludeList) && is_file($file); + } + private static function fileIsExcluded(string $file, \PHPUnit\Util\ExcludeList $excludeList): bool + { + return (!isset($GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST']) || !is_array($GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST']) || $GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'] === [] || !in_array($file, $GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'], \true)) && !$excludeList->isExcluded($file); + } + /** + * @param list $trace + */ + private static function frameExists(array $trace, string $file, int $line): bool + { + return array_any($trace, static fn(array $frame) => isset($frame['file'], $frame['line']) && $frame['file'] === $file && $frame['line'] === $line); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const PHP_MAJOR_VERSION; +use const PHP_MINOR_VERSION; +use function array_reverse; +use function array_shift; +use function assert; +use function defined; +use function get_defined_constants; +use function get_included_files; +use function in_array; +use function ini_get_all; +use function is_array; +use function is_file; +use function is_scalar; +use function preg_match; +use function serialize; +use function sprintf; +use function str_ends_with; +use function str_starts_with; +use function strtr; +use function var_export; +use Closure; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GlobalState +{ + /** + * @var non-empty-list + */ + private const array SUPER_GLOBAL_ARRAYS = ['_ENV', '_POST', '_GET', '_COOKIE', '_SERVER', '_FILES', '_REQUEST']; + /** + * Keys in $_SERVER that are populated by the SAPI in the child process + * and must therefore not be preserved from the parent process. + * + * @var non-empty-list + */ + private const array SAPI_SERVER_KEYS = ['PHP_SELF', 'SCRIPT_NAME', 'SCRIPT_FILENAME', 'PATH_TRANSLATED', 'DOCUMENT_ROOT', 'REQUEST_TIME', 'REQUEST_TIME_FLOAT', 'argv', 'argc']; + /** + * @var non-empty-array> + */ + private const array DEPRECATED_INI_SETTINGS = ['7.3' => ['iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.func_overload' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'string.strip_tags' => \true], '7.4' => ['iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.func_overload' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'pdo_odbc.db2_instance_name' => \true, 'string.strip_tags' => \true], '8.0' => ['iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true], '8.1' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true], '8.2' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true], '8.3' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true], '8.4' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true], '8.5' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true], '8.6' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true]]; + /** + * @throws Exception + */ + public static function getIncludedFilesAsString(): string + { + return self::processIncludedFilesAsString(get_included_files()); + } + /** + * @param list $files + * + * @throws Exception + */ + public static function processIncludedFilesAsString(array $files): string + { + $excludeList = new \PHPUnit\Util\ExcludeList(); + $prefix = \false; + $result = ''; + if (defined('__PHPUNIT_PHAR__')) { + // @codeCoverageIgnoreStart + $prefix = 'phar://' . __PHPUNIT_PHAR__ . '/'; + // @codeCoverageIgnoreEnd + } + // Do not process bootstrap script + array_shift($files); + // If bootstrap script was a Composer bin proxy, skip the second entry as well + if (str_ends_with(strtr($files[0], '\\', '/'), '/phpunit/phpunit/phpunit')) { + // @codeCoverageIgnoreStart + array_shift($files); + // @codeCoverageIgnoreEnd + } + foreach (array_reverse($files) as $file) { + if (isset($GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST']) && is_array($GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST']) && $GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'] !== [] && in_array($file, $GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'], \true)) { + continue; + } + if ($prefix !== \false && str_starts_with($file, $prefix)) { + continue; + } + // Skip virtual file system protocols + if (preg_match('/^(vfs|phpvfs[a-z0-9]+):/', $file) > 0) { + continue; + } + if (!$excludeList->isExcluded($file) && is_file($file)) { + $result = 'require_once \'' . $file . "';\n" . $result; + } + } + return $result; + } + public static function getIniSettingsAsString(): string + { + $result = ''; + $iniSettings = ini_get_all(null, \false); + assert($iniSettings !== \false); + foreach ($iniSettings as $key => $value) { + if (self::isIniSettingDeprecated($key)) { + continue; + } + $result .= sprintf('@ini_set(%s, %s);' . "\n", self::exportVariable($key), self::exportVariable((string) $value)); + } + return $result; + } + public static function getConstantsAsString(): string + { + $constants = get_defined_constants(\true); + $result = ''; + if (isset($constants['user'])) { + foreach ($constants['user'] as $name => $value) { + $result .= sprintf('if (!defined(\'%s\')) define(\'%s\', %s);' . "\n", $name, $name, self::exportVariable($value)); + } + } + return $result; + } + public static function exportGlobals(): \PHPUnit\Util\GlobalStateResult + { + $result = ''; + $skippedGlobals = []; + foreach (self::SUPER_GLOBAL_ARRAYS as $superGlobalArray) { + if (isset($GLOBALS[$superGlobalArray]) && is_array($GLOBALS[$superGlobalArray])) { + foreach ($GLOBALS[$superGlobalArray] as $key => $value) { + if ($superGlobalArray === '_SERVER' && in_array($key, self::SAPI_SERVER_KEYS, \true)) { + continue; + } + $name = sprintf('$GLOBALS[\'%s\'][\'%s\']', $superGlobalArray, $key); + if ($value instanceof Closure) { + $skippedGlobals[] = ['name' => $name, 'reason' => 'is a Closure']; + continue; + } + try { + $result .= sprintf('$GLOBALS[\'%s\'][\'%s\'] = %s;' . "\n", $superGlobalArray, $key, self::exportVariable($GLOBALS[$superGlobalArray][$key])); + } catch (Throwable) { + $skippedGlobals[] = ['name' => $name, 'reason' => 'is not serializable']; + } + } + } + } + $excludeList = self::SUPER_GLOBAL_ARRAYS; + $excludeList[] = 'GLOBALS'; + foreach ($GLOBALS as $key => $value) { + if (in_array($key, $excludeList, \true)) { + continue; + } + $name = sprintf('$GLOBALS[\'%s\']', $key); + if ($value instanceof Closure) { + $skippedGlobals[] = ['name' => $name, 'reason' => 'is a Closure']; + continue; + } + try { + $result .= sprintf('$GLOBALS[\'%s\'] = %s;' . "\n", $key, self::exportVariable($value)); + } catch (Throwable) { + $skippedGlobals[] = ['name' => $name, 'reason' => 'is not serializable']; + } + } + return new \PHPUnit\Util\GlobalStateResult($result, $skippedGlobals); + } + private static function exportVariable(mixed $variable): string + { + if (is_scalar($variable) || $variable === null || is_array($variable) && self::arrayOnlyContainsScalars($variable)) { + return var_export($variable, \true); + } + return 'unserialize(' . var_export(serialize($variable), \true) . ')'; + } + /** + * @param array $array + */ + private static function arrayOnlyContainsScalars(array $array): bool + { + $result = \true; + foreach ($array as $element) { + if (is_array($element)) { + $result = self::arrayOnlyContainsScalars($element); + } elseif (!is_scalar($element) && $element !== null) { + $result = \false; + } + if (!$result) { + break; + } + } + return $result; + } + private static function isIniSettingDeprecated(string $iniSetting): bool + { + return isset(self::DEPRECATED_INI_SETTINGS[PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION][$iniSetting]); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GlobalStateResult +{ + /** + * @param list $skippedGlobals + */ + private string $globalsString; + /** + * @var list + */ + private array $skippedGlobals; + /** + * @param list $skippedGlobals + */ + public function __construct(string $globalsString, array $skippedGlobals) + { + $this->globalsString = $globalsString; + $this->skippedGlobals = $skippedGlobals; + } + public function globalsString(): string + { + return $this->globalsString; + } + /** + * @return list + */ + public function skippedGlobals(): array + { + return $this->skippedGlobals; + } + public function hasSkippedGlobals(): bool + { + return $this->skippedGlobals !== []; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\Http; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Downloader +{ + /** + * @param non-empty-string $url + */ + public function download(string $url): false|string; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\Http; + +use function file_get_contents; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ +final class PhpDownloader implements \PHPUnit\Util\Http\Downloader +{ + /** + * @param non-empty-string $url + */ + public function download(string $url): false|string + { + return file_get_contents($url); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const JSON_ERROR_NONE; +use const JSON_PRETTY_PRINT; +use const JSON_UNESCAPED_SLASHES; +use const JSON_UNESCAPED_UNICODE; +use const SORT_STRING; +use function assert; +use function is_object; +use function is_scalar; +use function json_decode; +use function json_encode; +use function json_last_error; +use function ksort; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Json +{ + /** + * @throws InvalidJsonException + */ + public static function prettify(string $json): string + { + $decodedJson = json_decode($json, \false); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \PHPUnit\Util\InvalidJsonException(); + } + $result = json_encode($decodedJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + assert($result !== \false); + return $result; + } + /** + * Element 0 is true and element 1 is null when JSON decoding did not work. + * * Element 0 is false and element 1 has the decoded value when JSON decoding did work. + * * This is used to avoid ambiguity with JSON strings consisting entirely of 'null' or 'false'. + * + * @return array{0: false, 1: mixed}|array{0: true, 1: null} + */ + public static function canonicalize(string $json): array + { + $decodedJson = json_decode($json); + if (json_last_error() !== JSON_ERROR_NONE) { + return [\true, null]; + } + self::recursiveSort($decodedJson); + $reencodedJson = json_encode($decodedJson); + return [\false, $reencodedJson]; + } + /** + * JSON object keys are unordered while PHP array keys are ordered. + * + * Sort all array keys to ensure both the expected and actual values have + * their keys in the same order. + */ + private static function recursiveSort(mixed &$json): void + { + if ($json === null || $json === [] || is_scalar($json)) { + return; + } + $isObject = is_object($json); + if ($isObject) { + // Objects need to be sorted during canonicalization to ensure + // correct comparsion since JSON objects are unordered. It must be + // kept as an object so that the value correctly stays as a JSON + // object instead of potentially being converted to an array. This + // approach ensures that numeric string JSON keys are preserved and + // don't risk being flattened due to PHP's array semantics. + // See #2919, #4584, #4674 + $json = (array) $json; + ksort($json, SORT_STRING); + } + foreach ($json as &$value) { + self::recursiveSort($value); + } + if ($isObject) { + $json = (object) $json; + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Job +{ + /** + * @var non-empty-string + */ + private string $code; + /** + * @var list + */ + private array $phpSettings; + /** + * @var array + */ + private array $environmentVariables; + /** + * @var list + */ + private array $arguments; + /** + * @var ?non-empty-string + */ + private ?string $input; + private bool $redirectErrors; + private bool $requiresXdebug; + /** + * @param non-empty-string $code + * @param list $phpSettings + * @param array $environmentVariables + * @param list $arguments + * @param ?non-empty-string $input + */ + public function __construct(string $code, array $phpSettings = [], array $environmentVariables = [], array $arguments = [], ?string $input = null, bool $redirectErrors = \false, bool $requiresXdebug = \false) + { + $this->code = $code; + $this->phpSettings = $phpSettings; + $this->environmentVariables = $environmentVariables; + $this->arguments = $arguments; + $this->input = $input; + $this->redirectErrors = $redirectErrors; + $this->requiresXdebug = $requiresXdebug; + } + /** + * @return non-empty-string + */ + public function code(): string + { + return $this->code; + } + /** + * @return list + */ + public function phpSettings(): array + { + return $this->phpSettings; + } + /** + * @phpstan-assert-if-true !empty $this->environmentVariables + */ + public function hasEnvironmentVariables(): bool + { + return $this->environmentVariables !== []; + } + /** + * @return array + */ + public function environmentVariables(): array + { + return $this->environmentVariables; + } + /** + * @phpstan-assert-if-true !empty $this->arguments + */ + public function hasArguments(): bool + { + return $this->arguments !== []; + } + /** + * @return list + */ + public function arguments(): array + { + return $this->arguments; + } + /** + * @phpstan-assert-if-true !empty $this->input + */ + public function hasInput(): bool + { + return $this->input !== null; + } + /** + * @throws PhpProcessException + * + * @return non-empty-string + */ + public function input(): string + { + if ($this->input === null) { + throw new \PHPUnit\Util\PHP\PhpProcessException('No input specified'); + } + return $this->input; + } + public function redirectErrors(): bool + { + return $this->redirectErrors; + } + public function requiresXdebug(): bool + { + return $this->requiresXdebug; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +use const PHP_BINARY; +use const PHP_SAPI; +use function array_keys; +use function array_merge; +use function array_values; +use function assert; +use function count; +use function explode; +use function fclose; +use function file_get_contents; +use function file_put_contents; +use function function_exists; +use function fwrite; +use function ini_get_all; +use function is_array; +use function is_file; +use function is_resource; +use function proc_close; +use function proc_open; +use function sprintf; +use function str_contains; +use function str_replace; +use function str_starts_with; +use function stream_get_contents; +use function sys_get_temp_dir; +use function tempnam; +use function trim; +use function unlink; +use function xdebug_is_debugger_active; +use PHPUnit\Event\Facade; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\ChildProcessResultProcessor; +use PHPUnit\Framework\Test; +use PHPUnit\Runner\CodeCoverage; +use PHPUnitPHAR\SebastianBergmann\Environment\Runtime; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class JobRunner +{ + private ChildProcessResultProcessor $processor; + public function __construct(ChildProcessResultProcessor $processor) + { + $this->processor = $processor; + } + /** + * @param non-empty-string $processResultFile + * @param ?non-empty-string $processResultNonce + */ + public function runTestJob(\PHPUnit\Util\PHP\Job $job, string $processResultFile, Test $test, ?string $processResultNonce = null): void + { + $result = $this->run($job); + $processResult = ''; + if (is_file($processResultFile)) { + $processResult = file_get_contents($processResultFile); + assert($processResult !== \false); + @unlink($processResultFile); + } + $this->processor->process($test, $processResult, $result->stderr(), $processResultNonce); + EventFacade::emitter()->childProcessFinished($result->stdout(), $result->stderr()); + } + /** + * @throws PhpProcessException + */ + public function run(\PHPUnit\Util\PHP\Job $job): \PHPUnit\Util\PHP\Result + { + $temporaryFile = null; + if ($job->hasInput()) { + $temporaryFile = tempnam(sys_get_temp_dir(), 'phpunit_'); + if ($temporaryFile === \false || file_put_contents($temporaryFile, $job->code()) === \false) { + // @codeCoverageIgnoreStart + throw new \PHPUnit\Util\PHP\PhpProcessException('Unable to write temporary file'); + // @codeCoverageIgnoreEnd + } + $job = new \PHPUnit\Util\PHP\Job($job->input(), $job->phpSettings(), $job->environmentVariables(), $job->arguments(), null, $job->redirectErrors(), $job->requiresXdebug()); + } + assert($temporaryFile !== ''); + return $this->runProcess($job, $temporaryFile); + } + /** + * @param ?non-empty-string $temporaryFile + * + * @throws PhpProcessException + */ + private function runProcess(\PHPUnit\Util\PHP\Job $job, ?string $temporaryFile): \PHPUnit\Util\PHP\Result + { + $environmentVariables = null; + if ($job->hasEnvironmentVariables()) { + /** @phpstan-ignore nullCoalesce.variable */ + $environmentVariables = $_SERVER ?? []; + unset($environmentVariables['argv'], $environmentVariables['argc']); + $environmentVariables = array_merge($environmentVariables, $job->environmentVariables()); + foreach ($environmentVariables as $key => $value) { + if (is_array($value)) { + unset($environmentVariables[$key]); + } + } + unset($key, $value); + } + $pipeSpec = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; + if ($job->redirectErrors()) { + $pipeSpec[2] = ['redirect', 1]; + } + $process = proc_open($this->buildCommand($job, $temporaryFile), $pipeSpec, $pipes, null, $environmentVariables); + if (!is_resource($process)) { + // @codeCoverageIgnoreStart + throw new \PHPUnit\Util\PHP\PhpProcessException('Unable to spawn worker process'); + // @codeCoverageIgnoreEnd + } + Facade::emitter()->childProcessStarted(); + fwrite($pipes[0], $job->code()); + fclose($pipes[0]); + $stdout = ''; + $stderr = ''; + if (isset($pipes[1])) { + $stdout = stream_get_contents($pipes[1]); + fclose($pipes[1]); + } + if (isset($pipes[2])) { + $stderr = stream_get_contents($pipes[2]); + fclose($pipes[2]); + } + proc_close($process); + if ($temporaryFile !== null) { + unlink($temporaryFile); + } + assert($stdout !== \false); + assert($stderr !== \false); + return new \PHPUnit\Util\PHP\Result($stdout, $stderr); + } + /** + * @return non-empty-list + */ + private function buildCommand(\PHPUnit\Util\PHP\Job $job, ?string $file): array + { + $runtime = new Runtime(); + $command = [PHP_BINARY]; + $phpSettings = $job->phpSettings(); + $xdebugModeConfiguredExplicitly = \false; + foreach ($phpSettings as $phpSetting) { + if (str_starts_with($phpSetting, 'xdebug.mode')) { + $xdebugModeConfiguredExplicitly = \true; + break; + } + } + if ($runtime->hasPCOV()) { + $pcovSettings = ini_get_all('pcov'); + assert($pcovSettings !== \false); + // The settings forwarded from the current process must be applied + // before the settings configured for the job so that the latter, + // for instance a "pcov.directory" set in the --INI-- section of a + // PHPT test, take precedence: the value of the last -d flag wins. + $phpSettings = array_merge($runtime->getCurrentSettings(array_keys($pcovSettings)), $phpSettings); + } elseif ($runtime->hasXdebug()) { + assert(function_exists('xdebug_is_debugger_active')); + $xdebugSettings = ini_get_all('xdebug'); + assert($xdebugSettings !== \false); + // The settings forwarded from the current process must be applied + // before the settings configured for the job so that the latter + // take precedence: the value of the last -d flag wins. + $phpSettings = array_merge($runtime->getCurrentSettings(array_keys($xdebugSettings)), $phpSettings); + if (!$xdebugModeConfiguredExplicitly && !CodeCoverage::instance()->isActive() && xdebug_is_debugger_active() === \false && !$job->requiresXdebug()) { + // disable xdebug to speedup test execution + $phpSettings['xdebug.mode'] = 'xdebug.mode=off'; + } + } + $phpSettings = array_merge($phpSettings, $this->cliIniOverrides($phpSettings)); + $command = array_merge($command, $this->settingsToParameters(array_values($phpSettings))); + if (PHP_SAPI === 'phpdbg') { + $command[] = '-qrr'; + if ($file === null) { + $command[] = 's='; + } + } + if ($file !== null) { + $command[] = '-f'; + $command[] = $file; + } + if ($job->hasArguments()) { + if ($file === null) { + $command[] = '--'; + } + foreach ($job->arguments() as $argument) { + $command[] = trim($argument); + } + } + return $command; + } + /** + * Detects INI settings that cannot be set via ini_set() (PHP_INI_SYSTEM + * and PHP_INI_PERDIR) and whose current value differs from the value + * configured in INI files. + * + * These settings must be forwarded as -d flags to child processes + * because the @ini_set() calls in GlobalState::getIniSettingsAsString() + * cannot change them at runtime. + * + * @param array $alreadySet + * + * @return array + */ + private function cliIniOverrides(array $alreadySet): array + { + $overrides = (new Runtime())->getSettingsNotChangeableAtRuntime(); + foreach ($overrides as $key => $value) { + foreach ($alreadySet as $existing) { + if (str_starts_with($existing, $key . '=')) { + unset($overrides[$key]); + break; + } + } + } + return $overrides; + } + /** + * @param list $settings + * + * @throws PhpProcessException + * + * @return list + */ + private function settingsToParameters(array $settings): array + { + $buffer = []; + foreach ($settings as $setting) { + $buffer[] = '-d'; + $buffer[] = $this->processSettingValue($setting); + } + return $buffer; + } + /** + * Rejects "name=value" INI settings whose value contains a line-break + * character. A newline cannot legitimately appear in a PHP INI value and + * would, if forwarded unchanged, be parsed by the child process as a + * directive separator — turning a single setting into an attacker- + * controlled sequence of directives. + * + * Otherwise quotes the value portion only when it contains characters + * PHP's INI parser would interpret as metacharacters (`;` starts a + * comment, `"` is a string delimiter, `=` is the assignment operator + * that would otherwise be parsed as starting a new directive and + * trigger `PHP: syntax error, unexpected '='`). + * + * Quoting is avoided for plain values so that boolean keywords such as + * `On` / `Off` keep their special INI semantics; wrapping them in quotes + * turns them into the literal strings `"On"` / `"Off"` and breaks + * settings like `output_buffering`. + * + * @throws PhpProcessException + */ + private function processSettingValue(string $setting): string + { + $parts = explode('=', $setting, 2); + if (count($parts) !== 2) { + return $setting; + } + [$name, $value] = $parts; + if (str_contains($value, "\n") || str_contains($value, "\r")) { + throw new \PHPUnit\Util\PHP\PhpProcessException(sprintf('PHP setting "%s" contains a line-break character, which is not permitted', $name)); + } + if (!str_contains($value, ';') && !str_contains($value, '"') && !str_contains($value, '=')) { + return $setting; + } + return $name . '="' . str_replace('"', '\"', $value) . '"'; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +use PHPUnit\Event\Facade; +use PHPUnit\Framework\ChildProcessResultProcessor; +use PHPUnit\Framework\Test; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\TestRunner\TestResult\PassedTests; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class JobRunnerRegistry +{ + private static ?\PHPUnit\Util\PHP\JobRunner $runner = null; + public static function run(\PHPUnit\Util\PHP\Job $job): \PHPUnit\Util\PHP\Result + { + return self::runner()->run($job); + } + /** + * @param non-empty-string $processResultFile + * @param ?non-empty-string $processResultNonce + */ + public static function runTestJob(\PHPUnit\Util\PHP\Job $job, string $processResultFile, Test $test, ?string $processResultNonce = null): void + { + self::runner()->runTestJob($job, $processResultFile, $test, $processResultNonce); + } + public static function set(\PHPUnit\Util\PHP\JobRunner $runner): void + { + self::$runner = $runner; + } + private static function runner(): \PHPUnit\Util\PHP\JobRunner + { + if (self::$runner === null) { + self::$runner = new \PHPUnit\Util\PHP\JobRunner(new ChildProcessResultProcessor(Facade::instance(), Facade::emitter(), PassedTests::instance(), CodeCoverage::instance())); + } + return self::$runner; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Result +{ + private string $stdout; + private string $stderr; + public function __construct(string $stdout, string $stderr) + { + $this->stdout = $stdout; + $this->stderr = $stderr; + } + public function stdout(): string + { + return $this->stdout; + } + public function stderr(): string + { + return $this->stderr; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function array_keys; +use function array_merge; +use function array_reverse; +use function assert; +use PHPUnit\Framework\Assert; +use PHPUnit\Framework\TestCase; +use ReflectionClass; +use ReflectionException; +use ReflectionMethod; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Reflection +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @return array{file: non-empty-string, line: non-negative-int} + */ + public static function sourceLocationFor(string $className, string $methodName): array + { + try { + $reflector = new ReflectionMethod($className, $methodName); + $file = $reflector->getFileName(); + $line = $reflector->getStartLine(); + } catch (ReflectionException) { + $file = 'unknown'; + $line = 0; + } + assert($file !== \false && $file !== ''); + assert($line !== \false && $line >= 0); + return ['file' => $file, 'line' => $line]; + } + /** + * @param ReflectionClass $class + * + * @return list + */ + public static function publicMethodsDeclaredDirectlyInTestClass(ReflectionClass $class): array + { + return self::filterAndSortMethods($class, ReflectionMethod::IS_PUBLIC, \true); + } + /** + * @param ReflectionClass $class + * + * @return list + */ + public static function methodsDeclaredDirectlyInTestClass(ReflectionClass $class): array + { + return self::filterAndSortMethods($class, null, \false); + } + /** + * @param ReflectionClass $class + * + * @return list + */ + private static function filterAndSortMethods(ReflectionClass $class, ?int $filter, bool $sortHighestToLowest): array + { + $methodsByClass = []; + foreach ($class->getMethods($filter) as $method) { + $declaringClassName = $method->getDeclaringClass()->getName(); + if ($declaringClassName === TestCase::class) { + continue; + } + if ($declaringClassName === Assert::class) { + continue; + } + if (!isset($methodsByClass[$declaringClassName])) { + $methodsByClass[$declaringClassName] = []; + } + $methodsByClass[$declaringClassName][] = $method; + } + $classNames = array_keys($methodsByClass); + if ($sortHighestToLowest) { + $classNames = array_reverse($classNames); + } + $methods = []; + foreach ($classNames as $className) { + $methods = array_merge($methods, $methodsByClass[$className]); + } + return $methods; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function mb_ord; +use function preg_replace_callback; +use function sprintf; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Sanitizer +{ + /** + * Replaces Unicode bidirectional formatting characters with their visible \u{NNNN} escape sequence. + * + * Matches the UTF-8 byte sequences for U+202A-U+202E and U+2066-U+2069 directly so that + * the function is safe to call on strings that are not valid UTF-8. + * + * @see https://github.com/sebastianbergmann/phpunit/issues/6605 + */ + public static function sanitizeBidirectionalControlCharacters(string $value): string + { + return preg_replace_callback('/\xE2\x80[\xAA-\xAE]|\xE2\x81[\xA6-\xA9]/', static fn(array $matches) => sprintf('\u{%04X}', mb_ord($matches[0], 'UTF-8')), $value); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const DEBUG_BACKTRACE_IGNORE_ARGS; +use const DEBUG_BACKTRACE_PROVIDE_OBJECT; +use function debug_backtrace; +use function str_starts_with; +use PHPUnit\Event\Code\NoTestCaseObjectOnCallStackException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\Parser\Registry; +use ReflectionMethod; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Test +{ + /** + * @throws NoTestCaseObjectOnCallStackException + */ + public static function currentTestCase(): TestCase + { + foreach (debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) { + if (isset($frame['object']) && $frame['object'] instanceof TestCase) { + return $frame['object']; + } + } + throw new NoTestCaseObjectOnCallStackException(); + } + public static function isTestMethod(ReflectionMethod $method): bool + { + if (!$method->isPublic()) { + return \false; + } + if (str_starts_with($method->getName(), 'test')) { + return \true; + } + $metadata = Registry::parser()->forMethod($method->getDeclaringClass()->getName(), $method->getName()); + return $metadata->isTest()->isNotEmpty(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function trim; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\PhptAssertionFailedError; +use PHPUnit\Framework\SelfDescribing; +use PHPUnit\Runner\ErrorException; +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ThrowableToStringMapper +{ + public static function map(Throwable $t): string + { + if ($t instanceof ErrorException) { + return $t->getMessage(); + } + if ($t instanceof SelfDescribing) { + $buffer = $t->toString(); + if ($t instanceof ExpectationFailedException && $t->getComparisonFailure() !== null) { + $buffer .= $t->getComparisonFailure()->getDiff(); + } + if ($t instanceof PhptAssertionFailedError) { + $buffer .= $t->diff(); + } + if ($buffer !== '') { + $buffer = trim($buffer) . "\n"; + } + return $buffer; + } + return $t::class . ': ' . $t->getMessage() . "\n"; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function in_array; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class VersionComparisonOperator +{ + /** + * @var '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' + */ + private string $operator; + /** + * @param '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' $operator + * + * @throws InvalidVersionOperatorException + */ + public function __construct(string $operator) + { + $this->ensureOperatorIsValid($operator); + $this->operator = $operator; + } + /** + * @return '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' + */ + public function asString(): string + { + return $this->operator; + } + /** + * @param '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' $operator + * + * @throws InvalidVersionOperatorException + */ + private function ensureOperatorIsValid(string $operator): void + { + if (!in_array($operator, ['<', 'lt', '<=', 'le', '>', 'gt', '>=', 'ge', '==', '=', 'eq', '!=', '<>', 'ne'], \true)) { + throw new \PHPUnit\Util\InvalidVersionOperatorException($operator); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\Xml; + +use const LIBXML_NONET; +use function assert; +use function error_reporting; +use function file_get_contents; +use function libxml_get_errors; +use function libxml_use_internal_errors; +use function sprintf; +use function trim; +use DOMDocument; +use DOMNode; +use DOMXPath; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Loader +{ + /** + * @throws XmlException + */ + public function loadFile(string $filename, bool $ignoreComments = \false): DOMDocument + { + $reporting = error_reporting(0); + $contents = file_get_contents($filename); + error_reporting($reporting); + if ($contents === \false) { + throw new \PHPUnit\Util\Xml\XmlException(sprintf('Could not read XML from file "%s"', $filename)); + } + if (trim($contents) === '') { + throw new \PHPUnit\Util\Xml\XmlException(sprintf('Could not parse XML from empty file "%s"', $filename)); + } + return $this->load($contents, $ignoreComments); + } + /** + * @throws XmlException + */ + public function load(string $actual, bool $ignoreComments = \false): DOMDocument + { + if ($actual === '') { + throw new \PHPUnit\Util\Xml\XmlException('Could not parse XML from empty string'); + } + $document = new DOMDocument(); + $document->preserveWhiteSpace = \false; + $internal = libxml_use_internal_errors(\true); + $message = ''; + $reporting = error_reporting(0); + $loaded = $document->loadXML($actual, LIBXML_NONET); + foreach (libxml_get_errors() as $error) { + $message .= "\n" . $error->message; + } + libxml_use_internal_errors($internal); + error_reporting($reporting); + if ($loaded === \false) { + if ($message === '') { + // @codeCoverageIgnoreStart + $message = 'Could not load XML for unknown reason'; + // @codeCoverageIgnoreEnd + } + throw new \PHPUnit\Util\Xml\XmlException($message); + } + if ($ignoreComments) { + $this->removeComments($document); + } + return $document; + } + private function removeComments(DOMDocument $document): void + { + $xpath = new DOMXPath($document); + $comments = $xpath->query('//comment()'); + assert($comments !== \false); + foreach ($comments as $comment) { + assert($comment instanceof DOMNode); + assert($comment->parentNode !== null); + $comment->parentNode->removeChild($comment); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const ENT_QUOTES; +use function assert; +use function htmlspecialchars; +use function mb_convert_encoding; +use function ord; +use function preg_replace; +use function strlen; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Xml +{ + /** + * Escapes a string for the use in XML documents. + * + * Any Unicode character is allowed, excluding the surrogate blocks, FFFE, + * and FFFF (not even as character reference). + * + * @see https://www.w3.org/TR/xml/#charsets + */ + public static function prepareString(string $string): string + { + $result = preg_replace('/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/', '', htmlspecialchars(self::convertToUtf8($string), ENT_QUOTES)); + assert($result !== null); + return $result; + } + private static function convertToUtf8(string $string): string + { + if (!self::isUtf8($string)) { + $string = mb_convert_encoding($string, 'UTF-8'); + } + return $string; + } + private static function isUtf8(string $string): bool + { + $length = strlen($string); + for ($i = 0; $i < $length; $i++) { + if (ord($string[$i]) < 0x80) { + $n = 0; + } elseif ((ord($string[$i]) & 0xe0) === 0xc0) { + $n = 1; + } elseif ((ord($string[$i]) & 0xf0) === 0xe0) { + $n = 2; + } elseif ((ord($string[$i]) & 0xf0) === 0xf0) { + $n = 3; + } else { + return \false; + } + for ($j = 0; $j < $n; $j++) { + if (++$i === $length || (ord($string[$i]) & 0xc0) !== 0x80) { + return \false; + } + } + } + return \true; + } +} + + + + + phpunit + phpunit + 13.1.13 + The PHP Unit Testing framework. + + + BSD-3-Clause + + + pkg:composer/phpunit/phpunit@13.1.13 + + + myclabs + deep-copy + 1.13.4 + Create deep copies (clones) of your objects + + + MIT + + + pkg:composer/myclabs/deep-copy@1.13.4 + + + nikic + php-parser + v5.7.0 + A PHP parser written in PHP + + + BSD-3-Clause + + + pkg:composer/nikic/php-parser@v5.7.0 + + + phar-io + manifest + 2.0.4 + Component for reading phar.io manifest information from a PHP Archive (PHAR) + + + BSD-3-Clause + + + pkg:composer/phar-io/manifest@2.0.4 + + + phar-io + version + 3.2.1 + Library for handling version information and constraints + + + BSD-3-Clause + + + pkg:composer/phar-io/version@3.2.1 + + + phpunit + php-code-coverage + 14.1.9 + Library that provides collection, processing, and rendering functionality for PHP code coverage information. + + + BSD-3-Clause + + + pkg:composer/phpunit/php-code-coverage@14.1.9 + + + phpunit + php-file-iterator + 7.0.0 + FilterIterator implementation that filters files based on a list of suffixes. + + + BSD-3-Clause + + + pkg:composer/phpunit/php-file-iterator@7.0.0 + + + phpunit + php-invoker + 7.0.0 + Invoke callables with a timeout + + + BSD-3-Clause + + + pkg:composer/phpunit/php-invoker@7.0.0 + + + phpunit + php-text-template + 6.0.0 + Simple template engine. + + + BSD-3-Clause + + + pkg:composer/phpunit/php-text-template@6.0.0 + + + phpunit + php-timer + 9.0.0 + Utility class for timing + + + BSD-3-Clause + + + pkg:composer/phpunit/php-timer@9.0.0 + + + sebastian + cli-parser + 5.0.0 + Library for parsing CLI options + + + BSD-3-Clause + + + pkg:composer/sebastian/cli-parser@5.0.0 + + + sebastian + comparator + 8.2.1 + Provides the functionality to compare PHP values for equality + + + BSD-3-Clause + + + pkg:composer/sebastian/comparator@8.2.1 + + + sebastian + complexity + 6.0.0 + Library for calculating the complexity of PHP code units + + + BSD-3-Clause + + + pkg:composer/sebastian/complexity@6.0.0 + + + sebastian + diff + 8.3.0 + Diff implementation + + + BSD-3-Clause + + + pkg:composer/sebastian/diff@8.3.0 + + + sebastian + environment + 9.3.2 + Provides functionality to handle HHVM/PHP environments + + + BSD-3-Clause + + + pkg:composer/sebastian/environment@9.3.2 + + + sebastian + exporter + 8.1.0 + Provides the functionality to export PHP variables for visualization + + + BSD-3-Clause + + + pkg:composer/sebastian/exporter@8.1.0 + + + sebastian + git-state + 1.0.0 + Library for describing the state of a Git checkout + + + BSD-3-Clause + + + pkg:composer/sebastian/git-state@1.0.0 + + + sebastian + global-state + 9.0.0 + Snapshotting of global state + + + BSD-3-Clause + + + pkg:composer/sebastian/global-state@9.0.0 + + + sebastian + lines-of-code + 5.0.1 + Library for counting the lines of code in PHP source code + + + BSD-3-Clause + + + pkg:composer/sebastian/lines-of-code@5.0.1 + + + sebastian + object-enumerator + 8.0.0 + Traverses array structures and object graphs to enumerate all referenced objects + + + BSD-3-Clause + + + pkg:composer/sebastian/object-enumerator@8.0.0 + + + sebastian + object-reflector + 6.0.0 + Allows reflection of object attributes, including inherited and non-public ones + + + BSD-3-Clause + + + pkg:composer/sebastian/object-reflector@6.0.0 + + + sebastian + recursion-context + 8.0.0 + Provides functionality to recursively process PHP variables + + + BSD-3-Clause + + + pkg:composer/sebastian/recursion-context@8.0.0 + + + sebastian + type + 7.0.1 + Collection of value objects that represent the types of the PHP type system + + + BSD-3-Clause + + + pkg:composer/sebastian/type@7.0.1 + + + sebastian + version + 7.0.0 + Library that helps with managing the version number of Git-hosted PHP projects + + + BSD-3-Clause + + + pkg:composer/sebastian/version@7.0.0 + + + staabm + side-effects-detector + 1.0.5 + A static analysis tool to detect side effects in PHP code + + + MIT + + + pkg:composer/staabm/side-effects-detector@1.0.5 + + + theseer + tokenizer + 2.0.1 + A small library for converting tokenized PHP source code into XML and potentially other formats + + + BSD-3-Clause + + + pkg:composer/theseer/tokenizer@2.0.1 + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.1 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.2 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.3 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.4 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.5 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.1 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.2 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.3 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.4 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.5 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 12.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 12.1 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 12.2 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 12.3 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 12.4 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 12.5 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 13.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 8.5 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.2 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.3 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.4 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.5 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.6 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +BSD 3-Clause License + +Copyright (c) 2020-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CliParser; + +use function array_map; +use function array_merge; +use function array_shift; +use function array_slice; +use function assert; +use function count; +use function current; +use function explode; +use function is_array; +use function is_int; +use function key; +use function levenshtein; +use function next; +use function preg_replace; +use function reset; +use function rtrim; +use function sort; +use function str_ends_with; +use function str_starts_with; +use function strlen; +use function strstr; +use function substr; +use function usort; +final readonly class Parser +{ + /** + * @param list $argv + * @param list $longOptions + * + * @throws AmbiguousOptionException + * @throws OptionDoesNotAllowArgumentException + * @throws RequiredOptionArgumentMissingException + * @throws UnknownOptionException + * + * @return array{0: list, 1: list} + */ + public function parse(array $argv, string $shortOptions, ?array $longOptions = null): array + { + if ($argv === []) { + return [[], []]; + } + $options = []; + $nonOptions = []; + if ($longOptions !== null) { + sort($longOptions); + } + if (isset($argv[0][0]) && $argv[0][0] !== '-') { + array_shift($argv); + } + reset($argv); + $argv = array_map(trim(...), $argv); + while (\false !== $arg = current($argv)) { + $i = key($argv); + assert(is_int($i)); + next($argv); + if ($arg === '') { + continue; + } + if ($arg === '--') { + $nonOptions = array_merge($nonOptions, array_slice($argv, $i + 1)); + break; + } + if ($arg[0] !== '-' || strlen($arg) > 1 && $arg[1] === '-' && $longOptions === null) { + $nonOptions[] = $arg; + continue; + } + if (strlen($arg) > 1 && $arg[1] === '-' && is_array($longOptions)) { + $this->parseLongOption(substr($arg, 2), $longOptions, $options, $argv); + continue; + } + $this->parseShortOption(substr($arg, 1), $shortOptions, $options, $argv); + } + return [$options, $nonOptions]; + } + /** + * @param list $options + * @param list $argv + * + * @throws RequiredOptionArgumentMissingException + */ + private function parseShortOption(string $argument, string $shortOptions, array &$options, array &$argv): void + { + $argumentLength = strlen($argument); + for ($i = 0; $i < $argumentLength; $i++) { + $option = $argument[$i]; + $optionArgument = null; + if ($argument[$i] === ':' || ($spec = strstr($shortOptions, $option)) === \false) { + throw new UnknownOptionException('-' . $option, []); + } + if (strlen($spec) > 1 && $spec[1] === ':') { + if ($i + 1 < $argumentLength) { + $options[] = [$option, substr($argument, $i + 1)]; + break; + } + if (!(strlen($spec) > 2 && $spec[2] === ':')) { + $optionArgument = current($argv); + if ($optionArgument === \false) { + throw new RequiredOptionArgumentMissingException('-' . $option); + } + next($argv); + } + } + $options[] = [$option, $optionArgument]; + } + } + /** + * @param list $longOptions + * @param list $options + * @param list $argv + * + * @throws AmbiguousOptionException + * @throws OptionDoesNotAllowArgumentException + * @throws RequiredOptionArgumentMissingException + * @throws UnknownOptionException + */ + private function parseLongOption(string $argument, array $longOptions, array &$options, array &$argv): void + { + $count = count($longOptions); + $list = explode('=', $argument); + $option = $list[0]; + $optionLength = strlen($option); + $similarOptions = []; + $optionArgument = null; + if (count($list) > 1) { + /** @phpstan-ignore offsetAccess.notFound */ + $optionArgument = $list[1]; + } + foreach ($longOptions as $i => $longOption) { + $similarOptions[] = [levenshtein($longOption, $option), '--' . rtrim($longOption, '=')]; + $opt_start = substr($longOption, 0, $optionLength); + if ($opt_start !== $option) { + continue; + } + $opt_rest = substr($longOption, $optionLength); + if ($opt_rest !== '' && $i + 1 < $count && $option[0] !== '=' && str_starts_with($longOptions[$i + 1], $option)) { + $candidates = []; + foreach ($longOptions as $aLongOption) { + if (str_starts_with($aLongOption, $option)) { + $candidates[] = '--' . rtrim($aLongOption, '='); + } + } + throw new AmbiguousOptionException('--' . $option, $candidates); + } + if (str_ends_with($longOption, '=')) { + if (!str_ends_with($longOption, '==') && (string) $optionArgument === '') { + if (\false === $optionArgument = current($argv)) { + throw new RequiredOptionArgumentMissingException('--' . $option); + } + next($argv); + } + } elseif ($optionArgument !== null) { + throw new OptionDoesNotAllowArgumentException('--' . $option); + } + $fullOption = '--' . preg_replace('/={1,2}$/', '', $longOption); + $options[] = [$fullOption, $optionArgument]; + return; + } + throw new UnknownOptionException('--' . $option, $this->formatSimilarOptions($similarOptions)); + } + /** + * @param list $similarOptions + * + * @return array + */ + private function formatSimilarOptions(array $similarOptions): array + { + usort($similarOptions, static fn(array $a, array $b): int => $a[0] <=> $b[0]); + $similarFormatted = []; + foreach (array_slice($similarOptions, 0, 5) as [$distance, $label]) { + $similarFormatted[] = $label; + } + return $similarFormatted; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CliParser; + +use function implode; +use function sprintf; +use RuntimeException; +final class AmbiguousOptionException extends RuntimeException implements Exception +{ + /** + * @param array $candiates + */ + public function __construct(string $option, array $candiates) + { + parent::__construct(sprintf('Option "%s" is ambiguous. Similar options are: %s', $option, implode(', ', $candiates))); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CliParser; + +use Throwable; +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CliParser; + +use function sprintf; +use RuntimeException; +final class OptionDoesNotAllowArgumentException extends RuntimeException implements Exception +{ + public function __construct(string $option) + { + parent::__construct(sprintf('Option "%s" does not allow an argument', $option)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CliParser; + +use function sprintf; +use RuntimeException; +final class RequiredOptionArgumentMissingException extends RuntimeException implements Exception +{ + public function __construct(string $option) + { + parent::__construct(sprintf('Required argument for option "%s" is missing', $option)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\CliParser; + +use function implode; +use function sprintf; +use RuntimeException; +final class UnknownOptionException extends RuntimeException implements Exception +{ + /** + * @param array $similarOptions + */ + public function __construct(string $option, array $similarOptions) + { + $message = sprintf('Unknown option "%s"', $option); + if ($similarOptions !== []) { + $message = sprintf('Unknown option "%s". Most similar options are %s', $option, implode(', ', $similarOptions)); + } + parent::__construct($message); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function array_is_list; +use function array_key_exists; +use function assert; +use function is_array; +use function is_bool; +use function is_float; +use function is_int; +use function is_object; +use function is_string; +use function ksort; +use function serialize; +use function sprintf; +use function str_replace; +use function trim; +use function usort; +use PHPUnitPHAR\SebastianBergmann\Exporter\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +class ArrayComparator extends Comparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return is_array($expected) && is_array($actual); + } + /** + * Arrays are equal if they contain the same key-value pairs. + * The order of the keys does not matter. + * The types of key-value pairs do not matter. + * + * @param array $processed + * + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false, array &$processed = []): void + { + assert(is_array($expected)); + assert(is_array($actual)); + $isList = \false; + if ($canonicalize) { + $isList = array_is_list($expected) && array_is_list($actual); + if ($isList) { + usort($expected, $this->compare(...)); + usort($actual, $this->compare(...)); + } else { + ksort($expected); + ksort($actual); + } + } + $remaining = $actual; + $actualAsString = "Array (\n"; + $expectedAsString = "Array (\n"; + $equal = \true; + $exporter = new Exporter(); + foreach ($expected as $key => $value) { + unset($remaining[$key]); + if (!array_key_exists($key, $actual)) { + if ($canonicalize && $isList) { + $expectedAsString .= sprintf(" %s\n", $exporter->shortenedExport($value)); + } else { + $expectedAsString .= sprintf(" %s => %s\n", $exporter->export($key), $exporter->shortenedExport($value)); + } + $equal = \false; + continue; + } + try { + $comparator = $this->factory()->getComparatorFor($value, $actual[$key]); + /** @phpstan-ignore arguments.count */ + $comparator->assertEquals($value, $actual[$key], $delta, $canonicalize, $ignoreCase, $processed); + if ($canonicalize && $isList) { + $expectedAsString .= sprintf(" %s\n", $exporter->shortenedExport($value)); + $actualAsString .= sprintf(" %s\n", $exporter->shortenedExport($actual[$key])); + } else { + $expectedAsString .= sprintf(" %s => %s\n", $exporter->export($key), $exporter->shortenedExport($value)); + $actualAsString .= sprintf(" %s => %s\n", $exporter->export($key), $exporter->shortenedExport($actual[$key])); + } + } catch (ComparisonFailure $e) { + if ($canonicalize && $isList) { + $expectedAsString .= sprintf(" %s\n", $e->getExpectedAsString() !== '' ? $this->indent($e->getExpectedAsString()) : $exporter->shortenedExport($e->getExpected())); + $actualAsString .= sprintf(" %s\n", $e->getActualAsString() !== '' ? $this->indent($e->getActualAsString()) : $exporter->shortenedExport($e->getActual())); + } else { + $expectedAsString .= sprintf(" %s => %s\n", $exporter->export($key), $e->getExpectedAsString() !== '' ? $this->indent($e->getExpectedAsString()) : $exporter->shortenedExport($e->getExpected())); + $actualAsString .= sprintf(" %s => %s\n", $exporter->export($key), $e->getActualAsString() !== '' ? $this->indent($e->getActualAsString()) : $exporter->shortenedExport($e->getActual())); + } + $equal = \false; + } + } + foreach ($remaining as $key => $value) { + if ($canonicalize && $isList) { + $actualAsString .= sprintf(" %s\n", $exporter->shortenedExport($value)); + } else { + $actualAsString .= sprintf(" %s => %s\n", $exporter->export($key), $exporter->shortenedExport($value)); + } + $equal = \false; + } + $expectedAsString .= ')'; + $actualAsString .= ')'; + if (!$equal) { + throw new ComparisonFailure($expected, $actual, $expectedAsString, $actualAsString, 'Failed asserting that two arrays are equal.', $this->contextLines()); + } + } + private function indent(string $lines): string + { + return trim(str_replace("\n", "\n ", $lines)); + } + private function compare(mixed $a, mixed $b): int + { + $typeOrderA = $this->typeOrder($a); + $typeOrderB = $this->typeOrder($b); + if ($typeOrderA !== $typeOrderB) { + return $typeOrderA <=> $typeOrderB; + } + if (is_object($a) && is_object($b)) { + $classComparison = $a::class <=> $b::class; + if ($classComparison !== 0) { + return $classComparison; + } + try { + $this->factory()->getComparatorFor($a, $b)->assertEquals($a, $b); + return 0; + } catch (ComparisonFailure) { + return serialize($a) <=> serialize($b); + } + } + if (is_array($a) && is_array($b)) { + return serialize($a) <=> serialize($b); + } + return $a <=> $b; + } + private function typeOrder(mixed $value): int + { + if ($value === null) { + return 0; + } + if (is_bool($value)) { + return 1; + } + if (is_int($value) || is_float($value)) { + return 2; + } + if (is_string($value)) { + return 3; + } + if (is_array($value)) { + return 4; + } + if (is_object($value)) { + return 5; + } + return 6; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function assert; +use function spl_object_id; +use function sprintf; +use Closure; +use ReflectionFunction; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class ClosureComparator extends Comparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return $expected instanceof Closure && $actual instanceof Closure; + } + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false): void + { + assert($expected instanceof Closure); + assert($actual instanceof Closure); + if ($expected === $actual) { + return; + } + $expectedReflector = new ReflectionFunction($expected); + $actualReflector = new ReflectionFunction($actual); + if ($this->declarationIsEqual($expectedReflector, $actualReflector) && $this->bindingIsEqual($expectedReflector, $actualReflector) && $this->capturedStateIsEqual($expectedReflector, $actualReflector)) { + return; + } + $expectedFilename = $expectedReflector->getFileName(); + $expectedStartLine = $expectedReflector->getStartLine(); + $actualFilename = $actualReflector->getFileName(); + $actualStartLine = $actualReflector->getStartLine(); + assert($expectedFilename !== \false); + assert($expectedStartLine !== \false); + assert($actualFilename !== \false); + assert($actualStartLine !== \false); + throw new ComparisonFailure($expected, $actual, 'Closure Object #' . spl_object_id($expected) . ' ()', 'Closure Object #' . spl_object_id($actual) . ' ()', sprintf('Failed asserting that closure declared at %s:%d is equal to closure declared at %s:%d.', $expectedFilename, $expectedStartLine, $actualFilename, $actualStartLine), $this->contextLines()); + } + private function declarationIsEqual(ReflectionFunction $expected, ReflectionFunction $actual): bool + { + return $expected->getName() === $actual->getName() && $expected->getFileName() === $actual->getFileName() && $expected->getStartLine() === $actual->getStartLine() && $expected->getEndLine() === $actual->getEndLine(); + } + private function bindingIsEqual(ReflectionFunction $expected, ReflectionFunction $actual): bool + { + if ($expected->getClosureScopeClass()?->getName() !== $actual->getClosureScopeClass()?->getName()) { + return \false; + } + return $this->recursivelyEqual($expected->getClosureThis(), $actual->getClosureThis()); + } + private function capturedStateIsEqual(ReflectionFunction $expected, ReflectionFunction $actual): bool + { + return $this->recursivelyEqual($expected->getClosureUsedVariables(), $actual->getClosureUsedVariables()); + } + private function recursivelyEqual(mixed $expected, mixed $actual): bool + { + try { + $this->factory()->getComparatorFor($expected, $actual)->assertEquals($expected, $actual); + } catch (ComparisonFailure) { + return \false; + } + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + */ +abstract class Comparator +{ + private Factory $factory; + public function setFactory(Factory $factory): void + { + $this->factory = $factory; + } + abstract public function accepts(mixed $expected, mixed $actual): bool; + /** + * @throws ComparisonFailure + */ + abstract public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false): void; + protected function factory(): Factory + { + return $this->factory; + } + /** + * @return positive-int + */ + final protected function contextLines(): int + { + if (!isset($this->factory)) { + return 3; + } + return $this->factory->contextLines(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use RuntimeException; +use PHPUnitPHAR\SebastianBergmann\Diff\Differ; +use PHPUnitPHAR\SebastianBergmann\Diff\Output\StrictUnifiedDiffOutputBuilder; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + */ +final class ComparisonFailure extends RuntimeException +{ + private mixed $expected; + private mixed $actual; + private string $expectedAsString; + private string $actualAsString; + /** @var positive-int */ + private int $contextLines; + /** + * @param positive-int $contextLines + */ + public function __construct(mixed $expected, mixed $actual, string $expectedAsString, string $actualAsString, string $message = '', int $contextLines = 3) + { + parent::__construct($message); + $this->expected = $expected; + $this->actual = $actual; + $this->expectedAsString = $expectedAsString; + $this->actualAsString = $actualAsString; + $this->contextLines = $contextLines; + } + /** + * @return array{expected: mixed, actual: mixed, expectedAsString: string, actualAsString: string, message: string, contextLines: positive-int} + */ + public function __serialize(): array + { + return ['expected' => $this->expected, 'actual' => $this->actual, 'expectedAsString' => $this->expectedAsString, 'actualAsString' => $this->actualAsString, 'message' => $this->message, 'contextLines' => $this->contextLines]; + } + /** + * @param array{expected: mixed, actual: mixed, expectedAsString: string, actualAsString: string, message: string, contextLines: positive-int} $data + */ + public function __unserialize(array $data): void + { + $this->expected = $data['expected']; + $this->actual = $data['actual']; + $this->expectedAsString = $data['expectedAsString']; + $this->actualAsString = $data['actualAsString']; + $this->message = $data['message']; + $this->contextLines = $data['contextLines']; + } + public function getActual(): mixed + { + return $this->actual; + } + public function getExpected(): mixed + { + return $this->expected; + } + public function getActualAsString(): string + { + return $this->actualAsString; + } + public function getExpectedAsString(): string + { + return $this->expectedAsString; + } + public function getDiff(): string + { + if ($this->actualAsString === '' && $this->expectedAsString === '') { + return ''; + } + $differ = new Differ(new StrictUnifiedDiffOutputBuilder(['header' => "\n--- Expected\n+++ Actual\n", 'addLineNumbers' => \false, 'contextLines' => $this->contextLines, 'emitDiffLineEndWarning' => \true, 'emitNoLineEndEofWarning' => \false])); + return $differ->diff($this->expectedAsString, $this->actualAsString); + } + public function toString(): string + { + return $this->getMessage() . $this->getDiff(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function assert; +use function mb_strtolower; +use function sprintf; +use DOMDocument; +use DOMNode; +use ValueError; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class DOMNodeComparator extends ObjectComparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return $expected instanceof DOMNode && $actual instanceof DOMNode; + } + /** + * @param array $processed + * + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false, array &$processed = []): void + { + assert($expected instanceof DOMNode); + assert($actual instanceof DOMNode); + $expectedAsString = $this->nodeToText($expected, $ignoreCase); + $actualAsString = $this->nodeToText($actual, $ignoreCase); + if ($expectedAsString !== $actualAsString) { + $type = $expected instanceof DOMDocument ? 'documents' : 'nodes'; + throw new ComparisonFailure($expected, $actual, $expectedAsString, $actualAsString, sprintf("Failed asserting that two DOM %s are equal.\n", $type), $this->contextLines()); + } + } + /** + * Canonicalizes nodes, removes empty text nodes and merges adjacent text nodes, + * and optionally ignores case. + * + * @see https://github.com/sebastianbergmann/phpunit/pull/1236#issuecomment-41765023 + */ + private function nodeToText(DOMNode $node, bool $ignoreCase): string + { + $c14n = @$node->C14N(\false, \true); + if ($c14n === \false || $c14n === '') { + $text = $this->serialize($node); + } else { + $document = new DOMDocument(); + try { + @$document->loadXML($c14n); + // @codeCoverageIgnoreStart + } catch (ValueError) { + // @codeCoverageIgnoreEnd + } + $document->encoding = 'UTF-8'; + $document->formatOutput = \true; + $document->normalizeDocument(); + $saved = $document->saveXML(); + assert($saved !== \false); + $text = $saved; + } + if ($ignoreCase) { + return mb_strtolower($text, 'UTF-8'); + } + return $text; + } + /** + * Serializes a node without canonicalization. + * Used as a fallback when DOMNode::C14N() fails. + */ + private function serialize(DOMNode $node): string + { + if ($node instanceof DOMDocument) { + $document = $node; + $target = null; + } else { + $document = $node->ownerDocument; + $target = $node; + } + assert($document !== null); + $text = $document->saveXML($target); + return $text !== \false ? $text : ''; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function abs; +use function assert; +use function in_array; +use DateInterval; +use DateTimeImmutable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class DateIntervalComparator extends ObjectComparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return $expected instanceof DateInterval && $actual instanceof DateInterval; + } + /** + * @param array $processed + * + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false, array &$processed = []): void + { + assert($expected instanceof DateInterval); + assert($actual instanceof DateInterval); + if (in_array([$actual, $expected], $processed, \true) || in_array([$expected, $actual], $processed, \true)) { + return; + } + $processed[] = [$actual, $expected]; + if (abs($this->toSeconds($expected) - $this->toSeconds($actual)) > abs($delta)) { + throw new ComparisonFailure($expected, $actual, $this->format($expected), $this->format($actual), 'Failed asserting that two DateInterval objects are equal.', $this->contextLines()); + } + } + /** + * Converts a DateInterval to a duration in seconds by applying it to the + * Unix epoch. Month and year components are therefore evaluated against a + * fixed anchor (a month is not always 30 days, a year not always 365), so + * two intervals whose calendar components differ may still be considered + * equal within a delta when the resulting durations match. + */ + private function toSeconds(DateInterval $interval): float + { + $applied = (new DateTimeImmutable('@0'))->add($interval); + return (float) $applied->format('U') + (float) $applied->format('u') / 1000000; + } + private function format(DateInterval $interval): string + { + return $interval->format('%RP%yY%mM%dDT%hH%iM%sS.%fF'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function abs; +use function assert; +use function floor; +use function in_array; +use function sprintf; +use DateInterval; +use DateTime; +use DateTimeImmutable; +use DateTimeZone; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class DateTimeComparator extends ObjectComparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return ($expected instanceof DateTime || $expected instanceof DateTimeImmutable) && ($actual instanceof DateTime || $actual instanceof DateTimeImmutable); + } + /** + * @param array $processed + * + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false, array &$processed = []): void + { + assert($expected instanceof DateTime || $expected instanceof DateTimeImmutable); + assert($actual instanceof DateTime || $actual instanceof DateTimeImmutable); + if (in_array([$actual, $expected], $processed, \true) || in_array([$expected, $actual], $processed, \true)) { + return; + } + $processed[] = [$actual, $expected]; + $absDelta = abs($delta); + /** @phpstan-ignore argument.type */ + $delta = new DateInterval(sprintf('PT%dS', $absDelta)); + $delta->f = $absDelta - floor($absDelta); + $actualClone = (clone $actual)->setTimezone(new DateTimeZone('UTC')); + $expectedLower = (clone $expected)->setTimezone(new DateTimeZone('UTC'))->sub($delta); + $expectedUpper = (clone $expected)->setTimezone(new DateTimeZone('UTC'))->add($delta); + if ($actualClone < $expectedLower || $actualClone > $expectedUpper) { + throw new ComparisonFailure($expected, $actual, $expected->format('Y-m-d\TH:i:s.uO'), $actual->format('Y-m-d\TH:i:s.uO'), 'Failed asserting that two DateTime objects are equal.', $this->contextLines()); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function assert; +use function sprintf; +use UnitEnum; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class EnumerationComparator extends Comparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return $expected instanceof UnitEnum && $actual instanceof UnitEnum && $expected::class === $actual::class; + } + /** + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false): void + { + assert($expected instanceof UnitEnum); + assert($actual instanceof UnitEnum); + if ($expected === $actual) { + return; + } + throw new ComparisonFailure($expected, $actual, '', '', sprintf('Failed asserting that two values of enumeration %s are equal, %s does not match expected %s.', $expected::class, $actual->name, $expected->name), $this->contextLines()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function assert; +use Exception; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class ExceptionComparator extends ObjectComparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return $expected instanceof Exception && $actual instanceof Exception; + } + /** + * @return array + */ + protected function toArray(object $object): array + { + assert($object instanceof Exception); + $array = parent::toArray($object); + unset($array['file'], $array['line'], $array['trace'], $array['string'], $array['xdebug_message']); + return $array; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use const PHP_VERSION; +use function array_unshift; +use function extension_loaded; +use function version_compare; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + */ +final class Factory +{ + private static ?Factory $instance = null; + /** + * @var array + */ + private array $customComparators = []; + /** + * @var list + */ + private array $defaultComparators = []; + /** @var positive-int */ + private int $contextLines = 3; + public static function getInstance(): self + { + if (self::$instance === null) { + self::$instance = new self(); + // @codeCoverageIgnore + } + return self::$instance; + } + public function __construct() + { + $this->registerDefaultComparators(); + } + /** + * @return positive-int + */ + public function contextLines(): int + { + return $this->contextLines; + } + /** + * @param positive-int $contextLines + */ + public function setContextLines(int $contextLines): void + { + $this->contextLines = $contextLines; + } + public function getComparatorFor(mixed $expected, mixed $actual): Comparator + { + foreach ($this->customComparators as $comparator) { + if ($comparator->accepts($expected, $actual)) { + return $comparator; + } + } + foreach ($this->defaultComparators as $comparator) { + if ($comparator->accepts($expected, $actual)) { + return $comparator; + } + } + // @codeCoverageIgnoreStart + throw new RuntimeException('No suitable Comparator implementation found'); + // @codeCoverageIgnoreEnd + } + /** + * Registers a new comparator. + * + * This comparator will be returned by getComparatorFor() if its accept() method + * returns TRUE for the compared values. It has higher priority than the + * existing comparators, meaning that its accept() method will be invoked + * before those of the other comparators. + */ + public function register(Comparator $comparator): void + { + array_unshift($this->customComparators, $comparator); + $comparator->setFactory($this); + } + /** + * Unregisters a comparator. + * + * This comparator will no longer be considered by getComparatorFor(). + */ + public function unregister(Comparator $comparator): void + { + foreach ($this->customComparators as $key => $_comparator) { + if ($comparator === $_comparator) { + unset($this->customComparators[$key]); + } + } + } + public function reset(): void + { + $this->customComparators = []; + } + private function registerDefaultComparators(): void + { + $this->registerDefaultComparator(new ClosureComparator()); + $this->registerDefaultComparator(new MockObjectComparator()); + $this->registerDefaultComparator(new DateTimeComparator()); + $this->registerDefaultComparator(new DateIntervalComparator()); + $this->registerDefaultComparator(new DOMNodeComparator()); + $this->registerDefaultComparator(new SplObjectStorageComparator()); + $this->registerDefaultComparator(new ExceptionComparator()); + $this->registerDefaultComparator(new EnumerationComparator()); + if (extension_loaded('bcmath') && version_compare(PHP_VERSION, '8.4.0', '>=')) { + $this->registerDefaultComparator(new NumberComparator()); + } + $this->registerDefaultComparator(new ObjectComparator()); + $this->registerDefaultComparator(new ResourceComparator()); + $this->registerDefaultComparator(new ArrayComparator()); + $this->registerDefaultComparator(new NumericComparator()); + $this->registerDefaultComparator(new ScalarComparator()); + $this->registerDefaultComparator(new TypeComparator()); + } + private function registerDefaultComparator(Comparator $comparator): void + { + $this->defaultComparators[] = $comparator; + $comparator->setFactory($this); + } +} +BSD 3-Clause License + +Copyright (c) 2002-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function array_keys; +use function assert; +use function str_starts_with; +use PHPUnit\Framework\MockObject\Stub; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class MockObjectComparator extends ObjectComparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return $expected instanceof Stub && $actual instanceof Stub; + } + /** + * @return array + */ + protected function toArray(object $object): array + { + assert($object instanceof Stub); + $array = parent::toArray($object); + foreach (array_keys($array) as $key) { + if (!str_starts_with($key, '__phpunit_')) { + continue; + } + unset($array[$key]); + } + return $array; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function assert; +use function is_int; +use function is_numeric; +use function is_string; +use function max; +use function number_format; +use BcMath\Number; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class NumberComparator extends ObjectComparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return ($expected instanceof Number || $actual instanceof Number) && ($expected instanceof Number || is_int($expected) || is_string($expected) && is_numeric($expected)) && ($actual instanceof Number || is_int($actual) || is_string($actual) && is_numeric($actual)); + } + /** + * @param array $processed + * + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false, array &$processed = []): void + { + if (!$expected instanceof Number) { + assert(is_int($expected) || is_string($expected) && is_numeric($expected)); + $expected = new Number($expected); + } + if (!$actual instanceof Number) { + assert(is_int($actual) || is_string($actual) && is_numeric($actual)); + $actual = new Number($actual); + } + /** @phpstan-ignore argument.type */ + $deltaNumber = new Number(number_format($delta, max($expected->scale, $actual->scale))); + if ($actual < $expected - $deltaNumber || $actual > $expected + $deltaNumber) { + throw new ComparisonFailure($expected, $actual, (string) $expected, (string) $actual, 'Failed asserting that two Number objects are equal.', $this->contextLines()); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function abs; +use function assert; +use function is_float; +use function is_infinite; +use function is_nan; +use function is_numeric; +use function is_string; +use function sprintf; +use PHPUnitPHAR\SebastianBergmann\Exporter\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class NumericComparator extends ScalarComparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + // all numerical values, but not if both of them are strings + return is_numeric($expected) && is_numeric($actual) && !(is_string($expected) && is_string($actual)); + } + /** + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false): void + { + assert(is_numeric($expected)); + assert(is_numeric($actual)); + if ($this->isInfinite($expected) && $this->isInfinite($actual)) { + if ($expected < 0 && $actual < 0) { + return; + } + if ($expected > 0 && $actual > 0) { + return; + } + } + if (($this->isInfinite($actual) xor $this->isInfinite($expected)) || ($this->isNan($actual) || $this->isNan($expected)) || abs($actual - $expected) > $delta) { + $exporter = new Exporter(); + throw new ComparisonFailure($expected, $actual, '', '', sprintf('Failed asserting that %s matches expected %s.', $exporter->export($actual), $exporter->export($expected)), $this->contextLines()); + } + } + private function isInfinite(mixed $value): bool + { + return is_float($value) && is_infinite($value); + } + private function isNan(mixed $value): bool + { + return is_float($value) && is_nan($value); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function assert; +use function in_array; +use function is_object; +use function sprintf; +use function substr_replace; +use PHPUnitPHAR\SebastianBergmann\Exporter\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +class ObjectComparator extends ArrayComparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return is_object($expected) && is_object($actual); + } + /** + * @param array $processed + * + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false, array &$processed = []): void + { + assert(is_object($expected)); + assert(is_object($actual)); + if ($actual::class !== $expected::class) { + $exporter = new Exporter(); + throw new ComparisonFailure($expected, $actual, $exporter->export($expected), $exporter->export($actual), sprintf('%s is not instance of expected class "%s".', $exporter->export($actual), $expected::class), $this->contextLines()); + } + // don't compare twice to allow for cyclic dependencies + if (in_array([$actual, $expected], $processed, \true) || in_array([$expected, $actual], $processed, \true)) { + return; + } + $processed[] = [$actual, $expected]; + // don't compare objects if they are identical + // this helps to avoid the error "maximum function nesting level reached" + // CAUTION: this conditional clause is not tested + if ($actual !== $expected) { + try { + parent::assertEquals($this->toArray($expected), $this->toArray($actual), $delta, $canonicalize, $ignoreCase, $processed); + } catch (ComparisonFailure $e) { + throw new ComparisonFailure( + $expected, + $actual, + // replace "Array" with "MyClass object" + substr_replace($e->getExpectedAsString(), $expected::class . ' Object', 0, 5), + substr_replace($e->getActualAsString(), $actual::class . ' Object', 0, 5), + 'Failed asserting that two objects are equal.', + $this->contextLines() + ); + } + } + } + /** + * @return array + */ + protected function toArray(object $object): array + { + return (new Exporter())->toArray($object); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function assert; +use function is_resource; +use PHPUnitPHAR\SebastianBergmann\Exporter\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class ResourceComparator extends Comparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return is_resource($expected) && is_resource($actual); + } + /** + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false): void + { + assert(is_resource($expected)); + assert(is_resource($actual)); + $exporter = new Exporter(); + /** @phpstan-ignore notEqual.notAllowed */ + if ($actual != $expected) { + throw new ComparisonFailure($expected, $actual, $exporter->export($expected), $exporter->export($actual), '', $this->contextLines()); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function assert; +use function is_bool; +use function is_object; +use function is_scalar; +use function is_string; +use function mb_strtolower; +use function method_exists; +use function sprintf; +use function strlen; +use function substr; +use PHPUnitPHAR\SebastianBergmann\Exporter\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +class ScalarComparator extends Comparator +{ + private const int OVERLONG_THRESHOLD = 40; + private const int KEEP_CONTEXT_CHARS = 25; + public function accepts(mixed $expected, mixed $actual): bool + { + return (is_scalar($expected) xor null === $expected) && (is_scalar($actual) xor null === $actual) || is_string($expected) && is_object($actual) && method_exists($actual, '__toString') || is_object($expected) && method_exists($expected, '__toString') && is_string($actual); + } + /** + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false): void + { + $expectedToCompare = $expected; + $actualToCompare = $actual; + $exporter = new Exporter(); + // always compare as strings to avoid strange behaviour + // otherwise 0 == 'Foobar' + if (is_string($expected) && !is_bool($actual) || is_string($actual) && !is_bool($expected)) { + /** @phpstan-ignore cast.string */ + $expectedToCompare = @(string) $expectedToCompare; + /** @phpstan-ignore cast.string */ + $actualToCompare = @(string) $actualToCompare; + if ($ignoreCase) { + $expectedToCompare = mb_strtolower($expectedToCompare, 'UTF-8'); + $actualToCompare = mb_strtolower($actualToCompare, 'UTF-8'); + } + } + if ($expectedToCompare !== $actualToCompare && is_string($expected) && is_string($actual)) { + [$cutExpected, $cutActual] = self::removeOverlongCommonPrefix($expected, $actual); + [$cutExpected, $cutActual] = self::removeOverlongCommonSuffix($cutExpected, $cutActual); + throw new ComparisonFailure($expected, $actual, $exporter->export($cutExpected), $exporter->export($cutActual), 'Failed asserting that two strings are equal.', $this->contextLines()); + } + /** @phpstan-ignore notEqual.notAllowed */ + if ($expectedToCompare != $actualToCompare) { + throw new ComparisonFailure( + $expected, + $actual, + // no diff is required + '', + '', + sprintf('Failed asserting that %s matches expected %s.', $exporter->export($actual), $exporter->export($expected)), + $this->contextLines() + ); + } + } + /** + * @return array{string, string} + */ + private static function removeOverlongCommonPrefix(string $string1, string $string2): array + { + $commonPrefix = self::findCommonPrefix($string1, $string2); + if (strlen($commonPrefix) > self::OVERLONG_THRESHOLD) { + $string1 = '...' . substr($string1, strlen($commonPrefix) - self::KEEP_CONTEXT_CHARS); + $string2 = '...' . substr($string2, strlen($commonPrefix) - self::KEEP_CONTEXT_CHARS); + } + return [$string1, $string2]; + } + private static function findCommonPrefix(string $string1, string $string2): string + { + for ($i = 0; $i < strlen($string1); $i++) { + if (!isset($string2[$i]) || $string1[$i] !== $string2[$i]) { + break; + } + } + assert(isset($i)); + return substr($string1, 0, $i); + } + /** + * @return array{string, string} + */ + private static function removeOverlongCommonSuffix(string $string1, string $string2): array + { + $commonSuffix = self::findCommonSuffix($string1, $string2); + if (strlen($commonSuffix) > self::OVERLONG_THRESHOLD) { + $string1 = substr($string1, 0, -(strlen($commonSuffix) - self::KEEP_CONTEXT_CHARS)) . '...'; + $string2 = substr($string2, 0, -(strlen($commonSuffix) - self::KEEP_CONTEXT_CHARS)) . '...'; + } + return [$string1, $string2]; + } + private static function findCommonSuffix(string $string1, string $string2): string + { + if ($string1 === '' || $string2 === '') { + return ''; + } + $lastCharIndex1 = strlen($string1) - 1; + $lastCharIndex2 = strlen($string2) - 1; + if ($string1[$lastCharIndex1] !== $string2[$lastCharIndex2]) { + return ''; + } + while ($lastCharIndex1 > 0 && $lastCharIndex2 > 0 && $string1[$lastCharIndex1] === $string2[$lastCharIndex2]) { + $lastCharIndex1--; + $lastCharIndex2--; + } + return substr($string1, $lastCharIndex1 - strlen($string1) + 1); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function assert; +use PHPUnitPHAR\SebastianBergmann\Exporter\Exporter; +use SplObjectStorage; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class SplObjectStorageComparator extends Comparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return $expected instanceof SplObjectStorage && $actual instanceof SplObjectStorage; + } + /** + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false): void + { + assert($expected instanceof SplObjectStorage); + assert($actual instanceof SplObjectStorage); + $exporter = new Exporter(); + foreach ($actual as $object) { + if (!$expected->offsetExists($object)) { + throw new ComparisonFailure($expected, $actual, $exporter->export($expected), $exporter->export($actual), 'Failed asserting that two objects are equal.', $this->contextLines()); + } + } + foreach ($expected as $object) { + if (!$actual->offsetExists($object)) { + throw new ComparisonFailure($expected, $actual, $exporter->export($expected), $exporter->export($actual), 'Failed asserting that two objects are equal.', $this->contextLines()); + } + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use function gettype; +use function sprintf; +use PHPUnitPHAR\SebastianBergmann\Exporter\Exporter; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + * + * @internal This class is not covered by the backward compatibility promise for sebastian/comparator + */ +final class TypeComparator extends Comparator +{ + public function accepts(mixed $expected, mixed $actual): bool + { + return \true; + } + /** + * @throws ComparisonFailure + */ + public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = \false, bool $ignoreCase = \false): void + { + if (gettype($expected) !== gettype($actual)) { + throw new ComparisonFailure( + $expected, + $actual, + // we don't need a diff + '', + '', + sprintf('%s does not match expected type "%s".', (new Exporter())->shortenedExport($actual), gettype($expected)), + $this->contextLines() + ); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + */ +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Comparator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/comparator + */ +final class RuntimeException extends \RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Complexity; + +use function assert; +use function file_exists; +use function file_get_contents; +use function is_readable; +use function is_string; +use PHPUnitPHAR\PhpParser\Error; +use PHPUnitPHAR\PhpParser\Node; +use PHPUnitPHAR\PhpParser\NodeTraverser; +use PHPUnitPHAR\PhpParser\NodeVisitor\NameResolver; +use PHPUnitPHAR\PhpParser\NodeVisitor\ParentConnectingVisitor; +use PHPUnitPHAR\PhpParser\ParserFactory; +final class Calculator +{ + /** + * @param non-empty-string $sourceFile + * + * @throws RuntimeException + */ + public function calculateForSourceFile(string $sourceFile): ComplexityCollection + { + assert(file_exists($sourceFile)); + assert(is_readable($sourceFile)); + $source = file_get_contents($sourceFile); + assert(is_string($source)); + return $this->calculateForSourceString($source); + } + /** + * @throws RuntimeException + */ + public function calculateForSourceString(string $source): ComplexityCollection + { + try { + $nodes = (new ParserFactory())->createForHostVersion()->parse($source); + assert($nodes !== null); + return $this->calculateForAbstractSyntaxTree($nodes); + // @codeCoverageIgnoreStart + } catch (Error $error) { + throw new RuntimeException($error->getMessage(), $error->getCode(), $error); + } + // @codeCoverageIgnoreEnd + } + /** + * @param Node[] $nodes + * + * @throws RuntimeException + */ + public function calculateForAbstractSyntaxTree(array $nodes): ComplexityCollection + { + $traverser = new NodeTraverser(); + $complexityCalculatingVisitor = new ComplexityCalculatingVisitor(\true); + $traverser->addVisitor(new NameResolver()); + $traverser->addVisitor(new ParentConnectingVisitor()); + $traverser->addVisitor($complexityCalculatingVisitor); + try { + /* @noinspection UnusedFunctionResultInspection */ + $traverser->traverse($nodes); + // @codeCoverageIgnoreStart + } catch (Error $error) { + throw new RuntimeException($error->getMessage(), $error->getCode(), $error); + } + // @codeCoverageIgnoreEnd + return $complexityCalculatingVisitor->result(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Complexity; + +use function str_contains; +/** + * @immutable + */ +final readonly class Complexity +{ + /** + * @var non-empty-string + */ + private string $name; + /** + * @var positive-int + */ + private int $cyclomaticComplexity; + /** + * @param non-empty-string $name + * @param positive-int $cyclomaticComplexity + */ + public function __construct(string $name, int $cyclomaticComplexity) + { + $this->name = $name; + $this->cyclomaticComplexity = $cyclomaticComplexity; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + /** + * @return positive-int + */ + public function cyclomaticComplexity(): int + { + return $this->cyclomaticComplexity; + } + public function isFunction(): bool + { + return !$this->isMethod(); + } + public function isMethod(): bool + { + return str_contains($this->name, '::'); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Complexity; + +use function array_filter; +use function array_merge; +use function array_reverse; +use function array_values; +use function count; +use function usort; +use Countable; +use IteratorAggregate; +/** + * @template-implements IteratorAggregate + * + * @psalm-immutable + */ +final readonly class ComplexityCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $items; + public static function fromList(Complexity ...$items): self + { + return new self(array_values($items)); + } + /** + * @param list $items + */ + private function __construct(array $items) + { + $this->items = $items; + } + /** + * @return list + */ + public function asArray(): array + { + return $this->items; + } + public function getIterator(): ComplexityCollectionIterator + { + return new ComplexityCollectionIterator($this); + } + /** + * @return non-negative-int + */ + public function count(): int + { + return count($this->items); + } + public function isEmpty(): bool + { + return $this->items === []; + } + /** + * @return non-negative-int + */ + public function cyclomaticComplexity(): int + { + $cyclomaticComplexity = 0; + foreach ($this as $item) { + $cyclomaticComplexity += $item->cyclomaticComplexity(); + } + return $cyclomaticComplexity; + } + public function isFunction(): self + { + return new self(array_values(array_filter($this->items, static fn(Complexity $complexity): bool => $complexity->isFunction()))); + } + public function isMethod(): self + { + return new self(array_values(array_filter($this->items, static fn(Complexity $complexity): bool => $complexity->isMethod()))); + } + public function mergeWith(self $other): self + { + return new self(array_merge($this->asArray(), $other->asArray())); + } + public function sortByDescendingCyclomaticComplexity(): self + { + $items = $this->items; + usort($items, static function (Complexity $a, Complexity $b): int { + return $a->cyclomaticComplexity() <=> $b->cyclomaticComplexity(); + }); + return new self(array_reverse($items)); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Complexity; + +use Iterator; +/** + * @template-implements Iterator + */ +final class ComplexityCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $items; + private int $position = 0; + public function __construct(ComplexityCollection $items) + { + $this->items = $items->asArray(); + } + public function rewind(): void + { + $this->position = 0; + } + public function valid(): bool + { + return isset($this->items[$this->position]); + } + public function key(): int + { + return $this->position; + } + public function current(): Complexity + { + return $this->items[$this->position]; + } + public function next(): void + { + $this->position++; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Complexity; + +use Throwable; +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Complexity; + +final class RuntimeException extends \RuntimeException implements Exception +{ +} +BSD 3-Clause License + +Copyright (c) 2020-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Complexity; + +use function assert; +use function is_array; +use PHPUnitPHAR\PhpParser\Node; +use PHPUnitPHAR\PhpParser\Node\Expr\New_; +use PHPUnitPHAR\PhpParser\Node\Stmt; +use PHPUnitPHAR\PhpParser\Node\Stmt\Class_; +use PHPUnitPHAR\PhpParser\Node\Stmt\ClassMethod; +use PHPUnitPHAR\PhpParser\Node\Stmt\Function_; +use PHPUnitPHAR\PhpParser\Node\Stmt\Interface_; +use PHPUnitPHAR\PhpParser\Node\Stmt\Trait_; +use PHPUnitPHAR\PhpParser\NodeTraverser; +use PHPUnitPHAR\PhpParser\NodeVisitor; +use PHPUnitPHAR\PhpParser\NodeVisitorAbstract; +final class ComplexityCalculatingVisitor extends NodeVisitorAbstract +{ + /** + * @var list + */ + private array $result = []; + private bool $shortCircuitTraversal; + public function __construct(bool $shortCircuitTraversal) + { + $this->shortCircuitTraversal = $shortCircuitTraversal; + } + public function enterNode(Node $node): ?int + { + if (!$node instanceof ClassMethod && !$node instanceof Function_) { + return null; + } + if ($node instanceof ClassMethod) { + if ($node->getAttribute('parent') instanceof Interface_) { + return null; + } + if ($node->isAbstract()) { + return null; + } + $name = $this->classMethodName($node); + } else { + $name = $this->functionName($node); + } + $statements = $node->getStmts(); + assert(is_array($statements)); + $this->result[] = new Complexity($name, $this->cyclomaticComplexity($statements)); + if ($this->shortCircuitTraversal) { + return NodeVisitor::DONT_TRAVERSE_CHILDREN; + } + return null; + } + public function result(): ComplexityCollection + { + return ComplexityCollection::fromList(...$this->result); + } + /** + * @param Stmt[] $statements + * + * @return positive-int + */ + private function cyclomaticComplexity(array $statements): int + { + $traverser = new NodeTraverser(); + $cyclomaticComplexityCalculatingVisitor = new CyclomaticComplexityCalculatingVisitor(); + $traverser->addVisitor($cyclomaticComplexityCalculatingVisitor); + /* @noinspection UnusedFunctionResultInspection */ + $traverser->traverse($statements); + return $cyclomaticComplexityCalculatingVisitor->cyclomaticComplexity(); + } + /** + * @return non-empty-string + */ + private function classMethodName(ClassMethod $node): string + { + $parent = $node->getAttribute('parent'); + assert($parent instanceof Class_ || $parent instanceof Trait_); + if ($parent->getAttribute('parent') instanceof New_) { + return 'anonymous class'; + } + assert(isset($parent->namespacedName)); + return $parent->namespacedName->toString() . '::' . $node->name->toString(); + } + /** + * @return non-empty-string + */ + private function functionName(Function_ $node): string + { + assert(isset($node->namespacedName)); + return $node->namespacedName->toString(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Complexity; + +use PHPUnitPHAR\PhpParser\Node; +use PHPUnitPHAR\PhpParser\Node\Expr\BinaryOp\BooleanAnd; +use PHPUnitPHAR\PhpParser\Node\Expr\BinaryOp\BooleanOr; +use PHPUnitPHAR\PhpParser\Node\Expr\BinaryOp\LogicalAnd; +use PHPUnitPHAR\PhpParser\Node\Expr\BinaryOp\LogicalOr; +use PHPUnitPHAR\PhpParser\Node\Expr\Ternary; +use PHPUnitPHAR\PhpParser\Node\Stmt\Case_; +use PHPUnitPHAR\PhpParser\Node\Stmt\Catch_; +use PHPUnitPHAR\PhpParser\Node\Stmt\ElseIf_; +use PHPUnitPHAR\PhpParser\Node\Stmt\For_; +use PHPUnitPHAR\PhpParser\Node\Stmt\Foreach_; +use PHPUnitPHAR\PhpParser\Node\Stmt\If_; +use PHPUnitPHAR\PhpParser\Node\Stmt\While_; +use PHPUnitPHAR\PhpParser\NodeVisitorAbstract; +final class CyclomaticComplexityCalculatingVisitor extends NodeVisitorAbstract +{ + /** + * @var positive-int + */ + private int $cyclomaticComplexity = 1; + public function enterNode(Node $node): null + { + switch ($node::class) { + case BooleanAnd::class: + case BooleanOr::class: + case Case_::class: + case Catch_::class: + case ElseIf_::class: + case For_::class: + case Foreach_::class: + case If_::class: + case LogicalAnd::class: + case LogicalOr::class: + case Node\MatchArm::class: + case Ternary::class: + case While_::class: + $this->cyclomaticComplexity++; + } + return null; + } + /** + * @return positive-int + */ + public function cyclomaticComplexity(): int + { + return $this->cyclomaticComplexity; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff; + +use ArrayIterator; +use IteratorAggregate; +use Traversable; +/** + * @template-implements IteratorAggregate + */ +final class Chunk implements IteratorAggregate +{ + private int $start; + private int $startRange; + private int $end; + private int $endRange; + /** + * @var list + */ + private array $lines; + /** + * @param list $lines + */ + public function __construct(int $start = 0, int $startRange = 1, int $end = 0, int $endRange = 1, array $lines = []) + { + $this->start = $start; + $this->startRange = $startRange; + $this->end = $end; + $this->endRange = $endRange; + $this->lines = $lines; + } + public function start(): int + { + return $this->start; + } + public function startRange(): int + { + return $this->startRange; + } + public function end(): int + { + return $this->end; + } + public function endRange(): int + { + return $this->endRange; + } + /** + * @return list + */ + public function lines(): array + { + return $this->lines; + } + /** + * @param list $lines + */ + public function setLines(array $lines): void + { + $this->lines = $lines; + } + public function getIterator(): Traversable + { + return new ArrayIterator($this->lines); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff; + +use ArrayIterator; +use IteratorAggregate; +use Traversable; +/** + * @template-implements IteratorAggregate + */ +final class Diff implements IteratorAggregate +{ + /** + * @var non-empty-string + */ + private string $from; + /** + * @var non-empty-string + */ + private string $to; + /** + * @var list + */ + private array $chunks; + /** + * @param non-empty-string $from + * @param non-empty-string $to + * @param list $chunks + */ + public function __construct(string $from, string $to, array $chunks = []) + { + $this->from = $from; + $this->to = $to; + $this->chunks = $chunks; + } + /** + * @return non-empty-string + */ + public function from(): string + { + return $this->from; + } + /** + * @return non-empty-string + */ + public function to(): string + { + return $this->to; + } + /** + * @return list + */ + public function chunks(): array + { + return $this->chunks; + } + /** + * @param list $chunks + */ + public function setChunks(array $chunks): void + { + $this->chunks = $chunks; + } + public function getIterator(): Traversable + { + return new ArrayIterator($this->chunks); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff; + +use const PHP_INT_SIZE; +use const PREG_SPLIT_DELIM_CAPTURE; +use const PREG_SPLIT_NO_EMPTY; +use function array_any; +use function array_shift; +use function array_unshift; +use function array_values; +use function count; +use function current; +use function end; +use function is_string; +use function key; +use function min; +use function preg_split; +use function prev; +use function reset; +use function str_ends_with; +use function substr; +use PHPUnitPHAR\SebastianBergmann\Diff\Output\DiffOutputBuilderInterface; +final class Differ +{ + public const int OLD = 0; + public const int ADDED = 1; + public const int REMOVED = 2; + public const int DIFF_LINE_END_WARNING = 3; + public const int NO_LINE_END_EOF_WARNING = 4; + private DiffOutputBuilderInterface $outputBuilder; + public function __construct(DiffOutputBuilderInterface $outputBuilder) + { + $this->outputBuilder = $outputBuilder; + } + /** + * @param list|string $from + * @param list|string $to + */ + public function diff(array|string $from, array|string $to, ?LongestCommonSubsequenceCalculator $lcs = null): string + { + $diff = $this->diffToArray($from, $to, $lcs); + return $this->outputBuilder->getDiff($diff); + } + /** + * @param list|string $from + * @param list|string $to + */ + public function diffToArray(array|string $from, array|string $to, ?LongestCommonSubsequenceCalculator $lcs = null): array + { + if (is_string($from)) { + $from = $this->splitStringByLines($from); + } + if (is_string($to)) { + $to = $this->splitStringByLines($to); + } + [$from, $to, $start, $end] = self::getArrayDiffParted($from, $to); + if ($lcs === null) { + $lcs = $this->selectLcsImplementation($from, $to); + } + $common = $lcs->calculate(array_values($from), array_values($to)); + $diff = []; + foreach ($start as $token) { + $diff[] = [$token, self::OLD]; + } + reset($from); + reset($to); + foreach ($common as $token) { + while (reset($from) !== $token) { + $diff[] = [array_shift($from), self::REMOVED]; + } + while (reset($to) !== $token) { + $diff[] = [array_shift($to), self::ADDED]; + } + $diff[] = [$token, self::OLD]; + array_shift($from); + array_shift($to); + } + while (($token = array_shift($from)) !== null) { + $diff[] = [$token, self::REMOVED]; + } + while (($token = array_shift($to)) !== null) { + $diff[] = [$token, self::ADDED]; + } + foreach ($end as $token) { + $diff[] = [$token, self::OLD]; + } + if ($this->detectUnmatchedLineEndings($diff)) { + array_unshift($diff, ["#Warning: Strings contain different line endings!\n", self::DIFF_LINE_END_WARNING]); + } + return $diff; + } + private function splitStringByLines(string $input): array + { + return preg_split('/(.*\R)/', $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + } + private function selectLcsImplementation(array $from, array $to): LongestCommonSubsequenceCalculator + { + // We do not want to use the time-efficient implementation if its memory + // footprint will probably exceed this value. Note that the footprint + // calculation is only an estimation for the matrix and the LCS method + // will typically allocate a bit more memory than this. + $memoryLimit = 100 * 1024 * 1024; + if ($this->calculateEstimatedFootprint($from, $to) > $memoryLimit) { + return new MemoryEfficientLongestCommonSubsequenceCalculator(); + } + return new TimeEfficientLongestCommonSubsequenceCalculator(); + } + private function calculateEstimatedFootprint(array $from, array $to): int + { + $itemSize = PHP_INT_SIZE === 4 ? 76 : 144; + return $itemSize * min(count($from), count($to)) ** 2; + } + private function detectUnmatchedLineEndings(array $diff): bool + { + $newLineBreaks = ['' => \true]; + $oldLineBreaks = ['' => \true]; + foreach ($diff as $entry) { + if (self::OLD === $entry[1]) { + $ln = $this->getLinebreak($entry[0]); + $oldLineBreaks[$ln] = \true; + $newLineBreaks[$ln] = \true; + } elseif (self::ADDED === $entry[1]) { + $newLineBreaks[$this->getLinebreak($entry[0])] = \true; + } elseif (self::REMOVED === $entry[1]) { + $oldLineBreaks[$this->getLinebreak($entry[0])] = \true; + } + } + // if either input or output is a single line without breaks than no warning should be raised + if (['' => \true] === $newLineBreaks || ['' => \true] === $oldLineBreaks) { + return \false; + } + // two-way compare + if (array_any($newLineBreaks, static fn(bool $set, string $break) => !isset($oldLineBreaks[$break]))) { + return \true; + } + return array_any($oldLineBreaks, static fn(bool $set, string $break) => !isset($newLineBreaks[$break])); + } + private function getLinebreak(int|string $line): string + { + if (!is_string($line)) { + return ''; + } + $lc = substr($line, -1); + if ("\r" === $lc) { + return "\r"; + } + if ("\n" !== $lc) { + return ''; + } + if (str_ends_with($line, "\r\n")) { + return "\r\n"; + } + return "\n"; + } + private static function getArrayDiffParted(array &$from, array &$to): array + { + $start = []; + $end = []; + reset($to); + foreach ($from as $k => $v) { + $toK = key($to); + if ($toK === $k && $v === $to[$k]) { + $start[$k] = $v; + unset($from[$k], $to[$k]); + } else { + break; + } + } + end($from); + end($to); + do { + $fromK = key($from); + $toK = key($to); + if (null === $fromK || null === $toK || current($from) !== current($to)) { + break; + } + prev($from); + prev($to); + $end = [$fromK => $from[$fromK]] + $end; + unset($from[$fromK], $to[$toK]); + } while (\true); + return [$from, $to, $start, $end]; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff; + +use function gettype; +use function is_object; +use function sprintf; +use InvalidArgumentException; +final class ConfigurationException extends InvalidArgumentException implements Exception +{ + public function __construct(string $option, string $expected, mixed $value, int $code = 0, ?\Exception $previous = null) + { + parent::__construct(sprintf('Option "%s" must be %s, got "%s".', $option, $expected, is_object($value) ? $value::class : (null === $value ? '' : gettype($value) . '#' . $value)), $code, $previous); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff; + +use Throwable; +interface Exception extends Throwable +{ +} +BSD 3-Clause License + +Copyright (c) 2002-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff; + +final class Line +{ + public const int ADDED = 1; + public const int REMOVED = 2; + public const int UNCHANGED = 3; + private int $type; + private string $content; + public function __construct(int $type = self::UNCHANGED, string $content = '') + { + $this->type = $type; + $this->content = $content; + } + public function content(): string + { + return $this->content; + } + public function type(): int + { + return $this->type; + } + public function isAdded(): bool + { + return $this->type === self::ADDED; + } + public function isRemoved(): bool + { + return $this->type === self::REMOVED; + } + public function isUnchanged(): bool + { + return $this->type === self::UNCHANGED; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff; + +/** + * @deprecated https://github.com/sebastianbergmann/diff/pull/138 + */ +interface LongestCommonSubsequenceCalculator +{ + /** + * Calculates the longest common subsequence of two arrays. + */ + public function calculate(array $from, array $to): array; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff; + +use function array_fill; +use function array_merge; +use function array_reverse; +use function array_slice; +use function count; +use function in_array; +/** + * @deprecated https://github.com/sebastianbergmann/diff/pull/138 + */ +final class MemoryEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator +{ + /** + * @inheritDoc + */ + public function calculate(array $from, array $to): array + { + $cFrom = count($from); + $cTo = count($to); + if ($cFrom === 0) { + return []; + } + if ($cFrom === 1) { + if (in_array($from[0], $to, \true)) { + return [$from[0]]; + } + return []; + } + $i = (int) ($cFrom / 2); + $fromStart = array_slice($from, 0, $i); + $fromEnd = array_slice($from, $i); + $llB = $this->length($fromStart, $to); + $llE = $this->length(array_reverse($fromEnd), array_reverse($to)); + $jMax = 0; + $max = 0; + for ($j = 0; $j <= $cTo; $j++) { + $m = $llB[$j] + $llE[$cTo - $j]; + if ($m >= $max) { + $max = $m; + $jMax = $j; + } + } + $toStart = array_slice($to, 0, $jMax); + $toEnd = array_slice($to, $jMax); + return array_merge($this->calculate($fromStart, $toStart), $this->calculate($fromEnd, $toEnd)); + } + private function length(array $from, array $to): array + { + $current = array_fill(0, count($to) + 1, 0); + $cFrom = count($from); + $cTo = count($to); + for ($i = 0; $i < $cFrom; $i++) { + $prev = $current; + for ($j = 0; $j < $cTo; $j++) { + if ($from[$i] === $to[$j]) { + $current[$j + 1] = $prev[$j] + 1; + } else if ($current[$j] > $prev[$j + 1]) { + $current[$j + 1] = $current[$j]; + } else { + $current[$j + 1] = $prev[$j + 1]; + } + } + } + return $current; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff\Output; + +use function count; +abstract class AbstractChunkOutputBuilder implements DiffOutputBuilderInterface +{ + /** + * Takes input of the diff array and returns the common parts. + * Iterates through diff line by line. + * + * @return array + */ + protected function getCommonChunks(array $diff, int $lineThreshold = 5): array + { + $diffSize = count($diff); + $capturing = \false; + $chunkStart = 0; + $chunkSize = 0; + $commonChunks = []; + for ($i = 0; $i < $diffSize; $i++) { + if ($diff[$i][1] === 0) { + if ($capturing === \false) { + $capturing = \true; + $chunkStart = $i; + $chunkSize = 0; + } else { + $chunkSize++; + } + } elseif ($capturing !== \false) { + if ($chunkSize >= $lineThreshold) { + $commonChunks[$chunkStart] = $chunkStart + $chunkSize; + } + $capturing = \false; + } + } + if ($capturing !== \false && $chunkSize >= $lineThreshold) { + $commonChunks[$chunkStart] = $chunkStart + $chunkSize; + } + return $commonChunks; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff\Output; + +use function assert; +use function fclose; +use function fopen; +use function fwrite; +use function is_resource; +use function str_ends_with; +use function stream_get_contents; +use function substr; +use PHPUnitPHAR\SebastianBergmann\Diff\Differ; +/** + * Builds a diff string representation in a loose unified diff format + * listing only changes lines. Does not include line numbers. + */ +final class DiffOnlyOutputBuilder implements DiffOutputBuilderInterface +{ + private string $header; + public function __construct(string $header = "--- Original\n+++ New\n") + { + $this->header = $header; + } + public function getDiff(array $diff): string + { + $buffer = fopen('php://memory', 'r+b'); + assert(is_resource($buffer)); + if ('' !== $this->header) { + fwrite($buffer, $this->header); + if (!str_ends_with($this->header, "\n")) { + fwrite($buffer, "\n"); + } + } + foreach ($diff as $diffEntry) { + if ($diffEntry[1] === Differ::ADDED) { + fwrite($buffer, '+' . $diffEntry[0]); + } elseif ($diffEntry[1] === Differ::REMOVED) { + fwrite($buffer, '-' . $diffEntry[0]); + } elseif ($diffEntry[1] === Differ::DIFF_LINE_END_WARNING) { + fwrite($buffer, ' ' . $diffEntry[0]); + continue; + // Warnings should not be tested for line break, it will always be there + } else { + /* Not changed (old) 0 */ + continue; + // we didn't write the not-changed line, so do not add a line break either + } + $lc = substr($diffEntry[0], -1); + if ($lc !== "\n" && $lc !== "\r") { + fwrite($buffer, "\n"); + // \No newline at end of file + } + } + $diff = stream_get_contents($buffer, -1, 0); + fclose($buffer); + return $diff; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff\Output; + +/** + * Defines how an output builder should take a generated + * diff array and return a string representation of that diff. + */ +interface DiffOutputBuilderInterface +{ + public function getDiff(array $diff): string; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff\Output; + +use function array_merge; +use function array_splice; +use function assert; +use function count; +use function fclose; +use function fopen; +use function fwrite; +use function is_bool; +use function is_int; +use function is_resource; +use function is_string; +use function max; +use function min; +use function sprintf; +use function str_ends_with; +use function stream_get_contents; +use function substr; +use PHPUnitPHAR\SebastianBergmann\Diff\ConfigurationException; +use PHPUnitPHAR\SebastianBergmann\Diff\Differ; +/** + * Strict Unified diff output builder. + * + * Generates (strict) Unified diff's (unidiffs) with hunks. + */ +final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface +{ + private static array $default = [ + 'addLineNumbers' => \true, + // when false, hunk header is rendered as `@@ @@` (no line numbers); when true, as `@@ -from,range +to,range @@` + 'collapseRanges' => \true, + // ranges of length one are rendered with the trailing `,1` + 'commonLineThreshold' => 6, + // number of same lines before ending a new hunk and creating a new one (if needed) + 'contextLines' => 3, + // like `diff: -u, -U NUM, --unified[=NUM]`, for patch/git apply compatibility best to keep at least @ 3 + 'emitDiffLineEndWarning' => \false, + // when true, the `#Warning: Strings contain different line endings!` line inserted by `Differ` is rendered (it is not part of strict unified diff format) + 'emitNoLineEndEofWarning' => \true, + // when false, the `\ No newline at end of file` marker is suppressed (useful for comparisons not related to files) + 'fromFile' => null, + 'fromFileDate' => null, + 'header' => null, + // when provided, used verbatim as the header; otherwise built from `fromFile`/`fromFileDate`/`toFile`/`toFileDate` + 'toFile' => null, + 'toFileDate' => null, + ]; + private bool $addLineNumbers; + private bool $changed; + private bool $collapseRanges; + /** + * @var positive-int + */ + private int $commonLineThreshold; + private bool $emitDiffLineEndWarning; + private bool $emitNoLineEndEofWarning; + private string $header; + /** + * @var positive-int + */ + private int $contextLines; + public function __construct(array $options = []) + { + $options = array_merge(self::$default, $options); + if (!is_bool($options['addLineNumbers'])) { + throw new ConfigurationException('addLineNumbers', 'a bool', $options['addLineNumbers']); + } + if (!is_bool($options['collapseRanges'])) { + throw new ConfigurationException('collapseRanges', 'a bool', $options['collapseRanges']); + } + if (!is_int($options['contextLines']) || $options['contextLines'] < 0) { + throw new ConfigurationException('contextLines', 'an int >= 0', $options['contextLines']); + } + if (!is_int($options['commonLineThreshold']) || $options['commonLineThreshold'] <= 0) { + throw new ConfigurationException('commonLineThreshold', 'an int > 0', $options['commonLineThreshold']); + } + if (!is_bool($options['emitDiffLineEndWarning'])) { + throw new ConfigurationException('emitDiffLineEndWarning', 'a bool', $options['emitDiffLineEndWarning']); + } + if (!is_bool($options['emitNoLineEndEofWarning'])) { + throw new ConfigurationException('emitNoLineEndEofWarning', 'a bool', $options['emitNoLineEndEofWarning']); + } + if (null !== $options['header']) { + $this->assertString($options, 'header'); + $this->header = $options['header']; + } else { + $this->assertString($options, 'fromFile'); + $this->assertString($options, 'toFile'); + $this->assertStringOrNull($options, 'fromFileDate'); + $this->assertStringOrNull($options, 'toFileDate'); + $this->header = sprintf("--- %s%s\n+++ %s%s\n", $options['fromFile'], null === $options['fromFileDate'] ? '' : "\t" . $options['fromFileDate'], $options['toFile'], null === $options['toFileDate'] ? '' : "\t" . $options['toFileDate']); + } + $this->addLineNumbers = $options['addLineNumbers']; + $this->collapseRanges = $options['collapseRanges']; + $this->commonLineThreshold = $options['commonLineThreshold']; + $this->contextLines = $options['contextLines']; + $this->emitDiffLineEndWarning = $options['emitDiffLineEndWarning']; + $this->emitNoLineEndEofWarning = $options['emitNoLineEndEofWarning']; + } + public function getDiff(array $diff): string + { + if (0 === count($diff)) { + return ''; + } + $this->changed = \false; + $buffer = fopen('php://memory', 'r+b'); + assert(is_resource($buffer)); + if ('' !== $this->header) { + fwrite($buffer, $this->header); + if (!str_ends_with($this->header, "\n")) { + fwrite($buffer, "\n"); + } + } + $this->writeDiffHunks($buffer, $diff); + if (!$this->changed) { + fclose($buffer); + return ''; + } + $diff = stream_get_contents($buffer, -1, 0); + fclose($buffer); + // If the last char is not a linebreak: add it. + // This might happen when both the `from` and `to` do not have a trailing linebreak + $last = substr($diff, -1); + return "\n" !== $last && "\r" !== $last ? $diff . "\n" : $diff; + } + private function writeDiffHunks(mixed $output, array $diff): void + { + assert(is_resource($output)); + // detect "No newline at end of file" and insert into `$diff` if needed + $upperLimit = count($diff); + if (0 === $diff[$upperLimit - 1][1]) { + $lc = substr($diff[$upperLimit - 1][0], -1); + if ("\n" !== $lc) { + array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); + } + } else { + // search back for the last `+` and `-` line, + // check if it has a trailing linebreak, else add a warning under it + $toFind = [1 => \true, 2 => \true]; + for ($i = $upperLimit - 1; $i >= 0; $i--) { + if (isset($toFind[$diff[$i][1]])) { + unset($toFind[$diff[$i][1]]); + $lc = substr($diff[$i][0], -1); + if ("\n" !== $lc) { + array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); + } + if ($toFind === []) { + break; + } + } + } + } + // write hunks to output buffer + $cutOff = max($this->commonLineThreshold, $this->contextLines); + $hunkCapture = \false; + $sameCount = $toRange = $fromRange = 0; + $toStart = $fromStart = 1; + foreach ($diff as $i => $entry) { + if (0 === $entry[1]) { + // same + if (\false === $hunkCapture) { + $fromStart++; + $toStart++; + continue; + } + $sameCount++; + $toRange++; + $fromRange++; + if ($sameCount === $cutOff) { + $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture : $this->contextLines; + // note: $contextEndOffset = $this->contextLines; + // + // because we never go beyond the end of the diff. + // with the cutoff/contextlines here the follow is never true; + // + // if ($i - $cutOff + $this->contextLines + 1 > \count($diff)) { + // $contextEndOffset = count($diff) - 1; + // } + // + // ; that would be true for a trailing incomplete hunk case which is dealt with after this loop + $this->writeHunk($diff, $hunkCapture - $contextStartOffset, $i - $cutOff + $this->contextLines + 1, $fromStart - $contextStartOffset, $fromRange - $cutOff + $contextStartOffset + $this->contextLines, $toStart - $contextStartOffset, $toRange - $cutOff + $contextStartOffset + $this->contextLines, $output); + $fromStart += $fromRange; + $toStart += $toRange; + $hunkCapture = \false; + $sameCount = $toRange = $fromRange = 0; + } + continue; + } + $sameCount = 0; + if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) { + continue; + } + $this->changed = \true; + if (\false === $hunkCapture) { + $hunkCapture = $i; + } + if (Differ::ADDED === $entry[1]) { + // added + $toRange++; + } + if (Differ::REMOVED === $entry[1]) { + // removed + $fromRange++; + } + } + if (\false === $hunkCapture) { + return; + } + // we end here when cutoff (commonLineThreshold) was not reached, but we were capturing a hunk, + // do not render hunk till end automatically because the number of context lines might be less than the commonLineThreshold + $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture : $this->contextLines; + // prevent trying to write out more common lines than there are in the diff _and_ + // do not write more than configured through the context lines + $contextEndOffset = min($sameCount, $this->contextLines); + $fromRange -= $sameCount; + $toRange -= $sameCount; + assert(isset($i) && is_int($i)); + $this->writeHunk($diff, $hunkCapture - $contextStartOffset, $i - $sameCount + $contextEndOffset + 1, $fromStart - $contextStartOffset, $fromRange + $contextStartOffset + $contextEndOffset, $toStart - $contextStartOffset, $toRange + $contextStartOffset + $contextEndOffset, $output); + } + private function writeHunk(array $diff, int $diffStartIndex, int $diffEndIndex, int $fromStart, int $fromRange, int $toStart, int $toRange, mixed $output): void + { + assert(is_resource($output)); + if ($this->addLineNumbers) { + fwrite($output, '@@ -' . $fromStart); + if (!$this->collapseRanges || 1 !== $fromRange) { + fwrite($output, ',' . $fromRange); + } + fwrite($output, ' +' . $toStart); + if (!$this->collapseRanges || 1 !== $toRange) { + fwrite($output, ',' . $toRange); + } + fwrite($output, " @@\n"); + } else { + fwrite($output, "@@ @@\n"); + } + for ($i = $diffStartIndex; $i < $diffEndIndex; $i++) { + if ($diff[$i][1] === Differ::ADDED) { + $this->changed = \true; + fwrite($output, '+' . $diff[$i][0]); + } elseif ($diff[$i][1] === Differ::REMOVED) { + $this->changed = \true; + fwrite($output, '-' . $diff[$i][0]); + } elseif ($diff[$i][1] === Differ::OLD) { + fwrite($output, ' ' . $diff[$i][0]); + } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) { + fwrite($output, $this->emitNoLineEndEofWarning ? $diff[$i][0] : "\n"); + } elseif ($this->emitDiffLineEndWarning && $diff[$i][1] === Differ::DIFF_LINE_END_WARNING) { + fwrite($output, ' ' . $diff[$i][0]); + } + // else: unknown/invalid type or skipped warning - silently skip + } + } + private function assertString(array $options, string $option): void + { + if (!is_string($options[$option])) { + throw new ConfigurationException($option, 'a string', $options[$option]); + } + } + private function assertStringOrNull(array $options, string $option): void + { + if (null !== $options[$option] && !is_string($options[$option])) { + throw new ConfigurationException($option, 'a string or ', $options[$option]); + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff\Output; + +use function array_splice; +use function assert; +use function count; +use function fclose; +use function fopen; +use function fwrite; +use function is_int; +use function is_resource; +use function max; +use function min; +use function str_ends_with; +use function stream_get_contents; +use function substr; +use PHPUnitPHAR\SebastianBergmann\Diff\Differ; +/** + * Builds a diff string representation in unified diff format in chunks. + */ +final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder +{ + /** @phpstan-ignore property.tooWideBool */ + private bool $collapseRanges = \true; + private int $commonLineThreshold = 6; + /** + * @var positive-int + */ + private int $contextLines; + private string $header; + private bool $addLineNumbers; + private bool $emitNoLineEndEofWarning; + private bool $changed; + /** + * @param positive-int $contextLines + */ + public function __construct(string $header = "--- Original\n+++ New\n", bool $addLineNumbers = \false, int $contextLines = 3, bool $emitNoLineEndEofWarning = \true) + { + $this->header = $header; + $this->addLineNumbers = $addLineNumbers; + $this->contextLines = $contextLines; + $this->emitNoLineEndEofWarning = $emitNoLineEndEofWarning; + } + public function getDiff(array $diff): string + { + if (0 === count($diff)) { + return ''; + } + $this->changed = \false; + $buffer = fopen('php://memory', 'r+b'); + assert(is_resource($buffer)); + if ('' !== $this->header) { + fwrite($buffer, $this->header); + if (!str_ends_with($this->header, "\n")) { + fwrite($buffer, "\n"); + } + } + $this->writeDiffHunks($buffer, $diff); + if (!$this->changed) { + fclose($buffer); + return ''; + } + $diff = stream_get_contents($buffer, -1, 0); + fclose($buffer); + // If the diff is non-empty and last char is not a linebreak: add it. + // This might happen when both the `from` and `to` do not have a trailing linebreak + $last = substr($diff, -1); + return '' !== $diff && "\n" !== $last && "\r" !== $last ? $diff . "\n" : $diff; + } + private function writeDiffHunks(mixed $output, array $diff): void + { + assert(is_resource($output)); + // detect "No newline at end of file" and insert into `$diff` if needed + $upperLimit = count($diff); + if (0 === $diff[$upperLimit - 1][1]) { + $lc = substr($diff[$upperLimit - 1][0], -1); + if ("\n" !== $lc) { + array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); + } + } else { + // search back for the last `+` and `-` line, + // check if it has trailing linebreak, else add a warning under it + $toFind = [1 => \true, 2 => \true]; + for ($i = $upperLimit - 1; $i >= 0; $i--) { + if (isset($toFind[$diff[$i][1]])) { + unset($toFind[$diff[$i][1]]); + $lc = substr($diff[$i][0], -1); + if ("\n" !== $lc) { + array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); + } + if ($toFind === []) { + break; + } + } + } + } + // write hunks to output buffer + $cutOff = max($this->commonLineThreshold, $this->contextLines); + $hunkCapture = \false; + $sameCount = $toRange = $fromRange = 0; + $toStart = $fromStart = 1; + foreach ($diff as $i => $entry) { + if (0 === $entry[1]) { + // same + if (\false === $hunkCapture) { + $fromStart++; + $toStart++; + continue; + } + $sameCount++; + $toRange++; + $fromRange++; + if ($sameCount === $cutOff) { + $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture : $this->contextLines; + // note: $contextEndOffset = $this->contextLines; + // + // because we never go beyond the end of the diff. + // with the cutoff/contextlines here the follow is never true; + // + // if ($i - $cutOff + $this->contextLines + 1 > \count($diff)) { + // $contextEndOffset = count($diff) - 1; + // } + // + // ; that would be true for a trailing incomplete hunk case which is dealt with after this loop + $this->writeHunk($diff, $hunkCapture - $contextStartOffset, $i - $cutOff + $this->contextLines + 1, $fromStart - $contextStartOffset, $fromRange - $cutOff + $contextStartOffset + $this->contextLines, $toStart - $contextStartOffset, $toRange - $cutOff + $contextStartOffset + $this->contextLines, $output); + $fromStart += $fromRange; + $toStart += $toRange; + $hunkCapture = \false; + $sameCount = $toRange = $fromRange = 0; + } + continue; + } + $sameCount = 0; + if ($entry[1] === Differ::NO_LINE_END_EOF_WARNING) { + continue; + } + $this->changed = \true; + if (\false === $hunkCapture) { + $hunkCapture = $i; + } + if (Differ::ADDED === $entry[1]) { + $toRange++; + } + if (Differ::REMOVED === $entry[1]) { + $fromRange++; + } + } + if (\false === $hunkCapture) { + return; + } + // we end here when cutoff (commonLineThreshold) was not reached, but we were capturing a hunk, + // do not render hunk till end automatically because the number of context lines might be less than the commonLineThreshold + $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture : $this->contextLines; + // prevent trying to write out more common lines than there are in the diff _and_ + // do not write more than configured through the context lines + $contextEndOffset = min($sameCount, $this->contextLines); + $fromRange -= $sameCount; + $toRange -= $sameCount; + assert(isset($i) && is_int($i)); + $this->writeHunk($diff, $hunkCapture - $contextStartOffset, $i - $sameCount + $contextEndOffset + 1, $fromStart - $contextStartOffset, $fromRange + $contextStartOffset + $contextEndOffset, $toStart - $contextStartOffset, $toRange + $contextStartOffset + $contextEndOffset, $output); + } + private function writeHunk(array $diff, int $diffStartIndex, int $diffEndIndex, int $fromStart, int $fromRange, int $toStart, int $toRange, mixed $output): void + { + assert(is_resource($output)); + if ($this->addLineNumbers) { + fwrite($output, '@@ -' . $fromStart); + if (!$this->collapseRanges || 1 !== $fromRange) { + fwrite($output, ',' . $fromRange); + } + fwrite($output, ' +' . $toStart); + if (!$this->collapseRanges || 1 !== $toRange) { + fwrite($output, ',' . $toRange); + } + fwrite($output, " @@\n"); + } else { + fwrite($output, "@@ @@\n"); + } + for ($i = $diffStartIndex; $i < $diffEndIndex; $i++) { + if ($diff[$i][1] === Differ::ADDED) { + fwrite($output, '+' . $diff[$i][0]); + } elseif ($diff[$i][1] === Differ::REMOVED) { + fwrite($output, '-' . $diff[$i][0]); + } elseif ($diff[$i][1] === Differ::OLD) { + fwrite($output, ' ' . $diff[$i][0]); + } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) { + fwrite($output, $this->emitNoLineEndEofWarning ? $diff[$i][0] : "\n"); + } elseif ($diff[$i][1] === Differ::DIFF_LINE_END_WARNING) { + fwrite($output, ' ' . $diff[$i][0]); + } + // else: unknown/invalid type - silently skip + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff; + +use const PREG_UNMATCHED_AS_NULL; +use function array_pop; +use function count; +use function max; +use function preg_match; +use function preg_split; +/** + * Unified diff parser. + */ +final class Parser +{ + /** + * @return list + */ + public function parse(string $string): array + { + $lines = preg_split('(\r\n|\r|\n)', $string); + if ($lines !== \false && $lines !== [] && $lines[count($lines) - 1] === '') { + array_pop($lines); + } + $lineCount = count($lines); + $diffs = []; + $diff = null; + $collected = []; + for ($i = 0; $i < $lineCount; $i++) { + if (preg_match('#^---\h+"?(?P[^\v\t"]+)#', $lines[$i], $fromMatch) && preg_match('#^\+\+\+\h+"?(?P[^\v\t"]+)#', $lines[$i + 1], $toMatch)) { + if ($diff !== null) { + $this->parseFileDiff($diff, $collected); + $diffs[] = $diff; + $collected = []; + } + $diff = new Diff($fromMatch['file'], $toMatch['file']); + $i++; + } else { + if (preg_match('/^(?:diff --git |index [\da-f.]+|[+-]{3} [ab])/', $lines[$i])) { + continue; + } + $collected[] = $lines[$i]; + } + } + if ($diff !== null && $collected !== []) { + $this->parseFileDiff($diff, $collected); + $diffs[] = $diff; + } + return $diffs; + } + /** + * @param string[] $lines + */ + private function parseFileDiff(Diff $diff, array $lines): void + { + $chunks = []; + $chunk = null; + $diffLines = []; + foreach ($lines as $line) { + if (preg_match('/^@@\s+-(?P\d+)(?:,\s*(?P\d+))?\s+\+(?P\d+)(?:,\s*(?P\d+))?\s+@@/', $line, $match, PREG_UNMATCHED_AS_NULL)) { + $chunk = new Chunk((int) $match['start'], isset($match['startrange']) ? max(0, (int) $match['startrange']) : 1, (int) $match['end'], isset($match['endrange']) ? max(0, (int) $match['endrange']) : 1); + $chunks[] = $chunk; + $diffLines = []; + continue; + } + if (preg_match('/^(?P[+ -])?(?P.*)/', $line, $match)) { + $type = Line::UNCHANGED; + if ($match['type'] === '+') { + $type = Line::ADDED; + } elseif ($match['type'] === '-') { + $type = Line::REMOVED; + } + $diffLines[] = new Line($type, $match['line']); + $chunk?->setLines($diffLines); + } + } + $diff->setChunks($chunks); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Diff; + +use function array_reverse; +use function count; +use SplFixedArray; +/** + * @deprecated https://github.com/sebastianbergmann/diff/pull/138 + */ +final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator +{ + /** + * @inheritDoc + */ + public function calculate(array $from, array $to): array + { + $common = []; + $fromLength = count($from); + $toLength = count($to); + $width = $fromLength + 1; + $matrix = new SplFixedArray($width * ($toLength + 1)); + for ($i = 0; $i <= $fromLength; $i++) { + $matrix[$i] = 0; + } + for ($j = 0; $j <= $toLength; $j++) { + $matrix[$j * $width] = 0; + } + for ($i = 1; $i <= $fromLength; $i++) { + for ($j = 1; $j <= $toLength; $j++) { + $o = $j * $width + $i; + // don't use max() to avoid function call overhead + $firstOrLast = $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0; + if ($matrix[$o - 1] > $matrix[$o - $width]) { + if ($firstOrLast > $matrix[$o - 1]) { + $matrix[$o] = $firstOrLast; + } else { + $matrix[$o] = $matrix[$o - 1]; + } + } else if ($firstOrLast > $matrix[$o - $width]) { + $matrix[$o] = $firstOrLast; + } else { + $matrix[$o] = $matrix[$o - $width]; + } + } + } + $i = $fromLength; + $j = $toLength; + while ($i > 0 && $j > 0) { + if ($from[$i - 1] === $to[$j - 1]) { + $common[] = $from[$i - 1]; + $i--; + $j--; + } else { + $o = $j * $width + $i; + if ($matrix[$o - $width] > $matrix[$o - 1]) { + $j--; + } else { + $i--; + } + } + } + return array_reverse($common); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Environment; + +use const DIRECTORY_SEPARATOR; +use const STDIN; +use const STDOUT; +use function assert; +use function defined; +use function fclose; +use function fstat; +use function function_exists; +use function getenv; +use function in_array; +use function is_int; +use function is_resource; +use function is_string; +use function posix_isatty; +use function preg_match; +use function proc_close; +use function proc_open; +use function sapi_windows_vt100_support; +use function shell_exec; +use function stream_get_contents; +use function stream_isatty; +use function strtoupper; +use function trim; +final class Console +{ + /** + * @var int + */ + public const int STDIN = 0; + /** + * @var int + */ + public const int STDOUT = 1; + /** + * @var int + */ + public const int STDERR = 2; + /** + * Returns true if STDOUT supports colorization. + * + * This code has been copied and adapted from + * Symfony\Component\Console\Output\StreamOutput. + */ + public function hasColorSupport(): bool + { + if (!defined('STDOUT')) { + return \false; + } + // Follow https://no-color.org/ + if (isset($_SERVER['NO_COLOR']) || \false !== getenv('NO_COLOR')) { + return \false; + } + // Follow https://force-color.org/ + if (isset($_SERVER['FORCE_COLOR']) || \false !== getenv('FORCE_COLOR')) { + return \true; + } + if (!@stream_isatty(STDOUT) && !in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], \true)) { + return \false; + } + if ($this->isWindows() && function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(STDOUT)) { + return \true; + } + if ('Hyper' === getenv('TERM_PROGRAM') || \false !== getenv('COLORTERM') || \false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI')) { + return \true; + } + if ('dumb' === $term = (string) getenv('TERM')) { + return \false; + } + return (bool) preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term); + } + /** + * Returns the number of columns of the terminal. + * + * @codeCoverageIgnore + */ + public function getNumberOfColumns(): int + { + if (!$this->isInteractive(defined('STDIN') ? STDIN : self::STDIN)) { + return 80; + } + if ($this->isWindows()) { + return $this->getNumberOfColumnsWindows(); + } + return $this->getNumberOfColumnsInteractive(); + } + /** + * Returns if the file descriptor is an interactive terminal or not. + * + * Normally, we want to use a resource as a parameter, yet sadly it's not always available, + * eg when running code in interactive console (`php -a`), STDIN/STDOUT/STDERR constants are not defined. + * + * @param int|resource $fileDescriptor + */ + public function isInteractive(mixed $fileDescriptor = self::STDOUT): bool + { + assert(is_int($fileDescriptor) || is_resource($fileDescriptor)); + if (is_resource($fileDescriptor)) { + if (function_exists('stream_isatty') && @stream_isatty($fileDescriptor)) { + return \true; + } + if (function_exists('fstat')) { + $stat = @fstat($fileDescriptor); + return $stat !== \false && 020000 === ($stat['mode'] & 0170000); + } + return \false; + } + return function_exists('posix_isatty') && @posix_isatty($fileDescriptor); + } + private function isWindows(): bool + { + return DIRECTORY_SEPARATOR === '\\'; + } + /** + * @codeCoverageIgnore + */ + private function getNumberOfColumnsInteractive(): int + { + if (function_exists('shell_exec')) { + $stty = shell_exec('stty size 2>/dev/null'); + if ($stty === \false || $stty === null) { + $stty = ''; + } + if (preg_match('#\d+ (\d+)#', $stty, $match) === 1) { + if ((int) $match[1] > 0) { + return (int) $match[1]; + } + } + $stty = shell_exec('stty 2>/dev/null'); + if ($stty === \false || $stty === null) { + $stty = ''; + } + if (preg_match('#columns = (\d+);#', $stty, $match) === 1) { + if ((int) $match[1] > 0) { + return (int) $match[1]; + } + } + } + return 80; + } + /** + * @codeCoverageIgnore + */ + private function getNumberOfColumnsWindows(): int + { + $ansicon = getenv('ANSICON'); + $columns = 80; + /** @phpstan-ignore booleanAnd.rightNotBoolean */ + if (is_string($ansicon) && preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim($ansicon), $matches)) { + $columns = (int) $matches[1]; + } elseif (function_exists('proc_open')) { + $process = proc_open('mode CON', [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes, null, null, ['suppress_errors' => \true]); + assert(isset($pipes[1]) && is_resource($pipes[1])); + assert(isset($pipes[2]) && is_resource($pipes[2])); + if (is_resource($process)) { + $info = stream_get_contents($pipes[1]); + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($process); + /** @phpstan-ignore if.condNotBoolean */ + if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', (string) $info, $matches)) { + $columns = (int) $matches[2]; + } + } + } + return $columns - 1; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Environment; + +use const PHP_OS_FAMILY; +use function assert; +use function function_exists; +use function getenv; +use function gethostname; +use function php_uname; +use function posix_geteuid; +use function posix_getpwuid; +use function trim; +final readonly class Host +{ + /** + * @return non-empty-string + */ + public function name(): string + { + $candidate = gethostname(); + if ($candidate === \false) { + return 'unknown'; + } + $candidate = trim($candidate); + if ($candidate === '') { + return 'unknown'; + } + return $candidate; + } + /** + * @return non-empty-string + */ + public function user(): string + { + if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) { + $info = posix_getpwuid(posix_geteuid()); + if ($info !== \false) { + $candidate = trim($info['name']); + } + } elseif (PHP_OS_FAMILY === 'Windows') { + $candidate = trim((string) getenv('USERNAME')); + } + if (!isset($candidate) || $candidate === '') { + return 'unknown'; + } + return $candidate; + } + /** + * @return non-empty-string + */ + public function operatingSystem(): string + { + $result = php_uname(); + assert($result !== ''); + return $result; + } +} +BSD 3-Clause License + +Copyright (c) 2014-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Environment; + +use const INI_SCANNER_NORMAL; +use const PHP_BINARY; +use const PHP_SAPI; +use const PHP_VERSION; +use function array_key_exists; +use function array_map; +use function array_merge; +use function assert; +use function escapeshellarg; +use function explode; +use function extension_loaded; +use function in_array; +use function ini_get; +use function ini_get_all; +use function is_array; +use function is_int; +use function is_string; +use function json_decode; +use function parse_ini_file; +use function php_ini_loaded_file; +use function php_ini_scanned_files; +use function phpversion; +use function proc_close; +use function proc_open; +use function sprintf; +use function stream_get_contents; +use function strrpos; +use function version_compare; +use function xdebug_info; +final class Runtime +{ + /** + * @var ?array + */ + private static ?array $compiledDefaults = null; + /** + * Returns true when Xdebug or PCOV is available or + * the runtime used is PHPDBG. + */ + public function canCollectCodeCoverage(): bool + { + if ($this->hasPHPDBGCodeCoverage()) { + return \true; + } + if ($this->hasPCOV()) { + return \true; + } + if (!$this->hasXdebug()) { + return \false; + } + $xdebugVersion = phpversion('xdebug'); + assert($xdebugVersion !== \false); + if (version_compare($xdebugVersion, '3', '<')) { + return \true; + } + $xdebugMode = xdebug_info('mode'); + assert(is_array($xdebugMode)); + if (in_array('coverage', $xdebugMode, \true)) { + return \true; + } + return \false; + } + /** + * Returns true when Zend OPcache is loaded, enabled, + * and is configured to discard comments. + */ + public function discardsComments(): bool + { + if (!$this->isOpcacheActive()) { + return \false; + } + if (ini_get('opcache.save_comments') !== '0') { + return \false; + } + return \true; + } + /** + * Returns true when Zend OPcache is loaded, enabled, + * and is configured to perform just-in-time compilation. + */ + public function performsJustInTimeCompilation(): bool + { + if (!$this->isOpcacheActive()) { + return \false; + } + if (ini_get('opcache.jit_buffer_size') === '0') { + return \false; + } + $jit = (string) ini_get('opcache.jit'); + if ($jit === 'disable' || $jit === 'off') { + return \false; + } + if (strrpos($jit, '0') === 3) { + return \false; + } + return \true; + } + /** + * Returns the raw path to the binary of the current runtime. + * + * @deprecated + */ + public function getRawBinary(): string + { + return PHP_BINARY; + } + /** + * Returns the escaped path to the binary of the current runtime. + * + * @deprecated + */ + public function getBinary(): string + { + return escapeshellarg(PHP_BINARY); + } + public function getNameWithVersion(): string + { + return $this->getName() . ' ' . $this->getVersion(); + } + public function getNameWithVersionAndCodeCoverageDriver(): string + { + if ($this->hasPCOV()) { + $version = phpversion('pcov'); + assert($version !== \false); + return sprintf('%s with PCOV %s', $this->getNameWithVersion(), $version); + } + if ($this->hasXdebug()) { + $version = phpversion('xdebug'); + assert($version !== \false); + return sprintf('%s with Xdebug %s', $this->getNameWithVersion(), $version); + } + return $this->getNameWithVersion(); + } + public function getName(): string + { + if ($this->isPHPDBG()) { + // @codeCoverageIgnoreStart + return 'PHPDBG'; + // @codeCoverageIgnoreEnd + } + return 'PHP'; + } + public function getVendorUrl(): string + { + return 'https://www.php.net/'; + } + public function getVersion(): string + { + return PHP_VERSION; + } + /** + * Returns true when the runtime used is PHP and Xdebug is loaded. + */ + public function hasXdebug(): bool + { + return $this->isPHP() && extension_loaded('xdebug'); + } + /** + * Returns true when the runtime used is PHP without the PHPDBG SAPI. + */ + public function isPHP(): bool + { + return !$this->isPHPDBG(); + } + /** + * Returns true when the runtime used is PHP with the PHPDBG SAPI. + */ + public function isPHPDBG(): bool + { + return PHP_SAPI === 'phpdbg'; + } + /** + * Returns true when the runtime used is PHP with the PHPDBG SAPI + * and the phpdbg_*_oplog() functions are available (PHP >= 7.0). + */ + public function hasPHPDBGCodeCoverage(): bool + { + return $this->isPHPDBG(); + } + /** + * Returns true when the runtime used is PHP with PCOV loaded and enabled. + */ + public function hasPCOV(): bool + { + return $this->isPHP() && extension_loaded('pcov') && ini_get('pcov.enabled') === '1'; + } + /** + * Parses the loaded php.ini file (if any) as well as all + * additional php.ini files from the additional ini dir into a + * single merged map of settings, and also obtains the compiled-in + * defaults by spawning a `php -n` child once per process. + * Then checks for each setting passed via the `$values` parameter + * whether the runtime value (`ini_get()`) differs from what the + * ini files specified or, when a setting is not configured in any + * ini file, from the compiled-in default. Returns an array of + * `key=value` strings for the changed settings. + * + * A setting whose runtime value is the empty string but that is + * absent from both the ini files and the compiled-in defaults is + * left alone: there is no evidence that it was overridden, so it + * is not forwarded. This avoids spurious empty overrides for + * settings of extensions that are not visible to the compiled-in + * defaults probe (e.g. extensions loaded only via php.ini), which + * would otherwise break child processes (see + * https://github.com/sebastianbergmann/environment/issues/99). + * + * @param list $values + * + * @return array + */ + public function getCurrentSettings(array $values): array + { + $iniFileValues = $this->parseLoadedIniFiles(); + $compiledDefaults = self::compiledDefaults(); + $diff = []; + foreach ($values as $value) { + $set = ini_get($value); + if ($set === \false) { + continue; + } + if (isset($iniFileValues[$value]) && $iniFileValues[$value] === $set) { + continue; + } + if (!isset($iniFileValues[$value]) && ($compiledDefaults[$value] ?? null) === $set) { + continue; + } + if ($set === '' && !isset($iniFileValues[$value]) && !array_key_exists($value, $compiledDefaults)) { + continue; + } + $diff[$value] = sprintf('%s=%s', $value, $set); + } + return $diff; + } + /** + * Returns INI settings that cannot be changed via ini_set() + * (PHP_INI_SYSTEM and PHP_INI_PERDIR) and whose current value + * differs from the value configured in INI files. + * + * These settings can only have been changed via CLI -d flags + * and must be forwarded as -d flags to child processes because + * ini_set() cannot change them at runtime. + * + * @return array + */ + public function getSettingsNotChangeableAtRuntime(): array + { + $allSettings = ini_get_all(null, \true); + assert($allSettings !== \false); + $nonRuntimeSettable = []; + foreach ($allSettings as $key => $info) { + assert(is_array($info)); + assert(isset($info['access'])); + assert(is_int($info['access'])); + /** + * Only consider settings that cannot be changed via ini_set(). + * + * PHP_INI_USER = 1 + * PHP_INI_PERDIR = 2 + * PHP_INI_SYSTEM = 4 + * PHP_INI_ALL = 7 + */ + if (($info['access'] & 1) !== 0) { + continue; + } + $nonRuntimeSettable[] = $key; + } + return $this->getCurrentSettings($nonRuntimeSettable); + } + public function isOpcacheActive(): bool + { + if (!extension_loaded('Zend OPcache')) { + return \false; + } + if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') && ini_get('opcache.enable_cli') === '1') { + return \true; + } + if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg' && ini_get('opcache.enable') === '1') { + return \true; + } + return \false; + } + /** + * @return array + */ + private function parseLoadedIniFiles(): array + { + $files = []; + $file = php_ini_loaded_file(); + if ($file !== \false) { + $files[] = $file; + } + $scanned = php_ini_scanned_files(); + if ($scanned !== \false) { + $files = array_merge($files, array_map('trim', explode(",\n", $scanned))); + } + $merged = []; + foreach ($files as $ini) { + $parsed = parse_ini_file($ini, \false, INI_SCANNER_NORMAL); + if ($parsed === \false) { + continue; + } + foreach ($parsed as $key => $val) { + if (is_string($val)) { + $merged[$key] = $val; + } + } + } + return $merged; + } + /** + * Returns the compiled-in default values of every ini setting by + * spawning a `php -n` child process once and caching the result + * for the lifetime of the PHP process. When the child cannot be + * launched or its output is unusable, an empty array is returned + * and cached so the failure is not retried. + * + * @return array + */ + private static function compiledDefaults(): array + { + if (self::$compiledDefaults !== null) { + return self::$compiledDefaults; + } + self::$compiledDefaults = []; + $process = proc_open([PHP_BINARY, '-n', '-r', 'echo json_encode(ini_get_all(null, true));'], [1 => ['pipe', 'w']], $pipes); + if ($process === \false) { + return self::$compiledDefaults; + } + assert(isset($pipes[1])); + $stdout = stream_get_contents($pipes[1]); + proc_close($process); + if (!is_string($stdout) || $stdout === '') { + return self::$compiledDefaults; + } + $parsed = json_decode($stdout, \true); + if (!is_array($parsed)) { + return self::$compiledDefaults; + } + foreach ($parsed as $key => $info) { + if (!is_string($key)) { + continue; + } + if (!is_array($info)) { + continue; + } + if (!isset($info['global_value']) || !is_string($info['global_value'])) { + continue; + } + self::$compiledDefaults[$key] = $info['global_value']; + } + return self::$compiledDefaults; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Exporter; + +use const COUNT_RECURSIVE; +use function assert; +use function bin2hex; +use function count; +use function get_resource_type; +use function gettype; +use function implode; +use function ini_get; +use function ini_set; +use function is_array; +use function is_bool; +use function is_float; +use function is_infinite; +use function is_nan; +use function is_object; +use function is_resource; +use function is_string; +use function mb_strlen; +use function mb_substr; +use function ord; +use function preg_match; +use function preg_match_all; +use function preg_replace_callback; +use function spl_object_id; +use function sprintf; +use function str_contains; +use function str_repeat; +use function str_replace; +use function strlen; +use function strpbrk; +use function strtr; +use function var_export; +use BackedEnum; +use PHPUnitPHAR\Google\Protobuf\Internal\Message; +use ReflectionClass; +use ReflectionObject; +use PHPUnitPHAR\SebastianBergmann\RecursionContext\Context as RecursionContext; +use SplObjectStorage; +use stdClass; +use UnitEnum; +final readonly class Exporter +{ + /** + * @var non-negative-int + */ + private int $shortenArraysLongerThan; + /** + * @var positive-int + */ + private int $maxLengthForStrings; + /** + * @param non-negative-int $shortenArraysLongerThan + * @param positive-int $maxLengthForStrings + */ + public function __construct(int $shortenArraysLongerThan = 0, int $maxLengthForStrings = 40) + { + $this->shortenArraysLongerThan = $shortenArraysLongerThan; + $this->maxLengthForStrings = $maxLengthForStrings; + } + /** + * Exports a value as a string. + * + * The output of this method is similar to the output of print_r(), but + * improved in various aspects: + * + * - NULL is rendered as "null" (instead of "") + * - TRUE is rendered as "true" (instead of "1") + * - FALSE is rendered as "false" (instead of "") + * - Strings are always quoted with single quotes + * - Carriage returns and newlines are normalized to \n + * - Recursion and repeated rendering is treated properly + */ + public function export(mixed $value, int $indentation = 0): string + { + return $this->recursiveExport($value, $indentation); + } + /** + * @param array $data + * @param positive-int $maxLengthForStrings + */ + public function shortenedRecursiveExport(array &$data, int $maxLengthForStrings = 40, ?RecursionContext $processed = null): string + { + if ($maxLengthForStrings === 40) { + $maxLengthForStrings = $this->maxLengthForStrings; + } + if ($processed === null) { + $processed = new RecursionContext(); + } + $overallCount = @count($data, COUNT_RECURSIVE); + $counter = 0; + $export = $this->shortenedCountedRecursiveExport($data, $processed, $counter, $maxLengthForStrings); + if ($this->shortenArraysLongerThan > 0 && $overallCount > $this->shortenArraysLongerThan) { + $export .= sprintf(', ...%d more elements', $overallCount - $this->shortenArraysLongerThan); + } + return $export; + } + /** + * Exports a value into a single-line string. + * + * The output of this method is similar to the output of + * SebastianBergmann\Exporter\Exporter::export(). + * + * Newlines are replaced by the visible string '\n'. + * Contents of arrays and objects (if any) are replaced by '...'. + * + * @param positive-int $maxLengthForStrings + */ + public function shortenedExport(mixed $value, int $maxLengthForStrings = 40): string + { + if ($maxLengthForStrings === 40) { + $maxLengthForStrings = $this->maxLengthForStrings; + } + if (is_string($value)) { + $string = str_replace("\n", '', $this->exportString($value)); + if (mb_strlen($string) > $maxLengthForStrings) { + return mb_substr($string, 0, $maxLengthForStrings - 10) . '...' . mb_substr($string, -7); + } + return $string; + } + if ($value instanceof BackedEnum) { + return sprintf('%s Enum (%s, %s)', $value::class, $value->name, $this->export($value->value)); + } + if ($value instanceof UnitEnum) { + return sprintf('%s Enum (%s)', $value::class, $value->name); + } + if (is_object($value)) { + return sprintf('%s Object (%s)', $value::class, $this->countProperties($value) > 0 ? '...' : ''); + } + if (is_array($value)) { + return sprintf('[%s]', count($value) > 0 ? '...' : ''); + } + return $this->export($value); + } + /** + * Converts an object to an array containing all of its private, protected + * and public properties. + * + * @return array + */ + public function toArray(mixed $value): array + { + if (!is_object($value)) { + return (array) $value; + } + $properties = (array) $value; + $shadowed = $this->shadowedPropertyNames($properties); + $array = []; + foreach ($properties as $key => $val) { + $key = (string) $key; + // Exception traces commonly reference hundreds to thousands of + // objects currently loaded in memory. Including them in the result + // has a severe negative performance impact. + if ($key === "\x00Error\x00trace" || $key === "\x00Exception\x00trace") { + continue; + } + // See https://github.com/php/php-src/commit/5721132 + if ($key === "\x00gcdata") { + continue; + } + // Properties are transformed to keys in the following way: + // private $propertyName => "\0DeclaringClassName\0propertyName" + // protected $propertyName => "\0*\0propertyName" + // public $propertyName => "propertyName" + // + // A private property that is redeclared in a derived class and the + // private property of the same name that it shadows both exist, + // independently of each other. To keep one from overwriting the + // other, the name of a shadowed private property is prefixed with + // the name of the class that declares it. + if (preg_match('/^\0([^\0]+)\0([^\0]+)$/', $key, $matches) === 1) { + if ($matches[1] !== '*' && isset($shadowed[$matches[2]])) { + $key = $matches[1] . '::' . $matches[2]; + } else { + $key = $matches[2]; + } + } + $array[$key] = $val; + } + // Some internal classes like SplObjectStorage do not work with the + // above (fast) mechanism nor with reflection in Zend. + // Format the output similarly to print_r() in this case + if ($value instanceof SplObjectStorage) { + $key = null; + if ($value->valid()) { + $key = $value->key(); + } + foreach ($value as $_value) { + $array['Object #' . spl_object_id($_value)] = ['obj' => $_value, 'inf' => $value->getInfo()]; + } + if ($key !== null) { + $value->seek($key); + } + } + return $array; + } + public function countProperties(object $value): int + { + if (!$this->canBeReflected($value)) { + // @codeCoverageIgnoreStart + return count($this->toArray($value)); + // @codeCoverageIgnoreEnd + } + if (!$value instanceof stdClass) { + // using ReflectionClass prevents initialization of potential lazy objects + return count((new ReflectionClass($value))->getProperties()); + } + return count((new ReflectionObject($value))->getProperties()); + } + /** + * Returns, as keys of the returned array, the names of properties that + * are declared more than once in the inheritance chain of an object. + * + * This can only happen when a derived class redeclares a private property + * that one of its parent classes also declares. + * + * @param array $properties + * + * @return array + */ + private function shadowedPropertyNames(array $properties): array + { + $seen = []; + $shadowed = []; + foreach ($properties as $key => $unused) { + $key = (string) $key; + if ($key === "\x00Error\x00trace" || $key === "\x00Exception\x00trace" || $key === "\x00gcdata") { + continue; + } + if (preg_match('/^\0[^\0]+\0([^\0]+)$/', $key, $matches) === 1) { + $key = $matches[1]; + } + if (isset($seen[$key])) { + $shadowed[$key] = \true; + } + $seen[$key] = \true; + } + return $shadowed; + } + /** + * @param array $data + * @param positive-int $maxLengthForStrings + */ + private function shortenedCountedRecursiveExport(array &$data, RecursionContext $processed, int &$counter, int $maxLengthForStrings): string + { + $result = []; + $array = $data; + /* @noinspection UnusedFunctionResultInspection */ + $processed->add($data); + foreach ($array as $key => $value) { + if ($this->shortenArraysLongerThan > 0 && $counter > $this->shortenArraysLongerThan) { + break; + } + if (is_array($value)) { + assert(isset($data[$key]) && (is_array($data[$key]) || is_object($data[$key]))); + if ($processed->contains($data[$key]) !== \false) { + $result[] = '*RECURSION*'; + } else { + assert(is_array($data[$key])); + $result[] = '[' . $this->shortenedCountedRecursiveExport($data[$key], $processed, $counter, $maxLengthForStrings) . ']'; + } + } else { + $result[] = $this->shortenedExport($value, $maxLengthForStrings); + } + $counter++; + } + return implode(', ', $result); + } + private function recursiveExport(mixed &$value, int $indentation = 0, ?RecursionContext $processed = null): string + { + if ($value === null) { + return 'null'; + } + if (is_bool($value)) { + return $value ? 'true' : 'false'; + } + if (is_float($value)) { + return $this->exportFloat($value); + } + if (gettype($value) === 'resource (closed)') { + return 'resource (closed)'; + } + if (is_resource($value)) { + return sprintf( + 'resource(%d) of type (%s)', + /** @phpstan-ignore cast.useless */ + (int) $value, + get_resource_type($value) + ); + } + if ($value instanceof BackedEnum) { + return sprintf('%s Enum #%d (%s, %s)', $value::class, spl_object_id($value), $value->name, $this->export($value->value)); + } + if ($value instanceof UnitEnum) { + return sprintf('%s Enum #%d (%s)', $value::class, spl_object_id($value), $value->name); + } + if (is_string($value)) { + return $this->exportString($value); + } + if ($processed === null) { + $processed = new RecursionContext(); + } + if (is_array($value)) { + return $this->exportArray($value, $processed, $indentation); + } + if (is_object($value)) { + return $this->exportObject($value, $processed, $indentation); + } + return var_export($value, \true); + } + private function exportFloat(float $value): string + { + if (is_nan($value)) { + return 'NAN'; + } + if (is_infinite($value)) { + return $value > 0 ? 'INF' : '-INF'; + } + $precisionBackup = ini_get('precision'); + ini_set('precision', '-1'); + $valueAsString = (string) $value; + ini_set('precision', $precisionBackup); + // Add '.0' only if decimals and scientific notation are absent. + if (strpbrk($valueAsString, '.E') === \false) { + return $valueAsString . '.0'; + } + return $valueAsString; + } + private function exportString(string $value): string + { + // Match for most non-printable chars somewhat taking multibyte chars into account + $unprintableCount = preg_match_all('/[^\x09-\x0d\x1b\x20-\xff]/', $value); + if ($unprintableCount === \false || $unprintableCount === 0) { + return "'" . strtr($value, ["\r\n" => '\r\n' . "\n", "\n\r" => '\n\r' . "\n", "\r" => '\r' . "\n", "\n" => '\n' . "\n"]) . "'"; + } + // A NUL byte or a high ratio of unprintable bytes signals truly + // binary data; keep the compact hex dump in those cases. + if (str_contains($value, "\x00") || $unprintableCount / strlen($value) > 0.3) { + return 'Binary String: 0x' . bin2hex($value); + } + // Mostly printable: keep printable bytes visible and escape only + // the offending ones inline using PHP-style \xNN escapes. + return 'Binary String: "' . preg_replace_callback('/[\x00-\x1f\x7f"\\\\]/', static fn(array $m): string => match ($m[0]) { + "\t" => '\t', + "\n" => '\n', + "\r" => '\r', + '"' => '\"', + '\\' => '\\\\', + default => sprintf('\x%02x', ord($m[0])), + }, $value) . '"'; + } + /** + * @param array $value + */ + private function exportArray(array &$value, RecursionContext $processed, int $indentation): string + { + if (($key = $processed->contains($value)) !== \false) { + return 'Array &' . $key; + } + $array = $value; + $key = $processed->add($value); + $values = ''; + if (count($array) > 0) { + $whitespace = str_repeat(' ', 4 * $indentation); + foreach ($array as $k => $v) { + $values .= $whitespace . ' ' . $this->recursiveExport($k, $indentation) . ' => ' . $this->recursiveExport($value[$k], $indentation + 1, $processed) . ",\n"; + } + $values = "\n" . $values . $whitespace; + } + return 'Array &' . (string) $key . ' [' . $values . ']'; + } + private function exportObject(object $value, RecursionContext $processed, int $indentation): string + { + $class = $value::class; + if ($processed->contains($value) !== \false) { + return $class . ' Object #' . spl_object_id($value); + } + $processed->add($value); + $array = $this->toArray($value); + $buffer = ''; + if (count($array) > 0) { + $whitespace = str_repeat(' ', 4 * $indentation); + foreach ($array as $k => $v) { + $buffer .= $whitespace . ' ' . $this->recursiveExport($k, $indentation) . ' => ' . $this->recursiveExport($v, $indentation + 1, $processed) . ",\n"; + } + $buffer = "\n" . $buffer . $whitespace; + } + return $class . ' Object #' . spl_object_id($value) . ' (' . $buffer . ')'; + } + private function canBeReflected(object $object): bool + { + /** @phpstan-ignore class.notFound */ + if ($object instanceof Message) { + // @codeCoverageIgnoreStart + return \false; + // @codeCoverageIgnoreEnd + } + return \true; + } +} +BSD 3-Clause License + +Copyright (c) 2002-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\GitState; + +use function assert; +use function explode; +use function preg_split; +use function str_contains; +use function str_replace; +use function str_starts_with; +use function trim; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/git-state + */ +final readonly class Builder +{ + private GitCommandRunner $runner; + public function __construct(?GitCommandRunner $runner = null) + { + if ($runner === null) { + $runner = new GitCommandRunner(new ShellCommandRunnerImplementation()); + } + $this->runner = $runner; + } + public function build(): false|State + { + $buffer = $this->runner->run('remote show -n'); + if ($buffer === \false) { + return \false; + } + if (!str_contains($buffer, 'origin')) { + return \false; + } + $buffer = $this->runner->run('remote show -n origin'); + if ($buffer === \false) { + return \false; + } + $lines = preg_split("/\r\n|\n|\r/", $buffer); + if (!isset($lines[1]) || !str_starts_with($lines[1], ' Fetch URL: ')) { + return \false; + } + $originUrl = trim(str_replace(' Fetch URL: ', '', $lines[1])); + if (str_contains($originUrl, '@')) { + $tmp = explode('@', $originUrl); + assert(isset($tmp[1])); + $originUrl = $tmp[1]; + } + assert($originUrl !== ''); + $branch = $this->runner->run('rev-parse --abbrev-ref HEAD'); + if ($branch === \false) { + return \false; + } + assert($branch !== ''); + $commit = $this->runner->run('rev-parse HEAD'); + if ($commit === \false) { + return \false; + } + assert($commit !== ''); + $status = $this->runner->run('status --porcelain'); + if ($status === \false) { + return \false; + } + return new State($originUrl, $branch, $commit, $status === '', $status); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\GitState; + +use const DIRECTORY_SEPARATOR; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/git-state + * + * @internal This class is not covered by the backward compatibility promise for sebastian/git-state + */ +final readonly class GitCommandRunner +{ + private ShellCommandRunner $runner; + public function __construct(?ShellCommandRunner $runner = null) + { + if ($runner === null) { + // @codeCoverageIgnoreStart + $runner = new ShellCommandRunnerImplementation(); + // @codeCoverageIgnoreEnd + } + $this->runner = $runner; + } + /** + * @param non-empty-string $command + */ + public function run(string $command): false|string + { + $command = 'git ' . $command; + if (DIRECTORY_SEPARATOR === '/') { + $command = 'LC_ALL=en_US.UTF-8 ' . $command; + } + return $this->runner->run($command); + } +} +BSD 3-Clause License + +Copyright (c) 2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\GitState; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/git-state + * + * @internal This class is not covered by the backward compatibility promise for sebastian/git-state + */ +interface ShellCommandRunner +{ + /** + * @param non-empty-string $command + */ + public function run(string $command): false|string; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\GitState; + +use function assert; +use function fclose; +use function is_resource; +use function proc_close; +use function proc_open; +use function stream_get_contents; +use function trim; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/git-state + * + * @internal This class is not covered by the backward compatibility promise for sebastian/git-state + */ +final readonly class ShellCommandRunnerImplementation implements ShellCommandRunner +{ + /** + * @param non-empty-string $command + */ + public function run(string $command): false|string + { + $process = @proc_open($command, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes); + if (!is_resource($process)) { + // @codeCoverageIgnoreStart + return \false; + // @codeCoverageIgnoreEnd + } + assert(isset($pipes[1]) && is_resource($pipes[1])); + assert(isset($pipes[2]) && is_resource($pipes[2])); + $result = trim((string) stream_get_contents($pipes[1])); + fclose($pipes[1]); + fclose($pipes[2]); + $returnCode = proc_close($process); + if ($returnCode !== 0) { + return \false; + } + return $result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\GitState; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for sebastian/git-state + */ +final readonly class State +{ + /** + * @var non-empty-string + */ + private string $originUrl; + /** + * @var non-empty-string + */ + private string $branch; + /** + * @var non-empty-string + */ + private string $commit; + private bool $clean; + private string $status; + /** + * @param non-empty-string $originUrl + * @param non-empty-string $branch + * @param non-empty-string $commit + */ + public function __construct(string $originUrl, string $branch, string $commit, bool $clean, string $status) + { + $this->originUrl = $originUrl; + $this->branch = $branch; + $this->commit = $commit; + $this->clean = $clean; + $this->status = $status; + } + /** + * @return non-empty-string + */ + public function originUrl(): string + { + return $this->originUrl; + } + /** + * @return non-empty-string + */ + public function branch(): string + { + return $this->branch; + } + /** + * @return non-empty-string + */ + public function commit(): string + { + return $this->commit; + } + public function isClean(): bool + { + return $this->clean; + } + public function status(): string + { + return $this->status; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\GlobalState; + +use const PHP_EOL; +use function is_array; +use function is_scalar; +use function serialize; +use function sprintf; +use function var_export; +final class CodeExporter +{ + public function constants(Snapshot $snapshot): string + { + $result = ''; + foreach ($snapshot->constants() as $name => $value) { + $result .= sprintf('if (!defined(\'%s\')) define(\'%s\', %s);' . "\n", $name, $name, $this->exportVariable($value)); + } + return $result; + } + public function globalVariables(Snapshot $snapshot): string + { + $result = <<<'EOT' +call_user_func( + function () + { + foreach (array_keys($GLOBALS) as $key) { + unset($GLOBALS[$key]); + } + } +); + + +EOT; + foreach ($snapshot->globalVariables() as $name => $value) { + $result .= sprintf('$GLOBALS[%s] = %s;' . PHP_EOL, $this->exportVariable($name), $this->exportVariable($value)); + } + return $result; + } + public function iniSettings(Snapshot $snapshot): string + { + $result = ''; + foreach ($snapshot->iniSettings() as $key => $value) { + $result .= sprintf('@ini_set(%s, %s);' . "\n", $this->exportVariable($key), $this->exportVariable($value)); + } + return $result; + } + private function exportVariable(mixed $variable): string + { + if (is_scalar($variable) || null === $variable || is_array($variable) && $this->arrayOnlyContainsScalars($variable)) { + return var_export($variable, \true); + } + return 'unserialize(' . var_export(serialize($variable), \true) . ')'; + } + /** + * @param array $array + */ + private function arrayOnlyContainsScalars(array $array): bool + { + $result = \true; + foreach ($array as $element) { + if (is_array($element)) { + $result = $this->arrayOnlyContainsScalars($element); + } elseif (!is_scalar($element) && null !== $element) { + $result = \false; + } + if ($result === \false) { + break; + } + } + return $result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\GlobalState; + +use function in_array; +use function str_starts_with; +use ReflectionClass; +final class ExcludeList +{ + /** + * @var array + */ + private array $globalVariables = []; + /** + * @var list + */ + private array $classes = []; + /** + * @var list + */ + private array $classNamePrefixes = []; + /** + * @var list + */ + private array $parentClasses = []; + /** + * @var list + */ + private array $interfaces = []; + /** + * @var array> + */ + private array $staticProperties = []; + /** + * @param non-empty-string $variableName + */ + public function addGlobalVariable(string $variableName): void + { + $this->globalVariables[$variableName] = \true; + } + /** + * @param non-empty-string $className + */ + public function addClass(string $className): void + { + $this->classes[] = $className; + } + /** + * @param non-empty-string $className + */ + public function addSubclassesOf(string $className): void + { + $this->parentClasses[] = $className; + } + /** + * @param non-empty-string $interfaceName + */ + public function addImplementorsOf(string $interfaceName): void + { + $this->interfaces[] = $interfaceName; + } + /** + * @param non-empty-string $classNamePrefix + */ + public function addClassNamePrefix(string $classNamePrefix): void + { + $this->classNamePrefixes[] = $classNamePrefix; + } + /** + * @param non-empty-string $className + * @param non-empty-string $propertyName + */ + public function addStaticProperty(string $className, string $propertyName): void + { + if (!isset($this->staticProperties[$className])) { + $this->staticProperties[$className] = []; + } + $this->staticProperties[$className][$propertyName] = \true; + } + public function isGlobalVariableExcluded(string $variableName): bool + { + return isset($this->globalVariables[$variableName]); + } + /** + * @param class-string $className + * @param non-empty-string $propertyName + */ + public function isStaticPropertyExcluded(string $className, string $propertyName): bool + { + if (in_array($className, $this->classes, \true)) { + return \true; + } + foreach ($this->classNamePrefixes as $prefix) { + if (str_starts_with($className, $prefix)) { + return \true; + } + } + $class = new ReflectionClass($className); + foreach ($this->parentClasses as $type) { + if ($class->isSubclassOf($type)) { + return \true; + } + } + foreach ($this->interfaces as $type) { + if ($class->implementsInterface($type)) { + return \true; + } + } + return isset($this->staticProperties[$className][$propertyName]); + } +} +BSD 3-Clause License + +Copyright (c) 2001-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\GlobalState; + +use function array_diff; +use function array_key_exists; +use function array_keys; +use function array_merge; +use function assert; +use function class_exists; +use function in_array; +use function is_array; +use function property_exists; +use ReflectionClass; +use ReflectionProperty; +final class Restorer +{ + public function restoreGlobalVariables(Snapshot $snapshot): void + { + $superGlobalArrays = $snapshot->superGlobalArrays(); + foreach ($superGlobalArrays as $superGlobalArray) { + $this->restoreSuperGlobalArray($snapshot, $superGlobalArray); + } + $globalVariables = $snapshot->globalVariables(); + foreach (array_keys($GLOBALS) as $key) { + if ($key !== 'GLOBALS' && !in_array($key, $superGlobalArrays, \true) && !$snapshot->excludeList()->isGlobalVariableExcluded((string) $key)) { + if (array_key_exists($key, $globalVariables)) { + $GLOBALS[$key] = $globalVariables[$key]; + } else { + unset($GLOBALS[$key]); + } + } + } + } + public function restoreStaticProperties(Snapshot $snapshot): void + { + $current = new Snapshot($snapshot->excludeList(), \false, \false, \false, \false, \true, \false, \false, \false, \false); + $newClasses = array_diff($current->classes(), $snapshot->classes()); + unset($current); + foreach ($snapshot->staticProperties() as $className => $staticProperties) { + foreach ($staticProperties as $name => $value) { + assert(class_exists($className)); + assert(property_exists($className, $name)); + $reflector = new ReflectionProperty($className, $name); + $reflector->setValue(null, $value); + } + } + foreach ($newClasses as $className) { + $class = new ReflectionClass($className); + $defaults = $class->getDefaultProperties(); + foreach ($class->getProperties() as $property) { + if (!$property->isStatic()) { + continue; + } + $name = $property->getName(); + if ($snapshot->excludeList()->isStaticPropertyExcluded($className, $name)) { + continue; + } + if (!isset($defaults[$name])) { + continue; + } + $property->setValue(null, $defaults[$name]); + } + } + } + private function restoreSuperGlobalArray(Snapshot $snapshot, string $superGlobalArray): void + { + $superGlobalVariables = $snapshot->superGlobalVariables(); + if (isset($GLOBALS[$superGlobalArray], $superGlobalVariables[$superGlobalArray]) && is_array($GLOBALS[$superGlobalArray])) { + $keys = array_keys(array_merge($GLOBALS[$superGlobalArray], $superGlobalVariables[$superGlobalArray])); + foreach ($keys as $key) { + assert(isset($GLOBALS[$superGlobalArray]) && is_array($GLOBALS[$superGlobalArray])); + if (array_key_exists($key, $superGlobalVariables[$superGlobalArray])) { + $GLOBALS[$superGlobalArray][$key] = $superGlobalVariables[$superGlobalArray][$key]; + } else { + unset($GLOBALS[$superGlobalArray][$key]); + } + } + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\GlobalState; + +use function array_keys; +use function array_merge; +use function array_reverse; +use function assert; +use function get_declared_classes; +use function get_declared_interfaces; +use function get_declared_traits; +use function get_defined_constants; +use function get_defined_functions; +use function get_included_files; +use function in_array; +use function ini_get_all; +use function is_array; +use function is_object; +use function is_resource; +use function is_scalar; +use function serialize; +use function unserialize; +use ReflectionClass; +use PHPUnitPHAR\SebastianBergmann\ObjectReflector\ObjectReflector; +use PHPUnitPHAR\SebastianBergmann\RecursionContext\Context; +use Throwable; +/** + * A snapshot of global state. + */ +final class Snapshot +{ + private ExcludeList $excludeList; + /** + * @var array + */ + private array $globalVariables = []; + /** + * @var list + */ + private array $superGlobalArrays = []; + /** + * @var array> + */ + private array $superGlobalVariables = []; + /** + * @var array> + */ + private array $staticProperties = []; + /** + * @var array + */ + private array $iniSettings = []; + /** + * @var list + */ + private array $includedFiles = []; + /** + * @var array + */ + private array $constants = []; + /** + * @var list + */ + private array $functions = []; + /** + * @var list + */ + private array $interfaces = []; + /** + * @var list + */ + private array $classes = []; + /** + * @var list + */ + private array $traits = []; + public function __construct(?ExcludeList $excludeList = null, bool $includeGlobalVariables = \true, bool $includeStaticProperties = \true, bool $includeConstants = \true, bool $includeFunctions = \true, bool $includeClasses = \true, bool $includeInterfaces = \true, bool $includeTraits = \true, bool $includeIniSettings = \true, bool $includeIncludedFiles = \true) + { + if ($excludeList === null) { + $excludeList = new ExcludeList(); + } + $this->excludeList = $excludeList; + if ($includeConstants) { + $this->snapshotConstants(); + } + if ($includeFunctions) { + $this->snapshotFunctions(); + } + if ($includeClasses || $includeStaticProperties) { + $this->snapshotClasses(); + } + if ($includeInterfaces) { + $this->snapshotInterfaces(); + } + if ($includeGlobalVariables) { + $this->setupSuperGlobalArrays(); + $this->snapshotGlobals(); + } + if ($includeStaticProperties) { + $this->snapshotStaticProperties(); + } + if ($includeIniSettings) { + $iniSettings = ini_get_all(null, \false); + assert($iniSettings !== \false); + /* @phpstan-ignore assign.propertyType */ + $this->iniSettings = $iniSettings; + } + if ($includeIncludedFiles) { + $this->includedFiles = get_included_files(); + } + if ($includeTraits) { + $this->traits = get_declared_traits(); + } + } + public function excludeList(): ExcludeList + { + return $this->excludeList; + } + /** + * @return array + */ + public function globalVariables(): array + { + return $this->globalVariables; + } + /** + * @return array> + */ + public function superGlobalVariables(): array + { + return $this->superGlobalVariables; + } + /** + * @return list + */ + public function superGlobalArrays(): array + { + return $this->superGlobalArrays; + } + /** + * @return array> + */ + public function staticProperties(): array + { + return $this->staticProperties; + } + /** + * @return array + */ + public function iniSettings(): array + { + return $this->iniSettings; + } + /** + * @return list + */ + public function includedFiles(): array + { + return $this->includedFiles; + } + /** + * @return array + */ + public function constants(): array + { + return $this->constants; + } + /** + * @return list + */ + public function functions(): array + { + return $this->functions; + } + /** + * @return list + */ + public function interfaces(): array + { + return $this->interfaces; + } + /** + * @return list + */ + public function classes(): array + { + return $this->classes; + } + /** + * @return list + */ + public function traits(): array + { + return $this->traits; + } + private function snapshotConstants(): void + { + $constants = get_defined_constants(\true); + if (isset($constants['user'])) { + $this->constants = $constants['user']; + } + } + private function snapshotFunctions(): void + { + $functions = get_defined_functions(); + $this->functions = $functions['user']; + } + private function snapshotClasses(): void + { + foreach (array_reverse(get_declared_classes()) as $className) { + $class = new ReflectionClass($className); + if (!$class->isUserDefined()) { + break; + } + $this->classes[] = $className; + } + $this->classes = array_reverse($this->classes); + } + private function snapshotInterfaces(): void + { + foreach (array_reverse(get_declared_interfaces()) as $interfaceName) { + $class = new ReflectionClass($interfaceName); + if (!$class->isUserDefined()) { + break; + } + $this->interfaces[] = $interfaceName; + } + $this->interfaces = array_reverse($this->interfaces); + } + private function snapshotGlobals(): void + { + $superGlobalArrays = $this->superGlobalArrays(); + foreach ($superGlobalArrays as $superGlobalArray) { + $this->snapshotSuperGlobalArray($superGlobalArray); + } + foreach (array_keys($GLOBALS) as $key) { + if ($key !== 'GLOBALS' && !in_array($key, $superGlobalArrays, \true) && !$this->excludeList->isGlobalVariableExcluded($key) && $this->canBeSerialized($GLOBALS[$key])) { + /* @phpstan-ignore assign.propertyType */ + $this->globalVariables[$key] = $this->copyWithSerialize($GLOBALS[$key]); + } + } + } + private function snapshotSuperGlobalArray(string $superGlobalArray): void + { + $this->superGlobalVariables[$superGlobalArray] = []; + if (isset($GLOBALS[$superGlobalArray]) && is_array($GLOBALS[$superGlobalArray])) { + foreach ($GLOBALS[$superGlobalArray] as $key => $value) { + /* @phpstan-ignore assign.propertyType */ + $this->superGlobalVariables[$superGlobalArray][$key] = $this->copyWithSerialize($value); + } + } + } + private function snapshotStaticProperties(): void + { + foreach ($this->classes as $className) { + $class = new ReflectionClass($className); + $snapshot = []; + foreach ($class->getProperties() as $property) { + if ($property->isStatic()) { + $name = $property->getName(); + if ($this->excludeList->isStaticPropertyExcluded($className, $name)) { + continue; + } + if (!$property->isInitialized()) { + continue; + } + $value = $property->getValue(); + if ($this->canBeSerialized($value)) { + $snapshot[$name] = $this->copyWithSerialize($value); + } + } + } + if ($snapshot !== []) { + $this->staticProperties[$className] = $snapshot; + } + } + } + private function setupSuperGlobalArrays(): void + { + $this->superGlobalArrays = ['_ENV', '_POST', '_GET', '_COOKIE', '_SERVER', '_FILES', '_REQUEST']; + } + private function copyWithSerialize(mixed $variable): mixed + { + if (is_scalar($variable) || $variable === null) { + return $variable; + } + /* @noinspection UnserializeExploitsInspection */ + return unserialize(serialize($variable)); + } + private function canBeSerialized(mixed $variable): bool + { + if (is_scalar($variable) || $variable === null) { + return \true; + } + if (is_resource($variable)) { + return \false; + } + foreach ($this->enumerateObjectsAndResources($variable) as $value) { + if (is_resource($value)) { + return \false; + } + if (is_object($value)) { + $class = new ReflectionClass($value); + if ($class->isAnonymous()) { + return \false; + } + try { + @serialize($value); + } catch (Throwable $t) { + return \false; + } + } + } + return \true; + } + /** + * @return array + */ + private function enumerateObjectsAndResources(mixed $variable, Context $processed = new Context()): array + { + $result = []; + /* @phpstan-ignore argument.type */ + if ($processed->contains($variable) !== \false) { + return $result; + } + $array = $variable; + /* @noinspection UnusedFunctionResultInspection */ + $processed->add($variable); + if (is_array($variable)) { + /** @phpstan-ignore foreach.nonIterable */ + foreach ($array as $element) { + if (!is_array($element) && !is_object($element) && !is_resource($element)) { + continue; + } + if (!is_resource($element)) { + /** @noinspection SlowArrayOperationsInLoopInspection */ + $result = array_merge($result, $this->enumerateObjectsAndResources($element, $processed)); + } else { + $result[] = $element; + } + } + } else { + $result[] = $variable; + foreach ((new ObjectReflector())->getProperties($variable) as $value) { + if (!is_array($value) && !is_object($value) && !is_resource($value)) { + continue; + } + if (!is_resource($value)) { + /** @noinspection SlowArrayOperationsInLoopInspection */ + $result = array_merge($result, $this->enumerateObjectsAndResources($value, $processed)); + } else { + $result[] = $value; + } + } + } + return $result; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\GlobalState; + +use Throwable; +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\GlobalState; + +final class RuntimeException extends \RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\LinesOfCode; + +use function assert; +use function file_get_contents; +use function substr_count; +use PHPUnitPHAR\PhpParser\Error; +use PHPUnitPHAR\PhpParser\Node; +use PHPUnitPHAR\PhpParser\NodeTraverser; +use PHPUnitPHAR\PhpParser\ParserFactory; +final class Counter +{ + /** + * @throws RuntimeException + */ + public function countInSourceFile(string $sourceFile): LinesOfCode + { + $source = file_get_contents($sourceFile); + assert($source !== \false); + return $this->countInSourceString($source); + } + /** + * @throws RuntimeException + */ + public function countInSourceString(string $source): LinesOfCode + { + $linesOfCode = substr_count($source, "\n"); + if ($linesOfCode === 0 && $source !== '') { + $linesOfCode = 1; + } + try { + $nodes = (new ParserFactory())->createForHostVersion()->parse($source); + assert($nodes !== null); + return $this->countInAbstractSyntaxTree($linesOfCode, $nodes); + // @codeCoverageIgnoreStart + } catch (Error $error) { + throw new RuntimeException($error->getMessage(), $error->getCode(), $error); + } + // @codeCoverageIgnoreEnd + } + /** + * @param non-negative-int $linesOfCode + * @param Node[] $nodes + * + * @throws RuntimeException + */ + public function countInAbstractSyntaxTree(int $linesOfCode, array $nodes): LinesOfCode + { + $traverser = new NodeTraverser(); + $visitor = new LineCountingVisitor($linesOfCode); + $traverser->addVisitor($visitor); + try { + /* @noinspection UnusedFunctionResultInspection */ + $traverser->traverse($nodes); + // @codeCoverageIgnoreStart + } catch (Error $error) { + throw new RuntimeException($error->getMessage(), $error->getCode(), $error); + } + // @codeCoverageIgnoreEnd + return $visitor->result(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\LinesOfCode; + +use Throwable; +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\LinesOfCode; + +use LogicException; +final class IllogicalValuesException extends LogicException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\LinesOfCode; + +final class RuntimeException extends \RuntimeException implements Exception +{ +} +BSD 3-Clause License + +Copyright (c) 2020-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\LinesOfCode; + +use function array_merge; +use function array_unique; +use function assert; +use function count; +use PHPUnitPHAR\PhpParser\Comment; +use PHPUnitPHAR\PhpParser\Node; +use PHPUnitPHAR\PhpParser\Node\Expr; +use PHPUnitPHAR\PhpParser\NodeVisitorAbstract; +final class LineCountingVisitor extends NodeVisitorAbstract +{ + /** + * @var non-negative-int + */ + private readonly int $linesOfCode; + /** + * @var Comment[] + */ + private array $comments = []; + /** + * @var int[] + */ + private array $linesWithStatements = []; + /** + * @param non-negative-int $linesOfCode + */ + public function __construct(int $linesOfCode) + { + $this->linesOfCode = $linesOfCode; + } + public function enterNode(Node $node): null + { + $this->comments = array_merge($this->comments, $node->getComments()); + if (!$node instanceof Expr) { + return null; + } + $this->linesWithStatements[] = $node->getStartLine(); + return null; + } + public function result(): LinesOfCode + { + $commentLines = []; + foreach ($this->comments() as $comment) { + for ($line = $comment->getStartLine(); $line <= $comment->getEndLine(); $line++) { + $commentLines[$line] = \true; + } + } + $commentLinesOfCode = count($commentLines); + $nonCommentLinesOfCode = $this->linesOfCode - $commentLinesOfCode; + $logicalLinesOfCode = count(array_unique($this->linesWithStatements)); + assert($nonCommentLinesOfCode >= 0); + return new LinesOfCode($this->linesOfCode, $commentLinesOfCode, $nonCommentLinesOfCode, $logicalLinesOfCode); + } + /** + * @return Comment[] + */ + private function comments(): array + { + $comments = []; + foreach ($this->comments as $comment) { + $comments[$comment->getStartLine() . '_' . $comment->getStartTokenPos() . '_' . $comment->getEndLine() . '_' . $comment->getEndTokenPos()] = $comment; + } + return $comments; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\LinesOfCode; + +/** + * @immutable + */ +final readonly class LinesOfCode +{ + /** + * @var non-negative-int + */ + private int $linesOfCode; + /** + * @var non-negative-int + */ + private int $commentLinesOfCode; + /** + * @var non-negative-int + */ + private int $nonCommentLinesOfCode; + /** + * @var non-negative-int + */ + private int $logicalLinesOfCode; + /** + * @param non-negative-int $linesOfCode + * @param non-negative-int $commentLinesOfCode + * @param non-negative-int $nonCommentLinesOfCode + * @param non-negative-int $logicalLinesOfCode + * + * @throws IllogicalValuesException + */ + public function __construct(int $linesOfCode, int $commentLinesOfCode, int $nonCommentLinesOfCode, int $logicalLinesOfCode) + { + if ($linesOfCode - $commentLinesOfCode !== $nonCommentLinesOfCode) { + throw new IllogicalValuesException('$linesOfCode !== $commentLinesOfCode + $nonCommentLinesOfCode'); + } + $this->linesOfCode = $linesOfCode; + $this->commentLinesOfCode = $commentLinesOfCode; + $this->nonCommentLinesOfCode = $nonCommentLinesOfCode; + $this->logicalLinesOfCode = $logicalLinesOfCode; + } + /** + * @return non-negative-int + */ + public function linesOfCode(): int + { + return $this->linesOfCode; + } + /** + * @return non-negative-int + */ + public function commentLinesOfCode(): int + { + return $this->commentLinesOfCode; + } + /** + * @return non-negative-int + */ + public function nonCommentLinesOfCode(): int + { + return $this->nonCommentLinesOfCode; + } + /** + * @return non-negative-int + */ + public function logicalLinesOfCode(): int + { + return $this->logicalLinesOfCode; + } + public function plus(self $other): self + { + return new self($this->linesOfCode() + $other->linesOfCode(), $this->commentLinesOfCode() + $other->commentLinesOfCode(), $this->nonCommentLinesOfCode() + $other->nonCommentLinesOfCode(), $this->logicalLinesOfCode() + $other->logicalLinesOfCode()); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\ObjectEnumerator; + +use function array_merge; +use function is_array; +use function is_object; +use PHPUnitPHAR\SebastianBergmann\ObjectReflector\ObjectReflector; +use PHPUnitPHAR\SebastianBergmann\RecursionContext\Context; +final class Enumerator +{ + /** + * @param array|object $variable + * + * @return list + */ + public function enumerate(array|object $variable, Context $processed = new Context()): array + { + $objects = []; + if ($processed->contains($variable) !== \false) { + return $objects; + } + $array = $variable; + /* @noinspection UnusedFunctionResultInspection */ + $processed->add($variable); + if (is_array($variable)) { + /** @phpstan-ignore foreach.nonIterable */ + foreach ($array as $element) { + if (!is_array($element) && !is_object($element)) { + continue; + } + /** @noinspection SlowArrayOperationsInLoopInspection */ + $objects = array_merge($objects, $this->enumerate($element, $processed)); + } + return $objects; + } + $objects[] = $variable; + foreach ((new ObjectReflector())->getProperties($variable) as $value) { + if (!is_array($value) && !is_object($value)) { + continue; + } + /** @noinspection SlowArrayOperationsInLoopInspection */ + $objects = array_merge($objects, $this->enumerate($value, $processed)); + } + return $objects; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\ObjectReflector; + +use function count; +use function explode; +final class ObjectReflector +{ + /** + * @return array + */ + public function getProperties(object $object): array + { + $properties = []; + $className = $object::class; + foreach ((array) $object as $name => $value) { + $name = explode("\x00", (string) $name); + if (count($name) === 1) { + $name = $name[0]; + } elseif ($name[1] !== $className) { + $name = $name[1] . '::' . $name[2]; + } else { + $name = $name[2]; + } + $properties[$name] = $value; + } + return $properties; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\RecursionContext; + +use const PHP_INT_MAX; +use const PHP_INT_MIN; +use function array_key_exists; +use function array_pop; +use function array_slice; +use function count; +use function is_array; +use function is_int; +use function random_int; +use function spl_object_id; +use SplObjectStorage; +final class Context +{ + /** + * @var list> + */ + private array $arrays = []; + /** + * @var SplObjectStorage + */ + private SplObjectStorage $objects; + public function __construct() + { + $this->objects = new SplObjectStorage(); + } + /** + * @codeCoverageIgnore + */ + public function __destruct() + { + foreach ($this->arrays as &$array) { + if (is_array($array)) { + array_pop($array); + array_pop($array); + } + } + } + /** + * @template T of object|array + * + * @param T $value + * + * @param-out T $value + */ + public function add(array|object &$value): int + { + if (is_array($value)) { + /* @phpstan-ignore paramOut.type */ + return $this->addArray($value); + } + return $this->addObject($value); + } + /** + * @template T of object|array + * + * @param T $value + * + * @param-out T $value + */ + public function contains(array|object &$value): false|int + { + if (is_array($value)) { + return $this->containsArray($value); + } + return $this->containsObject($value); + } + /** + * @param array $array + */ + private function addArray(array &$array): int + { + $key = $this->containsArray($array); + if ($key !== \false) { + return $key; + } + $key = count($this->arrays); + $this->arrays[] =& $array; + if (!array_key_exists(PHP_INT_MAX, $array) && !array_key_exists(PHP_INT_MAX - 1, $array)) { + $array[] = $key; + $array[] = $this->objects; + } else { + /* Cover the improbable case, too. + * + * Note that array_slice() (used in containsArray()) will return the + * last two values added, *not necessarily* the highest integer keys + * in the array. Therefore, the order of these writes to $array is + * important, but the actual keys used is not. */ + do { + /** @noinspection PhpUnhandledExceptionInspection */ + $key = random_int(PHP_INT_MIN, PHP_INT_MAX); + } while (array_key_exists($key, $array)); + $array[$key] = $key; + do { + /** @noinspection PhpUnhandledExceptionInspection */ + $key = random_int(PHP_INT_MIN, PHP_INT_MAX); + } while (array_key_exists($key, $array)); + $array[$key] = $this->objects; + } + return $key; + } + private function addObject(object $object): int + { + if (!$this->objects->offsetExists($object)) { + $this->objects->offsetSet($object); + } + return spl_object_id($object); + } + /** + * @param array $array + */ + private function containsArray(array $array): false|int + { + $end = array_slice($array, -2); + if (isset($end[1]) && $end[1] === $this->objects && isset($end[0]) && is_int($end[0])) { + return $end[0]; + } + return \false; + } + private function containsObject(object $value): false|int + { + if ($this->objects->offsetExists($value)) { + return spl_object_id($value); + } + return \false; + } +} +BSD 3-Clause License + +Copyright (c) 2002-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +BSD 3-Clause License + +Copyright (c) 2019-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final readonly class Parameter +{ + /** + * @var non-empty-string + */ + private string $name; + private Type $type; + /** + * @param non-empty-string $name + */ + public function __construct(string $name, Type $type) + { + $this->name = $name; + $this->type = $type; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + public function type(): Type + { + return $this->type; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +use function array_filter; +use function assert; +use ReflectionFunction; +use ReflectionIntersectionType; +use ReflectionMethod; +use ReflectionNamedType; +use ReflectionProperty; +use ReflectionType; +use ReflectionUnionType; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class ReflectionMapper +{ + /** + * @return list + */ + public function fromParameterTypes(ReflectionFunction|ReflectionMethod $reflector): array + { + $parameters = []; + foreach ($reflector->getParameters() as $parameter) { + $name = $parameter->getName(); + if (!$parameter->hasType()) { + $parameters[] = new Parameter($name, new UnknownType()); + continue; + } + $type = $parameter->getType(); + if ($type instanceof ReflectionNamedType) { + $parameters[] = new Parameter($name, $this->mapNamedType($type, $reflector)); + continue; + } + if ($type instanceof ReflectionUnionType) { + $parameters[] = new Parameter($name, $this->mapUnionType($type, $reflector)); + continue; + } + if ($type instanceof ReflectionIntersectionType) { + $parameters[] = new Parameter($name, $this->mapIntersectionType($type, $reflector)); + } + } + return $parameters; + } + public function fromReturnType(ReflectionFunction|ReflectionMethod $reflector): Type + { + if (!$this->hasReturnType($reflector)) { + return new UnknownType(); + } + $returnType = $this->returnType($reflector); + assert($returnType instanceof ReflectionNamedType || $returnType instanceof ReflectionUnionType || $returnType instanceof ReflectionIntersectionType); + if ($returnType instanceof ReflectionNamedType) { + return $this->mapNamedType($returnType, $reflector); + } + if ($returnType instanceof ReflectionUnionType) { + return $this->mapUnionType($returnType, $reflector); + } + return $this->mapIntersectionType($returnType, $reflector); + } + public function fromPropertyType(ReflectionProperty $reflector): Type + { + if (!$reflector->hasType()) { + return new UnknownType(); + } + $propertyType = $reflector->getType(); + assert($propertyType instanceof ReflectionNamedType || $propertyType instanceof ReflectionUnionType || $propertyType instanceof ReflectionIntersectionType); + if ($propertyType instanceof ReflectionNamedType) { + return $this->mapNamedType($propertyType, $reflector); + } + if ($propertyType instanceof ReflectionUnionType) { + return $this->mapUnionType($propertyType, $reflector); + } + return $this->mapIntersectionType($propertyType, $reflector); + } + private function mapNamedType(ReflectionNamedType $type, ReflectionFunction|ReflectionMethod|ReflectionProperty $reflector): Type + { + $classScope = !$reflector instanceof ReflectionFunction; + $typeName = $type->getName(); + assert($typeName !== ''); + if ($classScope && $typeName === 'self') { + return ObjectType::fromName($reflector->getDeclaringClass()->getName(), $type->allowsNull()); + } + if ($classScope && $typeName === 'static') { + return new StaticType(TypeName::fromReflection($reflector->getDeclaringClass()), $type->allowsNull()); + } + if ($typeName === 'mixed') { + return new MixedType(); + } + if ($classScope && $typeName === 'parent') { + $parentClass = $reflector->getDeclaringClass()->getParentClass(); + assert($parentClass !== \false); + return ObjectType::fromName($parentClass->getName(), $type->allowsNull()); + } + return Type::fromName($typeName, $type->allowsNull()); + } + private function mapUnionType(ReflectionUnionType $type, ReflectionFunction|ReflectionMethod|ReflectionProperty $reflector): Type + { + $types = []; + $objectType = \false; + $genericObjectType = \false; + foreach ($type->getTypes() as $_type) { + if ($_type instanceof ReflectionNamedType) { + $namedType = $this->mapNamedType($_type, $reflector); + if ($namedType instanceof GenericObjectType) { + $genericObjectType = \true; + } elseif ($namedType instanceof ObjectType) { + $objectType = \true; + } + $types[] = $namedType; + continue; + } + $types[] = $this->mapIntersectionType($_type, $reflector); + } + if ($objectType && $genericObjectType) { + $types = array_filter($types, static function (Type $type): bool { + if ($type instanceof ObjectType) { + return \false; + } + return \true; + }); + } + return new UnionType(...$types); + } + private function mapIntersectionType(ReflectionIntersectionType $type, ReflectionFunction|ReflectionMethod|ReflectionProperty $reflector): Type + { + $types = []; + foreach ($type->getTypes() as $_type) { + assert($_type instanceof ReflectionNamedType); + $types[] = $this->mapNamedType($_type, $reflector); + } + return new IntersectionType(...$types); + } + private function hasReturnType(ReflectionFunction|ReflectionMethod $reflector): bool + { + if ($reflector->hasReturnType()) { + return \true; + } + return $reflector->hasTentativeReturnType(); + } + private function returnType(ReflectionFunction|ReflectionMethod $reflector): ?ReflectionType + { + if ($reflector->hasReturnType()) { + return $reflector->getReturnType(); + } + return $reflector->getTentativeReturnType(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +use function array_pop; +use function assert; +use function explode; +use function implode; +use function substr; +use ReflectionClass; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final readonly class TypeName +{ + private ?string $namespaceName; + /** + * @var non-empty-string + */ + private string $simpleName; + /** + * @param class-string $fullClassName + */ + public static function fromQualifiedName(string $fullClassName): self + { + if ($fullClassName[0] === '\\') { + $fullClassName = substr($fullClassName, 1); + } + $classNameParts = explode('\\', $fullClassName); + $simpleName = array_pop($classNameParts); + $namespaceName = implode('\\', $classNameParts); + assert($simpleName !== ''); + return new self($namespaceName, $simpleName); + } + /** + * @param ReflectionClass $type + */ + public static function fromReflection(ReflectionClass $type): self + { + $simpleName = $type->getShortName(); + assert($simpleName !== ''); + return new self($type->getNamespaceName(), $simpleName); + } + /** + * @param non-empty-string $simpleName + */ + public function __construct(?string $namespaceName, string $simpleName) + { + if ($namespaceName === '') { + $namespaceName = null; + } + $this->namespaceName = $namespaceName; + $this->simpleName = $simpleName; + } + public function namespaceName(): ?string + { + return $this->namespaceName; + } + /** + * @return non-empty-string + */ + public function simpleName(): string + { + return $this->simpleName; + } + /** + * @return non-empty-string + */ + public function qualifiedName(): string + { + return $this->namespaceName === null ? $this->simpleName : $this->namespaceName . '\\' . $this->simpleName; + } + public function isNamespaced(): bool + { + return $this->namespaceName !== null; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +use Throwable; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +interface Exception extends Throwable +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class RuntimeException extends \RuntimeException implements Exception +{ +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +use function assert; +use function class_exists; +use function count; +use function explode; +use function function_exists; +use function is_array; +use function is_object; +use function is_string; +use function str_contains; +use Closure; +use ReflectionClass; +use ReflectionObject; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class CallableType extends Type +{ + private bool $allowsNull; + public function __construct(bool $nullable) + { + $this->allowsNull = $nullable; + } + public function isAssignable(Type $other): bool + { + if ($this->allowsNull && $other instanceof NullType) { + return \true; + } + if ($other instanceof self) { + return \true; + } + if ($other instanceof ObjectType) { + if ($this->isClosure($other)) { + return \true; + } + if ($this->hasInvokeMethod($other)) { + return \true; + } + } + if ($other instanceof SimpleType) { + if ($this->isFunction($other)) { + return \true; + } + if ($this->isClassCallback($other)) { + return \true; + } + if ($this->isObjectCallback($other)) { + return \true; + } + } + return \false; + } + /** + * @return 'callable' + */ + public function name(): string + { + return 'callable'; + } + public function allowsNull(): bool + { + return $this->allowsNull; + } + public function isCallable(): bool + { + return \true; + } + private function isClosure(ObjectType $type): bool + { + return $type->className()->qualifiedName() === Closure::class; + } + private function hasInvokeMethod(ObjectType $type): bool + { + $className = $type->className()->qualifiedName(); + assert(class_exists($className)); + return (new ReflectionClass($className))->hasMethod('__invoke'); + } + private function isFunction(SimpleType $type): bool + { + if (!is_string($type->value())) { + return \false; + } + return function_exists($type->value()); + } + private function isObjectCallback(SimpleType $type): bool + { + if (!is_array($type->value())) { + return \false; + } + if (count($type->value()) !== 2) { + return \false; + } + if (!isset($type->value()[0], $type->value()[1])) { + return \false; + } + if (!is_object($type->value()[0]) || !is_string($type->value()[1])) { + return \false; + } + [$object, $methodName] = $type->value(); + return (new ReflectionObject($object))->hasMethod($methodName); + } + private function isClassCallback(SimpleType $type): bool + { + if (!is_string($type->value()) && !is_array($type->value())) { + return \false; + } + if (is_string($type->value())) { + if (!str_contains($type->value(), '::')) { + return \false; + } + [$className, $methodName] = explode('::', $type->value()); + } + if (is_array($type->value())) { + if (count($type->value()) !== 2) { + return \false; + } + if (!isset($type->value()[0], $type->value()[1])) { + return \false; + } + if (!is_string($type->value()[0]) || !is_string($type->value()[1])) { + return \false; + } + [$className, $methodName] = $type->value(); + } + if (!class_exists($className)) { + return \false; + } + $class = new ReflectionClass($className); + if (!$class->hasMethod($methodName)) { + return \false; + } + $method = $class->getMethod($methodName); + return $method->isPublic() && $method->isStatic(); + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class FalseType extends Type +{ + public function isAssignable(Type $other): bool + { + if ($other instanceof self) { + return \true; + } + return $other instanceof SimpleType && $other->name() === 'bool' && $other->value() === \false; + } + /** + * @return 'false' + */ + public function name(): string + { + return 'false'; + } + public function allowsNull(): bool + { + return \false; + } + public function isFalse(): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class GenericObjectType extends Type +{ + private bool $allowsNull; + public function __construct(bool $nullable) + { + $this->allowsNull = $nullable; + } + public function isAssignable(Type $other): bool + { + if ($this->allowsNull && $other instanceof NullType) { + return \true; + } + if (!$other instanceof ObjectType) { + return \false; + } + return \true; + } + /** + * @return 'object' + */ + public function name(): string + { + return 'object'; + } + public function allowsNull(): bool + { + return $this->allowsNull; + } + public function isGenericObject(): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +use function assert; +use function count; +use function implode; +use function in_array; +use function sort; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class IntersectionType extends Type +{ + /** + * @var non-empty-list + */ + private array $types; + /** + * @throws RuntimeException + */ + public function __construct(Type ...$types) + { + $this->ensureMinimumOfTwoTypes(...$types); + $this->ensureOnlyValidTypes(...$types); + $this->ensureNoDuplicateTypes(...$types); + assert($types !== []); + $this->types = $types; + } + public function isAssignable(Type $other): bool + { + return $other->isObject(); + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return $this->name(); + } + /** + * @return non-empty-string + */ + public function name(): string + { + $types = []; + foreach ($this->types as $type) { + $types[] = $type->name(); + } + sort($types); + return implode('&', $types); + } + public function allowsNull(): bool + { + return \false; + } + public function isIntersection(): bool + { + return \true; + } + /** + * @return non-empty-list + */ + public function types(): array + { + return $this->types; + } + /** + * @throws RuntimeException + */ + private function ensureMinimumOfTwoTypes(Type ...$types): void + { + if (count($types) < 2) { + throw new RuntimeException('An intersection type must be composed of at least two types'); + } + } + /** + * @throws RuntimeException + */ + private function ensureOnlyValidTypes(Type ...$types): void + { + foreach ($types as $type) { + if (!$type->isObject()) { + throw new RuntimeException('An intersection type can only be composed of interfaces and classes'); + } + } + } + /** + * @throws RuntimeException + */ + private function ensureNoDuplicateTypes(Type ...$types): void + { + $names = []; + foreach ($types as $type) { + assert($type instanceof ObjectType); + $classQualifiedName = $type->className()->qualifiedName(); + if (in_array($classQualifiedName, $names, \true)) { + throw new RuntimeException('An intersection type must not contain duplicate types'); + } + $names[] = $classQualifiedName; + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +use function assert; +use function class_exists; +use function is_iterable; +use ReflectionClass; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class IterableType extends Type +{ + private bool $allowsNull; + public function __construct(bool $nullable) + { + $this->allowsNull = $nullable; + } + /** + * @throws RuntimeException + */ + public function isAssignable(Type $other): bool + { + if ($this->allowsNull && $other instanceof NullType) { + return \true; + } + if ($other instanceof self) { + return \true; + } + if ($other instanceof SimpleType) { + return is_iterable($other->value()); + } + if ($other instanceof ObjectType) { + $className = $other->className()->qualifiedName(); + assert(class_exists($className)); + return (new ReflectionClass($className))->isIterable(); + } + return \false; + } + /** + * @return 'iterable' + */ + public function name(): string + { + return 'iterable'; + } + public function allowsNull(): bool + { + return $this->allowsNull; + } + public function isIterable(): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class MixedType extends Type +{ + public function isAssignable(Type $other): bool + { + return !$other instanceof VoidType; + } + /** + * @return 'mixed' + */ + public function asString(): string + { + return 'mixed'; + } + /** + * @return 'mixed' + */ + public function name(): string + { + return 'mixed'; + } + public function allowsNull(): bool + { + return \true; + } + public function isMixed(): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class NeverType extends Type +{ + public function isAssignable(Type $other): bool + { + return $other instanceof self; + } + /** + * @return 'never' + */ + public function name(): string + { + return 'never'; + } + public function allowsNull(): bool + { + return \false; + } + public function isNever(): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class NullType extends Type +{ + public function isAssignable(Type $other): bool + { + return !$other instanceof VoidType; + } + /** + * @return 'null' + */ + public function name(): string + { + return 'null'; + } + /** + * @return 'null' + */ + public function asString(): string + { + return 'null'; + } + public function allowsNull(): bool + { + return \true; + } + public function isNull(): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +use function class_exists; +use function interface_exists; +use function is_subclass_of; +use function strcasecmp; +use ReflectionClass; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class ObjectType extends Type +{ + private TypeName $className; + private bool $allowsNull; + public function __construct(TypeName $className, bool $allowsNull) + { + $this->className = $className; + $this->allowsNull = $allowsNull; + } + public function isAssignable(Type $other): bool + { + if ($this->allowsNull && $other instanceof NullType) { + return \true; + } + if ($other instanceof self) { + $thisName = $this->canonicalClassName($this->className->qualifiedName()); + $otherName = $this->canonicalClassName($other->className->qualifiedName()); + if (strcasecmp($thisName, $otherName) === 0) { + return \true; + } + if (is_subclass_of($otherName, $thisName, \true)) { + return \true; + } + } + return \false; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->className->qualifiedName(); + } + public function allowsNull(): bool + { + return $this->allowsNull; + } + public function className(): TypeName + { + return $this->className; + } + public function isObject(): bool + { + return \true; + } + /** + * @param non-empty-string $name + * + * @return non-empty-string + */ + private function canonicalClassName(string $name): string + { + if (class_exists($name) || interface_exists($name)) { + return (new ReflectionClass($name))->getName(); + } + return $name; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +use function strtolower; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class SimpleType extends Type +{ + /** + * @var non-empty-string + */ + private string $name; + private bool $allowsNull; + private mixed $value; + /** + * @param non-empty-string $name + */ + public function __construct(string $name, bool $nullable, mixed $value = null) + { + $this->name = $this->normalize($name); + $this->allowsNull = $nullable; + $this->value = $value; + } + public function isAssignable(Type $other): bool + { + if ($this->allowsNull && $other instanceof NullType) { + return \true; + } + if ($this->name === 'bool' && $other->name() === 'true') { + return \true; + } + if ($this->name === 'bool' && $other->name() === 'false') { + return \true; + } + if ($other instanceof self) { + return $this->name === $other->name; + } + return \false; + } + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + public function allowsNull(): bool + { + return $this->allowsNull; + } + public function value(): mixed + { + return $this->value; + } + public function isSimple(): bool + { + return \true; + } + /** + * @param non-empty-string $name + * + * @return non-empty-string + */ + private function normalize(string $name): string + { + $name = strtolower($name); + return match ($name) { + 'boolean' => 'bool', + 'real', 'double' => 'float', + 'integer' => 'int', + '[]' => 'array', + default => $name, + }; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +use function is_subclass_of; +use function strcasecmp; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class StaticType extends Type +{ + private TypeName $className; + private bool $allowsNull; + public function __construct(TypeName $className, bool $allowsNull) + { + $this->className = $className; + $this->allowsNull = $allowsNull; + } + public function isAssignable(Type $other): bool + { + if ($this->allowsNull && $other instanceof NullType) { + return \true; + } + if (!$other instanceof ObjectType) { + return \false; + } + if (0 === strcasecmp($this->className->qualifiedName(), $other->className()->qualifiedName())) { + return \true; + } + if (is_subclass_of($other->className()->qualifiedName(), $this->className->qualifiedName(), \true)) { + return \true; + } + return \false; + } + /** + * @return 'static' + */ + public function name(): string + { + return 'static'; + } + public function allowsNull(): bool + { + return $this->allowsNull; + } + public function isStatic(): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class TrueType extends Type +{ + public function isAssignable(Type $other): bool + { + if ($other instanceof self) { + return \true; + } + return $other instanceof SimpleType && $other->name() === 'bool' && $other->value() === \true; + } + /** + * @return 'true' + */ + public function name(): string + { + return 'true'; + } + public function allowsNull(): bool + { + return \false; + } + public function isTrue(): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +use function gettype; +use function is_object; +use function strtolower; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +abstract class Type +{ + public static function fromValue(mixed $value, bool $allowsNull): self + { + if ($allowsNull === \false) { + if ($value === \true) { + return new TrueType(); + } + if ($value === \false) { + return new FalseType(); + } + } + $typeName = gettype($value); + if (is_object($value)) { + return new ObjectType(TypeName::fromQualifiedName($value::class), $allowsNull); + } + $type = self::fromName($typeName, $allowsNull); + if ($type instanceof SimpleType) { + $type = new SimpleType($typeName, $allowsNull, $value); + } + return $type; + } + /** + * @param non-empty-string $typeName + */ + public static function fromName(string $typeName, bool $allowsNull): self + { + return match (strtolower($typeName)) { + 'callable' => new CallableType($allowsNull), + 'true' => new TrueType(), + 'false' => new FalseType(), + 'iterable' => new IterableType($allowsNull), + 'never' => new NeverType(), + 'null' => new NullType(), + 'object' => new GenericObjectType($allowsNull), + 'unknown type' => new UnknownType(), + 'void' => new VoidType(), + 'array', 'bool', 'boolean', 'double', 'float', 'int', 'integer', 'real', 'resource', 'resource (closed)', 'string' => new SimpleType($typeName, $allowsNull), + 'mixed' => new MixedType(), + /** @phpstan-ignore argument.type */ + default => new ObjectType(TypeName::fromQualifiedName($typeName), $allowsNull), + }; + } + public function asString(): string + { + return ($this->allowsNull() ? '?' : '') . $this->name(); + } + /** + * @phpstan-assert-if-true CallableType $this + */ + public function isCallable(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true TrueType $this + */ + public function isTrue(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true FalseType $this + */ + public function isFalse(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true GenericObjectType $this + */ + public function isGenericObject(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true IntersectionType $this + */ + public function isIntersection(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true IterableType $this + */ + public function isIterable(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true MixedType $this + */ + public function isMixed(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true NeverType $this + */ + public function isNever(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true NullType $this + */ + public function isNull(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true ObjectType $this + */ + public function isObject(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true SimpleType $this + */ + public function isSimple(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true StaticType $this + */ + public function isStatic(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true UnionType $this + */ + public function isUnion(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true UnknownType $this + */ + public function isUnknown(): bool + { + return \false; + } + /** + * @phpstan-assert-if-true VoidType $this + */ + public function isVoid(): bool + { + return \false; + } + abstract public function isAssignable(self $other): bool; + /** + * @return non-empty-string + */ + abstract public function name(): string; + abstract public function allowsNull(): bool; +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +use function array_any; +use function assert; +use function count; +use function implode; +use function sort; +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class UnionType extends Type +{ + /** + * @var non-empty-list + */ + private array $types; + /** + * @throws RuntimeException + */ + public function __construct(Type ...$types) + { + $this->ensureMinimumOfTwoTypes(...$types); + $this->ensureOnlyValidTypes(...$types); + assert($types !== []); + $this->types = $types; + } + public function isAssignable(Type $other): bool + { + return array_any($this->types, static fn(Type $type) => $type->isAssignable($other)); + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return $this->name(); + } + /** + * @return non-empty-string + */ + public function name(): string + { + $types = []; + foreach ($this->types as $type) { + if ($type->isIntersection()) { + $types[] = '(' . $type->name() . ')'; + continue; + } + $types[] = $type->name(); + } + sort($types); + return implode('|', $types); + } + public function allowsNull(): bool + { + return array_any($this->types, static fn(Type $type) => $type instanceof NullType); + } + public function isUnion(): bool + { + return \true; + } + public function containsIntersectionTypes(): bool + { + return array_any($this->types, static fn(Type $type) => $type->isIntersection()); + } + /** + * @return non-empty-list + */ + public function types(): array + { + return $this->types; + } + /** + * @throws RuntimeException + */ + private function ensureMinimumOfTwoTypes(Type ...$types): void + { + if (count($types) < 2) { + throw new RuntimeException('A union type must be composed of at least two types'); + } + } + /** + * @throws RuntimeException + */ + private function ensureOnlyValidTypes(Type ...$types): void + { + foreach ($types as $type) { + if ($type instanceof UnknownType) { + throw new RuntimeException('A union type must not be composed of an unknown type'); + } + if ($type instanceof VoidType) { + throw new RuntimeException('A union type must not be composed of a void type'); + } + } + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class UnknownType extends Type +{ + public function isAssignable(Type $other): bool + { + return \true; + } + /** + * @return 'unknown type' + */ + public function name(): string + { + return 'unknown type'; + } + /** + * @return '' + */ + public function asString(): string + { + return ''; + } + public function allowsNull(): bool + { + return \true; + } + public function isUnknown(): bool + { + return \true; + } +} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library + */ +final class VoidType extends Type +{ + public function isAssignable(Type $other): bool + { + return $other instanceof self; + } + /** + * @return 'void' + */ + public function name(): string + { + return 'void'; + } + public function allowsNull(): bool + { + return \false; + } + public function isVoid(): bool + { + return \true; + } +} +BSD 3-Clause License + +Copyright (c) 2013-2026, Sebastian Bergmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnitPHAR\SebastianBergmann; + +use const DIRECTORY_SEPARATOR; +use function assert; +use function end; +use function explode; +use function fclose; +use function is_dir; +use function is_resource; +use function proc_close; +use function proc_open; +use function stream_get_contents; +use function substr_count; +use function trim; +final readonly class Version +{ + /** + * @var non-empty-string + */ + private string $version; + /** + * @param non-empty-string $release + * @param non-empty-string $path + */ + public function __construct(string $release, string $path) + { + $this->version = $this->generate($release, $path); + } + /** + * @return non-empty-string + */ + public function asString(): string + { + return $this->version; + } + /** + * @param non-empty-string $release + * @param non-empty-string $path + * + * @return non-empty-string + */ + private function generate(string $release, string $path): string + { + if (substr_count($release, '.') + 1 === 3) { + $version = $release; + } else { + $version = $release . '-dev'; + } + $git = $this->getGitInformation($path); + if ($git === \false) { + return $version; + } + if (substr_count($release, '.') + 1 === 3) { + return $git; + } + $git = explode('-', $git); + return $release . '-' . end($git); + } + /** + * @param non-empty-string $path + * + * @return false|non-empty-string + */ + private function getGitInformation(string $path): false|string + { + if (!is_dir($path . DIRECTORY_SEPARATOR . '.git')) { + return \false; + } + $process = @proc_open(['git', 'describe', '--tags'], [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes, $path); + if (!is_resource($process)) { + return \false; + } + assert(isset($pipes[1]) && is_resource($pipes[1])); + assert(isset($pipes[2]) && is_resource($pipes[2])); + $result = trim((string) stream_get_contents($pipes[1])); + fclose($pipes[1]); + fclose($pipes[2]); + $returnCode = proc_close($process); + if ($returnCode !== 0) { + return \false; + } + assert($result !== ''); + return $result; + } +} +MIT License + +Copyright (c) 2021 Markus Staab + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + */ + private array $scopePollutingTokens = [\T_CLASS, \T_FUNCTION, \T_NEW, \T_EVAL, \T_GLOBAL, \T_GOTO, \T_HALT_COMPILER, \T_INCLUDE, \T_INCLUDE_ONCE, \T_REQUIRE, \T_REQUIRE_ONCE, \T_THROW, \T_UNSET, \T_UNSET_CAST]; + private const PROCESS_EXIT_TOKENS = [\T_EXIT]; + private const OUTPUT_TOKENS = [\T_PRINT, \T_ECHO, \T_INLINE_HTML]; + private const SCOPE_POLLUTING_FUNCTIONS = ['putenv', 'setlocale', 'class_exists', 'ini_set']; + private const STANDARD_OUTPUT_FUNCTIONS = ['printf', 'vprintf']; + private const INPUT_OUTPUT_FUNCTIONS = ['fopen', 'file_get_contents', 'file_put_contents', 'fwrite', 'fputs', 'fread', 'unlink']; + /** + * @var array + */ + private array $functionMetadata; + public function __construct() + { + $functionMeta = require __DIR__ . '/functionMetadata.php'; + if (!is_array($functionMeta)) { + throw new \RuntimeException('Invalid function metadata'); + } + $this->functionMetadata = $functionMeta; + if (defined('T_ENUM')) { + $this->scopePollutingTokens[] = \T_ENUM; + } + } + /** + * @api + * + * @return array + */ + public function getSideEffects(string $code): array + { + $tokens = token_get_all($code); + $sideEffects = []; + for ($i = 0; $i < count($tokens); $i++) { + $token = $tokens[$i]; + if (!is_array($token)) { + continue; + } + if ($this->isAnonymousFunction($tokens, $i)) { + continue; + } + if (in_array($token[0], self::OUTPUT_TOKENS, \true)) { + $sideEffects[] = SideEffect::STANDARD_OUTPUT; + continue; + } + if (in_array($token[0], self::PROCESS_EXIT_TOKENS, \true)) { + $sideEffects[] = SideEffect::PROCESS_EXIT; + continue; + } + if (in_array($token[0], $this->scopePollutingTokens, \true)) { + $sideEffects[] = SideEffect::SCOPE_POLLUTION; + $i++; + if (in_array($token[0], [\T_FUNCTION, \T_CLASS], \true)) { + $this->consumeWhitespaces($tokens, $i); + } + // consume function/class-name + if (!array_key_exists($i, $tokens) || !is_array($tokens[$i]) || $tokens[$i][0] !== \T_STRING) { + continue; + } + $i++; + continue; + } + $functionCall = $this->getFunctionCall($tokens, $i); + if ($functionCall !== null) { + $callSideEffect = $this->getFunctionCallSideEffect($functionCall); + if ($callSideEffect !== null) { + $sideEffects[] = $callSideEffect; + } + continue; + } + $methodCall = $this->getMethodCall($tokens, $i); + if ($methodCall !== null) { + $sideEffects[] = SideEffect::MAYBE; + continue; + } + $propertyAccess = $this->getPropertyAccess($tokens, $i); + if ($propertyAccess !== null) { + $sideEffects[] = SideEffect::SCOPE_POLLUTION; + continue; + } + if ($this->isNonLocalVariable($tokens, $i)) { + $sideEffects[] = SideEffect::SCOPE_POLLUTION; + continue; + } + } + return array_values(array_unique($sideEffects)); + } + /** + * @return SideEffect::*|null + */ + private function getFunctionCallSideEffect(string $functionName): ?string + { + // @phpstan-ignore return.unusedType + if (in_array($functionName, self::STANDARD_OUTPUT_FUNCTIONS, \true)) { + return SideEffect::STANDARD_OUTPUT; + } + if (in_array($functionName, self::INPUT_OUTPUT_FUNCTIONS, \true)) { + return SideEffect::INPUT_OUTPUT; + } + if (in_array($functionName, self::SCOPE_POLLUTING_FUNCTIONS, \true)) { + return SideEffect::SCOPE_POLLUTION; + } + if (array_key_exists($functionName, $this->functionMetadata)) { + if ($this->functionMetadata[$functionName]['hasSideEffects'] === \true) { + return SideEffect::UNKNOWN_CLASS; + } + } else { + try { + $reflectionFunction = new \ReflectionFunction($functionName); + $returnType = $reflectionFunction->getReturnType(); + if ($returnType === null) { + return SideEffect::MAYBE; + // no reflection information -> we don't know + } + if ((string) $returnType === 'void') { + return SideEffect::UNKNOWN_CLASS; + // functions with void return type must have side-effects + } + } catch (\ReflectionException $e) { + return SideEffect::MAYBE; + // function does not exist -> we don't know + } + } + return null; + } + /** + * @param array $tokens + */ + private function getFunctionCall(array $tokens, int $index): ?string + { + if (!array_key_exists($index, $tokens) || !is_array($tokens[$index]) || $tokens[$index][0] !== \T_STRING) { + return null; + } + $functionName = $tokens[$index][1]; + $index++; + $this->consumeWhitespaces($tokens, $index); + if (array_key_exists($index, $tokens) && $tokens[$index] === '(') { + return $functionName; + } + return null; + } + /** + * @param array $tokens + */ + private function getMethodCall(array $tokens, int $index): ?string + { + if (!array_key_exists($index, $tokens) || !is_array($tokens[$index]) || !in_array($tokens[$index][0], [\T_VARIABLE, \T_STRING], \true)) { + return null; + } + $callee = $tokens[$index][1]; + $index++; + $this->consumeWhitespaces($tokens, $index); + if (!array_key_exists($index, $tokens) || !is_array($tokens[$index]) || !in_array($tokens[$index][0], [\T_OBJECT_OPERATOR, \T_DOUBLE_COLON], \true)) { + return null; + } + $operator = $tokens[$index][1]; + $index++; + $this->consumeWhitespaces($tokens, $index); + if (!array_key_exists($index, $tokens) || !is_array($tokens[$index]) || !in_array($tokens[$index][0], [\T_STRING], \true)) { + return null; + } + $method = $tokens[$index][1]; + $index++; + $this->consumeWhitespaces($tokens, $index); + if (array_key_exists($index, $tokens) && $tokens[$index] !== '(') { + return null; + } + return $callee . $operator . $method; + } + /** + * @param array $tokens + */ + private function getPropertyAccess(array $tokens, int $index): ?string + { + if (!array_key_exists($index, $tokens) || !is_array($tokens[$index]) || !in_array($tokens[$index][0], [\T_VARIABLE, \T_STRING], \true)) { + return null; + } + $objectOrClass = $tokens[$index][1]; + $index++; + $this->consumeWhitespaces($tokens, $index); + if (!array_key_exists($index, $tokens) || !is_array($tokens[$index]) || !in_array($tokens[$index][0], [\T_OBJECT_OPERATOR, \T_DOUBLE_COLON], \true)) { + return null; + } + $operator = $tokens[$index][1]; + $index++; + $this->consumeWhitespaces($tokens, $index); + if (!array_key_exists($index, $tokens) || !is_array($tokens[$index]) || !in_array($tokens[$index][0], [\T_STRING, \T_VARIABLE], \true)) { + return null; + } + $propName = $tokens[$index][1]; + return $objectOrClass . $operator . $propName; + } + /** + * @param array $tokens + */ + private function isAnonymousFunction(array $tokens, int $index): bool + { + if (!array_key_exists($index, $tokens) || !is_array($tokens[$index]) || $tokens[$index][0] !== \T_FUNCTION) { + return \false; + } + $index++; + $this->consumeWhitespaces($tokens, $index); + if (array_key_exists($index, $tokens) && $tokens[$index] === '(') { + return \true; + } + return \false; + } + /** + * @param array $tokens + */ + private function isNonLocalVariable(array $tokens, int $index): bool + { + if (array_key_exists($index, $tokens) && is_array($tokens[$index]) && $tokens[$index][0] === \T_VARIABLE) { + if (in_array($tokens[$index][1], ['$this', '$GLOBALS', '$_SERVER', '$_GET', '$_POST', '$_FILES', '$_COOKIE', '$_SESSION', '$_REQUEST', '$_ENV'], \true)) { + return \true; + } + } + return \false; + } + /** + * @param array $tokens + */ + private function consumeWhitespaces(array $tokens, int &$index): void + { + while (array_key_exists($index, $tokens) && is_array($tokens[$index]) && $tokens[$index][0] === \T_WHITESPACE) { + $index++; + } + } +} + ['hasSideEffects' => \true], + 'trigger_error' => ['hasSideEffects' => \true], + 'putenv' => ['hasSideEffects' => \true], + 'version_compare' => ['hasSideEffects' => \false], + // Intially copied from PHPStan + 'BackedEnum::from' => ['hasSideEffects' => \false], + 'BackedEnum::tryFrom' => ['hasSideEffects' => \false], + 'CURLFile::getFilename' => ['hasSideEffects' => \false], + 'CURLFile::getMimeType' => ['hasSideEffects' => \false], + 'CURLFile::getPostFilename' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\AlreadyExistsException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\AuthenticationException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\ConfigurationException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\DivideByZeroException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\DomainException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\ExecutionException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\InvalidArgumentException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\InvalidQueryException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\InvalidSyntaxException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\IsBootstrappingException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\LogicException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\OverloadedException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\ProtocolException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\RangeException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\ReadTimeoutException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\RuntimeException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\ServerException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\TimeoutException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\TruncateException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\UnauthorizedException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\UnavailableException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\UnpreparedException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\ValidationException::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\Cassandra\Exception\WriteTimeoutException::__construct' => ['hasSideEffects' => \false], + 'Closure::bind' => ['hasSideEffects' => \false], + 'Closure::bindTo' => ['hasSideEffects' => \false], + 'Collator::__construct' => ['hasSideEffects' => \false], + 'Collator::compare' => ['hasSideEffects' => \false], + 'Collator::getAttribute' => ['hasSideEffects' => \false], + 'Collator::getErrorCode' => ['hasSideEffects' => \false], + 'Collator::getErrorMessage' => ['hasSideEffects' => \false], + 'Collator::getLocale' => ['hasSideEffects' => \false], + 'Collator::getSortKey' => ['hasSideEffects' => \false], + 'Collator::getStrength' => ['hasSideEffects' => \false], + 'DateTime::add' => ['hasSideEffects' => \true], + 'DateTime::createFromFormat' => ['hasSideEffects' => \false], + 'DateTime::createFromImmutable' => ['hasSideEffects' => \false], + 'DateTime::diff' => ['hasSideEffects' => \false], + 'DateTime::format' => ['hasSideEffects' => \false], + 'DateTime::getLastErrors' => ['hasSideEffects' => \false], + 'DateTime::getOffset' => ['hasSideEffects' => \false], + 'DateTime::getTimestamp' => ['hasSideEffects' => \false], + 'DateTime::getTimezone' => ['hasSideEffects' => \false], + 'DateTime::modify' => ['hasSideEffects' => \true], + 'DateTime::setDate' => ['hasSideEffects' => \true], + 'DateTime::setISODate' => ['hasSideEffects' => \true], + 'DateTime::setTime' => ['hasSideEffects' => \true], + 'DateTime::setTimestamp' => ['hasSideEffects' => \true], + 'DateTime::setTimezone' => ['hasSideEffects' => \true], + 'DateTime::sub' => ['hasSideEffects' => \true], + 'DateTimeImmutable::add' => ['hasSideEffects' => \false], + 'DateTimeImmutable::createFromFormat' => ['hasSideEffects' => \false], + 'DateTimeImmutable::createFromMutable' => ['hasSideEffects' => \false], + 'DateTimeImmutable::diff' => ['hasSideEffects' => \false], + 'DateTimeImmutable::format' => ['hasSideEffects' => \false], + 'DateTimeImmutable::getLastErrors' => ['hasSideEffects' => \false], + 'DateTimeImmutable::getOffset' => ['hasSideEffects' => \false], + 'DateTimeImmutable::getTimestamp' => ['hasSideEffects' => \false], + 'DateTimeImmutable::getTimezone' => ['hasSideEffects' => \false], + 'DateTimeImmutable::modify' => ['hasSideEffects' => \false], + 'DateTimeImmutable::setDate' => ['hasSideEffects' => \false], + 'DateTimeImmutable::setISODate' => ['hasSideEffects' => \false], + 'DateTimeImmutable::setTime' => ['hasSideEffects' => \false], + 'DateTimeImmutable::setTimestamp' => ['hasSideEffects' => \false], + 'DateTimeImmutable::setTimezone' => ['hasSideEffects' => \false], + 'DateTimeImmutable::sub' => ['hasSideEffects' => \false], + 'Error::__construct' => ['hasSideEffects' => \false], + 'ErrorException::__construct' => ['hasSideEffects' => \false], + 'Event::__construct' => ['hasSideEffects' => \false], + 'EventBase::getFeatures' => ['hasSideEffects' => \false], + 'EventBase::getMethod' => ['hasSideEffects' => \false], + 'EventBase::getTimeOfDayCached' => ['hasSideEffects' => \false], + 'EventBase::gotExit' => ['hasSideEffects' => \false], + 'EventBase::gotStop' => ['hasSideEffects' => \false], + 'EventBuffer::__construct' => ['hasSideEffects' => \false], + 'EventBufferEvent::__construct' => ['hasSideEffects' => \false], + 'EventBufferEvent::getDnsErrorString' => ['hasSideEffects' => \false], + 'EventBufferEvent::getEnabled' => ['hasSideEffects' => \false], + 'EventBufferEvent::getInput' => ['hasSideEffects' => \false], + 'EventBufferEvent::getOutput' => ['hasSideEffects' => \false], + 'EventConfig::__construct' => ['hasSideEffects' => \false], + 'EventDnsBase::__construct' => ['hasSideEffects' => \false], + 'EventHttpConnection::__construct' => ['hasSideEffects' => \false], + 'EventHttpRequest::__construct' => ['hasSideEffects' => \false], + 'EventHttpRequest::getCommand' => ['hasSideEffects' => \false], + 'EventHttpRequest::getConnection' => ['hasSideEffects' => \false], + 'EventHttpRequest::getHost' => ['hasSideEffects' => \false], + 'EventHttpRequest::getInputBuffer' => ['hasSideEffects' => \false], + 'EventHttpRequest::getInputHeaders' => ['hasSideEffects' => \false], + 'EventHttpRequest::getOutputBuffer' => ['hasSideEffects' => \false], + 'EventHttpRequest::getOutputHeaders' => ['hasSideEffects' => \false], + 'EventHttpRequest::getResponseCode' => ['hasSideEffects' => \false], + 'EventHttpRequest::getUri' => ['hasSideEffects' => \false], + 'EventSslContext::__construct' => ['hasSideEffects' => \false], + 'Exception::__construct' => ['hasSideEffects' => \false], + 'Exception::getCode' => ['hasSideEffects' => \false], + 'Exception::getFile' => ['hasSideEffects' => \false], + 'Exception::getLine' => ['hasSideEffects' => \false], + 'Exception::getMessage' => ['hasSideEffects' => \false], + 'Exception::getPrevious' => ['hasSideEffects' => \false], + 'Exception::getTrace' => ['hasSideEffects' => \false], + 'Exception::getTraceAsString' => ['hasSideEffects' => \false], + 'Gmagick::getcopyright' => ['hasSideEffects' => \false], + 'Gmagick::getfilename' => ['hasSideEffects' => \false], + 'Gmagick::getimagebackgroundcolor' => ['hasSideEffects' => \false], + 'Gmagick::getimageblueprimary' => ['hasSideEffects' => \false], + 'Gmagick::getimagebordercolor' => ['hasSideEffects' => \false], + 'Gmagick::getimagechanneldepth' => ['hasSideEffects' => \false], + 'Gmagick::getimagecolors' => ['hasSideEffects' => \false], + 'Gmagick::getimagecolorspace' => ['hasSideEffects' => \false], + 'Gmagick::getimagecompose' => ['hasSideEffects' => \false], + 'Gmagick::getimagedelay' => ['hasSideEffects' => \false], + 'Gmagick::getimagedepth' => ['hasSideEffects' => \false], + 'Gmagick::getimagedispose' => ['hasSideEffects' => \false], + 'Gmagick::getimageextrema' => ['hasSideEffects' => \false], + 'Gmagick::getimagefilename' => ['hasSideEffects' => \false], + 'Gmagick::getimageformat' => ['hasSideEffects' => \false], + 'Gmagick::getimagegamma' => ['hasSideEffects' => \false], + 'Gmagick::getimagegreenprimary' => ['hasSideEffects' => \false], + 'Gmagick::getimageheight' => ['hasSideEffects' => \false], + 'Gmagick::getimagehistogram' => ['hasSideEffects' => \false], + 'Gmagick::getimageindex' => ['hasSideEffects' => \false], + 'Gmagick::getimageinterlacescheme' => ['hasSideEffects' => \false], + 'Gmagick::getimageiterations' => ['hasSideEffects' => \false], + 'Gmagick::getimagematte' => ['hasSideEffects' => \false], + 'Gmagick::getimagemattecolor' => ['hasSideEffects' => \false], + 'Gmagick::getimageprofile' => ['hasSideEffects' => \false], + 'Gmagick::getimageredprimary' => ['hasSideEffects' => \false], + 'Gmagick::getimagerenderingintent' => ['hasSideEffects' => \false], + 'Gmagick::getimageresolution' => ['hasSideEffects' => \false], + 'Gmagick::getimagescene' => ['hasSideEffects' => \false], + 'Gmagick::getimagesignature' => ['hasSideEffects' => \false], + 'Gmagick::getimagetype' => ['hasSideEffects' => \false], + 'Gmagick::getimageunits' => ['hasSideEffects' => \false], + 'Gmagick::getimagewhitepoint' => ['hasSideEffects' => \false], + 'Gmagick::getimagewidth' => ['hasSideEffects' => \false], + 'Gmagick::getpackagename' => ['hasSideEffects' => \false], + 'Gmagick::getquantumdepth' => ['hasSideEffects' => \false], + 'Gmagick::getreleasedate' => ['hasSideEffects' => \false], + 'Gmagick::getsamplingfactors' => ['hasSideEffects' => \false], + 'Gmagick::getsize' => ['hasSideEffects' => \false], + 'Gmagick::getversion' => ['hasSideEffects' => \false], + 'GmagickDraw::getfillcolor' => ['hasSideEffects' => \false], + 'GmagickDraw::getfillopacity' => ['hasSideEffects' => \false], + 'GmagickDraw::getfont' => ['hasSideEffects' => \false], + 'GmagickDraw::getfontsize' => ['hasSideEffects' => \false], + 'GmagickDraw::getfontstyle' => ['hasSideEffects' => \false], + 'GmagickDraw::getfontweight' => ['hasSideEffects' => \false], + 'GmagickDraw::getstrokecolor' => ['hasSideEffects' => \false], + 'GmagickDraw::getstrokeopacity' => ['hasSideEffects' => \false], + 'GmagickDraw::getstrokewidth' => ['hasSideEffects' => \false], + 'GmagickDraw::gettextdecoration' => ['hasSideEffects' => \false], + 'GmagickDraw::gettextencoding' => ['hasSideEffects' => \false], + 'GmagickPixel::getcolor' => ['hasSideEffects' => \false], + 'GmagickPixel::getcolorcount' => ['hasSideEffects' => \false], + 'GmagickPixel::getcolorvalue' => ['hasSideEffects' => \false], + 'HttpMessage::getBody' => ['hasSideEffects' => \false], + 'HttpMessage::getHeader' => ['hasSideEffects' => \false], + 'HttpMessage::getHeaders' => ['hasSideEffects' => \false], + 'HttpMessage::getHttpVersion' => ['hasSideEffects' => \false], + 'HttpMessage::getInfo' => ['hasSideEffects' => \false], + 'HttpMessage::getParentMessage' => ['hasSideEffects' => \false], + 'HttpMessage::getRequestMethod' => ['hasSideEffects' => \false], + 'HttpMessage::getRequestUrl' => ['hasSideEffects' => \false], + 'HttpMessage::getResponseCode' => ['hasSideEffects' => \false], + 'HttpMessage::getResponseStatus' => ['hasSideEffects' => \false], + 'HttpMessage::getType' => ['hasSideEffects' => \false], + 'HttpQueryString::get' => ['hasSideEffects' => \false], + 'HttpQueryString::getArray' => ['hasSideEffects' => \false], + 'HttpQueryString::getBool' => ['hasSideEffects' => \false], + 'HttpQueryString::getFloat' => ['hasSideEffects' => \false], + 'HttpQueryString::getInt' => ['hasSideEffects' => \false], + 'HttpQueryString::getObject' => ['hasSideEffects' => \false], + 'HttpQueryString::getString' => ['hasSideEffects' => \false], + 'HttpRequest::getBody' => ['hasSideEffects' => \false], + 'HttpRequest::getContentType' => ['hasSideEffects' => \false], + 'HttpRequest::getCookies' => ['hasSideEffects' => \false], + 'HttpRequest::getHeaders' => ['hasSideEffects' => \false], + 'HttpRequest::getHistory' => ['hasSideEffects' => \false], + 'HttpRequest::getMethod' => ['hasSideEffects' => \false], + 'HttpRequest::getOptions' => ['hasSideEffects' => \false], + 'HttpRequest::getPostFields' => ['hasSideEffects' => \false], + 'HttpRequest::getPostFiles' => ['hasSideEffects' => \false], + 'HttpRequest::getPutData' => ['hasSideEffects' => \false], + 'HttpRequest::getPutFile' => ['hasSideEffects' => \false], + 'HttpRequest::getQueryData' => ['hasSideEffects' => \false], + 'HttpRequest::getRawPostData' => ['hasSideEffects' => \false], + 'HttpRequest::getRawRequestMessage' => ['hasSideEffects' => \false], + 'HttpRequest::getRawResponseMessage' => ['hasSideEffects' => \false], + 'HttpRequest::getRequestMessage' => ['hasSideEffects' => \false], + 'HttpRequest::getResponseBody' => ['hasSideEffects' => \false], + 'HttpRequest::getResponseCode' => ['hasSideEffects' => \false], + 'HttpRequest::getResponseCookies' => ['hasSideEffects' => \false], + 'HttpRequest::getResponseData' => ['hasSideEffects' => \false], + 'HttpRequest::getResponseHeader' => ['hasSideEffects' => \false], + 'HttpRequest::getResponseInfo' => ['hasSideEffects' => \false], + 'HttpRequest::getResponseMessage' => ['hasSideEffects' => \false], + 'HttpRequest::getResponseStatus' => ['hasSideEffects' => \false], + 'HttpRequest::getSslOptions' => ['hasSideEffects' => \false], + 'HttpRequest::getUrl' => ['hasSideEffects' => \false], + 'HttpRequestPool::getAttachedRequests' => ['hasSideEffects' => \false], + 'HttpRequestPool::getFinishedRequests' => ['hasSideEffects' => \false], + 'Imagick::getColorspace' => ['hasSideEffects' => \false], + 'Imagick::getCompression' => ['hasSideEffects' => \false], + 'Imagick::getCompressionQuality' => ['hasSideEffects' => \false], + 'Imagick::getConfigureOptions' => ['hasSideEffects' => \false], + 'Imagick::getFeatures' => ['hasSideEffects' => \false], + 'Imagick::getFilename' => ['hasSideEffects' => \false], + 'Imagick::getFont' => ['hasSideEffects' => \false], + 'Imagick::getFormat' => ['hasSideEffects' => \false], + 'Imagick::getGravity' => ['hasSideEffects' => \false], + 'Imagick::getHDRIEnabled' => ['hasSideEffects' => \false], + 'Imagick::getImage' => ['hasSideEffects' => \false], + 'Imagick::getImageAlphaChannel' => ['hasSideEffects' => \false], + 'Imagick::getImageArtifact' => ['hasSideEffects' => \false], + 'Imagick::getImageAttribute' => ['hasSideEffects' => \false], + 'Imagick::getImageBackgroundColor' => ['hasSideEffects' => \false], + 'Imagick::getImageBlob' => ['hasSideEffects' => \false], + 'Imagick::getImageBluePrimary' => ['hasSideEffects' => \false], + 'Imagick::getImageBorderColor' => ['hasSideEffects' => \false], + 'Imagick::getImageChannelDepth' => ['hasSideEffects' => \false], + 'Imagick::getImageChannelDistortion' => ['hasSideEffects' => \false], + 'Imagick::getImageChannelDistortions' => ['hasSideEffects' => \false], + 'Imagick::getImageChannelExtrema' => ['hasSideEffects' => \false], + 'Imagick::getImageChannelKurtosis' => ['hasSideEffects' => \false], + 'Imagick::getImageChannelMean' => ['hasSideEffects' => \false], + 'Imagick::getImageChannelRange' => ['hasSideEffects' => \false], + 'Imagick::getImageChannelStatistics' => ['hasSideEffects' => \false], + 'Imagick::getImageClipMask' => ['hasSideEffects' => \false], + 'Imagick::getImageColormapColor' => ['hasSideEffects' => \false], + 'Imagick::getImageColors' => ['hasSideEffects' => \false], + 'Imagick::getImageColorspace' => ['hasSideEffects' => \false], + 'Imagick::getImageCompose' => ['hasSideEffects' => \false], + 'Imagick::getImageCompression' => ['hasSideEffects' => \false], + 'Imagick::getImageCompressionQuality' => ['hasSideEffects' => \false], + 'Imagick::getImageDelay' => ['hasSideEffects' => \false], + 'Imagick::getImageDepth' => ['hasSideEffects' => \false], + 'Imagick::getImageDispose' => ['hasSideEffects' => \false], + 'Imagick::getImageDistortion' => ['hasSideEffects' => \false], + 'Imagick::getImageExtrema' => ['hasSideEffects' => \false], + 'Imagick::getImageFilename' => ['hasSideEffects' => \false], + 'Imagick::getImageFormat' => ['hasSideEffects' => \false], + 'Imagick::getImageGamma' => ['hasSideEffects' => \false], + 'Imagick::getImageGeometry' => ['hasSideEffects' => \false], + 'Imagick::getImageGravity' => ['hasSideEffects' => \false], + 'Imagick::getImageGreenPrimary' => ['hasSideEffects' => \false], + 'Imagick::getImageHeight' => ['hasSideEffects' => \false], + 'Imagick::getImageHistogram' => ['hasSideEffects' => \false], + 'Imagick::getImageIndex' => ['hasSideEffects' => \false], + 'Imagick::getImageInterlaceScheme' => ['hasSideEffects' => \false], + 'Imagick::getImageInterpolateMethod' => ['hasSideEffects' => \false], + 'Imagick::getImageIterations' => ['hasSideEffects' => \false], + 'Imagick::getImageLength' => ['hasSideEffects' => \false], + 'Imagick::getImageMatte' => ['hasSideEffects' => \false], + 'Imagick::getImageMatteColor' => ['hasSideEffects' => \false], + 'Imagick::getImageMimeType' => ['hasSideEffects' => \false], + 'Imagick::getImageOrientation' => ['hasSideEffects' => \false], + 'Imagick::getImagePage' => ['hasSideEffects' => \false], + 'Imagick::getImagePixelColor' => ['hasSideEffects' => \false], + 'Imagick::getImageProfile' => ['hasSideEffects' => \false], + 'Imagick::getImageProfiles' => ['hasSideEffects' => \false], + 'Imagick::getImageProperties' => ['hasSideEffects' => \false], + 'Imagick::getImageProperty' => ['hasSideEffects' => \false], + 'Imagick::getImageRedPrimary' => ['hasSideEffects' => \false], + 'Imagick::getImageRegion' => ['hasSideEffects' => \false], + 'Imagick::getImageRenderingIntent' => ['hasSideEffects' => \false], + 'Imagick::getImageResolution' => ['hasSideEffects' => \false], + 'Imagick::getImageScene' => ['hasSideEffects' => \false], + 'Imagick::getImageSignature' => ['hasSideEffects' => \false], + 'Imagick::getImageSize' => ['hasSideEffects' => \false], + 'Imagick::getImageTicksPerSecond' => ['hasSideEffects' => \false], + 'Imagick::getImageTotalInkDensity' => ['hasSideEffects' => \false], + 'Imagick::getImageType' => ['hasSideEffects' => \false], + 'Imagick::getImageUnits' => ['hasSideEffects' => \false], + 'Imagick::getImageVirtualPixelMethod' => ['hasSideEffects' => \false], + 'Imagick::getImageWhitePoint' => ['hasSideEffects' => \false], + 'Imagick::getImageWidth' => ['hasSideEffects' => \false], + 'Imagick::getImagesBlob' => ['hasSideEffects' => \false], + 'Imagick::getInterlaceScheme' => ['hasSideEffects' => \false], + 'Imagick::getIteratorIndex' => ['hasSideEffects' => \false], + 'Imagick::getNumberImages' => ['hasSideEffects' => \false], + 'Imagick::getOption' => ['hasSideEffects' => \false], + 'Imagick::getPage' => ['hasSideEffects' => \false], + 'Imagick::getPixelIterator' => ['hasSideEffects' => \false], + 'Imagick::getPixelRegionIterator' => ['hasSideEffects' => \false], + 'Imagick::getPointSize' => ['hasSideEffects' => \false], + 'Imagick::getSamplingFactors' => ['hasSideEffects' => \false], + 'Imagick::getSize' => ['hasSideEffects' => \false], + 'Imagick::getSizeOffset' => ['hasSideEffects' => \false], + 'ImagickDraw::getBorderColor' => ['hasSideEffects' => \false], + 'ImagickDraw::getClipPath' => ['hasSideEffects' => \false], + 'ImagickDraw::getClipRule' => ['hasSideEffects' => \false], + 'ImagickDraw::getClipUnits' => ['hasSideEffects' => \false], + 'ImagickDraw::getDensity' => ['hasSideEffects' => \false], + 'ImagickDraw::getFillColor' => ['hasSideEffects' => \false], + 'ImagickDraw::getFillOpacity' => ['hasSideEffects' => \false], + 'ImagickDraw::getFillRule' => ['hasSideEffects' => \false], + 'ImagickDraw::getFont' => ['hasSideEffects' => \false], + 'ImagickDraw::getFontFamily' => ['hasSideEffects' => \false], + 'ImagickDraw::getFontResolution' => ['hasSideEffects' => \false], + 'ImagickDraw::getFontSize' => ['hasSideEffects' => \false], + 'ImagickDraw::getFontStretch' => ['hasSideEffects' => \false], + 'ImagickDraw::getFontStyle' => ['hasSideEffects' => \false], + 'ImagickDraw::getFontWeight' => ['hasSideEffects' => \false], + 'ImagickDraw::getGravity' => ['hasSideEffects' => \false], + 'ImagickDraw::getOpacity' => ['hasSideEffects' => \false], + 'ImagickDraw::getStrokeAntialias' => ['hasSideEffects' => \false], + 'ImagickDraw::getStrokeColor' => ['hasSideEffects' => \false], + 'ImagickDraw::getStrokeDashArray' => ['hasSideEffects' => \false], + 'ImagickDraw::getStrokeDashOffset' => ['hasSideEffects' => \false], + 'ImagickDraw::getStrokeLineCap' => ['hasSideEffects' => \false], + 'ImagickDraw::getStrokeLineJoin' => ['hasSideEffects' => \false], + 'ImagickDraw::getStrokeMiterLimit' => ['hasSideEffects' => \false], + 'ImagickDraw::getStrokeOpacity' => ['hasSideEffects' => \false], + 'ImagickDraw::getStrokeWidth' => ['hasSideEffects' => \false], + 'ImagickDraw::getTextAlignment' => ['hasSideEffects' => \false], + 'ImagickDraw::getTextAntialias' => ['hasSideEffects' => \false], + 'ImagickDraw::getTextDecoration' => ['hasSideEffects' => \false], + 'ImagickDraw::getTextDirection' => ['hasSideEffects' => \false], + 'ImagickDraw::getTextEncoding' => ['hasSideEffects' => \false], + 'ImagickDraw::getTextInterLineSpacing' => ['hasSideEffects' => \false], + 'ImagickDraw::getTextInterWordSpacing' => ['hasSideEffects' => \false], + 'ImagickDraw::getTextKerning' => ['hasSideEffects' => \false], + 'ImagickDraw::getTextUnderColor' => ['hasSideEffects' => \false], + 'ImagickDraw::getVectorGraphics' => ['hasSideEffects' => \false], + 'ImagickKernel::getMatrix' => ['hasSideEffects' => \false], + 'ImagickPixel::getColor' => ['hasSideEffects' => \false], + 'ImagickPixel::getColorAsString' => ['hasSideEffects' => \false], + 'ImagickPixel::getColorCount' => ['hasSideEffects' => \false], + 'ImagickPixel::getColorQuantum' => ['hasSideEffects' => \false], + 'ImagickPixel::getColorValue' => ['hasSideEffects' => \false], + 'ImagickPixel::getColorValueQuantum' => ['hasSideEffects' => \false], + 'ImagickPixel::getHSL' => ['hasSideEffects' => \false], + 'ImagickPixel::getIndex' => ['hasSideEffects' => \false], + 'ImagickPixelIterator::getCurrentIteratorRow' => ['hasSideEffects' => \false], + 'ImagickPixelIterator::getIteratorRow' => ['hasSideEffects' => \false], + 'ImagickPixelIterator::getNextIteratorRow' => ['hasSideEffects' => \false], + 'ImagickPixelIterator::getPreviousIteratorRow' => ['hasSideEffects' => \false], + 'IntBackedEnum::from' => ['hasSideEffects' => \false], + 'IntBackedEnum::tryFrom' => ['hasSideEffects' => \false], + 'IntlBreakIterator::current' => ['hasSideEffects' => \false], + 'IntlBreakIterator::getErrorCode' => ['hasSideEffects' => \false], + 'IntlBreakIterator::getErrorMessage' => ['hasSideEffects' => \false], + 'IntlBreakIterator::getIterator' => ['hasSideEffects' => \false], + 'IntlBreakIterator::getLocale' => ['hasSideEffects' => \false], + 'IntlBreakIterator::getPartsIterator' => ['hasSideEffects' => \false], + 'IntlBreakIterator::getText' => ['hasSideEffects' => \false], + 'IntlBreakIterator::isBoundary' => ['hasSideEffects' => \false], + 'IntlCalendar::after' => ['hasSideEffects' => \false], + 'IntlCalendar::before' => ['hasSideEffects' => \false], + 'IntlCalendar::equals' => ['hasSideEffects' => \false], + 'IntlCalendar::fieldDifference' => ['hasSideEffects' => \false], + 'IntlCalendar::get' => ['hasSideEffects' => \false], + 'IntlCalendar::getActualMaximum' => ['hasSideEffects' => \false], + 'IntlCalendar::getActualMinimum' => ['hasSideEffects' => \false], + 'IntlCalendar::getDayOfWeekType' => ['hasSideEffects' => \false], + 'IntlCalendar::getErrorCode' => ['hasSideEffects' => \false], + 'IntlCalendar::getErrorMessage' => ['hasSideEffects' => \false], + 'IntlCalendar::getFirstDayOfWeek' => ['hasSideEffects' => \false], + 'IntlCalendar::getGreatestMinimum' => ['hasSideEffects' => \false], + 'IntlCalendar::getLeastMaximum' => ['hasSideEffects' => \false], + 'IntlCalendar::getLocale' => ['hasSideEffects' => \false], + 'IntlCalendar::getMaximum' => ['hasSideEffects' => \false], + 'IntlCalendar::getMinimalDaysInFirstWeek' => ['hasSideEffects' => \false], + 'IntlCalendar::getMinimum' => ['hasSideEffects' => \false], + 'IntlCalendar::getRepeatedWallTimeOption' => ['hasSideEffects' => \false], + 'IntlCalendar::getSkippedWallTimeOption' => ['hasSideEffects' => \false], + 'IntlCalendar::getTime' => ['hasSideEffects' => \false], + 'IntlCalendar::getTimeZone' => ['hasSideEffects' => \false], + 'IntlCalendar::getType' => ['hasSideEffects' => \false], + 'IntlCalendar::getWeekendTransition' => ['hasSideEffects' => \false], + 'IntlCalendar::inDaylightTime' => ['hasSideEffects' => \false], + 'IntlCalendar::isEquivalentTo' => ['hasSideEffects' => \false], + 'IntlCalendar::isLenient' => ['hasSideEffects' => \false], + 'IntlCalendar::isWeekend' => ['hasSideEffects' => \false], + 'IntlCalendar::toDateTime' => ['hasSideEffects' => \false], + 'IntlChar::hasBinaryProperty' => ['hasSideEffects' => \false], + 'IntlCodePointBreakIterator::getLastCodePoint' => ['hasSideEffects' => \false], + 'IntlDateFormatter::__construct' => ['hasSideEffects' => \false], + 'IntlDateFormatter::getCalendar' => ['hasSideEffects' => \false], + 'IntlDateFormatter::getCalendarObject' => ['hasSideEffects' => \false], + 'IntlDateFormatter::getDateType' => ['hasSideEffects' => \false], + 'IntlDateFormatter::getErrorCode' => ['hasSideEffects' => \false], + 'IntlDateFormatter::getErrorMessage' => ['hasSideEffects' => \false], + 'IntlDateFormatter::getLocale' => ['hasSideEffects' => \false], + 'IntlDateFormatter::getPattern' => ['hasSideEffects' => \false], + 'IntlDateFormatter::getTimeType' => ['hasSideEffects' => \false], + 'IntlDateFormatter::getTimeZone' => ['hasSideEffects' => \false], + 'IntlDateFormatter::getTimeZoneId' => ['hasSideEffects' => \false], + 'IntlDateFormatter::isLenient' => ['hasSideEffects' => \false], + 'IntlGregorianCalendar::getGregorianChange' => ['hasSideEffects' => \false], + 'IntlGregorianCalendar::isLeapYear' => ['hasSideEffects' => \false], + 'IntlPartsIterator::getBreakIterator' => ['hasSideEffects' => \false], + 'IntlRuleBasedBreakIterator::__construct' => ['hasSideEffects' => \false], + 'IntlRuleBasedBreakIterator::getBinaryRules' => ['hasSideEffects' => \false], + 'IntlRuleBasedBreakIterator::getRuleStatus' => ['hasSideEffects' => \false], + 'IntlRuleBasedBreakIterator::getRuleStatusVec' => ['hasSideEffects' => \false], + 'IntlRuleBasedBreakIterator::getRules' => ['hasSideEffects' => \false], + 'IntlTimeZone::getDSTSavings' => ['hasSideEffects' => \false], + 'IntlTimeZone::getDisplayName' => ['hasSideEffects' => \false], + 'IntlTimeZone::getErrorCode' => ['hasSideEffects' => \false], + 'IntlTimeZone::getErrorMessage' => ['hasSideEffects' => \false], + 'IntlTimeZone::getID' => ['hasSideEffects' => \false], + 'IntlTimeZone::getRawOffset' => ['hasSideEffects' => \false], + 'IntlTimeZone::hasSameRules' => ['hasSideEffects' => \false], + 'IntlTimeZone::toDateTimeZone' => ['hasSideEffects' => \false], + 'JsonIncrementalParser::__construct' => ['hasSideEffects' => \false], + 'JsonIncrementalParser::get' => ['hasSideEffects' => \false], + 'JsonIncrementalParser::getError' => ['hasSideEffects' => \false], + 'MemcachedException::__construct' => ['hasSideEffects' => \false], + 'MessageFormatter::__construct' => ['hasSideEffects' => \false], + 'MessageFormatter::format' => ['hasSideEffects' => \false], + 'MessageFormatter::getErrorCode' => ['hasSideEffects' => \false], + 'MessageFormatter::getErrorMessage' => ['hasSideEffects' => \false], + 'MessageFormatter::getLocale' => ['hasSideEffects' => \false], + 'MessageFormatter::getPattern' => ['hasSideEffects' => \false], + 'MessageFormatter::parse' => ['hasSideEffects' => \false], + 'NumberFormatter::__construct' => ['hasSideEffects' => \false], + 'NumberFormatter::format' => ['hasSideEffects' => \false], + 'NumberFormatter::formatCurrency' => ['hasSideEffects' => \false], + 'NumberFormatter::getAttribute' => ['hasSideEffects' => \false], + 'NumberFormatter::getErrorCode' => ['hasSideEffects' => \false], + 'NumberFormatter::getErrorMessage' => ['hasSideEffects' => \false], + 'NumberFormatter::getLocale' => ['hasSideEffects' => \false], + 'NumberFormatter::getPattern' => ['hasSideEffects' => \false], + 'NumberFormatter::getSymbol' => ['hasSideEffects' => \false], + 'NumberFormatter::getTextAttribute' => ['hasSideEffects' => \false], + 'ReflectionAttribute::getArguments' => ['hasSideEffects' => \false], + 'ReflectionAttribute::getName' => ['hasSideEffects' => \false], + 'ReflectionAttribute::getTarget' => ['hasSideEffects' => \false], + 'ReflectionAttribute::isRepeated' => ['hasSideEffects' => \false], + 'ReflectionClass::getAttributes' => ['hasSideEffects' => \false], + 'ReflectionClass::getConstant' => ['hasSideEffects' => \false], + 'ReflectionClass::getConstants' => ['hasSideEffects' => \false], + 'ReflectionClass::getConstructor' => ['hasSideEffects' => \false], + 'ReflectionClass::getDefaultProperties' => ['hasSideEffects' => \false], + 'ReflectionClass::getDocComment' => ['hasSideEffects' => \false], + 'ReflectionClass::getEndLine' => ['hasSideEffects' => \false], + 'ReflectionClass::getExtension' => ['hasSideEffects' => \false], + 'ReflectionClass::getExtensionName' => ['hasSideEffects' => \false], + 'ReflectionClass::getFileName' => ['hasSideEffects' => \false], + 'ReflectionClass::getInterfaceNames' => ['hasSideEffects' => \false], + 'ReflectionClass::getInterfaces' => ['hasSideEffects' => \false], + 'ReflectionClass::getMethod' => ['hasSideEffects' => \false], + 'ReflectionClass::getMethods' => ['hasSideEffects' => \false], + 'ReflectionClass::getModifiers' => ['hasSideEffects' => \false], + 'ReflectionClass::getName' => ['hasSideEffects' => \false], + 'ReflectionClass::getNamespaceName' => ['hasSideEffects' => \false], + 'ReflectionClass::getParentClass' => ['hasSideEffects' => \false], + 'ReflectionClass::getProperties' => ['hasSideEffects' => \false], + 'ReflectionClass::getProperty' => ['hasSideEffects' => \false], + 'ReflectionClass::getReflectionConstant' => ['hasSideEffects' => \false], + 'ReflectionClass::getReflectionConstants' => ['hasSideEffects' => \false], + 'ReflectionClass::getShortName' => ['hasSideEffects' => \false], + 'ReflectionClass::getStartLine' => ['hasSideEffects' => \false], + 'ReflectionClass::getStaticProperties' => ['hasSideEffects' => \false], + 'ReflectionClass::getStaticPropertyValue' => ['hasSideEffects' => \false], + 'ReflectionClass::getTraitAliases' => ['hasSideEffects' => \false], + 'ReflectionClass::getTraitNames' => ['hasSideEffects' => \false], + 'ReflectionClass::getTraits' => ['hasSideEffects' => \false], + 'ReflectionClass::isAbstract' => ['hasSideEffects' => \false], + 'ReflectionClass::isAnonymous' => ['hasSideEffects' => \false], + 'ReflectionClass::isCloneable' => ['hasSideEffects' => \false], + 'ReflectionClass::isFinal' => ['hasSideEffects' => \false], + 'ReflectionClass::isInstance' => ['hasSideEffects' => \false], + 'ReflectionClass::isInstantiable' => ['hasSideEffects' => \false], + 'ReflectionClass::isInterface' => ['hasSideEffects' => \false], + 'ReflectionClass::isInternal' => ['hasSideEffects' => \false], + 'ReflectionClass::isIterable' => ['hasSideEffects' => \false], + 'ReflectionClass::isIterateable' => ['hasSideEffects' => \false], + 'ReflectionClass::isReadOnly' => ['hasSideEffects' => \false], + 'ReflectionClass::isSubclassOf' => ['hasSideEffects' => \false], + 'ReflectionClass::isTrait' => ['hasSideEffects' => \false], + 'ReflectionClass::isUserDefined' => ['hasSideEffects' => \false], + 'ReflectionClassConstant::getAttributes' => ['hasSideEffects' => \false], + 'ReflectionClassConstant::getDeclaringClass' => ['hasSideEffects' => \false], + 'ReflectionClassConstant::getDocComment' => ['hasSideEffects' => \false], + 'ReflectionClassConstant::getModifiers' => ['hasSideEffects' => \false], + 'ReflectionClassConstant::getName' => ['hasSideEffects' => \false], + 'ReflectionClassConstant::getValue' => ['hasSideEffects' => \false], + 'ReflectionClassConstant::isPrivate' => ['hasSideEffects' => \false], + 'ReflectionClassConstant::isProtected' => ['hasSideEffects' => \false], + 'ReflectionClassConstant::isPublic' => ['hasSideEffects' => \false], + 'ReflectionEnumBackedCase::getBackingValue' => ['hasSideEffects' => \false], + 'ReflectionEnumUnitCase::getEnum' => ['hasSideEffects' => \false], + 'ReflectionEnumUnitCase::getValue' => ['hasSideEffects' => \false], + 'ReflectionExtension::getClassNames' => ['hasSideEffects' => \false], + 'ReflectionExtension::getClasses' => ['hasSideEffects' => \false], + 'ReflectionExtension::getConstants' => ['hasSideEffects' => \false], + 'ReflectionExtension::getDependencies' => ['hasSideEffects' => \false], + 'ReflectionExtension::getFunctions' => ['hasSideEffects' => \false], + 'ReflectionExtension::getINIEntries' => ['hasSideEffects' => \false], + 'ReflectionExtension::getName' => ['hasSideEffects' => \false], + 'ReflectionExtension::getVersion' => ['hasSideEffects' => \false], + 'ReflectionExtension::isPersistent' => ['hasSideEffects' => \false], + 'ReflectionExtension::isTemporary' => ['hasSideEffects' => \false], + 'ReflectionFunction::getClosure' => ['hasSideEffects' => \false], + 'ReflectionFunction::isDisabled' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getAttributes' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getClosureCalledClass' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getClosureScopeClass' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getClosureThis' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getClosureUsedVariables' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getDocComment' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getEndLine' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getExtension' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getExtensionName' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getFileName' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getName' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getNamespaceName' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getNumberOfParameters' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getNumberOfRequiredParameters' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getParameters' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getReturnType' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getShortName' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getStartLine' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getStaticVariables' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::getTentativeReturnType' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::hasTentativeReturnType' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::isClosure' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::isDeprecated' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::isGenerator' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::isInternal' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::isStatic' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::isUserDefined' => ['hasSideEffects' => \false], + 'ReflectionFunctionAbstract::isVariadic' => ['hasSideEffects' => \false], + 'ReflectionGenerator::getExecutingFile' => ['hasSideEffects' => \false], + 'ReflectionGenerator::getExecutingGenerator' => ['hasSideEffects' => \false], + 'ReflectionGenerator::getExecutingLine' => ['hasSideEffects' => \false], + 'ReflectionGenerator::getFunction' => ['hasSideEffects' => \false], + 'ReflectionGenerator::getThis' => ['hasSideEffects' => \false], + 'ReflectionGenerator::getTrace' => ['hasSideEffects' => \false], + 'ReflectionIntersectionType::getTypes' => ['hasSideEffects' => \false], + 'ReflectionMethod::getClosure' => ['hasSideEffects' => \false], + 'ReflectionMethod::getDeclaringClass' => ['hasSideEffects' => \false], + 'ReflectionMethod::getModifiers' => ['hasSideEffects' => \false], + 'ReflectionMethod::getPrototype' => ['hasSideEffects' => \false], + 'ReflectionMethod::isAbstract' => ['hasSideEffects' => \false], + 'ReflectionMethod::isConstructor' => ['hasSideEffects' => \false], + 'ReflectionMethod::isDestructor' => ['hasSideEffects' => \false], + 'ReflectionMethod::isFinal' => ['hasSideEffects' => \false], + 'ReflectionMethod::isPrivate' => ['hasSideEffects' => \false], + 'ReflectionMethod::isProtected' => ['hasSideEffects' => \false], + 'ReflectionMethod::isPublic' => ['hasSideEffects' => \false], + 'ReflectionMethod::isStatic' => ['hasSideEffects' => \false], + 'ReflectionMethod::setAccessible' => ['hasSideEffects' => \false], + 'ReflectionNamedType::getName' => ['hasSideEffects' => \false], + 'ReflectionNamedType::isBuiltin' => ['hasSideEffects' => \false], + 'ReflectionParameter::getAttributes' => ['hasSideEffects' => \false], + 'ReflectionParameter::getClass' => ['hasSideEffects' => \false], + 'ReflectionParameter::getDeclaringClass' => ['hasSideEffects' => \false], + 'ReflectionParameter::getDeclaringFunction' => ['hasSideEffects' => \false], + 'ReflectionParameter::getDefaultValue' => ['hasSideEffects' => \false], + 'ReflectionParameter::getDefaultValueConstantName' => ['hasSideEffects' => \false], + 'ReflectionParameter::getName' => ['hasSideEffects' => \false], + 'ReflectionParameter::getPosition' => ['hasSideEffects' => \false], + 'ReflectionParameter::getType' => ['hasSideEffects' => \false], + 'ReflectionParameter::isArray' => ['hasSideEffects' => \false], + 'ReflectionParameter::isCallable' => ['hasSideEffects' => \false], + 'ReflectionParameter::isDefaultValueAvailable' => ['hasSideEffects' => \false], + 'ReflectionParameter::isDefaultValueConstant' => ['hasSideEffects' => \false], + 'ReflectionParameter::isOptional' => ['hasSideEffects' => \false], + 'ReflectionParameter::isPassedByReference' => ['hasSideEffects' => \false], + 'ReflectionParameter::isPromoted' => ['hasSideEffects' => \false], + 'ReflectionParameter::isVariadic' => ['hasSideEffects' => \false], + 'ReflectionProperty::getAttributes' => ['hasSideEffects' => \false], + 'ReflectionProperty::getDeclaringClass' => ['hasSideEffects' => \false], + 'ReflectionProperty::getDefaultValue' => ['hasSideEffects' => \false], + 'ReflectionProperty::getDocComment' => ['hasSideEffects' => \false], + 'ReflectionProperty::getModifiers' => ['hasSideEffects' => \false], + 'ReflectionProperty::getName' => ['hasSideEffects' => \false], + 'ReflectionProperty::getType' => ['hasSideEffects' => \false], + 'ReflectionProperty::getValue' => ['hasSideEffects' => \false], + 'ReflectionProperty::isDefault' => ['hasSideEffects' => \false], + 'ReflectionProperty::isInitialized' => ['hasSideEffects' => \false], + 'ReflectionProperty::isPrivate' => ['hasSideEffects' => \false], + 'ReflectionProperty::isPromoted' => ['hasSideEffects' => \false], + 'ReflectionProperty::isProtected' => ['hasSideEffects' => \false], + 'ReflectionProperty::isPublic' => ['hasSideEffects' => \false], + 'ReflectionProperty::isStatic' => ['hasSideEffects' => \false], + 'ReflectionProperty::setAccessible' => ['hasSideEffects' => \false], + 'ReflectionReference::getId' => ['hasSideEffects' => \false], + 'ReflectionType::isBuiltin' => ['hasSideEffects' => \false], + 'ReflectionUnionType::getTypes' => ['hasSideEffects' => \false], + 'ReflectionZendExtension::getAuthor' => ['hasSideEffects' => \false], + 'ReflectionZendExtension::getCopyright' => ['hasSideEffects' => \false], + 'ReflectionZendExtension::getName' => ['hasSideEffects' => \false], + 'ReflectionZendExtension::getURL' => ['hasSideEffects' => \false], + 'ReflectionZendExtension::getVersion' => ['hasSideEffects' => \false], + 'ResourceBundle::__construct' => ['hasSideEffects' => \false], + 'ResourceBundle::count' => ['hasSideEffects' => \false], + 'ResourceBundle::get' => ['hasSideEffects' => \false], + 'ResourceBundle::getErrorCode' => ['hasSideEffects' => \false], + 'ResourceBundle::getErrorMessage' => ['hasSideEffects' => \false], + 'ResourceBundle::getIterator' => ['hasSideEffects' => \false], + 'SQLiteException::__construct' => ['hasSideEffects' => \false], + 'SimpleXMLElement::__construct' => ['hasSideEffects' => \false], + 'SimpleXMLElement::children' => ['hasSideEffects' => \false], + 'SimpleXMLElement::count' => ['hasSideEffects' => \false], + 'SimpleXMLElement::current' => ['hasSideEffects' => \false], + 'SimpleXMLElement::getChildren' => ['hasSideEffects' => \false], + 'SimpleXMLElement::getDocNamespaces' => ['hasSideEffects' => \false], + 'SimpleXMLElement::getName' => ['hasSideEffects' => \false], + 'SimpleXMLElement::getNamespaces' => ['hasSideEffects' => \false], + 'SimpleXMLElement::hasChildren' => ['hasSideEffects' => \false], + 'SimpleXMLElement::offsetExists' => ['hasSideEffects' => \false], + 'SimpleXMLElement::offsetGet' => ['hasSideEffects' => \false], + 'SimpleXMLElement::valid' => ['hasSideEffects' => \false], + 'SimpleXMLIterator::count' => ['hasSideEffects' => \false], + 'SimpleXMLIterator::current' => ['hasSideEffects' => \false], + 'SimpleXMLIterator::getChildren' => ['hasSideEffects' => \false], + 'SimpleXMLIterator::hasChildren' => ['hasSideEffects' => \false], + 'SimpleXMLIterator::valid' => ['hasSideEffects' => \false], + 'SoapFault::__construct' => ['hasSideEffects' => \false], + 'SplFileObject::fflush' => ['hasSideEffects' => \true], + 'SplFileObject::fgetc' => ['hasSideEffects' => \true], + 'SplFileObject::fgetcsv' => ['hasSideEffects' => \true], + 'SplFileObject::fgets' => ['hasSideEffects' => \true], + 'SplFileObject::fgetss' => ['hasSideEffects' => \true], + 'SplFileObject::fpassthru' => ['hasSideEffects' => \true], + 'SplFileObject::fputcsv' => ['hasSideEffects' => \true], + 'SplFileObject::fread' => ['hasSideEffects' => \true], + 'SplFileObject::fscanf' => ['hasSideEffects' => \true], + 'SplFileObject::fseek' => ['hasSideEffects' => \true], + 'SplFileObject::ftruncate' => ['hasSideEffects' => \true], + 'SplFileObject::fwrite' => ['hasSideEffects' => \true], + 'Spoofchecker::__construct' => ['hasSideEffects' => \false], + 'StringBackedEnum::from' => ['hasSideEffects' => \false], + 'StringBackedEnum::tryFrom' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\StubTests\CodeStyle\BracesOneLineFixer::getDefinition' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\StubTests\Parsers\ExpectedFunctionArgumentsInfo::__toString' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\StubTests\Parsers\Visitors\CoreStubASTVisitor::__construct' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\StubTests\StubsMetaExpectedArgumentsTest::getClassMemberFqn' => ['hasSideEffects' => \false], + 'PHPUnitPHAR\StubTests\StubsParameterNamesTest::printParameters' => ['hasSideEffects' => \false], + 'Transliterator::createInverse' => ['hasSideEffects' => \false], + 'Transliterator::getErrorCode' => ['hasSideEffects' => \false], + 'Transliterator::getErrorMessage' => ['hasSideEffects' => \false], + 'Transliterator::transliterate' => ['hasSideEffects' => \false], + 'UConverter::__construct' => ['hasSideEffects' => \false], + 'UConverter::convert' => ['hasSideEffects' => \false], + 'UConverter::getDestinationEncoding' => ['hasSideEffects' => \false], + 'UConverter::getDestinationType' => ['hasSideEffects' => \false], + 'UConverter::getErrorCode' => ['hasSideEffects' => \false], + 'UConverter::getErrorMessage' => ['hasSideEffects' => \false], + 'UConverter::getSourceEncoding' => ['hasSideEffects' => \false], + 'UConverter::getSourceType' => ['hasSideEffects' => \false], + 'UConverter::getStandards' => ['hasSideEffects' => \false], + 'UConverter::getSubstChars' => ['hasSideEffects' => \false], + 'UConverter::reasonText' => ['hasSideEffects' => \false], + 'UnitEnum::cases' => ['hasSideEffects' => \false], + 'WeakMap::count' => ['hasSideEffects' => \false], + 'WeakMap::getIterator' => ['hasSideEffects' => \false], + 'WeakMap::offsetExists' => ['hasSideEffects' => \false], + 'WeakMap::offsetGet' => ['hasSideEffects' => \false], + 'WeakReference::create' => ['hasSideEffects' => \false], + 'WeakReference::get' => ['hasSideEffects' => \false], + 'XmlReader::next' => ['hasSideEffects' => \true], + 'XmlReader::read' => ['hasSideEffects' => \true], + 'Zookeeper::getAcl' => ['hasSideEffects' => \false], + 'Zookeeper::getChildren' => ['hasSideEffects' => \false], + 'Zookeeper::getClientId' => ['hasSideEffects' => \false], + 'Zookeeper::getRecvTimeout' => ['hasSideEffects' => \false], + 'Zookeeper::getState' => ['hasSideEffects' => \false], + '_' => ['hasSideEffects' => \false], + 'abs' => ['hasSideEffects' => \false], + 'acos' => ['hasSideEffects' => \false], + 'acosh' => ['hasSideEffects' => \false], + 'addcslashes' => ['hasSideEffects' => \false], + 'addslashes' => ['hasSideEffects' => \false], + 'apache_get_modules' => ['hasSideEffects' => \false], + 'apache_get_version' => ['hasSideEffects' => \false], + 'apache_getenv' => ['hasSideEffects' => \false], + 'apache_request_headers' => ['hasSideEffects' => \false], + 'array_change_key_case' => ['hasSideEffects' => \false], + 'array_chunk' => ['hasSideEffects' => \false], + 'array_column' => ['hasSideEffects' => \false], + 'array_combine' => ['hasSideEffects' => \false], + 'array_count_values' => ['hasSideEffects' => \false], + 'array_diff' => ['hasSideEffects' => \false], + 'array_diff_assoc' => ['hasSideEffects' => \false], + 'array_diff_key' => ['hasSideEffects' => \false], + 'array_diff_uassoc' => ['hasSideEffects' => \false], + 'array_diff_ukey' => ['hasSideEffects' => \false], + 'array_fill' => ['hasSideEffects' => \false], + 'array_fill_keys' => ['hasSideEffects' => \false], + 'array_flip' => ['hasSideEffects' => \false], + 'array_intersect' => ['hasSideEffects' => \false], + 'array_intersect_assoc' => ['hasSideEffects' => \false], + 'array_intersect_key' => ['hasSideEffects' => \false], + 'array_intersect_uassoc' => ['hasSideEffects' => \false], + 'array_intersect_ukey' => ['hasSideEffects' => \false], + 'array_is_list' => ['hasSideEffects' => \false], + 'array_key_exists' => ['hasSideEffects' => \false], + 'array_key_first' => ['hasSideEffects' => \false], + 'array_key_last' => ['hasSideEffects' => \false], + 'array_keys' => ['hasSideEffects' => \false], + 'array_merge' => ['hasSideEffects' => \false], + 'array_merge_recursive' => ['hasSideEffects' => \false], + 'array_pad' => ['hasSideEffects' => \false], + 'array_pop' => ['hasSideEffects' => \true], + 'array_product' => ['hasSideEffects' => \false], + 'array_push' => ['hasSideEffects' => \true], + 'array_rand' => ['hasSideEffects' => \false], + 'array_replace' => ['hasSideEffects' => \false], + 'array_replace_recursive' => ['hasSideEffects' => \false], + 'array_reverse' => ['hasSideEffects' => \false], + 'array_search' => ['hasSideEffects' => \false], + 'array_shift' => ['hasSideEffects' => \true], + 'array_slice' => ['hasSideEffects' => \false], + 'array_sum' => ['hasSideEffects' => \false], + 'array_udiff' => ['hasSideEffects' => \false], + 'array_udiff_assoc' => ['hasSideEffects' => \false], + 'array_udiff_uassoc' => ['hasSideEffects' => \false], + 'array_uintersect' => ['hasSideEffects' => \false], + 'array_uintersect_assoc' => ['hasSideEffects' => \false], + 'array_uintersect_uassoc' => ['hasSideEffects' => \false], + 'array_unique' => ['hasSideEffects' => \false], + 'array_unshift' => ['hasSideEffects' => \true], + 'array_values' => ['hasSideEffects' => \false], + 'asin' => ['hasSideEffects' => \false], + 'asinh' => ['hasSideEffects' => \false], + 'atan' => ['hasSideEffects' => \false], + 'atan2' => ['hasSideEffects' => \false], + 'atanh' => ['hasSideEffects' => \false], + 'base64_decode' => ['hasSideEffects' => \false], + 'base64_encode' => ['hasSideEffects' => \false], + 'base_convert' => ['hasSideEffects' => \false], + 'basename' => ['hasSideEffects' => \false], + 'bcadd' => ['hasSideEffects' => \false], + 'bccomp' => ['hasSideEffects' => \false], + 'bcdiv' => ['hasSideEffects' => \false], + 'bcmod' => ['hasSideEffects' => \false], + 'bcmul' => ['hasSideEffects' => \false], + 'bcpow' => ['hasSideEffects' => \false], + 'bcpowmod' => ['hasSideEffects' => \false], + 'bcsqrt' => ['hasSideEffects' => \false], + 'bcsub' => ['hasSideEffects' => \false], + 'bin2hex' => ['hasSideEffects' => \false], + 'bindec' => ['hasSideEffects' => \false], + 'boolval' => ['hasSideEffects' => \false], + 'bzcompress' => ['hasSideEffects' => \false], + 'bzdecompress' => ['hasSideEffects' => \false], + 'bzerrno' => ['hasSideEffects' => \false], + 'bzerror' => ['hasSideEffects' => \false], + 'bzerrstr' => ['hasSideEffects' => \false], + 'bzopen' => ['hasSideEffects' => \false], + 'ceil' => ['hasSideEffects' => \false], + 'checkdate' => ['hasSideEffects' => \false], + 'checkdnsrr' => ['hasSideEffects' => \false], + 'chgrp' => ['hasSideEffects' => \true], + 'chmod' => ['hasSideEffects' => \true], + 'chop' => ['hasSideEffects' => \false], + 'chown' => ['hasSideEffects' => \true], + 'chr' => ['hasSideEffects' => \false], + 'chunk_split' => ['hasSideEffects' => \false], + 'class_implements' => ['hasSideEffects' => \false], + 'class_parents' => ['hasSideEffects' => \false], + 'cli_get_process_title' => ['hasSideEffects' => \false], + 'collator_compare' => ['hasSideEffects' => \false], + 'collator_create' => ['hasSideEffects' => \false], + 'collator_get_attribute' => ['hasSideEffects' => \false], + 'collator_get_error_code' => ['hasSideEffects' => \false], + 'collator_get_error_message' => ['hasSideEffects' => \false], + 'collator_get_locale' => ['hasSideEffects' => \false], + 'collator_get_sort_key' => ['hasSideEffects' => \false], + 'collator_get_strength' => ['hasSideEffects' => \false], + 'compact' => ['hasSideEffects' => \false], + 'connection_aborted' => ['hasSideEffects' => \true], + 'connection_status' => ['hasSideEffects' => \true], + 'constant' => ['hasSideEffects' => \false], + 'convert_cyr_string' => ['hasSideEffects' => \false], + 'convert_uudecode' => ['hasSideEffects' => \false], + 'convert_uuencode' => ['hasSideEffects' => \false], + 'copy' => ['hasSideEffects' => \true], + 'cos' => ['hasSideEffects' => \false], + 'cosh' => ['hasSideEffects' => \false], + 'count' => ['hasSideEffects' => \false], + 'count_chars' => ['hasSideEffects' => \false], + 'crc32' => ['hasSideEffects' => \false], + 'crypt' => ['hasSideEffects' => \false], + 'ctype_alnum' => ['hasSideEffects' => \false], + 'ctype_alpha' => ['hasSideEffects' => \false], + 'ctype_cntrl' => ['hasSideEffects' => \false], + 'ctype_digit' => ['hasSideEffects' => \false], + 'ctype_graph' => ['hasSideEffects' => \false], + 'ctype_lower' => ['hasSideEffects' => \false], + 'ctype_print' => ['hasSideEffects' => \false], + 'ctype_punct' => ['hasSideEffects' => \false], + 'ctype_space' => ['hasSideEffects' => \false], + 'ctype_upper' => ['hasSideEffects' => \false], + 'ctype_xdigit' => ['hasSideEffects' => \false], + 'curl_copy_handle' => ['hasSideEffects' => \false], + 'curl_errno' => ['hasSideEffects' => \false], + 'curl_error' => ['hasSideEffects' => \false], + 'curl_escape' => ['hasSideEffects' => \false], + 'curl_file_create' => ['hasSideEffects' => \false], + 'curl_getinfo' => ['hasSideEffects' => \false], + 'curl_multi_errno' => ['hasSideEffects' => \false], + 'curl_multi_getcontent' => ['hasSideEffects' => \false], + 'curl_multi_info_read' => ['hasSideEffects' => \false], + 'curl_share_errno' => ['hasSideEffects' => \false], + 'curl_share_strerror' => ['hasSideEffects' => \false], + 'curl_strerror' => ['hasSideEffects' => \false], + 'curl_unescape' => ['hasSideEffects' => \false], + 'curl_version' => ['hasSideEffects' => \false], + 'current' => ['hasSideEffects' => \false], + 'date' => ['hasSideEffects' => \false], + 'date_create' => ['hasSideEffects' => \false], + 'date_create_from_format' => ['hasSideEffects' => \false], + 'date_create_immutable' => ['hasSideEffects' => \false], + 'date_create_immutable_from_format' => ['hasSideEffects' => \false], + 'date_default_timezone_get' => ['hasSideEffects' => \false], + 'date_diff' => ['hasSideEffects' => \false], + 'date_format' => ['hasSideEffects' => \false], + 'date_get_last_errors' => ['hasSideEffects' => \false], + 'date_interval_create_from_date_string' => ['hasSideEffects' => \false], + 'date_interval_format' => ['hasSideEffects' => \false], + 'date_offset_get' => ['hasSideEffects' => \false], + 'date_parse' => ['hasSideEffects' => \false], + 'date_parse_from_format' => ['hasSideEffects' => \false], + 'date_sun_info' => ['hasSideEffects' => \false], + 'date_sunrise' => ['hasSideEffects' => \false], + 'date_sunset' => ['hasSideEffects' => \false], + 'date_timestamp_get' => ['hasSideEffects' => \false], + 'date_timezone_get' => ['hasSideEffects' => \false], + 'datefmt_create' => ['hasSideEffects' => \false], + 'datefmt_format' => ['hasSideEffects' => \false], + 'datefmt_format_object' => ['hasSideEffects' => \false], + 'datefmt_get_calendar' => ['hasSideEffects' => \false], + 'datefmt_get_calendar_object' => ['hasSideEffects' => \false], + 'datefmt_get_datetype' => ['hasSideEffects' => \false], + 'datefmt_get_error_code' => ['hasSideEffects' => \false], + 'datefmt_get_error_message' => ['hasSideEffects' => \false], + 'datefmt_get_locale' => ['hasSideEffects' => \false], + 'datefmt_get_pattern' => ['hasSideEffects' => \false], + 'datefmt_get_timetype' => ['hasSideEffects' => \false], + 'datefmt_get_timezone' => ['hasSideEffects' => \false], + 'datefmt_get_timezone_id' => ['hasSideEffects' => \false], + 'datefmt_is_lenient' => ['hasSideEffects' => \false], + 'dcngettext' => ['hasSideEffects' => \false], + 'decbin' => ['hasSideEffects' => \false], + 'dechex' => ['hasSideEffects' => \false], + 'decoct' => ['hasSideEffects' => \false], + 'defined' => ['hasSideEffects' => \false], + 'deflate_init' => ['hasSideEffects' => \false], + 'deg2rad' => ['hasSideEffects' => \false], + 'dirname' => ['hasSideEffects' => \false], + 'disk_free_space' => ['hasSideEffects' => \false], + 'disk_total_space' => ['hasSideEffects' => \false], + 'diskfreespace' => ['hasSideEffects' => \false], + 'dngettext' => ['hasSideEffects' => \false], + 'doubleval' => ['hasSideEffects' => \false], + 'error_get_last' => ['hasSideEffects' => \false], + 'error_log' => ['hasSideEffects' => \true], + 'escapeshellarg' => ['hasSideEffects' => \false], + 'escapeshellcmd' => ['hasSideEffects' => \false], + 'exp' => ['hasSideEffects' => \false], + 'explode' => ['hasSideEffects' => \false], + 'expm1' => ['hasSideEffects' => \false], + 'extension_loaded' => ['hasSideEffects' => \false], + 'fclose' => ['hasSideEffects' => \true], + 'fdiv' => ['hasSideEffects' => \false], + 'feof' => ['hasSideEffects' => \false], + 'fflush' => ['hasSideEffects' => \true], + 'fgetc' => ['hasSideEffects' => \true], + 'fgetcsv' => ['hasSideEffects' => \true], + 'fgets' => ['hasSideEffects' => \true], + 'fgetss' => ['hasSideEffects' => \true], + 'file' => ['hasSideEffects' => \false], + 'file_exists' => ['hasSideEffects' => \false], + 'file_get_contents' => ['hasSideEffects' => \true], + 'file_put_contents' => ['hasSideEffects' => \true], + 'fileatime' => ['hasSideEffects' => \false], + 'filectime' => ['hasSideEffects' => \false], + 'filegroup' => ['hasSideEffects' => \false], + 'fileinode' => ['hasSideEffects' => \false], + 'filemtime' => ['hasSideEffects' => \false], + 'fileowner' => ['hasSideEffects' => \false], + 'fileperms' => ['hasSideEffects' => \false], + 'filesize' => ['hasSideEffects' => \false], + 'filetype' => ['hasSideEffects' => \false], + 'filter_has_var' => ['hasSideEffects' => \false], + 'filter_id' => ['hasSideEffects' => \false], + 'filter_input' => ['hasSideEffects' => \false], + 'filter_input_array' => ['hasSideEffects' => \false], + 'filter_list' => ['hasSideEffects' => \false], + 'filter_var' => ['hasSideEffects' => \false], + 'filter_var_array' => ['hasSideEffects' => \false], + 'finfo::buffer' => ['hasSideEffects' => \false], + 'finfo::file' => ['hasSideEffects' => \false], + 'floatval' => ['hasSideEffects' => \false], + 'flock' => ['hasSideEffects' => \true], + 'floor' => ['hasSideEffects' => \false], + 'fmod' => ['hasSideEffects' => \false], + 'fnmatch' => ['hasSideEffects' => \false], + 'fopen' => ['hasSideEffects' => \true], + 'fpassthru' => ['hasSideEffects' => \true], + 'fputcsv' => ['hasSideEffects' => \true], + 'fputs' => ['hasSideEffects' => \true], + 'fread' => ['hasSideEffects' => \true], + 'fscanf' => ['hasSideEffects' => \true], + 'fseek' => ['hasSideEffects' => \true], + 'fstat' => ['hasSideEffects' => \false], + 'ftell' => ['hasSideEffects' => \false], + 'ftok' => ['hasSideEffects' => \false], + 'ftruncate' => ['hasSideEffects' => \true], + 'func_get_arg' => ['hasSideEffects' => \false], + 'func_get_args' => ['hasSideEffects' => \false], + 'func_num_args' => ['hasSideEffects' => \false], + 'function_exists' => ['hasSideEffects' => \false], + 'fwrite' => ['hasSideEffects' => \true], + 'gc_enabled' => ['hasSideEffects' => \false], + 'gc_status' => ['hasSideEffects' => \false], + 'gd_info' => ['hasSideEffects' => \false], + 'geoip_continent_code_by_name' => ['hasSideEffects' => \false], + 'geoip_country_code3_by_name' => ['hasSideEffects' => \false], + 'geoip_country_code_by_name' => ['hasSideEffects' => \false], + 'geoip_country_name_by_name' => ['hasSideEffects' => \false], + 'geoip_database_info' => ['hasSideEffects' => \false], + 'geoip_db_avail' => ['hasSideEffects' => \false], + 'geoip_db_filename' => ['hasSideEffects' => \false], + 'geoip_db_get_all_info' => ['hasSideEffects' => \false], + 'geoip_id_by_name' => ['hasSideEffects' => \false], + 'geoip_isp_by_name' => ['hasSideEffects' => \false], + 'geoip_org_by_name' => ['hasSideEffects' => \false], + 'geoip_record_by_name' => ['hasSideEffects' => \false], + 'geoip_region_by_name' => ['hasSideEffects' => \false], + 'geoip_region_name_by_code' => ['hasSideEffects' => \false], + 'geoip_time_zone_by_country_and_region' => ['hasSideEffects' => \false], + 'get_browser' => ['hasSideEffects' => \false], + 'get_called_class' => ['hasSideEffects' => \false], + 'get_cfg_var' => ['hasSideEffects' => \false], + 'get_class' => ['hasSideEffects' => \false], + 'get_class_methods' => ['hasSideEffects' => \false], + 'get_class_vars' => ['hasSideEffects' => \false], + 'get_current_user' => ['hasSideEffects' => \false], + 'get_debug_type' => ['hasSideEffects' => \false], + 'get_declared_classes' => ['hasSideEffects' => \false], + 'get_declared_interfaces' => ['hasSideEffects' => \false], + 'get_declared_traits' => ['hasSideEffects' => \false], + 'get_defined_constants' => ['hasSideEffects' => \false], + 'get_defined_functions' => ['hasSideEffects' => \false], + 'get_defined_vars' => ['hasSideEffects' => \false], + 'get_extension_funcs' => ['hasSideEffects' => \false], + 'get_headers' => ['hasSideEffects' => \false], + 'get_html_translation_table' => ['hasSideEffects' => \false], + 'get_include_path' => ['hasSideEffects' => \false], + 'get_included_files' => ['hasSideEffects' => \false], + 'get_loaded_extensions' => ['hasSideEffects' => \false], + 'get_meta_tags' => ['hasSideEffects' => \false], + 'get_object_vars' => ['hasSideEffects' => \false], + 'get_parent_class' => ['hasSideEffects' => \false], + 'get_required_files' => ['hasSideEffects' => \false], + 'get_resource_id' => ['hasSideEffects' => \false], + 'get_resources' => ['hasSideEffects' => \false], + 'getallheaders' => ['hasSideEffects' => \false], + 'getcwd' => ['hasSideEffects' => \false], + 'getdate' => ['hasSideEffects' => \false], + 'getenv' => ['hasSideEffects' => \false], + 'gethostbyaddr' => ['hasSideEffects' => \false], + 'gethostbyname' => ['hasSideEffects' => \false], + 'gethostbynamel' => ['hasSideEffects' => \false], + 'gethostname' => ['hasSideEffects' => \false], + 'getlastmod' => ['hasSideEffects' => \false], + 'getmygid' => ['hasSideEffects' => \false], + 'getmyinode' => ['hasSideEffects' => \false], + 'getmypid' => ['hasSideEffects' => \false], + 'getmyuid' => ['hasSideEffects' => \false], + 'getprotobyname' => ['hasSideEffects' => \false], + 'getprotobynumber' => ['hasSideEffects' => \false], + 'getrandmax' => ['hasSideEffects' => \false], + 'getrusage' => ['hasSideEffects' => \false], + 'getservbyname' => ['hasSideEffects' => \false], + 'getservbyport' => ['hasSideEffects' => \false], + 'gettext' => ['hasSideEffects' => \false], + 'gettimeofday' => ['hasSideEffects' => \false], + 'gettype' => ['hasSideEffects' => \false], + 'glob' => ['hasSideEffects' => \false], + 'gmdate' => ['hasSideEffects' => \false], + 'gmmktime' => ['hasSideEffects' => \false], + 'gmp_abs' => ['hasSideEffects' => \false], + 'gmp_add' => ['hasSideEffects' => \false], + 'gmp_and' => ['hasSideEffects' => \false], + 'gmp_binomial' => ['hasSideEffects' => \false], + 'gmp_cmp' => ['hasSideEffects' => \false], + 'gmp_com' => ['hasSideEffects' => \false], + 'gmp_div' => ['hasSideEffects' => \false], + 'gmp_div_q' => ['hasSideEffects' => \false], + 'gmp_div_qr' => ['hasSideEffects' => \false], + 'gmp_div_r' => ['hasSideEffects' => \false], + 'gmp_divexact' => ['hasSideEffects' => \false], + 'gmp_export' => ['hasSideEffects' => \false], + 'gmp_fact' => ['hasSideEffects' => \false], + 'gmp_gcd' => ['hasSideEffects' => \false], + 'gmp_gcdext' => ['hasSideEffects' => \false], + 'gmp_hamdist' => ['hasSideEffects' => \false], + 'gmp_import' => ['hasSideEffects' => \false], + 'gmp_init' => ['hasSideEffects' => \false], + 'gmp_intval' => ['hasSideEffects' => \false], + 'gmp_invert' => ['hasSideEffects' => \false], + 'gmp_jacobi' => ['hasSideEffects' => \false], + 'gmp_kronecker' => ['hasSideEffects' => \false], + 'gmp_lcm' => ['hasSideEffects' => \false], + 'gmp_legendre' => ['hasSideEffects' => \false], + 'gmp_mod' => ['hasSideEffects' => \false], + 'gmp_mul' => ['hasSideEffects' => \false], + 'gmp_neg' => ['hasSideEffects' => \false], + 'gmp_nextprime' => ['hasSideEffects' => \false], + 'gmp_or' => ['hasSideEffects' => \false], + 'gmp_perfect_power' => ['hasSideEffects' => \false], + 'gmp_perfect_square' => ['hasSideEffects' => \false], + 'gmp_popcount' => ['hasSideEffects' => \false], + 'gmp_pow' => ['hasSideEffects' => \false], + 'gmp_powm' => ['hasSideEffects' => \false], + 'gmp_prob_prime' => ['hasSideEffects' => \false], + 'gmp_root' => ['hasSideEffects' => \false], + 'gmp_rootrem' => ['hasSideEffects' => \false], + 'gmp_scan0' => ['hasSideEffects' => \false], + 'gmp_scan1' => ['hasSideEffects' => \false], + 'gmp_sign' => ['hasSideEffects' => \false], + 'gmp_sqrt' => ['hasSideEffects' => \false], + 'gmp_sqrtrem' => ['hasSideEffects' => \false], + 'gmp_strval' => ['hasSideEffects' => \false], + 'gmp_sub' => ['hasSideEffects' => \false], + 'gmp_testbit' => ['hasSideEffects' => \false], + 'gmp_xor' => ['hasSideEffects' => \false], + 'grapheme_stripos' => ['hasSideEffects' => \false], + 'grapheme_stristr' => ['hasSideEffects' => \false], + 'grapheme_strlen' => ['hasSideEffects' => \false], + 'grapheme_strpos' => ['hasSideEffects' => \false], + 'grapheme_strripos' => ['hasSideEffects' => \false], + 'grapheme_strrpos' => ['hasSideEffects' => \false], + 'grapheme_strstr' => ['hasSideEffects' => \false], + 'grapheme_substr' => ['hasSideEffects' => \false], + 'gzcompress' => ['hasSideEffects' => \false], + 'gzdecode' => ['hasSideEffects' => \false], + 'gzdeflate' => ['hasSideEffects' => \false], + 'gzencode' => ['hasSideEffects' => \false], + 'gzinflate' => ['hasSideEffects' => \false], + 'gzuncompress' => ['hasSideEffects' => \false], + 'hash' => ['hasSideEffects' => \false], + 'hash_algos' => ['hasSideEffects' => \false], + 'hash_copy' => ['hasSideEffects' => \false], + 'hash_equals' => ['hasSideEffects' => \false], + 'hash_file' => ['hasSideEffects' => \false], + 'hash_hkdf' => ['hasSideEffects' => \false], + 'hash_hmac' => ['hasSideEffects' => \false], + 'hash_hmac_algos' => ['hasSideEffects' => \false], + 'hash_hmac_file' => ['hasSideEffects' => \false], + 'hash_init' => ['hasSideEffects' => \false], + 'hash_pbkdf2' => ['hasSideEffects' => \false], + 'headers_list' => ['hasSideEffects' => \false], + 'hebrev' => ['hasSideEffects' => \false], + 'hexdec' => ['hasSideEffects' => \false], + 'hrtime' => ['hasSideEffects' => \false], + 'html_entity_decode' => ['hasSideEffects' => \false], + 'htmlentities' => ['hasSideEffects' => \false], + 'htmlspecialchars' => ['hasSideEffects' => \false], + 'htmlspecialchars_decode' => ['hasSideEffects' => \false], + 'http_build_cookie' => ['hasSideEffects' => \false], + 'http_build_query' => ['hasSideEffects' => \false], + 'http_build_str' => ['hasSideEffects' => \false], + 'http_cache_etag' => ['hasSideEffects' => \false], + 'http_cache_last_modified' => ['hasSideEffects' => \false], + 'http_chunked_decode' => ['hasSideEffects' => \false], + 'http_date' => ['hasSideEffects' => \false], + 'http_deflate' => ['hasSideEffects' => \false], + 'http_get_request_body' => ['hasSideEffects' => \false], + 'http_get_request_body_stream' => ['hasSideEffects' => \false], + 'http_get_request_headers' => ['hasSideEffects' => \false], + 'http_inflate' => ['hasSideEffects' => \false], + 'http_match_etag' => ['hasSideEffects' => \false], + 'http_match_modified' => ['hasSideEffects' => \false], + 'http_match_request_header' => ['hasSideEffects' => \false], + 'http_parse_cookie' => ['hasSideEffects' => \false], + 'http_parse_headers' => ['hasSideEffects' => \false], + 'http_parse_message' => ['hasSideEffects' => \false], + 'http_parse_params' => ['hasSideEffects' => \false], + 'http_request_body_encode' => ['hasSideEffects' => \false], + 'http_request_method_exists' => ['hasSideEffects' => \false], + 'http_request_method_name' => ['hasSideEffects' => \false], + 'http_support' => ['hasSideEffects' => \false], + 'hypot' => ['hasSideEffects' => \false], + 'iconv' => ['hasSideEffects' => \false], + 'iconv_get_encoding' => ['hasSideEffects' => \false], + 'iconv_mime_decode' => ['hasSideEffects' => \false], + 'iconv_mime_decode_headers' => ['hasSideEffects' => \false], + 'iconv_mime_encode' => ['hasSideEffects' => \false], + 'iconv_strlen' => ['hasSideEffects' => \false], + 'iconv_strpos' => ['hasSideEffects' => \false], + 'iconv_strrpos' => ['hasSideEffects' => \false], + 'iconv_substr' => ['hasSideEffects' => \false], + 'idate' => ['hasSideEffects' => \false], + 'image_type_to_extension' => ['hasSideEffects' => \false], + 'image_type_to_mime_type' => ['hasSideEffects' => \false], + 'imagecolorat' => ['hasSideEffects' => \false], + 'imagecolorclosest' => ['hasSideEffects' => \false], + 'imagecolorclosestalpha' => ['hasSideEffects' => \false], + 'imagecolorclosesthwb' => ['hasSideEffects' => \false], + 'imagecolorexact' => ['hasSideEffects' => \false], + 'imagecolorexactalpha' => ['hasSideEffects' => \false], + 'imagecolorresolve' => ['hasSideEffects' => \false], + 'imagecolorresolvealpha' => ['hasSideEffects' => \false], + 'imagecolorsforindex' => ['hasSideEffects' => \false], + 'imagecolorstotal' => ['hasSideEffects' => \false], + 'imagecreate' => ['hasSideEffects' => \false], + 'imagecreatefromstring' => ['hasSideEffects' => \false], + 'imagecreatetruecolor' => ['hasSideEffects' => \false], + 'imagefontheight' => ['hasSideEffects' => \false], + 'imagefontwidth' => ['hasSideEffects' => \false], + 'imageftbbox' => ['hasSideEffects' => \false], + 'imagegetinterpolation' => ['hasSideEffects' => \false], + 'imagegrabscreen' => ['hasSideEffects' => \false], + 'imagegrabwindow' => ['hasSideEffects' => \false], + 'imageistruecolor' => ['hasSideEffects' => \false], + 'imagesx' => ['hasSideEffects' => \false], + 'imagesy' => ['hasSideEffects' => \false], + 'imagettfbbox' => ['hasSideEffects' => \false], + 'imagetypes' => ['hasSideEffects' => \false], + 'implode' => ['hasSideEffects' => \false], + 'in_array' => ['hasSideEffects' => \false], + 'inet_ntop' => ['hasSideEffects' => \false], + 'inet_pton' => ['hasSideEffects' => \false], + 'inflate_get_read_len' => ['hasSideEffects' => \false], + 'inflate_get_status' => ['hasSideEffects' => \false], + 'inflate_init' => ['hasSideEffects' => \false], + 'ini_get' => ['hasSideEffects' => \false], + 'ini_get_all' => ['hasSideEffects' => \false], + 'intcal_get_maximum' => ['hasSideEffects' => \false], + 'intdiv' => ['hasSideEffects' => \false], + 'intl_error_name' => ['hasSideEffects' => \false], + 'intl_get' => ['hasSideEffects' => \false], + 'intl_get_error_code' => ['hasSideEffects' => \false], + 'intl_get_error_message' => ['hasSideEffects' => \false], + 'intl_is_failure' => ['hasSideEffects' => \false], + 'intlcal_after' => ['hasSideEffects' => \false], + 'intlcal_before' => ['hasSideEffects' => \false], + 'intlcal_create_instance' => ['hasSideEffects' => \false], + 'intlcal_equals' => ['hasSideEffects' => \false], + 'intlcal_field_difference' => ['hasSideEffects' => \false], + 'intlcal_from_date_time' => ['hasSideEffects' => \false], + 'intlcal_get' => ['hasSideEffects' => \false], + 'intlcal_get_actual_maximum' => ['hasSideEffects' => \false], + 'intlcal_get_actual_minimum' => ['hasSideEffects' => \false], + 'intlcal_get_available_locales' => ['hasSideEffects' => \false], + 'intlcal_get_day_of_week_type' => ['hasSideEffects' => \false], + 'intlcal_get_error_code' => ['hasSideEffects' => \false], + 'intlcal_get_error_message' => ['hasSideEffects' => \false], + 'intlcal_get_first_day_of_week' => ['hasSideEffects' => \false], + 'intlcal_get_greatest_minimum' => ['hasSideEffects' => \false], + 'intlcal_get_keyword_values_for_locale' => ['hasSideEffects' => \false], + 'intlcal_get_least_maximum' => ['hasSideEffects' => \false], + 'intlcal_get_locale' => ['hasSideEffects' => \false], + 'intlcal_get_maximum' => ['hasSideEffects' => \false], + 'intlcal_get_minimal_days_in_first_week' => ['hasSideEffects' => \false], + 'intlcal_get_minimum' => ['hasSideEffects' => \false], + 'intlcal_get_now' => ['hasSideEffects' => \false], + 'intlcal_get_repeated_wall_time_option' => ['hasSideEffects' => \false], + 'intlcal_get_skipped_wall_time_option' => ['hasSideEffects' => \false], + 'intlcal_get_time' => ['hasSideEffects' => \false], + 'intlcal_get_time_zone' => ['hasSideEffects' => \false], + 'intlcal_get_type' => ['hasSideEffects' => \false], + 'intlcal_get_weekend_transition' => ['hasSideEffects' => \false], + 'intlcal_greates_minimum' => ['hasSideEffects' => \false], + 'intlcal_in_daylight_time' => ['hasSideEffects' => \false], + 'intlcal_is_equivalent_to' => ['hasSideEffects' => \false], + 'intlcal_is_lenient' => ['hasSideEffects' => \false], + 'intlcal_is_set' => ['hasSideEffects' => \false], + 'intlcal_is_weekend' => ['hasSideEffects' => \false], + 'intlcal_to_date_time' => ['hasSideEffects' => \false], + 'intlgregcal_create_instance' => ['hasSideEffects' => \false], + 'intlgregcal_get_gregorian_change' => ['hasSideEffects' => \false], + 'intlgregcal_is_leap_year' => ['hasSideEffects' => \false], + 'intltz_count_equivalent_ids' => ['hasSideEffects' => \false], + 'intltz_create_default' => ['hasSideEffects' => \false], + 'intltz_create_enumeration' => ['hasSideEffects' => \false], + 'intltz_create_time_zone' => ['hasSideEffects' => \false], + 'intltz_create_time_zone_id_enumeration' => ['hasSideEffects' => \false], + 'intltz_from_date_time_zone' => ['hasSideEffects' => \false], + 'intltz_get_canonical_id' => ['hasSideEffects' => \false], + 'intltz_get_display_name' => ['hasSideEffects' => \false], + 'intltz_get_dst_savings' => ['hasSideEffects' => \false], + 'intltz_get_equivalent_id' => ['hasSideEffects' => \false], + 'intltz_get_error_code' => ['hasSideEffects' => \false], + 'intltz_get_error_message' => ['hasSideEffects' => \false], + 'intltz_get_gmt' => ['hasSideEffects' => \false], + 'intltz_get_id' => ['hasSideEffects' => \false], + 'intltz_get_offset' => ['hasSideEffects' => \false], + 'intltz_get_raw_offset' => ['hasSideEffects' => \false], + 'intltz_get_region' => ['hasSideEffects' => \false], + 'intltz_get_tz_data_version' => ['hasSideEffects' => \false], + 'intltz_get_unknown' => ['hasSideEffects' => \false], + 'intltz_getgmt' => ['hasSideEffects' => \false], + 'intltz_has_same_rules' => ['hasSideEffects' => \false], + 'intltz_to_date_time_zone' => ['hasSideEffects' => \false], + 'intltz_use_daylight_time' => ['hasSideEffects' => \false], + 'intlz_create_default' => ['hasSideEffects' => \false], + 'intval' => ['hasSideEffects' => \false], + 'ip2long' => ['hasSideEffects' => \false], + 'iptcparse' => ['hasSideEffects' => \false], + 'is_a' => ['hasSideEffects' => \false], + 'is_array' => ['hasSideEffects' => \false], + 'is_bool' => ['hasSideEffects' => \false], + 'is_countable' => ['hasSideEffects' => \false], + 'is_dir' => ['hasSideEffects' => \false], + 'is_double' => ['hasSideEffects' => \false], + 'is_executable' => ['hasSideEffects' => \false], + 'is_file' => ['hasSideEffects' => \false], + 'is_finite' => ['hasSideEffects' => \false], + 'is_float' => ['hasSideEffects' => \false], + 'is_infinite' => ['hasSideEffects' => \false], + 'is_int' => ['hasSideEffects' => \false], + 'is_integer' => ['hasSideEffects' => \false], + 'is_iterable' => ['hasSideEffects' => \false], + 'is_link' => ['hasSideEffects' => \false], + 'is_long' => ['hasSideEffects' => \false], + 'is_nan' => ['hasSideEffects' => \false], + 'is_null' => ['hasSideEffects' => \false], + 'is_numeric' => ['hasSideEffects' => \false], + 'is_object' => ['hasSideEffects' => \false], + 'is_readable' => ['hasSideEffects' => \false], + 'is_real' => ['hasSideEffects' => \false], + 'is_resource' => ['hasSideEffects' => \false], + 'is_scalar' => ['hasSideEffects' => \false], + 'is_string' => ['hasSideEffects' => \false], + 'is_subclass_of' => ['hasSideEffects' => \false], + 'is_uploaded_file' => ['hasSideEffects' => \false], + 'is_writable' => ['hasSideEffects' => \false], + 'is_writeable' => ['hasSideEffects' => \false], + 'iterator_count' => ['hasSideEffects' => \false], + 'join' => ['hasSideEffects' => \false], + 'json_last_error' => ['hasSideEffects' => \false], + 'json_last_error_msg' => ['hasSideEffects' => \false], + 'json_validate' => ['hasSideEffects' => \false], + 'key' => ['hasSideEffects' => \false], + 'key_exists' => ['hasSideEffects' => \false], + 'lcfirst' => ['hasSideEffects' => \false], + 'lchgrp' => ['hasSideEffects' => \true], + 'lchown' => ['hasSideEffects' => \true], + 'libxml_get_errors' => ['hasSideEffects' => \false], + 'libxml_get_last_error' => ['hasSideEffects' => \false], + 'link' => ['hasSideEffects' => \true], + 'linkinfo' => ['hasSideEffects' => \false], + 'locale_accept_from_http' => ['hasSideEffects' => \false], + 'locale_canonicalize' => ['hasSideEffects' => \false], + 'locale_compose' => ['hasSideEffects' => \false], + 'locale_filter_matches' => ['hasSideEffects' => \false], + 'locale_get_all_variants' => ['hasSideEffects' => \false], + 'locale_get_default' => ['hasSideEffects' => \false], + 'locale_get_display_language' => ['hasSideEffects' => \false], + 'locale_get_display_name' => ['hasSideEffects' => \false], + 'locale_get_display_region' => ['hasSideEffects' => \false], + 'locale_get_display_script' => ['hasSideEffects' => \false], + 'locale_get_display_variant' => ['hasSideEffects' => \false], + 'locale_get_keywords' => ['hasSideEffects' => \false], + 'locale_get_primary_language' => ['hasSideEffects' => \false], + 'locale_get_region' => ['hasSideEffects' => \false], + 'locale_get_script' => ['hasSideEffects' => \false], + 'locale_lookup' => ['hasSideEffects' => \false], + 'locale_parse' => ['hasSideEffects' => \false], + 'localeconv' => ['hasSideEffects' => \false], + 'localtime' => ['hasSideEffects' => \false], + 'log' => ['hasSideEffects' => \false], + 'log10' => ['hasSideEffects' => \false], + 'log1p' => ['hasSideEffects' => \false], + 'long2ip' => ['hasSideEffects' => \false], + 'lstat' => ['hasSideEffects' => \false], + 'ltrim' => ['hasSideEffects' => \false], + 'max' => ['hasSideEffects' => \false], + 'mb_check_encoding' => ['hasSideEffects' => \false], + 'mb_chr' => ['hasSideEffects' => \false], + 'mb_convert_case' => ['hasSideEffects' => \false], + 'mb_convert_encoding' => ['hasSideEffects' => \false], + 'mb_convert_kana' => ['hasSideEffects' => \false], + 'mb_decode_mimeheader' => ['hasSideEffects' => \false], + 'mb_decode_numericentity' => ['hasSideEffects' => \false], + 'mb_detect_encoding' => ['hasSideEffects' => \false], + 'mb_encode_mimeheader' => ['hasSideEffects' => \false], + 'mb_encode_numericentity' => ['hasSideEffects' => \false], + 'mb_encoding_aliases' => ['hasSideEffects' => \false], + 'mb_ereg_match' => ['hasSideEffects' => \false], + 'mb_ereg_replace' => ['hasSideEffects' => \false], + 'mb_ereg_search' => ['hasSideEffects' => \false], + 'mb_ereg_search_getpos' => ['hasSideEffects' => \false], + 'mb_ereg_search_getregs' => ['hasSideEffects' => \false], + 'mb_ereg_search_pos' => ['hasSideEffects' => \false], + 'mb_ereg_search_regs' => ['hasSideEffects' => \false], + 'mb_ereg_search_setpos' => ['hasSideEffects' => \false], + 'mb_eregi_replace' => ['hasSideEffects' => \false], + 'mb_get_info' => ['hasSideEffects' => \false], + 'mb_http_input' => ['hasSideEffects' => \false], + 'mb_list_encodings' => ['hasSideEffects' => \false], + 'mb_ord' => ['hasSideEffects' => \false], + 'mb_output_handler' => ['hasSideEffects' => \false], + 'mb_preferred_mime_name' => ['hasSideEffects' => \false], + 'mb_scrub' => ['hasSideEffects' => \false], + 'mb_split' => ['hasSideEffects' => \false], + 'mb_str_pad' => ['hasSideEffects' => \false], + 'mb_str_split' => ['hasSideEffects' => \false], + 'mb_strcut' => ['hasSideEffects' => \false], + 'mb_strimwidth' => ['hasSideEffects' => \false], + 'mb_stripos' => ['hasSideEffects' => \false], + 'mb_stristr' => ['hasSideEffects' => \false], + 'mb_strlen' => ['hasSideEffects' => \false], + 'mb_strpos' => ['hasSideEffects' => \false], + 'mb_strrchr' => ['hasSideEffects' => \false], + 'mb_strrichr' => ['hasSideEffects' => \false], + 'mb_strripos' => ['hasSideEffects' => \false], + 'mb_strrpos' => ['hasSideEffects' => \false], + 'mb_strstr' => ['hasSideEffects' => \false], + 'mb_strtolower' => ['hasSideEffects' => \false], + 'mb_strtoupper' => ['hasSideEffects' => \false], + 'mb_strwidth' => ['hasSideEffects' => \false], + 'mb_substr' => ['hasSideEffects' => \false], + 'mb_substr_count' => ['hasSideEffects' => \false], + 'mbereg_search_setpos' => ['hasSideEffects' => \false], + 'md5' => ['hasSideEffects' => \false], + 'md5_file' => ['hasSideEffects' => \false], + 'memory_get_peak_usage' => ['hasSideEffects' => \false], + 'memory_get_usage' => ['hasSideEffects' => \false], + 'metaphone' => ['hasSideEffects' => \false], + 'method_exists' => ['hasSideEffects' => \false], + 'mhash' => ['hasSideEffects' => \false], + 'mhash_count' => ['hasSideEffects' => \false], + 'mhash_get_block_size' => ['hasSideEffects' => \false], + 'mhash_get_hash_name' => ['hasSideEffects' => \false], + 'mhash_keygen_s2k' => ['hasSideEffects' => \false], + 'microtime' => ['hasSideEffects' => \false], + 'min' => ['hasSideEffects' => \false], + 'mkdir' => ['hasSideEffects' => \true], + 'mktime' => ['hasSideEffects' => \false], + 'move_uploaded_file' => ['hasSideEffects' => \true], + 'msgfmt_create' => ['hasSideEffects' => \false], + 'msgfmt_format' => ['hasSideEffects' => \false], + 'msgfmt_format_message' => ['hasSideEffects' => \false], + 'msgfmt_get_error_code' => ['hasSideEffects' => \false], + 'msgfmt_get_error_message' => ['hasSideEffects' => \false], + 'msgfmt_get_locale' => ['hasSideEffects' => \false], + 'msgfmt_get_pattern' => ['hasSideEffects' => \false], + 'msgfmt_parse' => ['hasSideEffects' => \false], + 'msgfmt_parse_message' => ['hasSideEffects' => \false], + 'mt_getrandmax' => ['hasSideEffects' => \false], + 'mt_rand' => ['hasSideEffects' => \true], + 'net_get_interfaces' => ['hasSideEffects' => \false], + 'ngettext' => ['hasSideEffects' => \false], + 'nl2br' => ['hasSideEffects' => \false], + 'nl_langinfo' => ['hasSideEffects' => \false], + 'normalizer_get_raw_decomposition' => ['hasSideEffects' => \false], + 'normalizer_is_normalized' => ['hasSideEffects' => \false], + 'normalizer_normalize' => ['hasSideEffects' => \false], + 'number_format' => ['hasSideEffects' => \false], + 'numfmt_create' => ['hasSideEffects' => \false], + 'numfmt_format' => ['hasSideEffects' => \false], + 'numfmt_format_currency' => ['hasSideEffects' => \false], + 'numfmt_get_attribute' => ['hasSideEffects' => \false], + 'numfmt_get_error_code' => ['hasSideEffects' => \false], + 'numfmt_get_error_message' => ['hasSideEffects' => \false], + 'numfmt_get_locale' => ['hasSideEffects' => \false], + 'numfmt_get_pattern' => ['hasSideEffects' => \false], + 'numfmt_get_symbol' => ['hasSideEffects' => \false], + 'numfmt_get_text_attribute' => ['hasSideEffects' => \false], + 'numfmt_parse' => ['hasSideEffects' => \false], + 'ob_etaghandler' => ['hasSideEffects' => \false], + 'ob_get_contents' => ['hasSideEffects' => \false], + 'ob_iconv_handler' => ['hasSideEffects' => \false], + 'octdec' => ['hasSideEffects' => \false], + 'ord' => ['hasSideEffects' => \false], + 'pack' => ['hasSideEffects' => \false], + 'pam_auth' => ['hasSideEffects' => \false], + 'pam_chpass' => ['hasSideEffects' => \false], + 'parse_ini_file' => ['hasSideEffects' => \false], + 'parse_ini_string' => ['hasSideEffects' => \false], + 'parse_url' => ['hasSideEffects' => \false], + 'pathinfo' => ['hasSideEffects' => \false], + 'pclose' => ['hasSideEffects' => \true], + 'pcntl_errno' => ['hasSideEffects' => \false], + 'pcntl_get_last_error' => ['hasSideEffects' => \false], + 'pcntl_getpriority' => ['hasSideEffects' => \false], + 'pcntl_strerror' => ['hasSideEffects' => \false], + 'pcntl_wexitstatus' => ['hasSideEffects' => \false], + 'pcntl_wifcontinued' => ['hasSideEffects' => \false], + 'pcntl_wifexited' => ['hasSideEffects' => \false], + 'pcntl_wifsignaled' => ['hasSideEffects' => \false], + 'pcntl_wifstopped' => ['hasSideEffects' => \false], + 'pcntl_wstopsig' => ['hasSideEffects' => \false], + 'pcntl_wtermsig' => ['hasSideEffects' => \false], + 'pdo_drivers' => ['hasSideEffects' => \false], + 'php_ini_loaded_file' => ['hasSideEffects' => \false], + 'php_ini_scanned_files' => ['hasSideEffects' => \false], + 'php_logo_guid' => ['hasSideEffects' => \false], + 'php_sapi_name' => ['hasSideEffects' => \false], + 'php_strip_whitespace' => ['hasSideEffects' => \false], + 'php_uname' => ['hasSideEffects' => \false], + 'phpversion' => ['hasSideEffects' => \false], + 'pi' => ['hasSideEffects' => \false], + 'popen' => ['hasSideEffects' => \true], + 'pos' => ['hasSideEffects' => \false], + 'posix_ctermid' => ['hasSideEffects' => \false], + 'posix_errno' => ['hasSideEffects' => \false], + 'posix_get_last_error' => ['hasSideEffects' => \false], + 'posix_getcwd' => ['hasSideEffects' => \false], + 'posix_getegid' => ['hasSideEffects' => \false], + 'posix_geteuid' => ['hasSideEffects' => \false], + 'posix_getgid' => ['hasSideEffects' => \false], + 'posix_getgrgid' => ['hasSideEffects' => \false], + 'posix_getgrnam' => ['hasSideEffects' => \false], + 'posix_getgroups' => ['hasSideEffects' => \false], + 'posix_getlogin' => ['hasSideEffects' => \false], + 'posix_getpgid' => ['hasSideEffects' => \false], + 'posix_getpgrp' => ['hasSideEffects' => \false], + 'posix_getpid' => ['hasSideEffects' => \false], + 'posix_getppid' => ['hasSideEffects' => \false], + 'posix_getpwnam' => ['hasSideEffects' => \false], + 'posix_getpwuid' => ['hasSideEffects' => \false], + 'posix_getrlimit' => ['hasSideEffects' => \false], + 'posix_getsid' => ['hasSideEffects' => \false], + 'posix_getuid' => ['hasSideEffects' => \false], + 'posix_initgroups' => ['hasSideEffects' => \false], + 'posix_isatty' => ['hasSideEffects' => \false], + 'posix_strerror' => ['hasSideEffects' => \false], + 'posix_times' => ['hasSideEffects' => \false], + 'posix_ttyname' => ['hasSideEffects' => \false], + 'posix_uname' => ['hasSideEffects' => \false], + 'pow' => ['hasSideEffects' => \false], + 'preg_grep' => ['hasSideEffects' => \false], + 'preg_last_error' => ['hasSideEffects' => \false], + 'preg_last_error_msg' => ['hasSideEffects' => \false], + 'preg_quote' => ['hasSideEffects' => \false], + 'preg_split' => ['hasSideEffects' => \false], + 'property_exists' => ['hasSideEffects' => \false], + 'quoted_printable_decode' => ['hasSideEffects' => \false], + 'quoted_printable_encode' => ['hasSideEffects' => \false], + 'quotemeta' => ['hasSideEffects' => \false], + 'rad2deg' => ['hasSideEffects' => \false], + 'rand' => ['hasSideEffects' => \true], + 'random_bytes' => ['hasSideEffects' => \true], + 'random_int' => ['hasSideEffects' => \true], + 'range' => ['hasSideEffects' => \false], + 'rawurldecode' => ['hasSideEffects' => \false], + 'rawurlencode' => ['hasSideEffects' => \false], + 'readfile' => ['hasSideEffects' => \true], + 'readlink' => ['hasSideEffects' => \false], + 'realpath' => ['hasSideEffects' => \false], + 'realpath_cache_get' => ['hasSideEffects' => \false], + 'realpath_cache_size' => ['hasSideEffects' => \false], + 'rename' => ['hasSideEffects' => \true], + 'resourcebundle_count' => ['hasSideEffects' => \false], + 'resourcebundle_create' => ['hasSideEffects' => \false], + 'resourcebundle_get' => ['hasSideEffects' => \false], + 'resourcebundle_get_error_code' => ['hasSideEffects' => \false], + 'resourcebundle_get_error_message' => ['hasSideEffects' => \false], + 'resourcebundle_locales' => ['hasSideEffects' => \false], + 'rewind' => ['hasSideEffects' => \true], + 'rmdir' => ['hasSideEffects' => \true], + 'round' => ['hasSideEffects' => \false], + 'rtrim' => ['hasSideEffects' => \false], + 'sha1' => ['hasSideEffects' => \false], + 'sha1_file' => ['hasSideEffects' => \false], + 'sin' => ['hasSideEffects' => \false], + 'sinh' => ['hasSideEffects' => \false], + 'sizeof' => ['hasSideEffects' => \false], + 'soundex' => ['hasSideEffects' => \false], + 'spl_classes' => ['hasSideEffects' => \false], + 'spl_object_hash' => ['hasSideEffects' => \false], + 'sprintf' => ['hasSideEffects' => \false], + 'sqrt' => ['hasSideEffects' => \false], + 'stat' => ['hasSideEffects' => \false], + 'str_contains' => ['hasSideEffects' => \false], + 'str_decrement' => ['hasSideEffects' => \false], + 'str_ends_with' => ['hasSideEffects' => \false], + 'str_getcsv' => ['hasSideEffects' => \false], + 'str_increment' => ['hasSideEffects' => \false], + 'str_pad' => ['hasSideEffects' => \false], + 'str_repeat' => ['hasSideEffects' => \false], + 'str_rot13' => ['hasSideEffects' => \false], + 'str_split' => ['hasSideEffects' => \false], + 'str_starts_with' => ['hasSideEffects' => \false], + 'str_word_count' => ['hasSideEffects' => \false], + 'strcasecmp' => ['hasSideEffects' => \false], + 'strchr' => ['hasSideEffects' => \false], + 'strcmp' => ['hasSideEffects' => \false], + 'strcoll' => ['hasSideEffects' => \false], + 'strcspn' => ['hasSideEffects' => \false], + 'stream_get_filters' => ['hasSideEffects' => \false], + 'stream_get_transports' => ['hasSideEffects' => \false], + 'stream_get_wrappers' => ['hasSideEffects' => \false], + 'stream_is_local' => ['hasSideEffects' => \false], + 'stream_isatty' => ['hasSideEffects' => \false], + 'strip_tags' => ['hasSideEffects' => \false], + 'stripcslashes' => ['hasSideEffects' => \false], + 'stripos' => ['hasSideEffects' => \false], + 'stripslashes' => ['hasSideEffects' => \false], + 'stristr' => ['hasSideEffects' => \false], + 'strlen' => ['hasSideEffects' => \false], + 'strnatcasecmp' => ['hasSideEffects' => \false], + 'strnatcmp' => ['hasSideEffects' => \false], + 'strncasecmp' => ['hasSideEffects' => \false], + 'strncmp' => ['hasSideEffects' => \false], + 'strpbrk' => ['hasSideEffects' => \false], + 'strpos' => ['hasSideEffects' => \false], + 'strptime' => ['hasSideEffects' => \false], + 'strrchr' => ['hasSideEffects' => \false], + 'strrev' => ['hasSideEffects' => \false], + 'strripos' => ['hasSideEffects' => \false], + 'strrpos' => ['hasSideEffects' => \false], + 'strspn' => ['hasSideEffects' => \false], + 'strstr' => ['hasSideEffects' => \false], + 'strtolower' => ['hasSideEffects' => \false], + 'strtotime' => ['hasSideEffects' => \false], + 'strtoupper' => ['hasSideEffects' => \false], + 'strtr' => ['hasSideEffects' => \false], + 'strval' => ['hasSideEffects' => \false], + 'substr' => ['hasSideEffects' => \false], + 'substr_compare' => ['hasSideEffects' => \false], + 'substr_count' => ['hasSideEffects' => \false], + 'substr_replace' => ['hasSideEffects' => \false], + 'symlink' => ['hasSideEffects' => \true], + 'sys_getloadavg' => ['hasSideEffects' => \false], + 'tan' => ['hasSideEffects' => \false], + 'tanh' => ['hasSideEffects' => \false], + 'tempnam' => ['hasSideEffects' => \true], + 'timezone_abbreviations_list' => ['hasSideEffects' => \false], + 'timezone_identifiers_list' => ['hasSideEffects' => \false], + 'timezone_location_get' => ['hasSideEffects' => \false], + 'timezone_name_from_abbr' => ['hasSideEffects' => \false], + 'timezone_name_get' => ['hasSideEffects' => \false], + 'timezone_offset_get' => ['hasSideEffects' => \false], + 'timezone_open' => ['hasSideEffects' => \false], + 'timezone_transitions_get' => ['hasSideEffects' => \false], + 'timezone_version_get' => ['hasSideEffects' => \false], + 'tmpfile' => ['hasSideEffects' => \true], + 'token_get_all' => ['hasSideEffects' => \false], + 'token_name' => ['hasSideEffects' => \false], + 'touch' => ['hasSideEffects' => \true], + 'transliterator_create' => ['hasSideEffects' => \false], + 'transliterator_create_from_rules' => ['hasSideEffects' => \false], + 'transliterator_create_inverse' => ['hasSideEffects' => \false], + 'transliterator_get_error_code' => ['hasSideEffects' => \false], + 'transliterator_get_error_message' => ['hasSideEffects' => \false], + 'transliterator_list_ids' => ['hasSideEffects' => \false], + 'transliterator_transliterate' => ['hasSideEffects' => \false], + 'trim' => ['hasSideEffects' => \false], + 'ucfirst' => ['hasSideEffects' => \false], + 'ucwords' => ['hasSideEffects' => \false], + 'umask' => ['hasSideEffects' => \true], + 'unlink' => ['hasSideEffects' => \true], + 'unpack' => ['hasSideEffects' => \false], + 'urldecode' => ['hasSideEffects' => \false], + 'urlencode' => ['hasSideEffects' => \false], + 'utf8_decode' => ['hasSideEffects' => \false], + 'utf8_encode' => ['hasSideEffects' => \false], + 'vsprintf' => ['hasSideEffects' => \false], + 'wordwrap' => ['hasSideEffects' => \false], + 'xml_error_string' => ['hasSideEffects' => \false], + 'xml_get_current_byte_index' => ['hasSideEffects' => \false], + 'xml_get_current_column_number' => ['hasSideEffects' => \false], + 'xml_get_current_line_number' => ['hasSideEffects' => \false], + 'xml_get_error_code' => ['hasSideEffects' => \false], + 'xml_parser_create' => ['hasSideEffects' => \false], + 'xml_parser_create_ns' => ['hasSideEffects' => \false], + 'xml_parser_get_option' => ['hasSideEffects' => \false], + 'zend_version' => ['hasSideEffects' => \false], + 'zlib_decode' => ['hasSideEffects' => \false], + 'zlib_encode' => ['hasSideEffects' => \false], + 'zlib_get_coding_type' => ['hasSideEffects' => \false], +]; + and contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of Arne Blankerts nor the names of contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +ensureValidUri($value); + $this->value = $value; + } + public function asString(): string + { + return $this->value; + } + private function ensureValidUri($value): void + { + if (strpos($value, ':') === \false) { + throw new NamespaceUriException(sprintf("Namespace URI '%s' must contain at least one colon", $value)); + } + } +} +line = $line; + $this->name = $name; + $this->value = $value; + } + public function getLine(): int + { + return $this->line; + } + public function getName(): string + { + return $this->name; + } + public function getValue(): string + { + return $this->value; + } +} + + */ +class TokenCollection implements IteratorAggregate, ArrayAccess, Countable +{ + /** @var Token[] */ + private $tokens = []; + public function addToken(Token $token): void + { + $this->tokens[] = $token; + } + public function getIterator(): Iterator + { + return new ArrayIterator($this->tokens); + } + public function count(): int + { + return count($this->tokens); + } + public function offsetExists($offset): bool + { + return isset($this->tokens[$offset]); + } + /** + * @throws TokenCollectionException + */ + public function offsetGet($offset): Token + { + if (!$this->offsetExists($offset)) { + throw new TokenCollectionException(sprintf('No Token at offest %s', $offset)); + } + return $this->tokens[$offset]; + } + /** + * @param Token $value + * + * @throws TokenCollectionException + */ + public function offsetSet($offset, $value): void + { + if (!is_int($offset)) { + $type = gettype($offset); + throw new TokenCollectionException(sprintf('Offset must be of type integer, %s given', $type === 'object' ? get_class($value) : $type)); + } + if (!$value instanceof Token) { + $type = gettype($value); + throw new TokenCollectionException(sprintf('Value must be of type %s, %s given', Token::class, $type === 'object' ? get_class($value) : $type)); + } + $this->tokens[$offset] = $value; + } + public function offsetUnset($offset): void + { + unset($this->tokens[$offset]); + } +} + 'T_OPEN_BRACKET', ')' => 'T_CLOSE_BRACKET', '[' => 'T_OPEN_SQUARE', ']' => 'T_CLOSE_SQUARE', '{' => 'T_OPEN_CURLY', '}' => 'T_CLOSE_CURLY', ';' => 'T_SEMICOLON', '.' => 'T_DOT', ',' => 'T_COMMA', '=' => 'T_EQUAL', '<' => 'T_LT', '>' => 'T_GT', '+' => 'T_PLUS', '-' => 'T_MINUS', '*' => 'T_MULT', '/' => 'T_DIV', '?' => 'T_QUESTION_MARK', '!' => 'T_EXCLAMATION_MARK', ':' => 'T_COLON', '"' => 'T_DOUBLE_QUOTES', '@' => 'T_AT', '%' => 'T_PERCENT', '|' => 'T_PIPE', '$' => 'T_DOLLAR', '^' => 'T_CARET', '~' => 'T_TILDE', '`' => 'T_BACKTICK']; + public function parse(string $source): TokenCollection + { + $result = new TokenCollection(); + if ($source === '') { + return $result; + } + $tokens = PhpToken::tokenize($source); + $lastToken = new Token($tokens[0]->line, 'Placeholder', ''); + foreach ($tokens as $tok) { + if (isset(self::MAP[$tok->text])) { + $token = new Token($lastToken->getLine(), self::MAP[$tok->text], $tok->text); + $result->addToken($token); + $lastToken = $token; + continue; + } + $line = $tok->line; + $values = preg_split('/\R+/Uu', $tok->text); + if (!$values) { + $result->addToken(new Token($line, $tok->getTokenName(), '{binary data}')); + continue; + } + foreach ($values as $v) { + $token = new Token($line, $tok->getTokenName(), $v); + $lastToken = $token; + $line++; + if ($v === '') { + continue; + } + $result->addToken($token); + } + } + return $this->fillBlanks($result, $lastToken->getLine()); + } + private function fillBlanks(TokenCollection $tokens, int $maxLine): TokenCollection + { + $prev = new Token(0, 'Placeholder', ''); + $final = new TokenCollection(); + $prevLine = $prev->getLine(); + foreach ($tokens as $token) { + $line = $token->getLine(); + $gap = $line - $prevLine; + while ($gap > 1) { + $linebreak = new Token($prevLine + 1, 'T_WHITESPACE', ''); + $final->addToken($linebreak); + $prevLine = $linebreak->getLine(); + $gap--; + } + $final->addToken($token); + $prevLine = $line; + } + $gap = $maxLine - $prevLine; + while ($gap > 0) { + $linebreak = new Token($prevLine + 1, 'T_WHITESPACE', ''); + $final->addToken($linebreak); + $prevLine = $linebreak->getLine(); + $gap--; + } + return $final; + } +} +xmlns = $xmlns; + } + public function toDom(TokenCollection $tokens): DOMDocument + { + $dom = new DOMDocument(); + $dom->preserveWhiteSpace = \false; + $dom->loadXML($this->toXML($tokens)); + return $dom; + } + public function toXML(TokenCollection $tokens): string + { + $writer = new XMLWriter(); + $writer->openMemory(); + $writer->setIndent(\true); + $writer->startDocument(); + $this->appendToWriter($writer, $tokens); + $writer->endDocument(); + return $writer->outputMemory(); + } + public function appendToWriter(XMLWriter $writer, TokenCollection $tokens): void + { + $writer->startElement('source'); + $writer->writeAttribute('xmlns', $this->xmlns->asString()); + if (count($tokens) > 0) { + $writer->startElement('line'); + $writer->writeAttribute('no', '1'); + $iterator = $tokens->getIterator(); + $previousToken = $iterator->current(); + $previousLine = $previousToken->getLine(); + foreach ($iterator as $token) { + $line = $token->getLine(); + if ($previousLine < $line) { + $writer->endElement(); + $writer->startElement('line'); + $writer->writeAttribute('no', (string) $line); + $previousLine = $line; + } + $value = $token->getValue(); + if ($value !== '') { + $writer->startElement('token'); + $writer->writeAttribute('name', $token->getName()); + $writer->writeRaw(htmlspecialchars($value, ENT_NOQUOTES | ENT_DISALLOWED | ENT_XML1)); + $writer->endElement(); + } + } + $writer->endElement(); + } + $writer->endElement(); + } +} +…ˆ3W‘yÓÈÖ³-Ú×Yõ[GR·½T¦D ÆAåâÙ/GUf®€™TÃÑñ¹ã‰|£€„y_&¢ÚÈGBMB \ No newline at end of file diff --git a/services/nginx/app/.phpunit.cache/test-results b/services/nginx/app/.phpunit.cache/test-results index 46afcacf..a53289f4 100644 --- a/services/nginx/app/.phpunit.cache/test-results +++ b/services/nginx/app/.phpunit.cache/test-results @@ -1 +1 @@ -{"version":"pest_3.8.6","defects":{"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_type__eligibility__summary__and_webhook_endpoints":1,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_defines_reusable_self_serve_wash_and_machine_type_schemas":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_redistributes_booked_department_75_net_amounts_using_fixed_pricing_and_wash_subscription_weights":7,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_classified_booked_department_75_amounts_undistributed_when_no_monthly_basis_exists":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_unclassified_booked_department_75_lines_undistributed_with_warnings":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_v2_historical_distribution_and_pricing_history_paths_in_openapi":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_defines_new_reusable_v2_schemas_for_normalization_comparison_versioning_and_distribution":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_supports_bulk_booked_invoice_line_payloads_with_top_level_department_numbers":7,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_claims_a_slot_atomically_with_nx_and_expiration":8,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_returns_false_when_the_slot_is_already_claimed_and_clamps_ttl_to_one_second":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_economic_v2_invoice_paths_in_openapi":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_aligns_legacy_compare_schema_with_runtime_payload_by_removing_stale_required_order__ids":1,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_documents_every_supported_search_entity_type_in_openapi_enum":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_system_wide_search_endpoints_in_openapi":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_debug__intent_and_parser_metadata_schema_in_openapi":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_e_conomic_indexed_customer_matching_and_synonym_behavior":1,"P\\Tests\\Integration\\Database\\DbConnectionTest::__pest_evaluable_it_can_connect_to_a_configured_MySQL_instance_in_integration_mode":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_runs_best_effort_backfill_repeatedly_without_introducing_duplicate_same_start_rows":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_resolves_version_aware_distribution_payload_shapes_over_a_real_date_range":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_creates_closes_and_rotates_fixed_pricing_versions_without_overlap":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_tracks_vehicle_and_discount_version_lifecycles_with_closure_semantics":1,"P\\Tests\\Integration\\Permissions\\LegacyPermissionRedisCacheScriptTest::__pest_evaluable_it_keeps_legacy_route_permission_redis_cache_script_green":1,"P\\Tests\\Unit\\Goals\\GoalsOpenApiSpecTest::__pest_evaluable_it_documents_advanced_goals_target_duration_fields_in_openapi":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_documents_the_date_key_in_the_openapi_department_weather_timeline_schema":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_builds_timeline_entries_with_mostly__clear_weather_when_forecast_payload_is_empty":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_wires_departments_weather_route_through_the_forecast_fallback_path":7,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_groups_attachments_by_object_id_and_preserves_empty_object_groups":8,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_keeps_listMany_payload_parity_with_list_for_one_object_id":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_department_weather_target_endpoints_and_reusable_schemas_in_openapi":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_unknown_weather_status_behavior_when_targets_are_missing":1,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_1_request_per_second_Shelly_gate_for_back_to_back_requests":8,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_in_progress_self_serve_wash_start_and_machine_relay_fields":1,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_stores_config_json_with_apostrophes_without_violating_json_constraints":8,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_is_on__then_turns_off_cleaner_machine_and_selector_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_is_off_and_only_disables_configured_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_wash_included_minutes_in_config_schemas":1,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_channel_id_is_missing_for_gate_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_with_terminal_status_details_when_call_never_reaches_accepted_state":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_when_call_reaches_accepted_state":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_immediately_when_status_transitions_to_accepted":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_maps_legacy_timeout_option_to_documented_ringTimeout_payload_field":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_clamps_derived_ringTimeout_to_Bird_documented_max_when_gate_timeout_is_high":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_passes_documented_hangup_cause_when_provided":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_drops_unsupported_hangup_cause_values_from_request_payload":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_flash_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_creates_gate_flash_call_with_documented_ringTimeout_payload":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_polls_flash_call_and_succeeds_once_accepted":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_flash_gate_flow_when_terminal_failure_status_is_returned":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_does_not_fallback_to_regular_gate_call_when_flash_succeeds":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_fails":8,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_property_gate_lane_commands_and_sanitized_gate_failure_responses":1,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_returns_raw_payload_for_malformed_JSON_responses_and_null_for_empty_responses":8,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_keeps_Bird_number_and_webhook_routes_intact":7,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_handles_malformed_and_empty_response_bodies_without_throwing_transport_errors":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_multi_department_slot_statuses_using_worst_severity_and_unknown_fallback_rules":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_relay_is_online__then_turns_off_cleaner_and_machine_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_bills_primary_product_when_selector_relay_is_online_even_if_relay_output_is_off":7,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_all_Bird_voice_call_parity_endpoints_including_gather_recordings_insights_and_log":1,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_flash_hangup_endpoint_and_marks_end_alias_as_deprecated":1,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_defines_request_and_response_schemas_for_Bird_call_command_recording_insight_log_and_flash_payloads":1,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_collected_invoice_queue_endpoints_in_orderInvoicesRoute":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_missing_queue_dependencies":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_wires_zero_cost_and_zero_quantity_skip_guard_into_transfer_line_builder":7,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_queued_transfer_jobs_to_completion":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_deduplicates_active_jobs_per_transfer_target":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_rejects_invalid_payloads_without_inserting_queue_rows":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_supports_fail_retry_and_reprocess_lifecycle_transitions":1,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_supports_synchronous_fallback_branches_before_queue_enqueue_on_economic_invoice_export_routes":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_status_endpoints_guarded_while_collected_invoice_export_routes_support_synchronous_fallback":7,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_supports_independent_po__number_and_closed__at_updates_for_PUT__collected_invoices_in_user_route":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_returns_pagination_metadata_and_strict_status_handling_for_collected_invoice_queue_list":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_enforces_retry_constraints_for_collected_invoice_queue_jobs_before_retry_execution":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_collected_queue_list_metadata_and_strict_status_filter_enum_in_openapi":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_builds_a_completed_collected_invoice_queue_summary_from_payload_and_result":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_prefers_queue_error_messages_for_failed_jobs_and_keeps_null_safe_outcome_fields":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_uses_deterministic_status_message_fallback_when_no_explicit_message_exists":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_handles_object_payload_result_values_and_malformed_fields_without_throwing":8,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_collected_invoice_transfer_queue_from_queue_list_and_status_routes":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_order_transfer_queue_from_draft_and_invoice_status_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_PHP_agent_artifacts_and_management_polling_config":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__and_operation_endpoints_without_shell_transport_wiring":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_relay_fallback_and_transport_health_details_without_shell_or_update_runtime_state":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_the_source_tree_layout":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_mounted_and_baked_in_artifact_directories_before_repo_fallbacks":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_router_resources_before_mounted_and_baked_in_artifact_directories":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_orders_for_an_admin_scoped_user_and_limits_the_results_to_the_permitted_departments":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_only_the_targeted_customer_orders_for_subuser_sessions":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_returns_the_current_auth_and_permission_failures_when_order_listing_is_not_allowed":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_creates_orders_through_the_real_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_creation_requests":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_primary_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_reassigns_invoice_collections_when_changing_an_order_across_the_draft_customer_boundary":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_primary_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_primary_order_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_legacy_alias_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_alias_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_legacy_alias_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_unsupported_legacy_field_value_updates_on_both_update_endpoints":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_deletes_orders_through_the_real_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_delete_requests":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_when_certificate_metadata_changes_through_the_primary_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_for_legacy_field_value_updates_through_the_alias_endpoint":8,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_every_selected_API_operation_covered_by_happy_path_and_failure_tests":8,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_the_OpenAPI_manifest_entries_aligned_with_the_API_spec":8,"P\\Tests\\Api\\ApiFixturesCleanupTest::__pest_evaluable_it_removes_generated_customer_traces_during_fixture_cleanup":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_in_with_valid_customer_credentials":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_login_payloads_and_credentials":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_returns_the_cached_auth_session_payload_for_a_valid_token":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_includes_economic_runtime_config_for_uncached_auth_sessions":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_auth_session_tokens":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_the_token_for_future_session_calls":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_cached_subuser_sessions":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_logout_tokens":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_the_raw_202_gather_webhook_contract_over_HTTP":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_still_prompts_for_department_selection_when_only_one_department_is_eligible":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_accepts_the_legacy_initial_webhook_body_with_top_level_call_identifiers":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_native_flow_gather_data_after_a_top_level_department_selection_when_distinct_gate_choices_exist":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_opens_the_gate_immediately_after_a_top_level_department_selection_when_entrance_and_exit_share_the_same_gate":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_uses_a_multi_digit_gather_contract_when_10_departments_are_eligible":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_a_raw_400_transport_error_for_malformed_webhook_payloads":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_only_visible_departments_and_can_return_a_single_department_with_the_slack_webhook":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_department_listing_when_the_permission_is_missing":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_creates_departments_through_the_real_endpoint":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_create_requests":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_updates_departments_through_the_real_endpoint":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_update_requests":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_department_categories_for_a_department":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_category_requests":8,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_lists_the_draft_customer_config_entry_in_economic_config_responses":8,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_draft_customer_config_value_through_economic_config_updates":8,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_order_draft_exports_for_the_configured_draft_customer":8,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_booked_invoice_exports_for_the_configured_draft_customer":8,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_collected_invoice_exports_for_the_configured_draft_customer":8,"P\\Tests\\Api\\PingApiTest::__pest_evaluable_it_returns_the_ping_contract":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_department_terminal_readers_are_requested_without_terminal_setup":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_sends_a_Stripe_invoice_by_email_and_persists_the_hosted_invoice_association":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_conflict_when_a_Stripe_hosted_invoice_is_already_active_for_the_order":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_allows_sending_a_new_Stripe_hosted_invoice_when_the_existing_association_is_already_terminal":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_voids_an_unpaid_Stripe_hosted_invoice_and_clears_the_local_order_association":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_refuses_to_cancel_a_paid_Stripe_hosted_invoice":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_creating_a_payment_intent_for_a_department_without_terminal_setup":8,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_the_newest_vehicle_last__order__id_that_still_has_order_items":8,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_a_null_vehicle_last__order__id_when_no_order_with_items_exists":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_syncs_gateway_snapshots_into_cached_list_payloads_and_refreshes_fleet_usage":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_keeps_only_the_module_facade_in_the_global_classes_directory_and_conditionally_loads_module_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_compose_edge_gateway_artifacts_and_forwarded_https_scheme":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_compose_stack_artifacts_and_management_polling_config":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__cancel_endpoints__and_operation_endpoints_without_shell_transport_wiring":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_v2_operator_facing_edge_gateway_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_defines_the_v2_edge_gateway_schema_bootstrap_tables":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_stores_operation_metadata_and_event_timelines_for_management_workflows":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured":8,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_returns_the_updated_lane_id_after_editing_a_scanner_whose_null_lane_was_already_cached":8,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_serves_installer_artifacts_and_recovers_gateway_runtime_status_after_fresh_heartbeats":8,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_polls_operations_and_commands__submits_results__and_records_broker_presence_for_task_pages":8,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_builds_broker_backlog_and_completes_gateway_operations_through_broker_endpoints":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_creates_install_tokens__tracks_installer_status__and_exposes_claimed_gateway_detail_to_authorized_operators":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_manages_edge_gateway_metadata__bindings__operations__sessions__rotation__cutover__and_deletion":8,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_assembles_tasks__logs__statistics__operations__commands__and_shell_lifecycle_state_from_persisted_records":1,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_invalid_edge_broker_shared_secrets":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_rejects_operator_edge_routes_when_module_permission_or_department_access_is_missing":8,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_rejects_missing_and_invalid_edge_agent_tokens":8,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_persists_gateway_cutover_relay_bindings_used_by_self_serve_Shelly_dispatch":1,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_validates_broker_sessions_and_ingests_presence__telemetry__logs__and_shell_lifecycle_data":8,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_shell_session_creation_while_broker_presence_is_unavailable":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_ignores_and_soft_deletes_edge_gateways_whose_department_no_longer_exists":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_appends_forwarded_ports_when_the_forwarded_host_omits_them":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_websocket_broker_urls_on_the_traefik_broker_path":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_localhost_websocket_broker_urls_on_the_local_traefik_api_prefix":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_keeps_root_host_api_urls_unprefixed_when_the_request_is_not_under_the_local_api_alias":8,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_resolves_simulator_gateway_service_bindings_from_lane_relay_slots":7,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_overtime_minutes_when_a_saved_shift_end_extends_past_the_approved_original_end":7,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_unapproved_overtime_from_a_bounded_shift_updateTime_fallback":7,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_caps_current_slot_hours_to_elapsed_minutes_and_zeroes_future_slots":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_default_distribution_department_config_value_through_economic_config_updates":8,"P\\Tests\\Unit\\Replication\\ReplicationSecretBoxTest::__pest_evaluable_it_encrypts_replication_secrets_without_storing_plaintext":8,"P\\Tests\\Unit\\Replication\\ReplicationSecretBoxTest::__pest_evaluable_it_builds_active_database_and_redis_config_from_encrypted_bootstrap_snapshots":8,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_does_not_require_replica_SQL_threads_before_database_provisioning_configures_them":7,"P\\Tests\\Unit\\Invoicing\\EconomicDraftCustomerOpenApiSpecTest::__pest_evaluable_it_documents_transaction_draft_customer_config_and_auth_runtime_fields_in_all_tracked_openapi_copies":1,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_computes_MinIO_free_space_and_catch_up_math_safely":7,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_counts_complaint_rows_by_department_and_created__at_reporting_range":1,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_updates_and_deletes_complaint_rows":1,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_parses_created__by__name_from_the_users_table":1,"P\\Tests\\Integration\\DailyReports\\DepartmentOutsideHoursStatisticsServiceIntegrationTest::__pest_evaluable_it_integrates_orders__xlvask__and_self_serve_into_one_outside_hours_summary_with_missing_hours_diagnostics":1,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_persists_install_session_updates_and_derives_gateway_runtime_status_from_heartbeats":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_only_collected_invoice_jobs_and_respects_the_manual_batch_limit":1,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_the_configured_database_in_integration_mode":1,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_redis_in_integration_mode_when_configured":1,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_minio_in_integration_mode_when_configured":1,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_creates_Coolify_service_payloads_from_raw_compose_without_a_service_type":7,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_uses_the_selected_Coolify_project_and_resolves_server_UUID_from_the_instance_default":8,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_creates_Coolify_GitHub_App_application_payloads_so_pulls_use_the_app_token":7,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_uses_the_self_contained_Coolify_API_Dockerfile_for_API_applications":7,"P\\Tests\\Unit\\Tooling\\ComposerEntrypointTest::__pest_evaluable_it_checks_PSR_HTTP_message_interfaces_before_trusting_a_Composer_vendor_tree":7,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_defines_release_manager_schema__routes__permissions__and_system_status_integration_hooks":7,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_requires_non_default_release_channel_runtime_URLs_and_preserves_load_balancer_paths":7,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_wires_MinIO_replication_through_routes_and_bootstrap_snapshots":7,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_defines_Coolify_schema__route_permissions__and_replication_integration_hooks":7,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_chooses_a_requested_runtime_channel_only_when_it_is_available_to_the_principal":8,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_rejects_standalone_order_booking_completion_outside_POS":8,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_allows_linked_POS_order_booking_completion_for_mobile_POS_compatibility":8,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_accepts_numeric_safety_seal_strings_when_completing_a_linked_POS_order_booking":8,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_disables_the_legacy_complete_wash_without_certificate_route":8,"P\\Tests\\Api\\OrderBookingsUpdateApiTest::__pest_evaluable_it_detaches_an_order_booking_and_clears_the_matching_order_link":8,"P\\Tests\\Api\\OrderBookingsUpdateApiTest::__pest_evaluable_it_keeps_the_linked_order_when_order__id_is_omitted_from_an_order_booking_update":8,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_allows_explicit_runtime_selection_of_any_enabled_release_channel":7,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_requires_authentication_before_checking_in_progress_wash_permissions":8,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_reports_both_elevated_and_customer_self_serve_permissions_when_lane_polling_is_not_allowed":8,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_allows_customer_self_serve_permission_to_view_their_own_in_progress_wash_details":8,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_redacts_another_customers_in_progress_wash_from_customer_self_serve_lane_polling":8,"P\\Tests\\Api\\SelfserveFixtureApiTest::__pest_evaluable_it_creates_a_comprehensive_self_serve_API_scenario_with_demo_relays":8,"P\\Tests\\Api\\SelfserveZZZShellyGuardApiTest::__pest_evaluable_it_did_not_record_any_real_Shelly_request_attempts_during_self_serve_API_tests":8,"P\\Tests\\Api\\ApiFixturesCleanupTest::__pest_evaluable_it_restores_preserved_module_config_rows_during_fixture_cleanup":8,"P\\Tests\\Api\\BrandingApiTest::__pest_evaluable_it_creates_lists_and_updates_complete_branding_values":8,"P\\Tests\\Api\\BrandingApiTest::__pest_evaluable_it_rejects_branding_requests_without_permissions_or_valid_input":8,"P\\Tests\\Api\\BrandingApiTest::__pest_evaluable_it_assigns_and_clears_department_branding_for_superusers":8,"P\\Tests\\Api\\BrandingApiTest::__pest_evaluable_it_rejects_invalid_department_branding_assignments":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_previews_monthly_split_changes_without_moving_orders_or_creating_collections":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_splits_a_selected_March_and_April_collected_invoice_into_monthly_collections":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_sets_closed__at_to_month_end_when_split_month_has_ended":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_splits_the_whole_affected_collection_even_when_only_one_month_is_selected":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_does_not_affect_booked_collected_invoices":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_skips_draft_linked__Stripe__and_single_month_collections":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_rejects_invalid_monthly_split_date_ranges":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_allows_superusers_to_filter_archived_departments":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_does_not_allow_regular_department_listings_to_reveal_archived_departments_through_filters":8,"P\\Tests\\Api\\EdgeGatewayConfigApiTest::__pest_evaluable_it_stores_broker_settings_in_edge_gateway_module_config_and_uses_them_for_shell_sessions":8,"P\\Tests\\Api\\EdgeGatewayConfigApiTest::__pest_evaluable_it_returns_broker_diagnostics_for_the_current_edge_gateway_module_config_values":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_defaults_order_PO_from_a_linked_booking_when_creating_without_an_order_PO":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_keeps_an_explicit_order_PO_when_creating_a_linked_order":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_defaults_blank_order_PO_from_a_linked_booking_on_order_updates":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_requires_explicit_confirmation_before_deleting_protected_orders":8,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_rejects_plate_scanner_edits_when_the_permission_is_missing":8,"P\\Tests\\Api\\ReferenceSuggestionsApiTest::__pest_evaluable_it_returns_ranked_POS_reference_suggestions_from_bookings__orders__and_customer_vehicles":8,"P\\Tests\\Api\\ReferenceSuggestionsApiTest::__pest_evaluable_it_orders_reference_suggestions_by_match_relevance_before_context_and_frequency":8,"P\\Tests\\Api\\ReferenceSuggestionsApiTest::__pest_evaluable_it_enforces_authentication__list_permission__and_department_access_for_reference_suggestions":8},"times":{"P\\Tests\\Unit\\Auth\\CreateTokenTest::__pest_evaluable_it_creates_a_64_char_auth_token_for_an_existing_user":0.11,"P\\Tests\\Unit\\Auth\\CreateTokenTest::__pest_evaluable_it_throws_a_clear_exception_when_customer_user_is_missing":0.017,"P\\Tests\\Unit\\Auth\\LegacyAuthScriptParityTest::__pest_evaluable_it_keeps_passkey_challenge_legacy_script_green_during_migration":0.032,"P\\Tests\\Unit\\Auth\\LegacyAuthScriptParityTest::__pest_evaluable_it_keeps_register_CVR_legacy_script_green_during_migration":0.035,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_deterministic_department_digit_map_and_caps_to_9_options":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_resolves_department_ids_by_selected_digit":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_resolves_gate_type_digit_to_entrance_or_exit":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_stores__loads_and_clears_ivr_state_with_ttl":0.001,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_validates_state_caller_fingerprint_matching":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_department_and_gate_prompts":0,"P\\Tests\\Unit\\Permissions\\PermissionNodeDefinitionTest::__pest_evaluable_it_creates_permission_nodes_linked_to_subuser_permission_keys":0,"P\\Tests\\Unit\\Permissions\\PermissionNodeDefinitionTest::__pest_evaluable_it_rejects_empty_permission_definitions":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_normalizes_button_arrays__json_and_csv_inputs":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_invalid_button_inputs":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_normalizes_vehicle_type_values_and_null_semantics":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_invalid_vehicle_type_values":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_non_numeric_vehicle_type_strings":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_keeps_lane_service_enum_contract_for_MACHINE":0,"P\\Tests\\Unit\\Subusers\\SubuserGrantInitializationTest::__pest_evaluable_it_initializes_booking_node_grants_without_DB_dependency":0,"P\\Tests\\Unit\\Subusers\\SubuserGrantInitializationTest::__pest_evaluable_it_initializes_selfserve_node_grants_without_DB_dependency":0,"P\\Tests\\Unit\\Subusers\\SubusersRoutePermissionLinkTest::__pest_evaluable_it_keeps_subusers_route_list_permission_linked_to_SUBUSERS__LIST_node":0.009,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_keeps_route_and_service_entity_type_registries_in_sync_with_expanded_coverage":0,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_documents_every_supported_search_entity_type_in_openapi_enum":0.047,"P\\Tests\\Unit\\Search\\SystemSearchEconomicCustomerIndexWiringTest::__pest_evaluable_it_wires_local_e_conomic_customer_index_into_customer_related_search_entities":0.016,"P\\Tests\\Unit\\Search\\SystemSearchEconomicCustomerIndexWiringTest::__pest_evaluable_it_registers_cron_tasks_that_keep_the_e_conomic_search_index_refreshed":0.018,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_from_generic_db_object_mutation_flows":0.052,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_from_object_property_mutations":0.01,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_when_module_config_values_change":0.008,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_registers_cron_maintenance_task_for_system_search_cache":0.075,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_redacts_obvious_sensitive_fragments_before_sending_query_to_intent_parser":0.001,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_builds_payload_with_redacted_query_and_parses_strict_JSON_output":0.001,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_falls_back_safely_when_OpenAI_is_disabled":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_handles_malformed_OpenAI_response_payloads_without_throwing":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_uses_parser_cache_for_identical_query_and_allowed_type_combinations":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_caps_alias_and_hint_payloads_from_OpenAI_and_filters_hints_to_allowed_types":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_system_wide_search_endpoints_in_openapi":0.106,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_debug__intent_and_parser_metadata_schema_in_openapi":0.035,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_e_conomic_indexed_customer_matching_and_synonym_behavior":0.022,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_normalizes_type_lists_from_csv_json_and_arrays":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_parses_booleans_and_clamps_integers_using_route_defaults":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_exposes_expected_searchable_entity_types":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_registers_system_wide_search_GET_and_POST_endpoints_with_intent_debug_support":0.028,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_registers_superuser_cache_clear_and_rebuild_endpoints_for_system_search":0.031,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_passes_permission_and_own_scope_context_into_system_search_service":0.008,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_does_not_invoke_intent_parser_when_lexical_confidence_is_already_high":0.001,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_invokes_parser_on_low_confidence_lexical_results_and_applies_hints_only_boosts":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_never_lets_parser_entity_hints_override_explicit_include_filters":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_returns_fallback_parser_metadata_when_parser_fails_gracefully":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_scopes_query_cache_by_permission_context_to_avoid_cross_user_cache_leakage":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_caps_AI_driven_expanded_terms_to_prevent_query_amplification":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_expands_danish_discount_wording_into_lexical_discount_synonyms":0.003,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_invokes_parser_for_intent_driven_natural_language_queries_even_when_lexical_score_is_high":0.003,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_uses_association_hints_to_pull_related_customer_records_from_non_customer_matches":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_prefers_newer_records_when_relevance_scores_are_comparable":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_keeps_explicit_identifier_matches_ahead_of_newer_but_weaker_records":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_promotes_invoices_orders_order_bookings_and_customers_in_ranking":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_never_prioritizes_cancelled_bookings_over_active_bookings":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_heavily_demotes_configured_low_priority_entity_types_in_ranking":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_tokenizes_unicode_names_without_stripping_non_ascii_letters":0.001,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_does_not_treat_explicit_identifier_queries_as_intent_driven":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_requires_broader_term_coverage_for_multi_word_scoring":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_enriches_object_attachment_results_with_associated_customer_context":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_includes_the_economic_customer_index_in_cache_dependencies_for_customer_scoped_results":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_falls_back_to_invoice_date_ranges_when_invoice_names_are_missing":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_derives_xlvask_customer_numbers_only_from_digits_only_extern_ids":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_replaces_unnamed_user_titles_with_the_customer_context_name":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_uses_the_goal_criteria_label_for_department_goal_titles":0,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_reuses_parser_cache_entries_for_repeated_natural_language_intent_requests":0.129,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_clears_parser_cache_namespace_via_clearAll_to_force_a_fresh_parse":0,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_bumps_per_table_cache_versions_when_a_dirty_table_marker_is_registered":0.05,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_fixed_pricing_when_regular_orders_yield_no_customers":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_wash_subscriptions_when_regular_orders_yield_no_customers":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CliBackfillCommandTest::__pest_evaluable_it_registers_economic_v2_backfill_command_in_cli_dispatcher":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicV2CliBackfillCommandTest::__pest_evaluable_it_provides_a_backfill_cron_script_entrypoint":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_exact__match_when_totals_lines_and_departments_are_identical":0.001,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_total__mismatch_when_only_totals_differ":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_detects_line_level_mismatches_for_quantity_and_price":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_detects_departmental_distribution_mismatches":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_missing__target_when_draft_or_booked_target_is_unavailable":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_normalizes_draft_invoice_lines_including_departmental_distributions":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_marks_text_only_zero_value_lines_as_non_billable_and_keeps_deterministic_key":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_normalizes_booked_invoices_and_computes_net_total_delta_from_lines":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_contains_internal_normalization_path_with_departmental_metadata_support":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_economic_v2_invoice_paths_in_openapi":0.016,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_v2_historical_distribution_and_pricing_history_paths_in_openapi":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_aligns_legacy_compare_schema_with_runtime_payload_by_removing_stale_required_order__ids":0.012,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_defines_new_reusable_v2_schemas_for_normalization_comparison_versioning_and_distribution":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicV2RevenueAndBarredSupportTest::__pest_evaluable_it_supports_barred_filtering_when_listing_e_conomic_customers":0.08,"P\\Tests\\Unit\\Invoicing\\EconomicV2RevenueAndBarredSupportTest::__pest_evaluable_it_implements_a_dedicated_v2_e_conomic_revenue_statistics_service_and_route":0.014,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_registers_all_collected_invoice_economic_v2_routes_with_explicit_permissions":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_registers_version_aware_distribution_and_pricing_history_v2_routes":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_caches_v2_distribution_responses_with_a_configurable_redis_ttl":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_fixed_pricing_versions_from_create_and_delete_flows":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_vehicle_subscription_versions_for_create_update_delete_flows":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_discount_override_versions_from_superuser_discounts_route":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_keeps_legacy_compare_endpoint_path_for_backward_compatibility":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_implements_effective_range_lifecycle_methods_for_all_versioned_entities":0.036,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_closes_previous_active_interval_before_inserting_a_new_version":0.021,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_includes_best_effort_backfill_with_provenance_and_confidence_metadata":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_anchors_historical_resolution_on_order_created__at_timestamps_in_distribution_service":0.013,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_guards_against_empty_order_ids_in_net_amount_calculation":0.081,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_guards_against_empty_customer_arrays_in_date_range_transaction_fetches":0.074,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_uses_centralized_duplicate_filtering_for_possible_duplicate_detection":0.081,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_builds_deterministic_cache_keys_per_scope_and_date_range":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_falls_back_to_resolver_directly_when_cache_ttl_is_disabled":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_requires_superuser_permission_for_invoicing_period_distribution_all_endpoint":0.05,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_uses_shared_date_range_normalization_across_invoicing_period_endpoints":0.705,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_normalizes_a_valid_invoicing_date_range_to_full_day_timestamps":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_rejects_invalid_date_formats":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_rejects_descending_date_ranges":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_finds_duplicate_orders_regardless_of_original_input_order":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_runs_best_effort_backfill_when_fixed_pricing_version_history_is_empty":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_self_serve_conditions_with_combined_AND_and_OR_semantics":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_prefers_condition_results_over_question_answers_when_evaluating_task_gates":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_type__eligibility__summary__and_webhook_endpoints":0.008,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_defines_reusable_self_serve_wash_and_machine_type_schemas":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_machine_types__eligibility__summaries__and_machine_start_webhook_routes":0.012,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_machine_type_support_wired_into_lanes__tasks__and_conditions_routes":0.014,"P\\Tests\\Unit\\N8n\\N8nRouteHelpersTest::__pest_evaluable_it_normalizes_webhook_methods_and_falls_back_to_POST_for_unsupported_verbs":0,"P\\Tests\\Unit\\N8n\\N8nRouteHelpersTest::__pest_evaluable_it_filters_request_parameters_down_to_the_allowed_n8n_query_keys":0,"P\\Tests\\Unit\\N8n\\N8nRouteWiringTest::__pest_evaluable_it_registers_workflow_lifecycle_endpoints_for_the_n8n_module":0.182,"P\\Tests\\Unit\\N8n\\N8nRouteWiringTest::__pest_evaluable_it_registers_execution_and_webhook_trigger_endpoints_for_the_n8n_module":0.115,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_redistributes_booked_department_75_net_amounts_using_fixed_pricing_and_wash_subscription_weights":0.001,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_classified_booked_department_75_amounts_undistributed_when_no_monthly_basis_exists":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_unclassified_booked_department_75_lines_undistributed_with_warnings":0,"P\\Tests\\Unit\\Invoicing\\EconomicEndpointUrlEncodingTest::__pest_evaluable_it_encodes_raw_filter_query_values_that_include_timestamps":0,"P\\Tests\\Unit\\Invoicing\\EconomicEndpointUrlEncodingTest::__pest_evaluable_it_avoids_double_encoding_query_values_that_are_already_escaped":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_supports_bulk_booked_invoice_line_payloads_with_top_level_department_numbers":0,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_claims_a_slot_atomically_with_nx_and_expiration":0,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_returns_false_when_the_slot_is_already_claimed_and_clamps_ttl_to_one_second":0,"P\\Tests\\Unit\\Bookings\\OrderBookingRouteIdempotencyGuardTest::__pest_evaluable_it_guards_order_booking_creation_with_redis_backed_idempotency":0.101,"P\\Tests\\Unit\\DynamicImages\\DynamicImagePreRenderCronWiringTest::__pest_evaluable_it_registers_dynamic_image_pre_render_cron_task_and_related_helpers":0.01,"P\\Tests\\Integration\\Database\\DbConnectionTest::__pest_evaluable_it_can_connect_to_a_configured_MySQL_instance_in_integration_mode":0.016,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_runs_best_effort_backfill_repeatedly_without_introducing_duplicate_same_start_rows":0.013,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_resolves_version_aware_distribution_payload_shapes_over_a_real_date_range":0.016,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_creates_closes_and_rotates_fixed_pricing_versions_without_overlap":0.015,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_tracks_vehicle_and_discount_version_lifecycles_with_closure_semantics":0.014,"P\\Tests\\Integration\\Permissions\\LegacyPermissionRedisCacheScriptTest::__pest_evaluable_it_keeps_legacy_route_permission_redis_cache_script_green":0.01,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_returns_both_own_and_elevated_permissions_when_both_are_missing":0,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_returns_only_elevated_permission_when_own_permission_exists_but_own_context_fails":0,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_allows_elevated_permission_path_without_forbidden_and_validates_department_access":0,"P\\Tests\\Unit\\Permissions\\ForbiddenResponseWiringTest::__pest_evaluable_it_routes_and_trait_use_forbidden_responses_for_permission_and_ownership_denials":0.19,"P\\Tests\\Unit\\Permissions\\GroupPermissionSessionInvalidationWiringTest::__pest_evaluable_it_invalidates_related_user_permission_and_auth_session_caches_when_group_permissions_change":0.064,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_parses_advanced_target_duration_from_snake__case_fields":0.36,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_parses_advanced_target_duration_from_camelCase_aliases":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_normalizes_ENTIRE__DURATION_to_ignore_target__duration__every":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_defaults_recurring_target__duration__every_to_1_when_omitted":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_keeps_strict_legacy_mode_when_target__duration_is_invalid":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_computes_weekly_target_using_touched_ISO_weeks_for_March_2026":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_applies_target__duration__every_for_weekly_cadence":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_prorates_ENTIRE__DURATION_target_by_overlap_days":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_splits_advanced_target_by_override_weights_per_department":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_preserves_legacy_target_behavior_when_target__duration_is_missing":0,"P\\Tests\\Unit\\Goals\\GoalsLegacyRendererScriptsTest::__pest_evaluable_it_keeps_legacy_monthly_renderer_script_green":0.466,"P\\Tests\\Unit\\Goals\\GoalsLegacyRendererScriptsTest::__pest_evaluable_it_keeps_legacy_department_daily_renderer_script_green":0.879,"P\\Tests\\Unit\\Goals\\GoalsOpenApiSpecTest::__pest_evaluable_it_documents_advanced_goals_target_duration_fields_in_openapi":0.07,"P\\Tests\\Unit\\Workfeed\\WorkfeedClientConformanceTest::__pest_evaluable_it_uses_company_scoped_workfeed_endpoints_and_raw_Authorization_header":0.006,"P\\Tests\\Unit\\Workfeed\\WorkfeedClientConformanceTest::__pest_evaluable_it_normalizes_documented_shift_query_parameters":0.005,"P\\Tests\\Unit\\Workfeed\\WorkfeedConfigRouteWiringTest::__pest_evaluable_it_registers_module_config_endpoints_for_workfeed":0.007,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteHelpersTest::__pest_evaluable_it_filters_request_parameters_down_to_the_allowed_workfeed_query_keys":0.001,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteWiringTest::__pest_evaluable_it_registers_employee_and_department_endpoints_for_the_workfeed_module":0.008,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteWiringTest::__pest_evaluable_it_registers_shift_endpoints_for_the_workfeed_module":0.008,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_workfeed_employee_hours_for_the_hour_slot_based_on_overlap":0.001,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_extracts_department_id_from_supported_workfeed_shift_shapes":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_wrapped_workfeed_collections_from_common_response_keys":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_includes_a_date_key_in_department_weather_timeline_entries":0.006,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_documents_the_date_key_in_the_openapi_department_weather_timeline_schema":0.034,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_from_start_of_yesterday_to_end_of_today":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_relative_to_an_explicit_selected_date_override":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_workfeed_employee_hours_across_multiple_departments_for_one_hour_slot":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_department_id_input_from_scalar_csv_and_nested_array_values":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_relative_to_explicit_date__from_and_date__to_override":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_resolves_forecast_day_count_for_a_given_timeline_range_with_sane_limits":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_resolves_weather_coordinates_from_valid_coordinates_only":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_returns_null_weather_coordinates_when_all_department_locations_are_invalid":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_classifies_weatherapi_no_matching_location_errors_as_location_lookup_failures":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_does_not_classify_non_location_weatherapi_errors_as_location_lookup_failures":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_returns_an_empty_forecast_fallback_when_coordinates_are_unavailable":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_builds_timeline_entries_with_mostly__clear_weather_when_forecast_payload_is_empty":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_wires_departments_weather_route_through_the_forecast_fallback_path":0.007,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_builds_deterministic_cache_keys_for_department_sets_and_timeline_ranges":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_builds_order_insensitive_cache_keys_for_equivalent_department_id_sets":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_falls_back_to_resolver_directly_when_cache_ttl_is_disabled":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_marks_non_started_slots_as_unknown_regardless_of_wash_hour_ratio":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherPreloadCronWiringTest::__pest_evaluable_it_registers_and_implements_cron_preloading_for_department_weather_cache":0.012,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_stale_ttl_defaults_and_clamps_stale_ttl_below_fresh_ttl":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_hot_activity_ttl_defaults_and_clamps_to_a_positive_value":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_serves_fresh_cached_payloads_without_invoking_the_resolver":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_serves_stale_cached_payloads_and_enqueues_a_refresh_signal":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_recomputes_and_rewrites_cache_payloads_when_stale_window_is_exceeded":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_records_hot_keys_order_insensitively_and_applies_preload_target_caps":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_batched_wash_count_rows_into_hourly_slot_totals":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_wires_department_weather_route_to_use_batched_wash_aggregation":0.015,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_groups_attachments_by_object_id_and_preserves_empty_object_groups":0,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_keeps_listMany_payload_parity_with_list_for_one_object_id":0,"P\\Tests\\Unit\\Orders\\EconomicModuleOrdersBatchHelpersTest::__pest_evaluable_it_ensures_economic_module_rows_in_one_sanitized_batch":0,"P\\Tests\\Unit\\Orders\\EconomicModuleOrdersBatchHelpersTest::__pest_evaluable_it_returns_id_keyed_economic_module_payload_with_null_defaults":0,"P\\Tests\\Unit\\Orders\\OrdersRouteListBatchingWiringTest::__pest_evaluable_it_wires_GET__orders_through_batched_enrichment_and_stripe_snapshot_caching":0.116,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchTest::__pest_evaluable_it_returns_cashier_names_from_cache_and_fetches_missing_ones_in_batch":0,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchTest::__pest_evaluable_it_returns_deterministic_map_for_duplicate_and_unsorted_cashier_ids":0,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchWiringTest::__pest_evaluable_it_implements_batched_cashier_name_lookup_with_cache_first_fallback_behavior":0.141,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchWiringTest::__pest_evaluable_it_sanitizes_and_deduplicates_cashier_ids_before_batch_lookup":0.064,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_overtime_minutes_when_a_shift_carries_an_extended_approval_end_timestamp":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_unapproved_overtime_from_a_bounded_shift_updateTime_fallback":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_does_not_treat_late_unapproved_administrative_edits_as_overtime":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_changes_weather_timeline_cache_key_when_department_weather_targets_change":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_evaluates_healthy_degraded_and_unhealthy_statuses_from_configured_department_targets":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_returns_unknown_when_configured_targets_are_missing_for_department_status_evaluation":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_multi_department_slot_statuses_using_worst_severity_and_unknown_fallback_rules":0.046,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_department_weather_target_endpoints_and_reusable_schemas_in_openapi":0.008,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_unknown_weather_status_behavior_when_targets_are_missing":0.01,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsRouteWiringTest::__pest_evaluable_it_registers_department_weather_target_routes_with_explicit_read_and_manage_permissions":0.006,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsRouteWiringTest::__pest_evaluable_it_persists_department_weather_targets_using_canonical_department_variable_keys":0.005,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_machine_relay_status_get_and_set_endpoints":0.006,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_batches_sequential_machine_relay_status_requests_into_a_single_Shelly_get_call":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_1_request_per_second_Shelly_gate_for_back_to_back_requests":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_retries_missing_Shelly_status_payloads_until_relay_status_becomes_ready":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_times_out_with_a_clear_Shelly_readiness_error_when_payload_remains_missing":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_uses_direct_set_switch_and_seeds_cache_so_immediate_status_read_does_not_call_Shelly_get":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_lane_gate_open_endpoint":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_in_progress_self_serve_wash_details_endpoint":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_is_on__then_turns_off_cleaner_machine_and_selector_relays":0.132,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_is_off_and_only_disables_configured_relays":0.001,"P\\Tests\\Unit\\Selfserve\\DepartmentSelfServeEnabledRelaySyncWiringTest::__pest_evaluable_it_syncs_lane_relay_states_when_department_self_serve_enabled_flag_changes":0.034,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_supports_hard_relay_set_even_when_lane_status_is_CLOSED":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStartCleanerRelayWiringTest::__pest_evaluable_it_enables_cleaner_relay_on_wash_start_command_and_webhook_flow":0.016,"P\\Tests\\Unit\\Selfserve\\SelfserveWashCompletionRelayWiringTest::__pest_evaluable_it_forces_machine_relay_off_when_a_self_serve_wash_session_is_completed":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_exit_port_by_switching_relay__in__id_on":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_entrance_port_by_switching_relay__out__id_on":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_in_progress_self_serve_wash_start_and_machine_relay_fields":0.006,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_typed_task_gates_with_strict_semantics":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_validates_typed_task_gates_for_known_references":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_fails_validation_when_typed_task_gates_reference_unknown_entities":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_config_draft_publish_rollback_lifecycle_endpoints":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_legacy_self_serve_CRUD_routes_syncing_canonical_drafts":0.012,"P\\Tests\\Unit\\Selfserve\\SelfserveStartCleanerRelayWiringTest::__pest_evaluable_it_keeps_cleaner_relay_enable_wired_into_machine_relay_start_paths":0.01,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_stores_config_json_with_apostrophes_without_violating_json_constraints":0.277,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_encodes_config_json_payloads_with_apostrophes_before_persistence":0,"P\\Tests\\Unit\\Selfserve\\SelfserveWashCompletionRelayWiringTest::__pest_evaluable_it_forces_machine_and_cleaner_relays_off_when_a_self_serve_wash_session_is_completed":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_vehicle_type_override_into_self_serve_preview_and_synchronization_routes":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_uses_local_demo_responses_and_skips_Shelly_cloud_calls_for_demo_relay_ids":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_returns_default_OFF_status_for_demo_relay_ids_without_Shelly_lookups":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_excludes_demo_relay_ids_from_Shelly_status_batch_payloads":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_keeps_demo_relay_gate_open_queued_but_skips_Shelly_switch_calls":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_allowed_services_route_through_machine_relay_visibility_sync":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_enables_MACHINE_relay_when_MACHINE_is_visible_in_allowed_services":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_turns_MACHINE_relay_off_immediately_when_MACHINE_is_not_visible":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_does_not_enable_MACHINE_relay_when_allowEnable_is_false_even_if_MACHINE_is_visible":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_is_a_safe_no_op_when_MACHINE_relay_is_not_configured":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRelayVisibilitySyncWiringTest::__pest_evaluable_it_synchronizes_machine_relay_from_visible_services_during_session_synchronization":0.011,"P\\Tests\\Unit\\Selfserve\\SelfserveRelayVisibilitySyncWiringTest::__pest_evaluable_it_adds_explicit_relay_disable_session_helper_for_visibility_driven_OFF_transitions":0.006,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_property_gate_command_permissions":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneCommandEnumTest::__pest_evaluable_it_parses_property_gate_lane_commands":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_opens_entrance_gate_for_OPEN__PROPERTY__ACCESS__GATE_command":0.196,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_opens_exit_gate_for_OPEN__PROPERTY__EXIT__GATE_command":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_blocks_property_gate_commands_when_department_self_serve_is_disabled":0.033,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_throws_a_clear_error_when_entrance_gate_is_missing_for_property_access_command":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_wraps_low_level_gate_errors_for_property_access_command_failures":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveWashFlowMachineAllowedWiringTest::__pest_evaluable_it_reads_machine_allowed_state_from_session_summary_payload_safely":0.007,"P\\Tests\\Unit\\Selfserve\\DbObjectPaginationLegacyColumnCompatibilityTest::__pest_evaluable_it_guards_pagination_against_searchable_fields_missing_from_legacy_schemas":0.05,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_adds_dynamic__images__vehicle__type_column_for_legacy_selfserve_wash_session_task_schemas":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_billable_minutes_when_elapsed_minutes_exceed_included_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_zero_billable_minutes_when_elapsed_minutes_equal_included_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_zero_billable_minutes_when_included_minutes_exceed_elapsed_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_handles_zero_and_low_elapsed_wash_time_edge_cases":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_wash_included_minutes_in_config_schemas":0.006,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_machine_wash_included_minutes_into_self_serve_module_config":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_blocks_explicit_relay_writes_when_department_self_serve_is_disabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_returns_disabled_no_op_from_machine_relay_visibility_sync_when_department_self_serve_is_disabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_property_gate_lane_commands_and_sanitized_gate_failure_responses":0.005,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_calls":0.022,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_channel_id_is_missing_for_gate_calls":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_with_terminal_status_details_when_call_never_reaches_accepted_state":0.067,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_when_call_reaches_accepted_state":0.001,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_immediately_when_status_transitions_to_accepted":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_maps_legacy_timeout_option_to_documented_ringTimeout_payload_field":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_clamps_derived_ringTimeout_to_Bird_documented_max_when_gate_timeout_is_high":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_passes_documented_hangup_cause_when_provided":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_drops_unsupported_hangup_cause_values_from_request_payload":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_flash_calls":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_creates_gate_flash_call_with_documented_ringTimeout_payload":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_polls_flash_call_and_succeeds_once_accepted":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_flash_gate_flow_when_terminal_failure_status_is_returned":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_does_not_fallback_to_regular_gate_call_when_flash_succeeds":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_fails":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_wraps_low_level_gate_errors_for_property_exit_command_failures":0.002,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_caller_id_is_not_confirmed":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_voice_call_facade_methods_to_documented_endpoints_and_methods":0.024,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_recordings_insights_log_and_flash_methods_to_documented_resources":0.001,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_encodes_path_segments_before_building_outbound_endpoints":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_serializes_query_parameters_for_GET_transport_requests":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_4xx_and_5xx_transport_failures_into_informative_exceptions":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_returns_raw_payload_for_malformed_JSON_responses_and_null_for_empty_responses":0.007,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_all_Bird_voice_call_parity_endpoints_including_gather_recordings_insights_and_log":0.008,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_flash_hangup_endpoint_and_marks_end_alias_as_deprecated":0.006,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_defines_request_and_response_schemas_for_Bird_call_command_recording_insight_log_and_flash_payloads":0.009,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_accepts_valid_payloads_for_create_and_nested_call_flow_commands":0.002,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_rejects_unknown_fields_and_invalid_enum_values_in_strict_schemas":0.051,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_supports_CSV_normalization_in_schema_validation_for_log_filters":0,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_validates_flash_hangup_payloads_for_both_supported_request_shapes":0,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_fails_before_forward_step_when_strict_validation_fails_and_forwards_when_valid":0,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_registers_full_Bird_voice_call_route_surface_with_strict_validation_and_permissions":0.04,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_registers_flash_hangup_endpoint_and_keeps_end_alias_wired_as_compatibility_path":0.033,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_keeps_Bird_number_and_webhook_routes_intact":0.063,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_handles_malformed_and_empty_response_bodies_without_throwing_transport_errors":0.005,"P\\Tests\\Unit\\Selfserve\\DepartmentGatesRelaysRouteWiringTest::__pest_evaluable_it_validates_department_gate_config_on_both_create_and_update_routes":0.059,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_adds_wash__started__at_column_for_legacy_selfserve_wash_session_schemas":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_stores_wash__started__at_in_self_serve_wash_sessions_when_machine_start_is_triggered":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_passes_lane_wash_start_time_into_the_session_machine_start_marker":0.01,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_resolves_in_progress_wash__started__at_from_session_with_compatibility_fallbacks":0.004,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_say_payload_and_applies_hangup_default":0.596,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_log_query_csv_and_integer_fields":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_nested_create_call_payload_sections_and_drops_unknown_keys":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_keeps_gather_nested_say_payload_unchanged_when_hangup_is_omitted":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_supports_no_body_and_flash_hangup_payload_normalization":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_2_second_Shelly_gate_for_back_to_back_requests":0.023,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_enforces_a_2_second_gap_between_sequential_switch_requests_used_by_wash_start_and_stop_flows":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_keeps_back_to_back_get_switch_requests_ordered_through_the_relay_controller":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_executes_sequential_switch_requests_used_by_wash_start_and_stop_flows":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_does_not_print_Shelly_switch_responses_to_output":0,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitWiringTest::__pest_evaluable_it_enforces_a_global_2_second_Shelly_gate_in_sendPostRequest":0.006,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitWiringTest::__pest_evaluable_it_uses_Redis_NX_PX_semantics_for_cross_request_Shelly_rate_limiting":0.006,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitBehaviorTest::__pest_evaluable_it_enforces_the_2_second_Shelly_gate_across_separate_request_contexts":0,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitBehaviorTest::__pest_evaluable_it_does_not_delay_when_the_Shelly_gate_is_already_expired":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_relay_is_online__then_turns_off_cleaner_and_machine_relays":0.62,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_relay_is_offline_and_only_disables_configured_relays":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_bills_primary_product_when_selector_relay_is_online_even_if_relay_output_is_off":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceModeBillingTest::__pest_evaluable_it_bills_manual_self_serve_stop_using_full_elapsed_minutes_without_included_minute_reduction":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceModeBillingTest::__pest_evaluable_it_keeps_included_minute_reduction_for_automatic_mode":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_on_first_dtmf_input_captured_within_the_300_second_window":0.005,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_does_not_send_Slack_when_dtmf_input_repeats_without_change":0.008,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_again_when_dtmf_input_changes_within_the_window":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_gathering_and_does_not_hang_up_before_300_seconds_have_elapsed":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_announces_timeout_waits_10_seconds_and_sends_hangup_once_at_or_after_300_seconds":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_polling_until_terminal_status_and_only_then_finalizes":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_finalizes_immediately_when_webhook_payload_is_already_terminal_before_timeout_logic":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_does_not_duplicate_timeout_or_hangup_actions_across_retries_and_lock_contention":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_state_when_polling_fails_so_completion_is_not_falsely_reported":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_dtmf_input_repeats_without_change":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_answers_immediately_once_and_does_not_re_answer_on_subsequent_webhook_retries":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_configures_gather_with_retry_loop_semantics_until_input_is_entered":0.004,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_gather_result_provides_keys_field_instead_of_dtmf":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_gather_conditions_variable_keys_carries_the_entered_value":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_configures_gather_to_check_every_2_seconds_with_retry_loop_semantics_until_input_is_entered":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_ignores_non_numeric_customer__number_values_from_request":0.042,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_casts_numeric_customer__number_strings_to_int_before_lookup":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_prefers_user__id_when_both_user__id_and_customer__number_are_valid":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_falls_back_to_customer__number_when_user__id_is_invalid":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_normalizes_request_identifiers_before_user_lookups":0.005,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_rejects_non_positive_and_non_digit_request_values":0.003,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_pagination_results_when_present":0.006,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_falls_back_to_collection_count_when_pagination_metadata_is_missing":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_returns_zero_when_neither_pagination_nor_collection_is_available":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_counts_object_based_collections_when_pagination_metadata_is_missing":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_uses_collection_when_present":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_falls_back_to_paymentTerms_when_collection_is_missing":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_supports_top_level_array_payloads":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_returns_an_empty_array_when_no_known_collection_shape_exists":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_uses_grant__2_in_economic__endpoint__t_when_explicitly_requested_and_configured":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_falls_back_to_grant__1_in_economic__endpoint__t_when_grant__2_is_missing":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_required_primary_grant_in_economic__endpoint__t":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_app_secret_in_economic__endpoint__t":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_uses_grant__2_in_legacy_economic__m_when_available":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_falls_back_to_grant__1_in_legacy_economic__m_when_grant__2_is_missing":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_required_primary_grant_in_legacy_economic__m":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_app_secret_in_legacy_economic__m":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_unfiltered_total_when_no_customer_filters_are_active":0.004,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_filtered_total_when_search_is_active":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_filtered_total_when_barred_filter_is_active":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_treats__null__search_and_barred_values_as_no_filter":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_falls_back_to_filtered_total_when_unfiltered_total_is_missing":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_maps_e_conomic_integration_failures_in_customer_listing_to_explicit_502_responses":0.007,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_logs_LIST__CUSTOMERS_success_only_after_pagination_and_customer_mapping_are_completed":0.005,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_guards_against_malformed_customer_list_payloads_before_calling_paginate":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_deterministic_upstream_exceptions_for_non_2xx_endpoint_trait_responses":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_deterministic_upstream_exceptions_for_non_2xx_legacy_economic__m_responses":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_returns_raw_payload_unchanged_on_successful_HTTP_statuses":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_accepts_valid_list_payloads_that_include_collection_and_pagination_results":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_throws_when_pagination_is_missing_from_the_response_payload":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_throws_when_upstream_responds_with_an_error_shaped_payload":0,"P\\Tests\\Unit\\Router\\RouterThrowableHandlingTest::__pest_evaluable_it_catches_throwables_during_auto_route_loading_and_maps_them_to_internal_server_errors":0.039,"P\\Tests\\Unit\\Users\\EconomicCustomerZeroHandlingTest::__pest_evaluable_it_does_not_request_e_conomic_customer_data_when_customer_number_is_zero":0.004,"P\\Tests\\Unit\\Users\\EconomicCustomerZeroHandlingTest::__pest_evaluable_it_short_circuits_e_conomic_customer_lookup_for_non_positive_customer_numbers":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_queued_economic_invoice_endpoints_in_economicInvoiceRoute":0.013,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_collected_invoice_queue_endpoints_in_orderInvoicesRoute":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueSchemaBootstrapTest::__pest_evaluable_it_defines_economic_transfer_queue_jobs_schema_bootstrap_table_and_tracking_columns":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueSchemaBootstrapTest::__pest_evaluable_it_provides_queue_processor_class_constants_and_processing_entrypoint":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueCronIntegrationTest::__pest_evaluable_it_registers_economic_transfer_queue_cron_task_and_handler":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_economic_transfer_queue_paths_in_openapi":0.013,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_economic_transfer_queue_schemas_in_openapi":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_order_items_with_zero_quantity_for_e_conomic_export":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_order_items_with_zero_price_for_e_conomic_export":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_keeps_positive_quantity_and_price_items_billable_for_e_conomic_export":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_wires_zero_cost_and_zero_quantity_skip_guard_into_transfer_line_builder":0.048,"P\\Tests\\Unit\\Invoicing\\EconomicInvoiceDraftZeroItemSkipWiringTest::__pest_evaluable_it_skips_zero_cost_and_zero_quantity_items_in_legacy_economic_draft_helper":0.023,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_malformed_order_item_payloads_for_e_conomic_export_safety":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueHardeningTest::__pest_evaluable_it_hardens_transfer_queue_with_type_validation_retry_caps_and_stale_lock_recovery":0.043,"P\\Tests\\Unit\\Router\\AutoloadRedisCacheValidationTest::__pest_evaluable_it_validates_cached_autoload_paths_before_returning_and_clears_stale_cache_entries":0.008,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_applies_created__at_bounds_directly_in_SQL_when_filtering_orders_by_registration_number":0.001,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_rejects_an_inverted_date_range_for_registration_lookups":0,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_returns_early_when_registration_number_is_blank":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueCronIntegrationTest::__pest_evaluable_it_wires_queue_worker_class_loading_for_CLI_queue_action":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_all_economic_invoice_queue_endpoints_before_constructing_queue_service":0.012,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_all_collected_invoice_queue_endpoints_before_constructing_queue_service":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_missing_queue_dependencies":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_gracefully_handles_unavailable_queue_dependencies_on_collected_invoice_queue_endpoints":0.005,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_returns_the_queue_job_id_in_POST__collected_invoices_economic_enqueue_response":0.204,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_requires_id_and_at_least_one_mutable_field_for_PUT__collected_invoices_in_user_route":0.019,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_supports_independent_po__number_and_closed__at_updates_for_PUT__collected_invoices_in_user_route":0.008,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_returns_queued_contract_for_POST__collected_invoices_stripe_book":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_keeps_order_draft_export_route_queue_only":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_keeps_collected_invoice_draft_producing_routes_queue_only_in_orderInvoicesRoute":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_collected_invoice_and_stripe_draft_producing_endpoints_before_constructing_queue_service":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_unavailable_queue_dependency_responses_for_async_economic_transfer_endpoints":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_normalizes_order_payloads_to_strict_positive_integer_ids":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_normalizes_collected_invoice_payload_booleans_to_strict_bool_values":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_rejects_invalid_transfer_payloads_before_enqueue_write_attempts":0,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_queued_transfer_jobs_to_completion":0.016,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_deduplicates_active_jobs_per_transfer_target":0.016,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_rejects_invalid_payloads_without_inserting_queue_rows":0.013,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_supports_fail_retry_and_reprocess_lifecycle_transitions":0.014,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_guards_on_economic_invoice_queue_status_and_retry_routes":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_supports_synchronous_fallback_branches_before_queue_enqueue_on_economic_invoice_export_routes":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_status_endpoints_guarded_while_collected_invoice_export_routes_support_synchronous_fallback":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_queue_status_lifecycle_endpoints":0.057,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_supports_synchronous_fallback_and_queued_processing_for_order_draft_export_route":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_supports_synchronous_fallback_and_queued_processing_for_collected_invoice_draft_producing_routes":0.006,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_documents_both_synchronous_fallback_and_queued_response_contracts_for_POST__collected_invoices_economic":0.165,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_documents_both_synchronous_fallback_and_queued_response_contracts_for_POST__collected_invoices_stripe_book":0.018,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_200_fallback_plus_202_queue_contracts_for_export_endpoints_and_keeps_503_on_queue_lifecycle_endpoints":0.009,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_returns_pagination_metadata_and_strict_status_handling_for_collected_invoice_queue_list":0.006,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_enforces_retry_constraints_for_collected_invoice_queue_jobs_before_retry_execution":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_collected_queue_list_metadata_and_strict_status_filter_enum_in_openapi":0,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_builds_a_completed_collected_invoice_queue_summary_from_payload_and_result":0.029,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_prefers_queue_error_messages_for_failed_jobs_and_keeps_null_safe_outcome_fields":0,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_uses_deterministic_status_message_fallback_when_no_explicit_message_exists":0,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_handles_object_payload_result_values_and_malformed_fields_without_throwing":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_collected_invoice_transfer_queue_from_queue_list_and_status_routes":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_order_transfer_queue_from_draft_and_invoice_status_routes":0.009,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_marks_queued_transactions_and_clears_requires__action_when_all_actionable_work_is_already_queued":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_keeps_requires__action_true_when_a_customer_still_has_unqueued_actionable_transactions":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_blocks_fixed_pricing_or_subscription_customers_with_no_transactions_when_a_relevant_queue_job_exists":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_queues_admin_commands__exposes_agent_poll_result_handlers__and_keeps_heartbeats_from_mutating_discovery_state":0.003,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_defines_the_dispatchable_gateway_guard_on_the_loaded_manager_class":0.009,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"recent heartbeat stays online\"\"":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"late heartbeat degrades after one minute\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"stale heartbeat goes offline after five minutes\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"explicit offline reports stay offline even when heartbeat is fresh\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"missing heartbeat is treated as offline\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_marks_ready_discovery_as_stale_when_the_gateway_heartbeat_has_expired":0.727,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_edge_gateway_management_REST_endpoints":0.021,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_public_installer__claim__heartbeat__command_polling__and_internal_broker_auth_endpoints":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeBrokerClientConfigTest::__pest_evaluable_it_uses_the_same_default_broker_url_and_shared_secret_fallback_as_the_docker_stack":0.267,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_forwarded_https_scheme_when_proxied":0.336,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_appends_forwarded_ports_when_the_forwarded_host_omits_them":0.28,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_infers_https_for_the_staging_api_host_when_only_the_https_port_is_present":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured":1.003,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_normalizes_public_broker_overrides_to_https_and_browser_shell_urls_to_wss":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_keeps_localhost_broker_overrides_on_plain_http_and_ws_for_local_development":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_includes_node_pty_build_prerequisites_in_the_generated_install_script":0.007,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured_and_derives_the_broker_from_the_api_origin":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_normalizes_public_broker_overrides_to_https__strips_paths__and_browser_shell_urls_to_wss":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_merges_incoming_heartbeat_metadata_with_existing_gateway_metadata":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_v2_operator_facing_edge_gateway_routes":0.008,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_PHP_edge_agent_routes_for_operations_and_legacy_relay_command_polling":0.027,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_defines_the_v2_edge_gateway_schema_bootstrap_tables":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_stores_operation_metadata_and_event_timelines_for_management_workflows":0.005,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_PHP_agent_artifacts_and_management_polling_config":0.011,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__and_operation_endpoints_without_shell_transport_wiring":0.013,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_keeps_relay_dispatch_and_discovery_queueing_on_the_edge_gateway_manager":0.02,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_loads_relay_command_helpers_on_the_manager_and_gateway_operations_on_the_dedicated_service":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_relay_fallback_and_transport_health_details_without_shell_or_update_runtime_state":0.837,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_the_source_tree_layout":0.445,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_includes_the_container_mounted_artifact_directory_as_a_candidate":0.021,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_reads_install_artifacts_through_the_shared_locator":0.019,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_builds_update_payloads_with_checksums_from_resolved_artifact_paths":2.276,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_a_supported_runtime_layout":0.273,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_PHP_agent_artifacts_and_forwarded_https_scheme":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_explains_the_legacy_dist_mount_mismatch_when_php_artifacts_are_unavailable":0.005,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_mounted_and_baked_in_artifact_directories_before_repo_fallbacks":0.022,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_falls_back_to_baked_in_artifacts_when_the_mount_path_is_absent":0.013,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_router_resources_before_mounted_and_baked_in_artifact_directories":0,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_orders_for_an_admin_scoped_user_and_limits_the_results_to_the_permitted_departments":1.109,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_only_the_targeted_customer_orders_for_subuser_sessions":2.935,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_returns_the_current_auth_and_permission_failures_when_order_listing_is_not_allowed":1.375,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_creates_orders_through_the_real_endpoint":0.982,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_creation_requests":3.423,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_primary_endpoint":1.13,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_reassigns_invoice_collections_when_changing_an_order_across_the_draft_customer_boundary":1.615,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_primary_endpoint":5.592,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_primary_order_endpoint":1.29,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_legacy_alias_endpoint":1.517,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_alias_endpoint":4.136,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_legacy_alias_endpoint":0.512,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_unsupported_legacy_field_value_updates_on_both_update_endpoints":0.965,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_deletes_orders_through_the_real_endpoint":1.045,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_delete_requests":1.64,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_when_certificate_metadata_changes_through_the_primary_endpoint":3.683,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_for_legacy_field_value_updates_through_the_alias_endpoint":3.194,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayOperationLegacySchemaCompatibilityTest::__pest_evaluable_it_keeps_the_legacy_operation__type_column_compatible_with_v2_operation_queueing":0.022,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_builds_deterministic_keys_for_equivalent_contexts":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_stores_and_retrieves_full_order_bookings_payloads":0.001,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_ignores_malformed_cached_payloads_and_clears_order_bookings_list_caches":0.001,"P\\Tests\\Unit\\Bookings\\OrderBookingsRouteCacheWiringTest::__pest_evaluable_it_caches_the_paginated_order_bookings_list_response_and_invalidates_it_on_booking_changes":0.051,"P\\Tests\\Unit\\Bookings\\VehicleSearchBookedMetadataRouteContractTest::__pest_evaluable_it_keeps_booked_vehicle_search_metadata_aligned_with_filtered_pending_order_bookings":0.052,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0.001,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_builds_deterministic_keys_for_equivalent_count_contexts":0.039,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_stores_and_retrieves_normalized_booking_counts":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_ignores_malformed_payloads_and_clears_order_bookings_count_caches":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsRouteWiringTest::__pest_evaluable_it_adds_a_cached_order_bookings_counts_endpoint_and_invalidates_it_on_booking_changes":0.04,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayFleetUsageStatisticsTest::__pest_evaluable_it_summarizes_fleet_usage_statistics_for_the_dashboard_landing_view":0,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_every_selected_API_operation_covered_by_happy_path_and_failure_tests":0.271,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_the_OpenAPI_manifest_entries_aligned_with_the_API_spec":0.097,"P\\Tests\\Api\\ApiFixturesCleanupTest::__pest_evaluable_it_removes_generated_customer_traces_during_fixture_cleanup":8.099,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_in_with_valid_customer_credentials":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_login_payloads_and_credentials":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_returns_the_cached_auth_session_payload_for_a_valid_token":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_includes_economic_runtime_config_for_uncached_auth_sessions":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_auth_session_tokens":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_the_token_for_future_session_calls":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_cached_subuser_sessions":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_logout_tokens":0,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_the_raw_202_gather_webhook_contract_over_HTTP":0.788,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_still_prompts_for_department_selection_when_only_one_department_is_eligible":0.732,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_accepts_the_legacy_initial_webhook_body_with_top_level_call_identifiers":0.692,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_native_flow_gather_data_after_a_top_level_department_selection_when_distinct_gate_choices_exist":1.515,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_opens_the_gate_immediately_after_a_top_level_department_selection_when_entrance_and_exit_share_the_same_gate":1.719,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_uses_a_multi_digit_gather_contract_when_10_departments_are_eligible":0.587,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_a_raw_400_transport_error_for_malformed_webhook_payloads":0.419,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_only_visible_departments_and_can_return_a_single_department_with_the_slack_webhook":1.048,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_department_listing_when_the_permission_is_missing":0.378,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_creates_departments_through_the_real_endpoint":0.59,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_create_requests":1.554,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_updates_departments_through_the_real_endpoint":0.788,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_update_requests":1.552,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_department_categories_for_a_department":1.006,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_category_requests":1.191,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_lists_the_draft_customer_config_entry_in_economic_config_responses":0,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_draft_customer_config_value_through_economic_config_updates":0,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_order_draft_exports_for_the_configured_draft_customer":0,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_booked_invoice_exports_for_the_configured_draft_customer":0,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_collected_invoice_exports_for_the_configured_draft_customer":0,"P\\Tests\\Api\\PingApiTest::__pest_evaluable_it_returns_the_ping_contract":0.877,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_department_terminal_readers_are_requested_without_terminal_setup":1.281,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_sends_a_Stripe_invoice_by_email_and_persists_the_hosted_invoice_association":5.434,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_conflict_when_a_Stripe_hosted_invoice_is_already_active_for_the_order":4.756,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_allows_sending_a_new_Stripe_hosted_invoice_when_the_existing_association_is_already_terminal":3.943,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_voids_an_unpaid_Stripe_hosted_invoice_and_clears_the_local_order_association":3.746,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_refuses_to_cancel_a_paid_Stripe_hosted_invoice":4.131,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_creating_a_payment_intent_for_a_department_without_terminal_setup":0.726,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_the_newest_vehicle_last__order__id_that_still_has_order_items":1.326,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_a_null_vehicle_last__order__id_when_no_order_with_items_exists":1.159,"P\\Tests\\Unit\\Users\\EconomicCustomerModelParsingTest::__pest_evaluable_it_parses_cached_economic_customer_payloads_that_use_snake__case_customer__number":0,"P\\Tests\\Unit\\Users\\EconomicCustomerModelParsingTest::__pest_evaluable_it_leaves_the_economic_customer_model_empty_when_no_valid_customer_number_is_present":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayFleetUsageStatisticsTest::__pest_evaluable_it_derives_fleet_usage_directly_from_cached_gateway_row_summaries":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_compose_edge_gateway_artifacts_and_forwarded_https_scheme":1.031,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayMetadataUpdateContractTest::__pest_evaluable_it_adds_a_gateway_metadata_update_endpoint_with_label_and_primary_assignment_fields":0.009,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayMetadataUpdateContractTest::__pest_evaluable_it_reassigns_department_primary_gateways_through_dedicated_manager_helpers":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayShellPollingTransportTest::__pest_evaluable_it_removes_shell_access_from_the_edge_gateway_HTTP_contracts":0.007,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_compose_stack_artifacts_and_management_polling_config":0.06,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_deterministic_cache_keys":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_stores_and_retrieves_cached_list_and_detail_payloads":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_syncs_gateway_snapshots_into_cached_list_payloads_and_refreshes_fleet_usage":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_removes_deleted_gateways_from_cached_list_and_detail_payloads":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__cancel_endpoints__and_operation_endpoints_without_shell_transport_wiring":0.02,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_module_scoped_edge_gateway_operator_routes":0.008,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_edge_gateway_module_config_endpoints":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_edge_gateway_config_endpoints_from_the_module_route_directory":0.015,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_keeps_only_the_module_facade_in_the_global_classes_directory_and_conditionally_loads_module_routes":0.007,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_caps_install_session_diagnostics_and_events_while_preserving_the_first_start_timestamp":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_clears_terminal_failure_details_after_a_successful_claim_update":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_marks_expired_non_terminal_install_sessions_as_terminal_when_read_back":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_websocket_broker_urls_on_the_traefik_broker_path":0.965,"P\\Tests\\Unit\\Selfserve\\DepartmentGateConfigRelayTest::__pest_evaluable_it_validates_relay_gate_configs_and_keeps_relay_specific_fields_in_the_payload":0,"P\\Tests\\Unit\\Selfserve\\DepartmentGateConfigRelayTest::__pest_evaluable_it_rejects_relay_gate_configs_without_a_logical_relay_id":0,"P\\Tests\\Unit\\Bird\\DepartmentGatesRelayOpenTest::__pest_evaluable_it_dispatches_relay_backed_gates_through_the_edge_gateway_relay_manager":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayDepartmentWorkspaceContractTest::__pest_evaluable_it_defines_the_department_hardware_workspace_service_payload_surface":0.033,"P\\Tests\\Unit\\Selfserve\\PlateScannerWorkspaceContractTest::__pest_evaluable_it_adds_lane_aware_scanner_management_and_a_dedicated_rotate_key_action":0.01,"P\\Tests\\Unit\\Selfserve\\PlateScannerWorkspaceContractTest::__pest_evaluable_it_uses_the_scanner_default_lane_before_requiring_an_explicit_lane__id_in_machine_button_webhooks":0.004,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_maps_gateway_relay_status_responses_into_the_Shelly_cloud_payload_shape":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_maps_gateway_relay_switch_responses_into_the_Shelly_cloud_payload_shape":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_requires_a_valid_department_id_for_gateway_transport_requests":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_rejects_unsupported_gateway_transport_endpoints":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_surfaces_binding_lookup_failures_while_resolving_relay_state_through_the_gateway_transport":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_surfaces_offline_gateway_failures_while_dispatching_relay_switch_commands":0,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_returns_the_updated_lane_id_after_editing_a_scanner_whose_null_lane_was_already_cached":21.835,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_rejects_plate_scanner_edits_when_the_permission_is_missing":7.837,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_normalizes_owned_Shelly_devices_into_relay_select_options":0,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_fails_fast_when_Shelly_inventory_does_not_include_owned_devices_status":0,"P\\Tests\\Unit\\Selfserve\\DepartmentLaneRelayOptionsRouteWiringTest::__pest_evaluable_it_registers_a_department_lane_relay_options_endpoint_backed_by_Shelly_inventory":0.032,"P\\Tests\\Unit\\Selfserve\\DepartmentLaneRelayNullificationRouteWiringTest::__pest_evaluable_it_nullifies_department_lane_relay_fields_when_blank_select_values_are_submitted":0.008,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_serves_installer_artifacts_and_recovers_gateway_runtime_status_after_fresh_heartbeats":109.487,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_polls_operations_and_commands__submits_results__and_records_broker_presence_for_task_pages":229.768,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_rejects_missing_and_invalid_edge_agent_tokens":12.815,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_validates_broker_sessions_and_ingests_presence__telemetry__logs__and_shell_lifecycle_data":180.867,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_builds_broker_backlog_and_completes_gateway_operations_through_broker_endpoints":147.749,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_invalid_edge_broker_shared_secrets":6.832,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_creates_install_tokens__tracks_installer_status__and_exposes_claimed_gateway_detail_to_authorized_operators":134.744,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_manages_edge_gateway_metadata__bindings__operations__sessions__rotation__cutover__and_deletion":272.219,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_rejects_operator_edge_routes_when_module_permission_or_department_access_is_missing":46.681,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_persists_install_session_updates_and_derives_gateway_runtime_status_from_heartbeats":0.015,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_assembles_tasks__logs__statistics__operations__commands__and_shell_lifecycle_state_from_persisted_records":0.019,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_localhost_websocket_broker_urls_on_the_local_traefik_api_prefix":1.312,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_keeps_root_host_api_urls_unprefixed_when_the_request_is_not_under_the_local_api_alias":0.603,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_imports_a_matching_e_conomic_customer_into_the_local_system_when_no_local_record_exists":0.001,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_reports_when_the_local_customer_already_has_a_login_account":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_creates_a_new_e_conomic_customer_and_returns_a_created_result_for_new_rows":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_creates_the_economic_record_for_an_existing_local_account_when_no_matching_upstream_customer_exists":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_rejects_CVR_conflicts_when_the_upstream_customer_number_does_not_match_the_submitted_phone_number":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_registers_the_customer_import_route_and_wires_it_through_the_mass_import_service":0.009,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_builds_customer_name_cache_payloads_from_economic_data_or_display_name_fallbacks":0,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_guards_bulk_customer_name_cache_writes_behind_a_resolved_payload_check":0.003,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_ignores_and_soft_deletes_edge_gateways_whose_department_no_longer_exists":35.946,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_only_trusts_broker_presence_while_the_broker_heartbeat_is_fresh":1.458,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_refreshes_broker_presence_from_broker_telemetry_heartbeats":0.006,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_resolves_the_injected_gateway_transport_when_a_department_is_in_gateway_mode":0,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_resolves_the_injected_cloud_transport_when_a_department_is_in_cloud_mode":0,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_lets_relay_tests_override_the_department_transport_without_changing_department_mode":0,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_falls_back_to_local_device_and_control_names_when_Shelly_cloud_list_metadata_is_unavailable":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_uses_local_only_gateway_dispatch_for_explicit_local_transport_overrides":0,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_marks_non_injected_local_overrides_as_local_only_gateway_transport":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_exit_port_by_switching_relay__out__id_on":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_entrance_port_by_switching_relay__in__id_on":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_forwards_Shelly_toggle__after_timers_to_gateway_relay_switches":0,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_marks_non_injected_local_and_gateway_overrides_as_local_only_gateway_transport":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_preserves_local_gateway_diagnostic_metadata_on_relay_status_snapshots":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_includes_positive_relay_timers_in_Shelly_switch_payloads":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_applies_Shelly_transport_overrides_across_self_serve_relay_side_effect_routes":0.029,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayLegacyRouteShimTest::__pest_evaluable_it_keeps_guarded_legacy_root_shims_for_moved_edge_gateway_routes":0.025,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_persists_gateway_cutover_relay_bindings_used_by_self_serve_Shelly_dispatch":0.015,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_passes_explicit_timer_values_when_opening_lane_gates":0,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_keeps_Shelly_1_Mini_Gen3_type__model__and_generation_aligned_with_Shelly_metadata":0,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_shell_session_creation_while_broker_presence_is_unavailable":23.503,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_broker_settings_as_editable_edge_gateway_module_config":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_session_management_endpoints_and_OpenAPI_coverage":0.011,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_self_serve_force_stop_distinct_from_normal_STOP_relay_and_gate_behavior":0.015,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_read_only_self_serve_preview_and_summary_refreshes_from_touching_relay_hardware":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveWashFlowMachineAllowedWiringTest::__pest_evaluable_it_separates_session_synchronization_from_relay_hardware_synchronization":0.016,"P\\Tests\\Unit\\Selfserve\\ShellyRealRequestGuardTest::__pest_evaluable_it_blocks_and_records_test_mode_Shelly_POST_requests_before_cURL_can_run":0.001,"P\\Tests\\Unit\\Selfserve\\ShellyRealRequestGuardTest::__pest_evaluable_it_blocks_and_records_test_mode_Shelly_GET_requests_before_cURL_can_run":0,"P\\Tests\\Unit\\Selfserve\\ZZZShellyGuardSafetyMetaTest::__pest_evaluable_it_did_not_record_any_real_Shelly_request_attempts_during_self_serve_tests":0,"P\\Tests\\Api\\SelfserveFixtureApiTest::__pest_evaluable_it_creates_a_comprehensive_self_serve_API_scenario_with_demo_relays":0,"P\\Tests\\Api\\SelfserveZZZShellyGuardApiTest::__pest_evaluable_it_did_not_record_any_real_Shelly_request_attempts_during_self_serve_API_tests":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_serializes_questions__conditions__tasks__scopes__and_gateways_into_one_graph":0.239,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_derives_studio_vehicle_type_lookup_rows_from_selectable_wash_products":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_applies_saved_layout_without_changing_graph_semantics":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_keeps_layout_loading_compatible_with_native_PDO_named_placeholders":0.013,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_builds_guided_simulator_debug_payload_with_blockers_and_canvas_annotations":0.028,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_resolves_simulator_gateway_service_bindings_from_lane_relay_slots":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_persists_allowed_services_without_relay_writes_for_pre_start_wash_setup":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_the_all_in_one_self_serve_studio_replacement_endpoints":0.009,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_continues_start_when_entrance_relay_dispatch_times_out_ambiguously":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_still_fails_start_for_non_timeout_entrance_relay_errors":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_parses_deferred_relay_side_effects_on_start_command_arguments":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_skips_cleaner_and_machine_relay_side_effects_when_start_asks_to_defer_them":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_keeps_cleaner_and_machine_relay_side_effects_for_normal_start_commands":0,"P\\Tests\\Unit\\Selfserve\\SelfservePropertyGatePermissionBypassTest::__pest_evaluable_it_allows_property_gate_commands_for_customers_with_an_active_wash_in_the_target_department":0,"P\\Tests\\Unit\\Selfserve\\SelfservePropertyGatePermissionBypassTest::__pest_evaluable_it_does_not_bypass_property_gate_permissions_without_a_positive_customer_number":0,"P\\Tests\\Unit\\Selfserve\\SelfservePropertyGatePermissionBypassTest::__pest_evaluable_it_does_not_bypass_property_gate_permissions_when_the_customer_has_no_active_wash_in_the_target_department":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_the_all_in_one_self_serve_studio_replacement_API":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveNonOwnedVehicleWashAccessTest::__pest_evaluable_it_allows_own_permission_customers_to_preview_borrowed_registration_plates_without_ownership_checks":0.005,"P\\Tests\\Unit\\Selfserve\\SelfserveNonOwnedVehicleWashAccessTest::__pest_evaluable_it_allows_customer_scoped_answers_to_be_stored_for_borrowed_registration_plates":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveNonOwnedVehicleWashAccessTest::__pest_evaluable_it_does_not_apply_saved_answers_from_another_customer_for_the_same_registration_plate":0.027,"P\\Tests\\Unit\\Selfserve\\SelfserveNonOwnedVehicleWashAccessTest::__pest_evaluable_it_scopes_saved_self_serve_answers_by_customer_number_and_registration_plate":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveNonOwnedVehicleWashAccessTest::__pest_evaluable_it_loads_saved_answers_from_the_authenticated_customer_context_instead_of_the_plate_owner":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_does_not_count_shifts_without_punches_when_checkIn_checkOut_are_null":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_overtime_minutes_when_a_saved_shift_end_extends_past_the_approved_original_end":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_does_not_count_removed_approved_time_when_a_saved_shift_end_is_shortened":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_caps_current_slot_hours_to_elapsed_minutes_and_zeroes_future_slots":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_checked_in_shifts_without_checkOut_up_to_occurredUntil":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_keeps_the_main_period_response_local_only_for_booked_state_and_customer_names":0.024,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_streams_the_main_period_response_instead_of_encoding_the_full_payload_at_once":0.033,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_maps_batched_period_transaction_rows_to_the_legacy_transaction_response_shape":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_uses_batched_period_transactions_and_keyed_customer_maps_in_the_main_period_route":0.033,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_falls_back_to_configured_e_conomic_default_department_for_missing_customer_default_department_in_distributions":0.021,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_default_distribution_department_config_value_through_economic_config_updates":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_computes_MySQL_GTID_interval_counts_and_coverage_percentages":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_reports_empty_source_GTID_sets_as_caught_up":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_computes_Redis_offset_percentages_safely":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_computes_MariaDB_GTID_coverage_by_domain_sequence":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_normalizes_public_replication_kind_aliases":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_supports_MariaDB_prerequisites_without_requiring_Oracle_MySQL_variables":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_reports_MariaDB_specific_blockers_when_GTID_or_binary_logging_prerequisites_are_missing":0,"P\\Tests\\Unit\\Replication\\ReplicationSecretBoxTest::__pest_evaluable_it_encrypts_replication_secrets_without_storing_plaintext":0.002,"P\\Tests\\Unit\\Replication\\ReplicationSecretBoxTest::__pest_evaluable_it_builds_active_database_and_redis_config_from_encrypted_bootstrap_snapshots":0,"P\\Tests\\Unit\\Replication\\SuperuserReplicationRouteWiringTest::__pest_evaluable_it_registers_superuser_replication_endpoints_and_permissions":0.019,"P\\Tests\\Unit\\Replication\\SuperuserReplicationRouteWiringTest::__pest_evaluable_it_documents_replication_management_in_openapi":0.016,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_generates_replication_ready_MariaDB_compose_templates_without_embedding_secrets":0.001,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_generates_Redis_replica_compose_templates_with_primary_connection_placeholders":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_does_not_require_replica_SQL_threads_before_database_provisioning_configures_them":0.006,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_creates_the_generated_replication_user_on_the_primary_during_provisioning":0.007,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_detects_missing_database_tables_before_provisioning_a_preseeded_replica":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_allows_failed_replicas_to_be_removed_without_allowing_primary_or_healthy_replica_removal":0.033,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_seeds_MariaDB_replicas_in_place_instead_of_requiring_container_recreation":0.024,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_keeps_replication_operation_progress_schema_idempotent_for_existing_installs":0.039,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_limits_MariaDB_log_table_seeding_to_the_last_month":0.002,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_skips_log_table_data_during_MariaDB_seeding_and_replication":0.003,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_keeps_operational_log_tables_schema_only_during_MariaDB_seeding_and_replication":0.005,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_provisions_Redis_replicas_after_a_connectivity_only_preflight_and_reports_sync_progress":0.015,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_keeps_Redis_promotion_caught_up__durable__and_metadata_safe":0.007,"P\\Tests\\Unit\\Auth\\CreateTokenTest::__pest_evaluable_it_creates_auth_tokens_and_reports_missing_customer_users_clearly":0.271,"P\\Tests\\Unit\\Auth\\EconomicCreateCustomerResponseTest::__pest_evaluable_it_returns_the_raw_upstream_create_response_and_preserves_the_requested_payload":0,"P\\Tests\\Unit\\Auth\\RegisterCvrLegacyScriptTest::__pest_evaluable_it_keeps_the_legacy_register_cvr_route_harness_passing":0.043,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_raw_202_gather_response_for_initial_department_selection":0.205,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_accepts_legacy_initial_webhook_payloads_with_top_level_call_identifiers":0.005,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_flow_data_gather_payload_after_department_selection_in_native_flow_mode_when_distinct_gate_choices_exist":0.002,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_opens_the_gate_immediately_after_department_selection_when_entrance_and_exit_resolve_to_the_same_gate_in_native_flow_mode":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_flow_data_completion_payload_after_gate_confirmation_in_native_flow_mode":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_second_stage_raw_202_gather_response_after_department_selection_when_distinct_gate_choices_exist":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_opens_the_shared_gate_immediately_after_department_selection_in_raw_command_mode":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_opens_the_selected_gate_and_clears_redis_state_on_final_selection":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_reprompts_with_invalid_selection_while_keeping_webhook_state":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_uses_fallback_dtmf_extraction_when_event_gather_keys_are_missing":0.001,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_prompts_for_department_selection_even_when_only_one_eligible_department_exists":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_prompts_for_a_single_available_gate_type_and_opens_only_after_explicit_confirmation":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_supports_multi_digit_department_selections_before_gate_confirmation":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_direct_raw_200_completion_when_no_departments_are_eligible":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_continues_with_the_first_gather_prompt_when_backend_call_acceptance_fails":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_business_failure_raw_200_response_when_gate_opening_fails":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_deterministic_department_digit_map_without_capping_options":0.009,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_compact_gate_option_maps_and_resolves_selected_gate_type_by_digit":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_department_prompts_with_multi_digit_guidance_and_compact_gate_prompts":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_normalizes_menu_digit_input_from_Bird_dtmf_payload_values":0,"P\\Tests\\Unit\\Bird\\DepartmentGatesPhoneCallOpenTest::__pest_evaluable_it_forwards_phone_number_and_call_duration_threshold_to_the_Bird_gate_helper":0.002,"P\\Tests\\Unit\\Bird\\DepartmentGatesPhoneCallOpenTest::__pest_evaluable_it_wraps_Bird_helper_failures_and_reports_them_to_Slack":0,"P\\Tests\\Unit\\Bookings\\NonPosBookingCompletionRemovalTest::__pest_evaluable_it_unregisters_legacy_booking_completion_forms":0.13,"P\\Tests\\Unit\\Bookings\\NonPosBookingCompletionRemovalTest::__pest_evaluable_it_keeps_legacy_wash_certificate_downloads_but_disables_generation_and_completion":0.166,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsComplaintsOpenApiSpecTest::__pest_evaluable_it_documents_the_daily_report_complaints_CRUD_and_customer_lookup_endpoints_in_openapi":0.011,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsComplaintsRouteContractTest::__pest_evaluable_it_wires_complaint_create__lookup__list__edit__and_delete_routes_with_validation_and_parsing":0.01,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOutsideHoursOpenApiSpecTest::__pest_evaluable_it_documents_outside_hours_summary_and_trend_schemas_in_openapi":0.016,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOutsideHoursRouteContractTest::__pest_evaluable_it_wires_outside_hours_summary_and_trend_endpoints_through_the_dedicated_statistics_service":0.007,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOutsideHoursRouteContractTest::__pest_evaluable_it_initializes_the_outside_hours_statistics_service_before_building_the_transaction_count_summary_payload":0.006,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewOpenApiSpecTest::__pest_evaluable_it_documents_the_daily_report_overview_endpoint_and_reusable_schemas_in_openapi":0.013,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_builds_the_overview_payload_from_batched_repository_data_with_deterministic_tile_states":0.013,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_marks_overtime_unavailable_when_not_every_selected_department_can_be_mapped_to_workfeed":0,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_normalizes_department_id_input_from_csv_strings_and_nested_values":0,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_limits_overtime_counting_to_the_selected_reporting_range":0,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_does_not_count_negative_approved_overtime_when_a_saved_end_shortens_the_shift":0,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_ignores_late_unapproved_administrative_edits_when_calculating_overtime":0,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_wires_the_overview_route_to_batched_repository_methods_and_overview_path":0.013,"P\\Tests\\Unit\\DailyReports\\DepartmentOutsideHoursStatisticsServiceTest::__pest_evaluable_it_counts_only_outside_hours_washes_and_flags_missing_opening_hours_without_counting_them_as_closed":0.002,"P\\Tests\\Unit\\DailyReports\\DepartmentOutsideHoursStatisticsServiceTest::__pest_evaluable_it_deduplicates_linked_washes_with_self_serve_first__then_xlvask__then_orders":0,"P\\Tests\\Unit\\DailyReports\\DepartmentOutsideHoursStatisticsServiceTest::__pest_evaluable_it_builds_daily_trend_points_with_per_day_missing_hours_diagnostics":0.001,"P\\Tests\\Unit\\Database\\DbObjectRedisNamespaceSafetyTest::__pest_evaluable_it_keeps_db_object_Redis_access_namespace_safe":0.008,"P\\Tests\\Unit\\DynamicImages\\DepartmentLaneDynamicImageRouteTest::__pest_evaluable_it_allows_studio_lane_dynamic_image_previews_to_override_the_saved_image_id":0.012,"P\\Tests\\Unit\\DynamicImages\\DepartmentLaneDynamicImageRouteTest::__pest_evaluable_it_accepts_ordered_dynamic_image_button_tokens_including_reset_start_and_zero":0.003,"P\\Tests\\Unit\\DynamicImages\\DepartmentLaneDynamicImageRouteTest::__pest_evaluable_it_renders_machine_one_dynamic_image_steps_from_the_ordered_button_payload":0.014,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_uses_queued_job_payload_customer_context_before_result_data_exists":0,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_exposes_collected_invoice_queue_monitor_and_per_user_terminal_clear_routes":0.008,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_runs_collected_invoice_queue_batches_through_an_explicit_manual_endpoint":0.026,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_bounds_e_conomic_curl_calls_below_the_PHP_request_timeout":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersDiscountFallbackTest::__pest_evaluable_it_falls_back_to_a_later_customer_template_product_when_earlier_probes_fail_on_missing_currency_prices":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersDiscountFallbackTest::__pest_evaluable_it_returns_zero_when_every_customer_template_lookup_fails_due_to_missing_currency_prices":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersDiscountFallbackTest::__pest_evaluable_it_rethrows_unrelated_discount_lookup_failures":0,"P\\Tests\\Unit\\Invoicing\\EconomicDraftCustomerOpenApiSpecTest::__pest_evaluable_it_documents_transaction_draft_customer_config_and_auth_runtime_fields_in_all_tracked_openapi_copies":0.306,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueCronEntrypointWiringTest::__pest_evaluable_it_wires_root_cron_entrypoint_to_the_full_cron_scheduler_with_queue_worker_tasks":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_additive_collected_invoice_queue_pagination_metadata_and_retry_conflict_semantics":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_exposes_an_explicit_collected_invoice_transfer_queue_run_route_instead_of_ticking_read_endpoints":0.013,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_keeps_order_transfer_queue_status_routes_read_only":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_assigns_classified_booked_department_75_amounts_to_fallback_when_no_monthly_basis_exists":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_fixed_pricing_using_the_configured_fallback_department":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_wash_subscriptions_using_the_configured_fallback_department":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_uses_the_configured_fallback_department_when_a_subscription_has_no_customer_department_basis":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_excludes_orphaned_customer_traces_from_fixed_pricing_and_customer_price_distributions":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_excludes_orphaned_customers_from_subscription_fallback_versions":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceOrderOverrideTest::__pest_evaluable_it_inherits_department_eligibility_when_no_order_override_is_set":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceOrderOverrideTest::__pest_evaluable_it_allows_an_order_level_include_override_to_overrule_department_exclusion":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceOrderOverrideTest::__pest_evaluable_it_allows_an_order_level_exclude_override_to_overrule_department_inclusion":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_builds_deterministic_automatic_flag_fingerprints_and_interactive_price_message_parts":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_builds_interactive_message_parts_for_order_and_wash_certificate_warnings":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_includes_order_item_preview_context_for_required_order_field_warnings":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_allows_tank_cleaning_products_for_only_tank_cleaning_customers":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_does_not_flag_interior_wash_variants_as_historical_primary_product_mismatches":0.001,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_does_not_report_duplicate_primary_vehicle_products_from_duplicated_detector_rows_for_the_same_order_item":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_uses_attached_wash_certificate_documents_instead_of_safety_seal_text_for_certificate_presence":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_loads_wash_certificate_attachment_presence_from_order_attachment_content":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_uses_the_highest_customer_specific_discount_in_expected_price_breakdowns":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_uses_a_preloaded_e_conomic_global_discount_in_expected_price_breakdowns":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_does_not_report_a_price_mismatch_when_a_product_specific_discount_makes_the_expected_price_zero":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_preloads_and_caches_missing_e_conomic_discounts_before_price_mismatch_detection":0.04,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_seeds_order_item_preview_cache_from_period_rows":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_sorts_manual_flags_before_automatic_warnings_and_preserves_legacy_circle_indicators_without_flags":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_scopes_invoice_period_flags_to_the_customer_card_that_can_render_them":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_keeps_order_item_preview_context_compact_for_the_period_response":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_formats_stored_manual_flags_with_the_creating_superuser_display_name":0.003,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_validates_supported_manual_flag_fields_by_target_type":0.136,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_wires_invoice_period_flag_routes_with_explicit_list_create_and_update_permissions":0.043,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_uses_the_users_display__name_column_in_detector_queries":0.115,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_aggregates_customer_price_overrides_by_customer_number_for_price_mismatch_detection":0.115,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_guards_optional_customer_vehicle_deleted__at_filtering_behind_a_column_check":0.097,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_limits_historical_primary_product_lookup_to_current_period_registrations":0.08,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_provides_a_batched_plain_row_transaction_query_for_invoicing_period_responses":0.11,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_adds_guarded_composite_indexes_for_invoicing_period_lookups":0.155,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_blocks_invoicing_when_all_actionable_transactions_are_backed_by_valid_e_conomic_drafts":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_keeps_invoicing_available_when_valid_drafts_only_cover_part_of_the_actionable_work":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_excludes_errored__booked__deleted__and_missing_external_id_invoice_collections_at_query_time":0.027,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_still_checks_valid_drafts_when_the_collection_table_has_no_deleted_marker_column":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_blocks_fixed_pricing_and_subscription_customer_level_work_when_a_relevant_valid_draft_exists":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_keeps_queue_blocking_ahead_of_the_draft_label_when_all_work_is_covered_by_queue_or_draft_state":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_detects_paginated_period_mode_only_when_pagination_parameters_are_present":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_normalizes_period_pagination_options_and_clamps_invalid_page_and_limit_values":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_slices_only_the_active_period_view_and_keeps_exact_full_result_type_counts":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_returns_the_entire_active_period_view_when_the_limit_is_all":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_searches_customer_fields_and_order_fields_at_the_customer_card_level":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_applies_requires_action_and_booked_visibility_filters_before_counting_and_slicing":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_normalizes_targeted_customer_number_filters_from_comma_separated_or_repeated_values":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_filters_period_customer_number_candidates_to_targeted_customers_only":0,"P\\Tests\\Unit\\MotorApi\\MotorApiCachedResultTest::__pest_evaluable_it_only_writes_cached_MotorAPI_metadata_when_a_response_object_exists":0,"P\\Tests\\Unit\\Orders\\OrderBookingsCompletionDedupTest::__pest_evaluable_it_attaches_and_emails_a_wash_certificate_when_a_booking_is_already_linked_to_a_pos_order_without_one":0,"P\\Tests\\Unit\\Orders\\OrderBookingsCompletionDedupTest::__pest_evaluable_it_does_not_create_or_email_a_duplicate_wash_certificate_when_a_linked_pos_order_already_has_one":0,"P\\Tests\\Unit\\Orders\\OrderBookingsCompletionDedupTest::__pest_evaluable_it_keeps_standalone_booking_completion_behavior_unchanged_for_wash_certificates":0,"P\\Tests\\Unit\\Orders\\OrdersAutoWashCertificateCompletionTest::__pest_evaluable_it_auto_attaches_a_wash_certificate_on_order_completion_when_a_wash_certificate_item_is_present":0.001,"P\\Tests\\Unit\\Orders\\OrdersAutoWashCertificateCompletionTest::__pest_evaluable_it_keeps_order_completion_idempotent_when_a_wash_certificate_is_already_attached":0,"P\\Tests\\Unit\\Orders\\OrdersAutoWashCertificateCompletionTest::__pest_evaluable_it_allows_blank_safety_seal_values_when_auto_attaching_a_wash_certificate_on_completion":0,"P\\Tests\\Unit\\Orders\\OrdersIncludeInInvoiceOverrideTest::__pest_evaluable_it_lets_the_order_level_override_include_an_otherwise_excluded_order":0,"P\\Tests\\Unit\\Orders\\OrdersIncludeInInvoiceOverrideTest::__pest_evaluable_it_lets_the_order_level_override_exclude_an_otherwise_included_order":0,"P\\Tests\\Unit\\Orders\\OrdersIncludeInInvoiceOverrideTest::__pest_evaluable_it_falls_back_to_the_department_invoicing_rule_when_the_override_is_null":0,"P\\Tests\\Unit\\Orders\\OrdersIncludeInInvoiceOverrideTest::__pest_evaluable_it_serializes_both_raw_and_effective_include__in__invoice_values":0,"P\\Tests\\Unit\\Orders\\OrdersInputNormalizerTest::__pest_evaluable_it_normalizes_sql_and_datetime_local_created__at_values":0,"P\\Tests\\Unit\\Orders\\OrdersInputNormalizerTest::__pest_evaluable_it_rejects_invalid_created__at_values":0,"P\\Tests\\Unit\\Orders\\OrdersInputNormalizerTest::__pest_evaluable_it_normalizes_include__in__invoice_tri_state_inputs":0,"P\\Tests\\Unit\\Orders\\OrdersInputNormalizerTest::__pest_evaluable_it_rejects_invalid_include__in__invoice_values":0,"P\\Tests\\Unit\\Orders\\OrdersRouteSettingsUpdateWiringTest::__pest_evaluable_it_wires_order_create_and_update_routes_through_the_settings_normalizers":0.035,"P\\Tests\\Unit\\Orders\\OrdersRouteSettingsUpdateWiringTest::__pest_evaluable_it_keeps_line_item_invoice_filtering_in_the_order_net_amount_calculation":0.004,"P\\Tests\\Unit\\Orders\\OrdersRouteStripePaymentIntentLifecycleWiringTest::__pest_evaluable_it_wires_mobile_stripe_payment_intent_routes_to_normalized_lifecycle_handling":0.008,"P\\Tests\\Unit\\Orders\\StripePaymentIntentsPersistenceWiringTest::__pest_evaluable_it_wires_stripe_payment_intent_persistence_to_prune_duplicates_and_clear_reader_state_safely":0.104,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_does_not_send_empty_mget_commands_to_redis":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_generates_MinIO_replica_compose_templates_without_embedding_secrets":0.001,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_computes_MinIO_free_space_and_catch_up_math_safely":0.001,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_wires_MinIO_replication_through_routes_and_bootstrap_snapshots":0.07,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_nested_v2_ALL_and_ANY_expression_trees_with_trace_output":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_v2_if__else_if__and_else_condition_branches_in_order":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_v2_case_expressions_against_question_values":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_returns_false_and_traces_v2_condition_expression_cycles":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_fails_validation_when_nested_conditions_form_cycles":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_migrates_legacy_AND_and_OR_rules_into_grouped_v2_condition_expressions":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_repairs_legacy_defaulted_always_task_gates_during_v2_normalization":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_does_not_let_legacy_defaulted_always_task_gates_bypass_validation":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_rejects_unsupported_legacy_task_target_rules_after_migration":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_validates_v2_expressions_for_empty_used_conditions__missing_refs__invalid_operators__and_cycles":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_validates_nested_v2_branch_and_case_expressions":0,"P\\Tests\\Unit\\Selfserve\\SelfserveInProgressWashAccessTest::__pest_evaluable_it_keeps_own_in_progress_self_serve_wash_details_visible_to_the_customer":0,"P\\Tests\\Unit\\Selfserve\\SelfserveInProgressWashAccessTest::__pest_evaluable_it_redacts_another_customers_in_progress_wash_details_during_customer_lane_polling":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_the_physical_machine_ON_signal_was_recorded__then_turns_off_cleaner_and_machine_relays":0.014,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_no_physical_machine_ON_signal_was_recorded_and_only_disables_configured_relays":0.009,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_does_not_use_selector_relay_online_status_as_machine_wash_billing_evidence":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_continues_STOP_when_exit_relay_dispatch_times_out_ambiguously":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_still_fails_STOP_for_non_timeout_exit_relay_errors":0.012,"P\\Tests\\Unit\\Selfserve\\SelfserveMachineSignalTest::__pest_evaluable_it_normalizes_Shelly_input_toggle_ON_events_as_machine_start_signals":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveMachineSignalTest::__pest_evaluable_it_normalizes_Shelly_switch_ON_events_and_nested_status_payloads":0,"P\\Tests\\Unit\\Selfserve\\SelfserveMachineSignalTest::__pest_evaluable_it_recognizes_Shelly_OFF_events_but_does_not_treat_them_as_billable_machine_starts":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_local_edge_gateway_machine_ON_signal_monitor_endpoints":0.021,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_lane_level_self_serve_toggles_through_lane_APIs__guest_payloads__and_edge_workspace_readiness":0.011,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_returns_authoritative_allowed_service_state_from_self_serve_session_summaries":0.006,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_filters_machine_button_tasks_out_of_self_serve_snapshots_when_MACHINE_is_not_allowed":0.006,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_blocks_new_self_serve_eligibility_and_session_sync_for_disabled_lanes":0.009,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_adds_lane_level_self_serve_enablement_for_existing_department_lanes":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_creates_canvas_only_self_serve_studio_layout_storage":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_uses_mysql_safe_identifiers_for_self_serve_studio_virtual_hardware_storage":0.009,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_serializes_configurable_studio_actions_with_event__gate__scope__and_ordering_edges":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_validates_action_configuration_and_keeps_warnings_non_blocking":0.018,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_serializes_v2_condition_expressions_without_standalone_rule_nodes":0.05,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_serializes_branch_and_case_condition_expression_dependencies":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_keeps_runtime_on_published_v2_configs_and_leaves_draft_JSON_as_the_studio_edit_surface":0.008,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_surfaces_task_attachments_in_studio_graph__simulator__and_flow_responses":0.016,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_exposes_dynamic_images_and_referenced_machine_types_as_studio_lookup_choices":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_keeps_lane_management_fields_on_lane_scope_nodes":0.024,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_routes_studio_lane_graph_operations_through_department__lanes":0.005,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_projects_visible_question_answer_paths_into_grouped_task_service_and_signal_outcomes":0.011,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_truncates_path_outcome_projection_when_the_state_cap_is_reached":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_returns_complete_terminal_path_results_for_wide_question_trees_and_reports_progress":0.364,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_generates_and_merges_virtual_hardware_as_studio_only_relay_coverage":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_renders_virtual_gateway_nodes_and_task_service_edges_in_the_studio_graph":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_inserts_configured_action_signals_into_the_simulator_timeline_in_runtime_order":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_simulates_lane_scoped_wash_start_actions_for_property_gates_and_lane_entrance_ports":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_adds_ordered_simulator_signal_timeline_rows_for_virtual_hardware_dry_runs":0,"P\\Tests\\Unit\\Selfserve\\SelfserveWashFlowMachineAllowedWiringTest::__pest_evaluable_it_infers_legacy_defaulted_always_task_gates_from_condition__id_at_runtime":0,"P\\Tests\\Unit\\Selfserve\\SelfserveWashSessionStateTest::__pest_evaluable_it_treats_terminal_self_serve_wash_session_statuses_as_closed":0,"P\\Tests\\Unit\\Selfserve\\SelfserveWashSessionStateTest::__pest_evaluable_it_freezes_elapsed_self_serve_wash_minutes_at_completion_time":0,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_exposes_chauffeur_management_endpoints_on_the_subusers_route":0.728,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_includes_grant_management_fields_in_the_subusers_payload_builder":0.014,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_links_grant_disable_operations_to_SUBUSERS__DELETE_for_own_customer_managers":0.022,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_prevents_own_customer_managers_from_editing_driver_owned_account_profiles":0.018,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_only_allows_invite_resend_while_setup_is_still_pending":0.028,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusOpenApiSpecTest::__pest_evaluable_it_documents_the_superuser_system_status_snapshot_endpoint_in_openapi":0.008,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusOpenApiSpecTest::__pest_evaluable_it_defines_the_reusable_system_status_schemas_and_enums":0.006,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusRouteWiringTest::__pest_evaluable_it_registers_the_aggregated_superuser_system_status_endpoint_and_permission":0.006,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusRouteWiringTest::__pest_evaluable_it_keeps_the_legacy_database_status_endpoint_wired_through_the_shared_snapshot_service":0.004,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_reduces_overall_status_using_down_and_degraded_precedence":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_runtime_usage_percentages_consistently":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_reuses_cached_module_probes_only_when_the_ttl_is_still_valid_and_force_is_false":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"success\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"unauthorized\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"forbidden\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"rate limited\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"server error\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"no response\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_transport_errors_as_down":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_normalizes_and_deduplicates_warning_entries_for_snapshots":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_interprets_recaptcha_probe_payloads_safely with data set \"dataset \"dummy token rejected but credentials valid\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_interprets_recaptcha_probe_payloads_safely with data set \"dataset \"invalid secret is down\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_interprets_recaptcha_probe_payloads_safely with data set \"dataset \"unexpected validation errors degrade\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"recaptcha\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"email\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"motorapi\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"fxratesapi\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"weatherapi\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"workfeed\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"gatewayapi\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"xlvask\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"limble\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"license plate recognizer\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"bird\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_uses_runtime_economic_credentials_for_the_economic_probe":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_returns_down_without_attempting_economic_http_calls_when_runtime_credentials_are_missing":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_reports_backup_probe_failures_from_local_validation":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_returns_configured_for_shelly_when_no_known_device_id_is_available_for_probing":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_an_authenticated_shelly_status_probe_when_a_known_device_id_exists":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_validates_selfserve_schema_and_minute_product_configuration":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_reports_invalid_selfserve_minute_configuration_before_touching_the_schema":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_reports_missing_selfserve_minute_products":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_surfaces_selfserve_bootstrap_failures":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_adds_localization_metadata_for_disabled_and_missing_config_modules":40.262,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_marks_newly_supported_modules_as_probe_backed_and_leaves_only_truly_unsupported_modules_as_configuration_only":38.499,"P\\Tests\\Unit\\SystemStatus\\SystemSessionActivityTrackerTest::__pest_evaluable_it_detects_device_types_from_common_user_agents":0,"P\\Tests\\Unit\\SystemStatus\\SystemSessionActivityTrackerTest::__pest_evaluable_it_treats_recent_sessions_as_active_within_the_configured_activity_window":0,"P\\Tests\\Unit\\SystemStatus\\SystemSessionActivityTrackerTest::__pest_evaluable_it_converts_database_utc_datetimes_into_timezone_aware_iso_strings":0,"P\\Tests\\Unit\\SystemStatus\\SystemSessionActivityTrackerTest::__pest_evaluable_it_treats_timezone_aware_iso_timestamps_as_active_using_absolute_time":0,"P\\Tests\\Unit\\Tooling\\LegacyTestInventoryTest::__pest_evaluable_it_keeps_every_legacy_PHP_test_accounted_for_in_the_manifest":0.489,"P\\Tests\\Unit\\Tooling\\MySqlSchemaCompatibilityTest::__pest_evaluable_it_keeps_schema_bootstrap_SQL_compatible_with_the_MySQL_runner":6.55,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_allows_callers_to_resolve_customer_names_without_e_conomic_fallback":0.003,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_returns_an_empty_customer_name_map_without_touching_cache_for_empty_input":0,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_returns_no_rows_for_empty_array_field_filters":0,"P\\Tests\\Unit\\Users\\UsersRedisNamespaceSafetyTest::__pest_evaluable_it_keeps_users_Redis_access_namespace_safe":0.005,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_builds_department_weather_preload_targets_in_cli_without_a_request_uri":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherPreloadCronWiringTest::__pest_evaluable_it_registers_and_implements_cron_warming_for_workfeed_employee_name_cache":0.007,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_multi_department_slot_statuses_using_worst_severity_when_any_department_is_unhealthy":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_all_unhealthy_multi_department_slot_statuses_as_unhealthy":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_returns_unknown_when_aggregated_multi_department_slot_targets_are_missing":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_returns_unknown_when_aggregated_multi_department_slot_has_no_evaluable_hours":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_returns_unknown_when_aggregated_multi_department_slot_has_not_started_yet":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsRouteWiringTest::__pest_evaluable_it_registers_department_weather_hour_details_route_with_weather_read_and_department_access_checks":0.007,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_weather_hour_contributions_grouped_per_employee_for_a_slot":0.001,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_weather_hour_contributions_for_canonical_nested_workfeed_employee_schema":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_extracts_weather_employee_identity_from_supported_shift_payload_shapes":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_prefers_canonical_workfeed_employee_schema_fields_over_generic_employee_names":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_does_not_use_workfeed_schema_name_fields_as_employee_ids":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_returns_a_null_employee_name_when_no_workfeed_employee_name_is_available":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_resolves_missing_workfeed_employee_names_from_the_employees_endpoint":0.042,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_filters_employee_hour_rows_that_cannot_be_resolved_to_a_workfeed_schema_name":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_resolves_employee_display_name_from_cache_when_shift_payload_lacks_a_name":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedEmployeeNameFormatterTest::__pest_evaluable_it_formats_workfeed_employee_display_names_from_the_documented_firstname_lastname_schema":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedEmployeeNameFormatterTest::__pest_evaluable_it_prefers_workfeed_schema_names_over_generic_display_name_fields":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedEmployeeNameFormatterTest::__pest_evaluable_it_falls_back_to_legacy_display_name_fields_when_schema_names_are_absent":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedEmployeeNameFormatterTest::__pest_evaluable_it_ignores_placeholder_workfeed_display_names":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedEmployeeNameFormatterTest::__pest_evaluable_it_ignores_employee_id_placeholder_display_names_when_the_id_is_known":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_normalizes_registrations_for_XL_Vask_automation_signatures":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_builds_stable_XL_Vask_automation_item_signatures":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_normalizes_persisted_XL_Vask_usage_log_rows_before_helper_hydration":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_builds_stable_OpenAI_cache_keys_for_identical_automation_input":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_changes_OpenAI_cache_keys_when_automation_eligibility_input_changes":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_declares_a_persistent_OpenAI_cache_table_for_XL_Vask_automation":0.005,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_declares_cached_amount_summary_columns_for_XL_Vask_usage_logs":0.012,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_scores_same_day_orders_with_matching_XL_Vask_products_and_extra_add_ons_as_attach_suggestions":0.003,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_does_not_score_an_order_with_only_the_primary_product_as_a_matching_add_on_attachment":0,"P\\Tests\\Unit\\XLVask\\XLVaskUsageLogHelperTest::__pest_evaluable_it_accepts_persisted_ignore_metadata_from_xlvask_usage_log_rows":0.019,"P\\Tests\\Unit\\XLVask\\XLVaskUsageLogHelperTest::__pest_evaluable_it_calculates_XL_Vask_amount_summaries_without_hydrating_order_item_previews":0.006,"P\\Tests\\Unit\\XLVask\\XLVaskUsageRouteContractTest::__pest_evaluable_it_exposes_direct_linked_order_metadata_on_XL_Vask_usage_order_rows":0.003,"P\\Tests\\Unit\\XLVask\\XLVaskUsageRouteContractTest::__pest_evaluable_it_returns_cached_amount_summaries_on_XL_Vask_usage_order_rows_without_widening_the_usage_log_object_payload":0.003,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_counts_complaint_rows_by_department_and_created__at_reporting_range":0.284,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_updates_and_deletes_complaint_rows":0.005,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_parses_created__by__name_from_the_users_table":0.005,"P\\Tests\\Integration\\DailyReports\\DepartmentOutsideHoursStatisticsServiceIntegrationTest::__pest_evaluable_it_integrates_orders__xlvask__and_self_serve_into_one_outside_hours_summary_with_missing_hours_diagnostics":0.016,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_only_collected_invoice_jobs_and_respects_the_manual_batch_limit":0.014,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_the_configured_database_in_integration_mode":0,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_redis_in_integration_mode_when_configured":0,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_minio_in_integration_mode_when_configured":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_redacts_sensitive_release_timeline_payload_fields_recursively":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_verifies_GitHub_sha256_webhook_signatures":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_normalizes_GitHub_repository_identifiers_for_private_repository_access_checks":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_defines_release_manager_schema__routes__permissions__and_system_status_integration_hooks":0.575,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_summarizes_failed_deployments_and_blocks_promotion_until_a_deployment_succeeds":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_uses_the_selected_Coolify_project_and_resolves_server_UUID_from_the_instance_default":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_supports_isolated_stack_mode_and_names_new_Coolify_services_explicitly":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_creates_Coolify_service_payloads_from_raw_compose_without_a_service_type":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_normalizes_Coolify_API_base_URLs_to_the_v1_API_root":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_parses_generated_env_files_for_Coolify_service_env_bulk_updates":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_prefers_public_Coolify_server_hosts_over_Docker_local_addresses":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_blocks_planned_downtime_operations_against_active_replication_primaries":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_allows_failed_Coolify_replica_targets_to_be_removed_after_the_service_disappears":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_retries_Coolify_maintenance_while_linked_replication_provisioning_is_still_incomplete":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_plans_Hetzner_load_balancer_target_and_service_drift_without_mutating_state":0.24,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_does_not_plan_removal_of_the_last_Hetzner_load_balancer_target":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_plans_removal_only_for_disabled_or_deleted_Hetzner_load_balancer_targets":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_defines_Coolify_schema__route_permissions__and_replication_integration_hooks":0.418,"P\\Tests\\Unit\\ErrorReports\\ErrorReportTest::__pest_evaluable_it_redacts_sensitive_error_report_payload_fields_recursively":0.001,"P\\Tests\\Unit\\ErrorReports\\ErrorReportTest::__pest_evaluable_it_validates_supported_screenshot_data_uris":0,"P\\Tests\\Unit\\ErrorReports\\ErrorReportTest::__pest_evaluable_it_defines_error_report_schema__routes__permissions__storage__and_OpenAPI_docs":0.04,"P\\Tests\\Unit\\Http\\ResponseRequestParametersTest::__pest_evaluable_it_reads_JSON_payloads_for_DELETE_request_parameter_arrays":0,"P\\Tests\\Unit\\Http\\ResponseRequestParametersTest::__pest_evaluable_it_keeps_DELETE_query_parameters_when_no_JSON_body_is_present":0,"P\\Tests\\Unit\\Infrastructure\\CorsReleaseHeadersTest::__pest_evaluable_it_allows_release_telemetry_headers_at_PHP_served_CORS_entry_points":0.424,"P\\Tests\\Unit\\Orders\\OrderBookingsCompletionDedupTest::__pest_evaluable_it_uses_the_linked_pos_order_wash_certificate_item_added_during_mobile_completion":0,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_normalizes_failover_config_defaults_and_per_kind_enablement":0,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_requires_strict_fresh_100_percent_replica_status_for_candidates":0,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_selects_the_freshest_eligible_replica_for_failover":0,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_promotes_enabled_startup_dependencies_from_snapshot_in_dependency_order":0.004,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_does_not_promote_a_disabled_dependency_during_startup_failover":0.001,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_wires_the_failover_module_config_endpoint_and_promotion_paths":0.312,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_can_embed_primary_admin_credentials_in_generated_MariaDB_replica_env_files":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_keeps_operational_and_derived_tables_schema_only_during_MariaDB_seeding_and_replication":0.021,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_supports_metadata_only_replication_host_renames":0.005,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_keeps_MinIO_backup_replicas_bounded_to_the_recent_backup_window":0.014,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_prefills_MinIO_replica_compose_primary_values_from_current_config_when_available":0.001,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_allows_the_MinIO_client_binary_to_be_configured_explicitly":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_supports_MinIO_client_runtime_fallback_configuration":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_extracts_host_specific_MariaDB_replication_account_denials":0.001,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_identifies_stopped_database_replication_threads_as_a_restartable_status":0,"P\\Tests\\Unit\\Scanner\\ModuleScannerRouteTest::__pest_evaluable_it_returns_no_plate_LPR_results_without_a_failed_HTTP_status":0.046,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_does_not_invent_GHCR_images_for_Coolify_service_payloads":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_keeps_release_branch_services_out_of_the_production_Coolify_environment_except_beta":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_creates_Coolify_GitHub_App_application_payloads_so_pulls_use_the_app_token":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_does_not_treat_an_existing_Coolify_service_as_an_application_just_because_a_GitHub_App_UUID_is_stored":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_can_use_the_Coolify_instance_default_GitHub_App_when_source_targets_do_not_store_it_yet":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_updates_existing_frontend_Coolify_applications_away_from_legacy_Nixpacks_detection":0,"P\\Tests\\Unit\\Auth\\EconomicCreateCustomerResponseTest::__pest_evaluable_it_adds_supported_CVR_company_fields_to_the_e_conomic_customer_payload":0.014,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_keeps_release_channel_runtime_availability_independent_from_channel_URLs":0.007,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_chooses_a_requested_runtime_channel_only_when_it_is_available_to_the_principal":0.199,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_normalizes_release_assignment_subject_suggestions_without_leaking_private_fields":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_keeps_GitHub_commit_timestamps_in_public_release_manager_commit_payloads":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_requires_non_default_release_channel_runtime_URLs_and_preserves_load_balancer_paths":0.105,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_exposes_release_version_git_commit_metadata_for_runtime_channel_cards":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_builds_gateway_API_auto_provision_context_for_connected_Coolify_servers":0.001,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_adds_explicit_Coolify_application_route_labels_for_gateway_API_domains":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_builds_explicit_Coolify_application_route_labels_for_release_API_targets":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_uses_the_self_contained_Coolify_API_Dockerfile_for_API_applications":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_isolates_and_restores_Hetzner_load_balancer_IP_targets_for_gateway_certificate_bootstrap":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_requires_gateway_ping_probes_to_return_the_API_ping_contract":0,"P\\Tests\\Unit\\Tooling\\ComposerEntrypointTest::__pest_evaluable_it_checks_PSR_HTTP_message_interfaces_before_trusting_a_Composer_vendor_tree":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_marks_a_channel_ready_when_all_release_services_are_healthy":0.001,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_reports_non_default_channels_missing_bundles__versions__and_URLs_as_blocking_missing_values":0.024,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_surfaces_failed_latest_deployments_as_critical_promotion_blockers":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_flags_isolated_stacks_that_are_missing_database_Redis_and_MinIO_services":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_maps_degraded_Coolify_targets_and_reconcile_failures_to_release_service_issues":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_plans_Hetzner_load_balancer_service_health_check_drift_updates":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_returns_structured_errors_for_failed_gateway_certificate_bootstrap_and_verification":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_captures_release_request_context_from_headers_and_runtime_query_parameters":0.004,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_normalizes_channel_prefixed_API_ingress_paths_before_route_dispatch":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_creates_frontend_Coolify_GitHub_App_application_payloads_with_the_release_Dockerfile":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_builds_gateway_frontend_auto_provision_context_with_the_release_Dockerfile":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_allows_explicit_runtime_selection_of_any_enabled_release_channel":0.289,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_chooses_requested_runtime_channels_from_available_channels_or_enabled_channel_slugs":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_normalizes_gateway_probe_paths_for_release_gateway_health_checks":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_resolves_release_deployment_endpoints_from_manual_overrides__URLs__health_checks__and_gateway_defaults":0.001,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_does_not_report_frontend_or_API_URLs_missing_when_target_auto_endpoints_are_resolvable":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_offers_a_release_bundle_action_when_exactly_one_deployed_bundle_is_eligible":0.008,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_offers_application_target_preparation_for_path_routed_Coolify_failures":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_maps_the_public_master_API_prefix_to_the_stable_release_channel":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_uses_master_as_the_public_route_slug_for_the_stable_release_channel":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_does_not_block_channels_on_unhealthy_data_targets_when_data_services_are_production_shared":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_ignores_missing_legacy_bundles_but_still_blocks_on_missing_versions_and_URLs":0.001,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_marks_a_branch_based_channel_ready_without_a_release_bundle_when_app_versions_and_URLs_exist":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_does_not_surface_legacy_release_bundle_actions_as_readiness_blockers":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_adds_exact_hidden_question__skipped_action__signal__and_button_decision_causes":0,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_rejects_standalone_order_booking_completion_outside_POS":5.621,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_allows_linked_POS_order_booking_completion_for_mobile_POS_compatibility":4.121,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_accepts_numeric_safety_seal_strings_when_completing_a_linked_POS_order_booking":4.366,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_disables_the_legacy_complete_wash_without_certificate_route":1.122,"P\\Tests\\Api\\OrderBookingsUpdateApiTest::__pest_evaluable_it_detaches_an_order_booking_and_clears_the_matching_order_link":5.559,"P\\Tests\\Api\\OrderBookingsUpdateApiTest::__pest_evaluable_it_keeps_the_linked_order_when_order__id_is_omitted_from_an_order_booking_update":5.22,"P\\Tests\\Unit\\DynamicImages\\DepartmentLaneDynamicImageRouteTest::__pest_evaluable_it_accepts_ordered_dynamic_image_button_tokens_including_program_picker_reset_start_and_zero":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_adds_program_picker_before_mapped_machine_buttons_in_simulator_debug_decisions":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_verifies_CI_release_gate_bearer_tokens_from_dedicated_release_credentials":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_only_chooses_requested_runtime_channels_from_channels_available_to_the_principal":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_ignores_explicit_runtime_selection_for_channels_outside_the_principal_channel_set":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_auto_prepares_path_routed_release_targets_for_Coolify_application_creation":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_offers_application_target_preparation_for_missing_Coolify_service_creation_failures":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_builds_API_Coolify_runtime_environment_from_allowed_process_variables":0.001,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_normalizes_URL_like_CORS_entries_to_origins":0,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_merges_required_release_and_existing_frontend_origins_into_configured_CORS":0,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_builds_credential_safe_normal_CORS_response_headers_for_allowed_origins":0,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_builds_preflight_CORS_response_headers_for_api_v2_release_URLs":0,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_rejects_unknown_CORS_origins":0,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_reflects_the_request_origin_for_wildcard_CORS_instead_of_sending_credentialed_wildcard_headers":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_allows_customers_with_own_self_serve_permission_to_use_enabled_self_serve_lanes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_blocks_customer_lane_mutations_without_own_self_serve_permission":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_blocks_customer_lane_mutations_when_the_lane_is_not_operationally_enabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_allows_active_wash_operations_when_the_lane_runtime_belongs_to_the_customer":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_falls_back_to_active_department_sessions_for_customer_active_wash_operations":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_blocks_active_wash_operations_for_other_customers":0,"P\\Tests\\Unit\\Selfserve\\SelfservePropertyGatePermissionBypassTest::__pest_evaluable_it_does_not_bypass_property_gate_permissions_without_customer_self_serve_permission":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_keeps_active_wash_operations_available_if_a_lane_is_disabled_after_start":0,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_requires_authentication_before_checking_in_progress_wash_permissions":0,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_reports_both_elevated_and_customer_self_serve_permissions_when_lane_polling_is_not_allowed":0,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_allows_customer_self_serve_permission_to_view_their_own_in_progress_wash_details":0,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_redacts_another_customers_in_progress_wash_from_customer_self_serve_lane_polling":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_keeps_beta_API_runtime_environment_on_production_database_target":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_treats_attach_existing_service_sets_without_data_target_ids_as_production_shared_ready":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_rejects_beta_release_bundles_that_resolve_to_isolated_cloned_or_fresh_data_services":0.01,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_detects_explicit_data_target_ids_so_beta_service_sets_can_stay_data_only":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_resolves_backend_commit_sha_from_API_runtime_environment_in_priority_order":0.009,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_injects_selected_API_commit_into_Coolify_runtime_env_unless_explicitly_set":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_allows_beta_production_service_bundles_only_when_data_services_stay_production_shared":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_keeps_release_branch_services_out_of_the_production_Coolify_environment":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_marks_beta_ready_from_the_production_frontend_and_API_services":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_uses_program_picker_button_numbers_as_thumb_selectors_in_simulator_debug_decisions":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_upserts_path_editor_answers_into_generated_condition_and_task_config_rows":0.021,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_marks_projected_path_confirmations_confirmed_or_stale_by_stable_signatures":0,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_creates_self_serve_studio_path_confirmation_storage":0.003,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_resolves_subuser_customer_names_without_external_lookups_during_list_requests":0.208}} \ No newline at end of file +{"version":"pest_3.8.6","defects":{"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_type__eligibility__summary__and_webhook_endpoints":1,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_defines_reusable_self_serve_wash_and_machine_type_schemas":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_redistributes_booked_department_75_net_amounts_using_fixed_pricing_and_wash_subscription_weights":7,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_classified_booked_department_75_amounts_undistributed_when_no_monthly_basis_exists":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_unclassified_booked_department_75_lines_undistributed_with_warnings":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_v2_historical_distribution_and_pricing_history_paths_in_openapi":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_defines_new_reusable_v2_schemas_for_normalization_comparison_versioning_and_distribution":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_supports_bulk_booked_invoice_line_payloads_with_top_level_department_numbers":7,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_claims_a_slot_atomically_with_nx_and_expiration":8,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_returns_false_when_the_slot_is_already_claimed_and_clamps_ttl_to_one_second":8,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_economic_v2_invoice_paths_in_openapi":1,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_aligns_legacy_compare_schema_with_runtime_payload_by_removing_stale_required_order__ids":1,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_documents_every_supported_search_entity_type_in_openapi_enum":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_system_wide_search_endpoints_in_openapi":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_debug__intent_and_parser_metadata_schema_in_openapi":1,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_e_conomic_indexed_customer_matching_and_synonym_behavior":1,"P\\Tests\\Integration\\Database\\DbConnectionTest::__pest_evaluable_it_can_connect_to_a_configured_MySQL_instance_in_integration_mode":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_runs_best_effort_backfill_repeatedly_without_introducing_duplicate_same_start_rows":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_resolves_version_aware_distribution_payload_shapes_over_a_real_date_range":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_creates_closes_and_rotates_fixed_pricing_versions_without_overlap":1,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_tracks_vehicle_and_discount_version_lifecycles_with_closure_semantics":1,"P\\Tests\\Integration\\Permissions\\LegacyPermissionRedisCacheScriptTest::__pest_evaluable_it_keeps_legacy_route_permission_redis_cache_script_green":1,"P\\Tests\\Unit\\Goals\\GoalsOpenApiSpecTest::__pest_evaluable_it_documents_advanced_goals_target_duration_fields_in_openapi":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_documents_the_date_key_in_the_openapi_department_weather_timeline_schema":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_builds_timeline_entries_with_mostly__clear_weather_when_forecast_payload_is_empty":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_wires_departments_weather_route_through_the_forecast_fallback_path":7,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_groups_attachments_by_object_id_and_preserves_empty_object_groups":8,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_keeps_listMany_payload_parity_with_list_for_one_object_id":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_department_weather_target_endpoints_and_reusable_schemas_in_openapi":1,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_unknown_weather_status_behavior_when_targets_are_missing":1,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_1_request_per_second_Shelly_gate_for_back_to_back_requests":8,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_in_progress_self_serve_wash_start_and_machine_relay_fields":1,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_stores_config_json_with_apostrophes_without_violating_json_constraints":8,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_is_on__then_turns_off_cleaner_machine_and_selector_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_is_off_and_only_disables_configured_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_wash_included_minutes_in_config_schemas":1,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_channel_id_is_missing_for_gate_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_with_terminal_status_details_when_call_never_reaches_accepted_state":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_when_call_reaches_accepted_state":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_immediately_when_status_transitions_to_accepted":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_maps_legacy_timeout_option_to_documented_ringTimeout_payload_field":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_clamps_derived_ringTimeout_to_Bird_documented_max_when_gate_timeout_is_high":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_passes_documented_hangup_cause_when_provided":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_drops_unsupported_hangup_cause_values_from_request_payload":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_flash_calls":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_creates_gate_flash_call_with_documented_ringTimeout_payload":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_polls_flash_call_and_succeeds_once_accepted":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_flash_gate_flow_when_terminal_failure_status_is_returned":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_does_not_fallback_to_regular_gate_call_when_flash_succeeds":8,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_fails":8,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_property_gate_lane_commands_and_sanitized_gate_failure_responses":1,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_returns_raw_payload_for_malformed_JSON_responses_and_null_for_empty_responses":8,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_keeps_Bird_number_and_webhook_routes_intact":7,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_handles_malformed_and_empty_response_bodies_without_throwing_transport_errors":8,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_multi_department_slot_statuses_using_worst_severity_and_unknown_fallback_rules":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_relay_is_online__then_turns_off_cleaner_and_machine_relays":7,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_bills_primary_product_when_selector_relay_is_online_even_if_relay_output_is_off":7,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_all_Bird_voice_call_parity_endpoints_including_gather_recordings_insights_and_log":1,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_flash_hangup_endpoint_and_marks_end_alias_as_deprecated":1,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_defines_request_and_response_schemas_for_Bird_call_command_recording_insight_log_and_flash_payloads":1,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_collected_invoice_queue_endpoints_in_orderInvoicesRoute":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_missing_queue_dependencies":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_wires_zero_cost_and_zero_quantity_skip_guard_into_transfer_line_builder":7,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_queued_transfer_jobs_to_completion":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_deduplicates_active_jobs_per_transfer_target":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_rejects_invalid_payloads_without_inserting_queue_rows":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_supports_fail_retry_and_reprocess_lifecycle_transitions":1,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_supports_synchronous_fallback_branches_before_queue_enqueue_on_economic_invoice_export_routes":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_status_endpoints_guarded_while_collected_invoice_export_routes_support_synchronous_fallback":7,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_supports_independent_po__number_and_closed__at_updates_for_PUT__collected_invoices_in_user_route":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_returns_pagination_metadata_and_strict_status_handling_for_collected_invoice_queue_list":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_enforces_retry_constraints_for_collected_invoice_queue_jobs_before_retry_execution":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_collected_queue_list_metadata_and_strict_status_filter_enum_in_openapi":7,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_builds_a_completed_collected_invoice_queue_summary_from_payload_and_result":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_prefers_queue_error_messages_for_failed_jobs_and_keeps_null_safe_outcome_fields":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_uses_deterministic_status_message_fallback_when_no_explicit_message_exists":8,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_handles_object_payload_result_values_and_malformed_fields_without_throwing":8,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_collected_invoice_transfer_queue_from_queue_list_and_status_routes":7,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_order_transfer_queue_from_draft_and_invoice_status_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_PHP_agent_artifacts_and_management_polling_config":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__and_operation_endpoints_without_shell_transport_wiring":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_relay_fallback_and_transport_health_details_without_shell_or_update_runtime_state":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_the_source_tree_layout":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_mounted_and_baked_in_artifact_directories_before_repo_fallbacks":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_router_resources_before_mounted_and_baked_in_artifact_directories":7,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_orders_for_an_admin_scoped_user_and_limits_the_results_to_the_permitted_departments":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_only_the_targeted_customer_orders_for_subuser_sessions":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_returns_the_current_auth_and_permission_failures_when_order_listing_is_not_allowed":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_creates_orders_through_the_real_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_creation_requests":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_primary_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_reassigns_invoice_collections_when_changing_an_order_across_the_draft_customer_boundary":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_primary_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_primary_order_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_legacy_alias_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_alias_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_legacy_alias_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_unsupported_legacy_field_value_updates_on_both_update_endpoints":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_deletes_orders_through_the_real_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_delete_requests":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_when_certificate_metadata_changes_through_the_primary_endpoint":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_for_legacy_field_value_updates_through_the_alias_endpoint":8,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_every_selected_API_operation_covered_by_happy_path_and_failure_tests":8,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_the_OpenAPI_manifest_entries_aligned_with_the_API_spec":8,"P\\Tests\\Api\\ApiFixturesCleanupTest::__pest_evaluable_it_removes_generated_customer_traces_during_fixture_cleanup":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_in_with_valid_customer_credentials":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_login_payloads_and_credentials":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_returns_the_cached_auth_session_payload_for_a_valid_token":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_includes_economic_runtime_config_for_uncached_auth_sessions":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_auth_session_tokens":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_the_token_for_future_session_calls":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_cached_subuser_sessions":8,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_logout_tokens":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_the_raw_202_gather_webhook_contract_over_HTTP":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_still_prompts_for_department_selection_when_only_one_department_is_eligible":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_accepts_the_legacy_initial_webhook_body_with_top_level_call_identifiers":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_native_flow_gather_data_after_a_top_level_department_selection_when_distinct_gate_choices_exist":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_opens_the_gate_immediately_after_a_top_level_department_selection_when_entrance_and_exit_share_the_same_gate":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_uses_a_multi_digit_gather_contract_when_10_departments_are_eligible":8,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_a_raw_400_transport_error_for_malformed_webhook_payloads":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_only_visible_departments_and_can_return_a_single_department_with_the_slack_webhook":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_department_listing_when_the_permission_is_missing":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_creates_departments_through_the_real_endpoint":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_create_requests":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_updates_departments_through_the_real_endpoint":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_update_requests":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_department_categories_for_a_department":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_category_requests":8,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_lists_the_draft_customer_config_entry_in_economic_config_responses":8,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_draft_customer_config_value_through_economic_config_updates":8,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_order_draft_exports_for_the_configured_draft_customer":8,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_booked_invoice_exports_for_the_configured_draft_customer":8,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_collected_invoice_exports_for_the_configured_draft_customer":8,"P\\Tests\\Api\\PingApiTest::__pest_evaluable_it_returns_the_ping_contract":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_department_terminal_readers_are_requested_without_terminal_setup":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_sends_a_Stripe_invoice_by_email_and_persists_the_hosted_invoice_association":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_conflict_when_a_Stripe_hosted_invoice_is_already_active_for_the_order":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_allows_sending_a_new_Stripe_hosted_invoice_when_the_existing_association_is_already_terminal":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_voids_an_unpaid_Stripe_hosted_invoice_and_clears_the_local_order_association":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_refuses_to_cancel_a_paid_Stripe_hosted_invoice":8,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_creating_a_payment_intent_for_a_department_without_terminal_setup":8,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_the_newest_vehicle_last__order__id_that_still_has_order_items":8,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_a_null_vehicle_last__order__id_when_no_order_with_items_exists":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_syncs_gateway_snapshots_into_cached_list_payloads_and_refreshes_fleet_usage":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_keeps_only_the_module_facade_in_the_global_classes_directory_and_conditionally_loads_module_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_compose_edge_gateway_artifacts_and_forwarded_https_scheme":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_compose_stack_artifacts_and_management_polling_config":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__cancel_endpoints__and_operation_endpoints_without_shell_transport_wiring":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_v2_operator_facing_edge_gateway_routes":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_defines_the_v2_edge_gateway_schema_bootstrap_tables":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_stores_operation_metadata_and_event_timelines_for_management_workflows":7,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured":8,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_returns_the_updated_lane_id_after_editing_a_scanner_whose_null_lane_was_already_cached":8,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_serves_installer_artifacts_and_recovers_gateway_runtime_status_after_fresh_heartbeats":8,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_polls_operations_and_commands__submits_results__and_records_broker_presence_for_task_pages":8,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_builds_broker_backlog_and_completes_gateway_operations_through_broker_endpoints":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_creates_install_tokens__tracks_installer_status__and_exposes_claimed_gateway_detail_to_authorized_operators":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_manages_edge_gateway_metadata__bindings__operations__sessions__rotation__cutover__and_deletion":8,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_assembles_tasks__logs__statistics__operations__commands__and_shell_lifecycle_state_from_persisted_records":1,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_invalid_edge_broker_shared_secrets":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_rejects_operator_edge_routes_when_module_permission_or_department_access_is_missing":8,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_rejects_missing_and_invalid_edge_agent_tokens":8,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_persists_gateway_cutover_relay_bindings_used_by_self_serve_Shelly_dispatch":1,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_validates_broker_sessions_and_ingests_presence__telemetry__logs__and_shell_lifecycle_data":8,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_shell_session_creation_while_broker_presence_is_unavailable":8,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_ignores_and_soft_deletes_edge_gateways_whose_department_no_longer_exists":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_appends_forwarded_ports_when_the_forwarded_host_omits_them":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_websocket_broker_urls_on_the_traefik_broker_path":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_localhost_websocket_broker_urls_on_the_local_traefik_api_prefix":8,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_keeps_root_host_api_urls_unprefixed_when_the_request_is_not_under_the_local_api_alias":8,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_resolves_simulator_gateway_service_bindings_from_lane_relay_slots":7,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_overtime_minutes_when_a_saved_shift_end_extends_past_the_approved_original_end":7,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_unapproved_overtime_from_a_bounded_shift_updateTime_fallback":7,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_caps_current_slot_hours_to_elapsed_minutes_and_zeroes_future_slots":7,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_default_distribution_department_config_value_through_economic_config_updates":8,"P\\Tests\\Unit\\Replication\\ReplicationSecretBoxTest::__pest_evaluable_it_encrypts_replication_secrets_without_storing_plaintext":8,"P\\Tests\\Unit\\Replication\\ReplicationSecretBoxTest::__pest_evaluable_it_builds_active_database_and_redis_config_from_encrypted_bootstrap_snapshots":8,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_does_not_require_replica_SQL_threads_before_database_provisioning_configures_them":7,"P\\Tests\\Unit\\Invoicing\\EconomicDraftCustomerOpenApiSpecTest::__pest_evaluable_it_documents_transaction_draft_customer_config_and_auth_runtime_fields_in_all_tracked_openapi_copies":1,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_computes_MinIO_free_space_and_catch_up_math_safely":7,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_counts_complaint_rows_by_department_and_created__at_reporting_range":1,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_updates_and_deletes_complaint_rows":1,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_parses_created__by__name_from_the_users_table":1,"P\\Tests\\Integration\\DailyReports\\DepartmentOutsideHoursStatisticsServiceIntegrationTest::__pest_evaluable_it_integrates_orders__xlvask__and_self_serve_into_one_outside_hours_summary_with_missing_hours_diagnostics":1,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_persists_install_session_updates_and_derives_gateway_runtime_status_from_heartbeats":1,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_only_collected_invoice_jobs_and_respects_the_manual_batch_limit":1,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_the_configured_database_in_integration_mode":1,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_redis_in_integration_mode_when_configured":1,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_minio_in_integration_mode_when_configured":1,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_creates_Coolify_service_payloads_from_raw_compose_without_a_service_type":7,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_uses_the_selected_Coolify_project_and_resolves_server_UUID_from_the_instance_default":8,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_creates_Coolify_GitHub_App_application_payloads_so_pulls_use_the_app_token":7,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_uses_the_self_contained_Coolify_API_Dockerfile_for_API_applications":7,"P\\Tests\\Unit\\Tooling\\ComposerEntrypointTest::__pest_evaluable_it_checks_PSR_HTTP_message_interfaces_before_trusting_a_Composer_vendor_tree":7,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_defines_release_manager_schema__routes__permissions__and_system_status_integration_hooks":7,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_requires_non_default_release_channel_runtime_URLs_and_preserves_load_balancer_paths":7,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_wires_MinIO_replication_through_routes_and_bootstrap_snapshots":7,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_defines_Coolify_schema__route_permissions__and_replication_integration_hooks":7,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_chooses_a_requested_runtime_channel_only_when_it_is_available_to_the_principal":8,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_rejects_standalone_order_booking_completion_outside_POS":8,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_allows_linked_POS_order_booking_completion_for_mobile_POS_compatibility":8,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_accepts_numeric_safety_seal_strings_when_completing_a_linked_POS_order_booking":8,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_disables_the_legacy_complete_wash_without_certificate_route":8,"P\\Tests\\Api\\OrderBookingsUpdateApiTest::__pest_evaluable_it_detaches_an_order_booking_and_clears_the_matching_order_link":8,"P\\Tests\\Api\\OrderBookingsUpdateApiTest::__pest_evaluable_it_keeps_the_linked_order_when_order__id_is_omitted_from_an_order_booking_update":8,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_allows_explicit_runtime_selection_of_any_enabled_release_channel":7,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_requires_authentication_before_checking_in_progress_wash_permissions":7,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_reports_both_elevated_and_customer_self_serve_permissions_when_lane_polling_is_not_allowed":7,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_allows_customer_self_serve_permission_to_view_their_own_in_progress_wash_details":7,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_redacts_another_customers_in_progress_wash_from_customer_self_serve_lane_polling":7,"P\\Tests\\Api\\SelfserveFixtureApiTest::__pest_evaluable_it_creates_a_comprehensive_self_serve_API_scenario_with_demo_relays":1,"P\\Tests\\Api\\SelfserveZZZShellyGuardApiTest::__pest_evaluable_it_did_not_record_any_real_Shelly_request_attempts_during_self_serve_API_tests":8,"P\\Tests\\Api\\ApiFixturesCleanupTest::__pest_evaluable_it_restores_preserved_module_config_rows_during_fixture_cleanup":8,"P\\Tests\\Api\\BrandingApiTest::__pest_evaluable_it_creates_lists_and_updates_complete_branding_values":8,"P\\Tests\\Api\\BrandingApiTest::__pest_evaluable_it_rejects_branding_requests_without_permissions_or_valid_input":8,"P\\Tests\\Api\\BrandingApiTest::__pest_evaluable_it_assigns_and_clears_department_branding_for_superusers":8,"P\\Tests\\Api\\BrandingApiTest::__pest_evaluable_it_rejects_invalid_department_branding_assignments":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_previews_monthly_split_changes_without_moving_orders_or_creating_collections":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_splits_a_selected_March_and_April_collected_invoice_into_monthly_collections":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_sets_closed__at_to_month_end_when_split_month_has_ended":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_splits_the_whole_affected_collection_even_when_only_one_month_is_selected":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_does_not_affect_booked_collected_invoices":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_skips_draft_linked__Stripe__and_single_month_collections":8,"P\\Tests\\Api\\CollectedInvoiceMonthlySplitApiTest::__pest_evaluable_it_rejects_invalid_monthly_split_date_ranges":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_allows_superusers_to_filter_archived_departments":8,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_does_not_allow_regular_department_listings_to_reveal_archived_departments_through_filters":8,"P\\Tests\\Api\\EdgeGatewayConfigApiTest::__pest_evaluable_it_stores_broker_settings_in_edge_gateway_module_config_and_uses_them_for_shell_sessions":8,"P\\Tests\\Api\\EdgeGatewayConfigApiTest::__pest_evaluable_it_returns_broker_diagnostics_for_the_current_edge_gateway_module_config_values":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_defaults_order_PO_from_a_linked_booking_when_creating_without_an_order_PO":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_keeps_an_explicit_order_PO_when_creating_a_linked_order":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_defaults_blank_order_PO_from_a_linked_booking_on_order_updates":8,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_requires_explicit_confirmation_before_deleting_protected_orders":8,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_rejects_plate_scanner_edits_when_the_permission_is_missing":8,"P\\Tests\\Api\\ReferenceSuggestionsApiTest::__pest_evaluable_it_returns_ranked_POS_reference_suggestions_from_bookings__orders__and_customer_vehicles":8,"P\\Tests\\Api\\ReferenceSuggestionsApiTest::__pest_evaluable_it_orders_reference_suggestions_by_match_relevance_before_context_and_frequency":8,"P\\Tests\\Api\\ReferenceSuggestionsApiTest::__pest_evaluable_it_enforces_authentication__list_permission__and_department_access_for_reference_suggestions":8,"P\\Tests\\Api\\SelfserveFixtureApiTest::__pest_evaluable_it_creates_self_serve_invoice_orders_for_the_lane_customer_with_draft_customer_and_driver_metadata_attached":8,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_allows_customer_self_serve_permission_to_execute_START_without_department_access_when_department_and_lane_are_enabled":8,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_denies_customer_START_when_department_self_serve_is_disabled":8,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_denies_customer_START_when_lane_self_serve_is_disabled":8,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_denies_a_customer_STOP_for_another_customers_active_lane":8,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_still_allows_elevated_operators_with_department_access_to_execute_lane_commands":8,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_keeps_operator_only_commands_elevated_only_for_customers_and_reports_command_permissions":8,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_requires_authentication_before_checking_the_current_customers_active_self_serve_wash":7,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_requires_customer_self_serve_permission_before_checking_my_active_wash":7,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_returns_the_authenticated_customers_active_self_serve_wash_without_requiring_a_lane_id":7,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_returns_404_when_the_authenticated_customer_has_no_active_self_serve_wash":7,"P\\Tests\\Unit\\Selfserve\\SelfserveEligibilityLaneAccessTest::__pest_evaluable_it_authorizes_customer_eligibility_preview_lanes_before_returning_task_attachments":8,"P\\Tests\\Api\\SelfserveCustomerStartApiTest::__pest_evaluable_it_allows_the_customer_self_serve_start_sequence_without_department_access":1,"P\\Tests\\Api\\SelfserveCustomerStartApiTest::__pest_evaluable_it_derives_allowed_services_from_v2_session_task_snapshots_when_task_rows_are_not_legacy_records":7},"times":{"P\\Tests\\Unit\\Auth\\CreateTokenTest::__pest_evaluable_it_creates_a_64_char_auth_token_for_an_existing_user":0.11,"P\\Tests\\Unit\\Auth\\CreateTokenTest::__pest_evaluable_it_throws_a_clear_exception_when_customer_user_is_missing":0.017,"P\\Tests\\Unit\\Auth\\LegacyAuthScriptParityTest::__pest_evaluable_it_keeps_passkey_challenge_legacy_script_green_during_migration":0.032,"P\\Tests\\Unit\\Auth\\LegacyAuthScriptParityTest::__pest_evaluable_it_keeps_register_CVR_legacy_script_green_during_migration":0.035,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_deterministic_department_digit_map_and_caps_to_9_options":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_resolves_department_ids_by_selected_digit":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_resolves_gate_type_digit_to_entrance_or_exit":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_stores__loads_and_clears_ivr_state_with_ttl":0.001,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_validates_state_caller_fingerprint_matching":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_department_and_gate_prompts":0,"P\\Tests\\Unit\\Permissions\\PermissionNodeDefinitionTest::__pest_evaluable_it_creates_permission_nodes_linked_to_subuser_permission_keys":0,"P\\Tests\\Unit\\Permissions\\PermissionNodeDefinitionTest::__pest_evaluable_it_rejects_empty_permission_definitions":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_normalizes_button_arrays__json_and_csv_inputs":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_invalid_button_inputs":0.001,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_normalizes_vehicle_type_values_and_null_semantics":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_invalid_vehicle_type_values":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_rejects_non_numeric_vehicle_type_strings":0,"P\\Tests\\Unit\\Selfserve\\NormalizationTest::__pest_evaluable_it_keeps_lane_service_enum_contract_for_MACHINE":0,"P\\Tests\\Unit\\Subusers\\SubuserGrantInitializationTest::__pest_evaluable_it_initializes_booking_node_grants_without_DB_dependency":0.001,"P\\Tests\\Unit\\Subusers\\SubuserGrantInitializationTest::__pest_evaluable_it_initializes_selfserve_node_grants_without_DB_dependency":0,"P\\Tests\\Unit\\Subusers\\SubusersRoutePermissionLinkTest::__pest_evaluable_it_keeps_subusers_route_list_permission_linked_to_SUBUSERS__LIST_node":0.009,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_keeps_route_and_service_entity_type_registries_in_sync_with_expanded_coverage":0,"P\\Tests\\Unit\\Search\\SystemSearchEntityTypeCoverageTest::__pest_evaluable_it_documents_every_supported_search_entity_type_in_openapi_enum":0.047,"P\\Tests\\Unit\\Search\\SystemSearchEconomicCustomerIndexWiringTest::__pest_evaluable_it_wires_local_e_conomic_customer_index_into_customer_related_search_entities":0.016,"P\\Tests\\Unit\\Search\\SystemSearchEconomicCustomerIndexWiringTest::__pest_evaluable_it_registers_cron_tasks_that_keep_the_e_conomic_search_index_refreshed":0.018,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_from_generic_db_object_mutation_flows":0.052,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_from_object_property_mutations":0.01,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_marks_system_search_cache_dirty_when_module_config_values_change":0.008,"P\\Tests\\Unit\\Search\\SystemSearchInvalidationHooksTest::__pest_evaluable_it_registers_cron_maintenance_task_for_system_search_cache":0.075,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_redacts_obvious_sensitive_fragments_before_sending_query_to_intent_parser":0.001,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_builds_payload_with_redacted_query_and_parses_strict_JSON_output":0.001,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_falls_back_safely_when_OpenAI_is_disabled":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_handles_malformed_OpenAI_response_payloads_without_throwing":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_uses_parser_cache_for_identical_query_and_allowed_type_combinations":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenAiIntentParserTest::__pest_evaluable_it_caps_alias_and_hint_payloads_from_OpenAI_and_filters_hints_to_allowed_types":0,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_system_wide_search_endpoints_in_openapi":0.106,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_debug__intent_and_parser_metadata_schema_in_openapi":0.035,"P\\Tests\\Unit\\Search\\SystemSearchOpenApiSpecTest::__pest_evaluable_it_documents_e_conomic_indexed_customer_matching_and_synonym_behavior":0.022,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_normalizes_type_lists_from_csv_json_and_arrays":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_parses_booleans_and_clamps_integers_using_route_defaults":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteBehaviorTest::__pest_evaluable_it_exposes_expected_searchable_entity_types":0,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_registers_system_wide_search_GET_and_POST_endpoints_with_intent_debug_support":0.028,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_registers_superuser_cache_clear_and_rebuild_endpoints_for_system_search":0.031,"P\\Tests\\Unit\\Search\\SystemSearchRouteWiringTest::__pest_evaluable_it_passes_permission_and_own_scope_context_into_system_search_service":0.008,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_does_not_invoke_intent_parser_when_lexical_confidence_is_already_high":0.001,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_invokes_parser_on_low_confidence_lexical_results_and_applies_hints_only_boosts":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_never_lets_parser_entity_hints_override_explicit_include_filters":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_returns_fallback_parser_metadata_when_parser_fails_gracefully":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_scopes_query_cache_by_permission_context_to_avoid_cross_user_cache_leakage":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_caps_AI_driven_expanded_terms_to_prevent_query_amplification":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_expands_danish_discount_wording_into_lexical_discount_synonyms":0.003,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_invokes_parser_for_intent_driven_natural_language_queries_even_when_lexical_score_is_high":0.003,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_uses_association_hints_to_pull_related_customer_records_from_non_customer_matches":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_prefers_newer_records_when_relevance_scores_are_comparable":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_keeps_explicit_identifier_matches_ahead_of_newer_but_weaker_records":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_promotes_invoices_orders_order_bookings_and_customers_in_ranking":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_never_prioritizes_cancelled_bookings_over_active_bookings":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_heavily_demotes_configured_low_priority_entity_types_in_ranking":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_tokenizes_unicode_names_without_stripping_non_ascii_letters":0.001,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_does_not_treat_explicit_identifier_queries_as_intent_driven":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_requires_broader_term_coverage_for_multi_word_scoring":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_enriches_object_attachment_results_with_associated_customer_context":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_includes_the_economic_customer_index_in_cache_dependencies_for_customer_scoped_results":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_falls_back_to_invoice_date_ranges_when_invoice_names_are_missing":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_derives_xlvask_customer_numbers_only_from_digits_only_extern_ids":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_replaces_unnamed_user_titles_with_the_customer_context_name":0,"P\\Tests\\Unit\\Search\\SystemSearchServiceIntentFlowTest::__pest_evaluable_it_uses_the_goal_criteria_label_for_department_goal_titles":0,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_reuses_parser_cache_entries_for_repeated_natural_language_intent_requests":0.129,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_clears_parser_cache_namespace_via_clearAll_to_force_a_fresh_parse":0,"P\\Tests\\Integration\\Search\\SystemSearchCacheIntegrationTest::__pest_evaluable_it_bumps_per_table_cache_versions_when_a_dirty_table_marker_is_registered":0.05,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_fixed_pricing_when_regular_orders_yield_no_customers":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_wash_subscriptions_when_regular_orders_yield_no_customers":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CliBackfillCommandTest::__pest_evaluable_it_registers_economic_v2_backfill_command_in_cli_dispatcher":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicV2CliBackfillCommandTest::__pest_evaluable_it_provides_a_backfill_cron_script_entrypoint":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_exact__match_when_totals_lines_and_departments_are_identical":0.001,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_total__mismatch_when_only_totals_differ":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_detects_line_level_mismatches_for_quantity_and_price":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_detects_departmental_distribution_mismatches":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2CompareEngineTest::__pest_evaluable_it_returns_missing__target_when_draft_or_booked_target_is_unavailable":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_normalizes_draft_invoice_lines_including_departmental_distributions":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_marks_text_only_zero_value_lines_as_non_billable_and_keeps_deterministic_key":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_normalizes_booked_invoices_and_computes_net_total_delta_from_lines":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2LineNormalizerTest::__pest_evaluable_it_contains_internal_normalization_path_with_departmental_metadata_support":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_economic_v2_invoice_paths_in_openapi":0.016,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_documents_v2_historical_distribution_and_pricing_history_paths_in_openapi":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_aligns_legacy_compare_schema_with_runtime_payload_by_removing_stale_required_order__ids":0.012,"P\\Tests\\Unit\\Invoicing\\EconomicV2OpenApiSpecTest::__pest_evaluable_it_defines_new_reusable_v2_schemas_for_normalization_comparison_versioning_and_distribution":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicV2RevenueAndBarredSupportTest::__pest_evaluable_it_supports_barred_filtering_when_listing_e_conomic_customers":0.08,"P\\Tests\\Unit\\Invoicing\\EconomicV2RevenueAndBarredSupportTest::__pest_evaluable_it_implements_a_dedicated_v2_e_conomic_revenue_statistics_service_and_route":0.014,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_registers_all_collected_invoice_economic_v2_routes_with_explicit_permissions":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_registers_version_aware_distribution_and_pricing_history_v2_routes":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_caches_v2_distribution_responses_with_a_configurable_redis_ttl":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_fixed_pricing_versions_from_create_and_delete_flows":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_vehicle_subscription_versions_for_create_update_delete_flows":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_writes_discount_override_versions_from_superuser_discounts_route":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicV2RouteAndVersioningHooksTest::__pest_evaluable_it_keeps_legacy_compare_endpoint_path_for_backward_compatibility":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_implements_effective_range_lifecycle_methods_for_all_versioned_entities":0.036,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_closes_previous_active_interval_before_inserting_a_new_version":0.021,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_includes_best_effort_backfill_with_provenance_and_confidence_metadata":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicV2VersioningServiceStructureTest::__pest_evaluable_it_anchors_historical_resolution_on_order_created__at_timestamps_in_distribution_service":0.013,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_guards_against_empty_order_ids_in_net_amount_calculation":0.081,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_guards_against_empty_customer_arrays_in_date_range_transaction_fetches":0.074,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_uses_centralized_duplicate_filtering_for_possible_duplicate_detection":0.081,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_builds_deterministic_cache_keys_per_scope_and_date_range":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteCacheHelpersTest::__pest_evaluable_it_falls_back_to_resolver_directly_when_cache_ttl_is_disabled":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_requires_superuser_permission_for_invoicing_period_distribution_all_endpoint":0.05,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_uses_shared_date_range_normalization_across_invoicing_period_endpoints":0.705,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_normalizes_a_valid_invoicing_date_range_to_full_day_timestamps":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_rejects_invalid_date_formats":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_rejects_descending_date_ranges":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodUtilsTest::__pest_evaluable_it_finds_duplicate_orders_regardless_of_original_input_order":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_runs_best_effort_backfill_when_fixed_pricing_version_history_is_empty":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_self_serve_conditions_with_combined_AND_and_OR_semantics":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_prefers_condition_results_over_question_answers_when_evaluating_task_gates":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_type__eligibility__summary__and_webhook_endpoints":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_defines_reusable_self_serve_wash_and_machine_type_schemas":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_machine_types__eligibility__summaries__and_machine_start_webhook_routes":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_machine_type_support_wired_into_lanes__tasks__and_conditions_routes":0,"P\\Tests\\Unit\\N8n\\N8nRouteHelpersTest::__pest_evaluable_it_normalizes_webhook_methods_and_falls_back_to_POST_for_unsupported_verbs":0,"P\\Tests\\Unit\\N8n\\N8nRouteHelpersTest::__pest_evaluable_it_filters_request_parameters_down_to_the_allowed_n8n_query_keys":0,"P\\Tests\\Unit\\N8n\\N8nRouteWiringTest::__pest_evaluable_it_registers_workflow_lifecycle_endpoints_for_the_n8n_module":0.182,"P\\Tests\\Unit\\N8n\\N8nRouteWiringTest::__pest_evaluable_it_registers_execution_and_webhook_trigger_endpoints_for_the_n8n_module":0.115,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_redistributes_booked_department_75_net_amounts_using_fixed_pricing_and_wash_subscription_weights":0.001,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_classified_booked_department_75_amounts_undistributed_when_no_monthly_basis_exists":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_keeps_unclassified_booked_department_75_lines_undistributed_with_warnings":0,"P\\Tests\\Unit\\Invoicing\\EconomicEndpointUrlEncodingTest::__pest_evaluable_it_encodes_raw_filter_query_values_that_include_timestamps":0,"P\\Tests\\Unit\\Invoicing\\EconomicEndpointUrlEncodingTest::__pest_evaluable_it_avoids_double_encoding_query_values_that_are_already_escaped":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_supports_bulk_booked_invoice_line_payloads_with_top_level_department_numbers":0,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_claims_a_slot_atomically_with_nx_and_expiration":0,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_returns_false_when_the_slot_is_already_claimed_and_clamps_ttl_to_one_second":0,"P\\Tests\\Unit\\Bookings\\OrderBookingRouteIdempotencyGuardTest::__pest_evaluable_it_guards_order_booking_creation_with_redis_backed_idempotency":0.101,"P\\Tests\\Unit\\DynamicImages\\DynamicImagePreRenderCronWiringTest::__pest_evaluable_it_registers_dynamic_image_pre_render_cron_task_and_related_helpers":0.01,"P\\Tests\\Integration\\Database\\DbConnectionTest::__pest_evaluable_it_can_connect_to_a_configured_MySQL_instance_in_integration_mode":0.016,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_runs_best_effort_backfill_repeatedly_without_introducing_duplicate_same_start_rows":0.013,"P\\Tests\\Integration\\Invoicing\\EconomicV2BackfillAndDistributionIntegrationTest::__pest_evaluable_it_resolves_version_aware_distribution_payload_shapes_over_a_real_date_range":0.016,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_creates_closes_and_rotates_fixed_pricing_versions_without_overlap":0.015,"P\\Tests\\Integration\\Invoicing\\EconomicV2VersioningServiceIntegrationTest::__pest_evaluable_it_tracks_vehicle_and_discount_version_lifecycles_with_closure_semantics":0.014,"P\\Tests\\Integration\\Permissions\\LegacyPermissionRedisCacheScriptTest::__pest_evaluable_it_keeps_legacy_route_permission_redis_cache_script_green":0.01,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_returns_both_own_and_elevated_permissions_when_both_are_missing":0,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_returns_only_elevated_permission_when_own_permission_exists_but_own_context_fails":0,"P\\Tests\\Unit\\Permissions\\AllowOwnOrDepartmentAccessForbiddenTest::__pest_evaluable_it_allows_elevated_permission_path_without_forbidden_and_validates_department_access":0,"P\\Tests\\Unit\\Permissions\\ForbiddenResponseWiringTest::__pest_evaluable_it_routes_and_trait_use_forbidden_responses_for_permission_and_ownership_denials":0.19,"P\\Tests\\Unit\\Permissions\\GroupPermissionSessionInvalidationWiringTest::__pest_evaluable_it_invalidates_related_user_permission_and_auth_session_caches_when_group_permissions_change":0.064,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_parses_advanced_target_duration_from_snake__case_fields":0.36,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_parses_advanced_target_duration_from_camelCase_aliases":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_normalizes_ENTIRE__DURATION_to_ignore_target__duration__every":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_defaults_recurring_target__duration__every_to_1_when_omitted":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetDurationTest::__pest_evaluable_it_keeps_strict_legacy_mode_when_target__duration_is_invalid":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_computes_weekly_target_using_touched_ISO_weeks_for_March_2026":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_applies_target__duration__every_for_weekly_cadence":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_prorates_ENTIRE__DURATION_target_by_overlap_days":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_splits_advanced_target_by_override_weights_per_department":0,"P\\Tests\\Unit\\Goals\\GoalsCriteriaTargetMathTest::__pest_evaluable_it_preserves_legacy_target_behavior_when_target__duration_is_missing":0,"P\\Tests\\Unit\\Goals\\GoalsLegacyRendererScriptsTest::__pest_evaluable_it_keeps_legacy_monthly_renderer_script_green":0.466,"P\\Tests\\Unit\\Goals\\GoalsLegacyRendererScriptsTest::__pest_evaluable_it_keeps_legacy_department_daily_renderer_script_green":0.879,"P\\Tests\\Unit\\Goals\\GoalsOpenApiSpecTest::__pest_evaluable_it_documents_advanced_goals_target_duration_fields_in_openapi":0.07,"P\\Tests\\Unit\\Workfeed\\WorkfeedClientConformanceTest::__pest_evaluable_it_uses_company_scoped_workfeed_endpoints_and_raw_Authorization_header":0.006,"P\\Tests\\Unit\\Workfeed\\WorkfeedClientConformanceTest::__pest_evaluable_it_normalizes_documented_shift_query_parameters":0.005,"P\\Tests\\Unit\\Workfeed\\WorkfeedConfigRouteWiringTest::__pest_evaluable_it_registers_module_config_endpoints_for_workfeed":0.007,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteHelpersTest::__pest_evaluable_it_filters_request_parameters_down_to_the_allowed_workfeed_query_keys":0.001,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteWiringTest::__pest_evaluable_it_registers_employee_and_department_endpoints_for_the_workfeed_module":0.008,"P\\Tests\\Unit\\Workfeed\\WorkfeedRouteWiringTest::__pest_evaluable_it_registers_shift_endpoints_for_the_workfeed_module":0.008,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_workfeed_employee_hours_for_the_hour_slot_based_on_overlap":0.001,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_extracts_department_id_from_supported_workfeed_shift_shapes":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_wrapped_workfeed_collections_from_common_response_keys":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_includes_a_date_key_in_department_weather_timeline_entries":0.006,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineSchemaConformanceTest::__pest_evaluable_it_documents_the_date_key_in_the_openapi_department_weather_timeline_schema":0.034,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_from_start_of_yesterday_to_end_of_today":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_relative_to_an_explicit_selected_date_override":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_workfeed_employee_hours_across_multiple_departments_for_one_hour_slot":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_department_id_input_from_scalar_csv_and_nested_array_values":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_builds_a_timeline_range_relative_to_explicit_date__from_and_date__to_override":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_resolves_forecast_day_count_for_a_given_timeline_range_with_sane_limits":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_resolves_weather_coordinates_from_valid_coordinates_only":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_returns_null_weather_coordinates_when_all_department_locations_are_invalid":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_classifies_weatherapi_no_matching_location_errors_as_location_lookup_failures":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_does_not_classify_non_location_weatherapi_errors_as_location_lookup_failures":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_returns_an_empty_forecast_fallback_when_coordinates_are_unavailable":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_builds_timeline_entries_with_mostly__clear_weather_when_forecast_payload_is_empty":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherFallbackBehaviorTest::__pest_evaluable_it_wires_departments_weather_route_through_the_forecast_fallback_path":0.007,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_builds_deterministic_cache_keys_for_department_sets_and_timeline_ranges":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_builds_order_insensitive_cache_keys_for_equivalent_department_id_sets":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_falls_back_to_resolver_directly_when_cache_ttl_is_disabled":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTimelineRangeTest::__pest_evaluable_it_marks_non_started_slots_as_unknown_regardless_of_wash_hour_ratio":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherPreloadCronWiringTest::__pest_evaluable_it_registers_and_implements_cron_preloading_for_department_weather_cache":0.012,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_stale_ttl_defaults_and_clamps_stale_ttl_below_fresh_ttl":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_uses_sane_hot_activity_ttl_defaults_and_clamps_to_a_positive_value":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_serves_fresh_cached_payloads_without_invoking_the_resolver":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_serves_stale_cached_payloads_and_enqueues_a_refresh_signal":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_recomputes_and_rewrites_cache_payloads_when_stale_window_is_exceeded":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_records_hot_keys_order_insensitively_and_applies_preload_target_caps":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_normalizes_batched_wash_count_rows_into_hourly_slot_totals":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_wires_department_weather_route_to_use_batched_wash_aggregation":0.015,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_groups_attachments_by_object_id_and_preserves_empty_object_groups":0,"P\\Tests\\Unit\\Orders\\AttachmentsListManyTest::__pest_evaluable_it_keeps_listMany_payload_parity_with_list_for_one_object_id":0,"P\\Tests\\Unit\\Orders\\EconomicModuleOrdersBatchHelpersTest::__pest_evaluable_it_ensures_economic_module_rows_in_one_sanitized_batch":0,"P\\Tests\\Unit\\Orders\\EconomicModuleOrdersBatchHelpersTest::__pest_evaluable_it_returns_id_keyed_economic_module_payload_with_null_defaults":0,"P\\Tests\\Unit\\Orders\\OrdersRouteListBatchingWiringTest::__pest_evaluable_it_wires_GET__orders_through_batched_enrichment_and_stripe_snapshot_caching":0.116,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchTest::__pest_evaluable_it_returns_cashier_names_from_cache_and_fetches_missing_ones_in_batch":0,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchTest::__pest_evaluable_it_returns_deterministic_map_for_duplicate_and_unsorted_cashier_ids":0,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchWiringTest::__pest_evaluable_it_implements_batched_cashier_name_lookup_with_cache_first_fallback_behavior":0.141,"P\\Tests\\Unit\\Orders\\UsersCashierNamesBatchWiringTest::__pest_evaluable_it_sanitizes_and_deduplicates_cashier_ids_before_batch_lookup":0.064,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_overtime_minutes_when_a_shift_carries_an_extended_approval_end_timestamp":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_unapproved_overtime_from_a_bounded_shift_updateTime_fallback":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_does_not_treat_late_unapproved_administrative_edits_as_overtime":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheHelpersTest::__pest_evaluable_it_changes_weather_timeline_cache_key_when_department_weather_targets_change":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_evaluates_healthy_degraded_and_unhealthy_statuses_from_configured_department_targets":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_returns_unknown_when_configured_targets_are_missing_for_department_status_evaluation":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_multi_department_slot_statuses_using_worst_severity_and_unknown_fallback_rules":0.046,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_department_weather_target_endpoints_and_reusable_schemas_in_openapi":0.008,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsOpenApiSpecTest::__pest_evaluable_it_documents_unknown_weather_status_behavior_when_targets_are_missing":0.01,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsRouteWiringTest::__pest_evaluable_it_registers_department_weather_target_routes_with_explicit_read_and_manage_permissions":0.006,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsRouteWiringTest::__pest_evaluable_it_persists_department_weather_targets_using_canonical_department_variable_keys":0.005,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_machine_relay_status_get_and_set_endpoints":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_batches_sequential_machine_relay_status_requests_into_a_single_Shelly_get_call":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_1_request_per_second_Shelly_gate_for_back_to_back_requests":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_retries_missing_Shelly_status_payloads_until_relay_status_becomes_ready":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_times_out_with_a_clear_Shelly_readiness_error_when_payload_remains_missing":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_uses_direct_set_switch_and_seeds_cache_so_immediate_status_read_does_not_call_Shelly_get":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_lane_gate_open_endpoint":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_in_progress_self_serve_wash_details_endpoint":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_is_on__then_turns_off_cleaner_machine_and_selector_relays":0.132,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_is_off_and_only_disables_configured_relays":0.001,"P\\Tests\\Unit\\Selfserve\\DepartmentSelfServeEnabledRelaySyncWiringTest::__pest_evaluable_it_syncs_lane_relay_states_when_department_self_serve_enabled_flag_changes":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_supports_hard_relay_set_even_when_lane_status_is_CLOSED":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStartCleanerRelayWiringTest::__pest_evaluable_it_enables_cleaner_relay_on_wash_start_command_and_webhook_flow":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveWashCompletionRelayWiringTest::__pest_evaluable_it_forces_machine_relay_off_when_a_self_serve_wash_session_is_completed":0.003,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_exit_port_by_switching_relay__in__id_on":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_entrance_port_by_switching_relay__out__id_on":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_in_progress_self_serve_wash_start_and_machine_relay_fields":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_typed_task_gates_with_strict_semantics":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_validates_typed_task_gates_for_known_references":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_fails_validation_when_typed_task_gates_reference_unknown_entities":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_config_draft_publish_rollback_lifecycle_endpoints":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_legacy_self_serve_CRUD_routes_syncing_canonical_drafts":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStartCleanerRelayWiringTest::__pest_evaluable_it_keeps_cleaner_relay_enable_wired_into_machine_relay_start_paths":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_stores_config_json_with_apostrophes_without_violating_json_constraints":0.277,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_encodes_config_json_payloads_with_apostrophes_before_persistence":0,"P\\Tests\\Unit\\Selfserve\\SelfserveWashCompletionRelayWiringTest::__pest_evaluable_it_forces_machine_and_cleaner_relays_off_when_a_self_serve_wash_session_is_completed":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_vehicle_type_override_into_self_serve_preview_and_synchronization_routes":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_uses_local_demo_responses_and_skips_Shelly_cloud_calls_for_demo_relay_ids":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_returns_default_OFF_status_for_demo_relay_ids_without_Shelly_lookups":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_excludes_demo_relay_ids_from_Shelly_status_batch_payloads":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_keeps_demo_relay_gate_open_queued_but_skips_Shelly_switch_calls":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_allowed_services_route_through_machine_relay_visibility_sync":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_enables_MACHINE_relay_when_MACHINE_is_visible_in_allowed_services":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_turns_MACHINE_relay_off_immediately_when_MACHINE_is_not_visible":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_does_not_enable_MACHINE_relay_when_allowEnable_is_false_even_if_MACHINE_is_visible":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_is_a_safe_no_op_when_MACHINE_relay_is_not_configured":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRelayVisibilitySyncWiringTest::__pest_evaluable_it_synchronizes_machine_relay_from_visible_services_during_session_synchronization":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveRelayVisibilitySyncWiringTest::__pest_evaluable_it_adds_explicit_relay_disable_session_helper_for_visibility_driven_OFF_transitions":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_property_gate_command_permissions":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneCommandEnumTest::__pest_evaluable_it_parses_property_gate_lane_commands":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_opens_entrance_gate_for_OPEN__PROPERTY__ACCESS__GATE_command":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_opens_exit_gate_for_OPEN__PROPERTY__EXIT__GATE_command":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_blocks_property_gate_commands_when_department_self_serve_is_disabled":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_throws_a_clear_error_when_entrance_gate_is_missing_for_property_access_command":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_wraps_low_level_gate_errors_for_property_access_command_failures":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveWashFlowMachineAllowedWiringTest::__pest_evaluable_it_reads_machine_allowed_state_from_session_summary_payload_safely":0.003,"P\\Tests\\Unit\\Selfserve\\DbObjectPaginationLegacyColumnCompatibilityTest::__pest_evaluable_it_guards_pagination_against_searchable_fields_missing_from_legacy_schemas":0.004,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_adds_dynamic__images__vehicle__type_column_for_legacy_selfserve_wash_session_task_schemas":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_billable_minutes_when_elapsed_minutes_exceed_included_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_zero_billable_minutes_when_elapsed_minutes_equal_included_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_computes_zero_billable_minutes_when_included_minutes_exceed_elapsed_minutes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceIncludedMinutesTest::__pest_evaluable_it_handles_zero_and_low_elapsed_wash_time_edge_cases":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_self_serve_machine_wash_included_minutes_in_config_schemas":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_machine_wash_included_minutes_into_self_serve_module_config":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_blocks_explicit_relay_writes_when_department_self_serve_is_disabled":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_returns_disabled_no_op_from_machine_relay_visibility_sync_when_department_self_serve_is_disabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_property_gate_lane_commands_and_sanitized_gate_failure_responses":0.001,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_calls":0.022,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_channel_id_is_missing_for_gate_calls":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_with_terminal_status_details_when_call_never_reaches_accepted_state":0.067,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_when_call_reaches_accepted_state":0.001,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_hangs_up_immediately_when_status_transitions_to_accepted":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_maps_legacy_timeout_option_to_documented_ringTimeout_payload_field":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_clamps_derived_ringTimeout_to_Bird_documented_max_when_gate_timeout_is_high":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_passes_documented_hangup_cause_when_provided":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_drops_unsupported_hangup_cause_values_from_request_payload":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_fast_when_workspace_id_is_missing_for_gate_flash_calls":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_creates_gate_flash_call_with_documented_ringTimeout_payload":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_polls_flash_call_and_succeeds_once_accepted":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_fails_flash_gate_flow_when_terminal_failure_status_is_returned":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_does_not_fallback_to_regular_gate_call_when_flash_succeeds":0,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_fails":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePropertyGateCommandTest::__pest_evaluable_it_wraps_low_level_gate_errors_for_property_exit_command_failures":0.001,"P\\Tests\\Unit\\Bird\\BirdGateCallFlowTest::__pest_evaluable_it_falls_back_to_regular_gate_call_when_flash_caller_id_is_not_confirmed":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_voice_call_facade_methods_to_documented_endpoints_and_methods":0.024,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_recordings_insights_log_and_flash_methods_to_documented_resources":0.001,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_encodes_path_segments_before_building_outbound_endpoints":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_serializes_query_parameters_for_GET_transport_requests":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_maps_4xx_and_5xx_transport_failures_into_informative_exceptions":0,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_returns_raw_payload_for_malformed_JSON_responses_and_null_for_empty_responses":0.007,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_all_Bird_voice_call_parity_endpoints_including_gather_recordings_insights_and_log":0.008,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_documents_flash_hangup_endpoint_and_marks_end_alias_as_deprecated":0.006,"P\\Tests\\Unit\\Bird\\BirdOpenApiSpecTest::__pest_evaluable_it_defines_request_and_response_schemas_for_Bird_call_command_recording_insight_log_and_flash_payloads":0.009,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_accepts_valid_payloads_for_create_and_nested_call_flow_commands":0.002,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_rejects_unknown_fields_and_invalid_enum_values_in_strict_schemas":0.051,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_supports_CSV_normalization_in_schema_validation_for_log_filters":0,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_validates_flash_hangup_payloads_for_both_supported_request_shapes":0,"P\\Tests\\Unit\\Bird\\BirdRequestValidationTest::__pest_evaluable_it_fails_before_forward_step_when_strict_validation_fails_and_forwards_when_valid":0,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_registers_full_Bird_voice_call_route_surface_with_strict_validation_and_permissions":0.04,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_registers_flash_hangup_endpoint_and_keeps_end_alias_wired_as_compatibility_path":0.033,"P\\Tests\\Unit\\Bird\\BirdRouteWiringTest::__pest_evaluable_it_keeps_Bird_number_and_webhook_routes_intact":0.063,"P\\Tests\\Unit\\Bird\\BirdModuleClientMappingTest::__pest_evaluable_it_handles_malformed_and_empty_response_bodies_without_throwing_transport_errors":0.005,"P\\Tests\\Unit\\Selfserve\\DepartmentGatesRelaysRouteWiringTest::__pest_evaluable_it_validates_department_gate_config_on_both_create_and_update_routes":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_adds_wash__started__at_column_for_legacy_selfserve_wash_session_schemas":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_stores_wash__started__at_in_self_serve_wash_sessions_when_machine_start_is_triggered":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_passes_lane_wash_start_time_into_the_session_machine_start_marker":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveWashStartedAtWiringTest::__pest_evaluable_it_resolves_in_progress_wash__started__at_from_session_with_compatibility_fallbacks":0.001,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_say_payload_and_applies_hangup_default":0.596,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_log_query_csv_and_integer_fields":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_normalizes_nested_create_call_payload_sections_and_drops_unknown_keys":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_keeps_gather_nested_say_payload_unchanged_when_hangup_is_omitted":0,"P\\Tests\\Unit\\Bird\\BirdPayloadClassesTest::__pest_evaluable_it_supports_no_body_and_flash_hangup_payload_normalization":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_respects_the_2_second_Shelly_gate_for_back_to_back_requests":0.023,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_enforces_a_2_second_gap_between_sequential_switch_requests_used_by_wash_start_and_stop_flows":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_keeps_back_to_back_get_switch_requests_ordered_through_the_relay_controller":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_executes_sequential_switch_requests_used_by_wash_start_and_stop_flows":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_does_not_print_Shelly_switch_responses_to_output":0,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitWiringTest::__pest_evaluable_it_enforces_a_global_2_second_Shelly_gate_in_sendPostRequest":0.001,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitWiringTest::__pest_evaluable_it_uses_Redis_NX_PX_semantics_for_cross_request_Shelly_rate_limiting":0.001,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitBehaviorTest::__pest_evaluable_it_enforces_the_2_second_Shelly_gate_across_separate_request_contexts":0.001,"P\\Tests\\Unit\\Selfserve\\ShellyGlobalRateLimitBehaviorTest::__pest_evaluable_it_does_not_delay_when_the_Shelly_gate_is_already_expired":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_program_selector_relay_is_online__then_turns_off_cleaner_and_machine_relays":0.62,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_program_selector_relay_is_offline_and_only_disables_configured_relays":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_bills_primary_product_when_selector_relay_is_online_even_if_relay_output_is_off":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceModeBillingTest::__pest_evaluable_it_bills_manual_self_serve_stop_using_full_elapsed_minutes_without_included_minute_reduction":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceModeBillingTest::__pest_evaluable_it_keeps_included_minute_reduction_for_automatic_mode":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_on_first_dtmf_input_captured_within_the_300_second_window":0.005,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_does_not_send_Slack_when_dtmf_input_repeats_without_change":0.008,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_again_when_dtmf_input_changes_within_the_window":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_gathering_and_does_not_hang_up_before_300_seconds_have_elapsed":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_announces_timeout_waits_10_seconds_and_sends_hangup_once_at_or_after_300_seconds":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_polling_until_terminal_status_and_only_then_finalizes":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_finalizes_immediately_when_webhook_payload_is_already_terminal_before_timeout_logic":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_does_not_duplicate_timeout_or_hangup_actions_across_retries_and_lock_contention":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_keeps_state_when_polling_fails_so_completion_is_not_falsely_reported":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_dtmf_input_repeats_without_change":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_answers_immediately_once_and_does_not_re_answer_on_subsequent_webhook_retries":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_configures_gather_with_retry_loop_semantics_until_input_is_entered":0.004,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_gather_result_provides_keys_field_instead_of_dtmf":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_sends_Slack_when_gather_conditions_variable_keys_carries_the_entered_value":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_configures_gather_to_check_every_2_seconds_with_retry_loop_semantics_until_input_is_entered":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_ignores_non_numeric_customer__number_values_from_request":0.042,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_casts_numeric_customer__number_strings_to_int_before_lookup":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_prefers_user__id_when_both_user__id_and_customer__number_are_valid":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_falls_back_to_customer__number_when_user__id_is_invalid":0,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_normalizes_request_identifiers_before_user_lookups":0.005,"P\\Tests\\Unit\\Users\\UsersAutomaticGetTargetUserFromRequestTest::__pest_evaluable_it_rejects_non_positive_and_non_digit_request_values":0.003,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_pagination_results_when_present":0.006,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_falls_back_to_collection_count_when_pagination_metadata_is_missing":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_returns_zero_when_neither_pagination_nor_collection_is_available":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_counts_object_based_collections_when_pagination_metadata_is_missing":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_uses_collection_when_present":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_falls_back_to_paymentTerms_when_collection_is_missing":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_supports_top_level_array_payloads":0,"P\\Tests\\Unit\\Invoicing\\EconomicPaymentTermsRouteCollectionExtractionTest::__pest_evaluable_it_returns_an_empty_array_when_no_known_collection_shape_exists":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_uses_grant__2_in_economic__endpoint__t_when_explicitly_requested_and_configured":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_falls_back_to_grant__1_in_economic__endpoint__t_when_grant__2_is_missing":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_required_primary_grant_in_economic__endpoint__t":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_app_secret_in_economic__endpoint__t":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_uses_grant__2_in_legacy_economic__m_when_available":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_falls_back_to_grant__1_in_legacy_economic__m_when_grant__2_is_missing":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_required_primary_grant_in_legacy_economic__m":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_for_missing_app_secret_in_legacy_economic__m":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_unfiltered_total_when_no_customer_filters_are_active":0.004,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_filtered_total_when_search_is_active":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_uses_filtered_total_when_barred_filter_is_active":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_treats__null__search_and_barred_values_as_no_filter":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRoutePaginationFallbackTest::__pest_evaluable_it_falls_back_to_filtered_total_when_unfiltered_total_is_missing":0,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_maps_e_conomic_integration_failures_in_customer_listing_to_explicit_502_responses":0.007,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_logs_LIST__CUSTOMERS_success_only_after_pagination_and_customer_mapping_are_completed":0.005,"P\\Tests\\Unit\\Invoicing\\CustomerSearchRouteEconomicFailureHandlingTest::__pest_evaluable_it_guards_against_malformed_customer_list_payloads_before_calling_paginate":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_deterministic_upstream_exceptions_for_non_2xx_endpoint_trait_responses":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_throws_deterministic_upstream_exceptions_for_non_2xx_legacy_economic__m_responses":0,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_returns_raw_payload_unchanged_on_successful_HTTP_statuses":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_accepts_valid_list_payloads_that_include_collection_and_pagination_results":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_throws_when_pagination_is_missing_from_the_response_payload":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersListResponseValidationTest::__pest_evaluable_it_throws_when_upstream_responds_with_an_error_shaped_payload":0,"P\\Tests\\Unit\\Router\\RouterThrowableHandlingTest::__pest_evaluable_it_catches_throwables_during_auto_route_loading_and_maps_them_to_internal_server_errors":0.039,"P\\Tests\\Unit\\Users\\EconomicCustomerZeroHandlingTest::__pest_evaluable_it_does_not_request_e_conomic_customer_data_when_customer_number_is_zero":0.004,"P\\Tests\\Unit\\Users\\EconomicCustomerZeroHandlingTest::__pest_evaluable_it_short_circuits_e_conomic_customer_lookup_for_non_positive_customer_numbers":0.003,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_queued_economic_invoice_endpoints_in_economicInvoiceRoute":0.013,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueRouteRegistrationTest::__pest_evaluable_it_registers_collected_invoice_queue_endpoints_in_orderInvoicesRoute":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueSchemaBootstrapTest::__pest_evaluable_it_defines_economic_transfer_queue_jobs_schema_bootstrap_table_and_tracking_columns":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueSchemaBootstrapTest::__pest_evaluable_it_provides_queue_processor_class_constants_and_processing_entrypoint":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueCronIntegrationTest::__pest_evaluable_it_registers_economic_transfer_queue_cron_task_and_handler":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_economic_transfer_queue_paths_in_openapi":0.013,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_economic_transfer_queue_schemas_in_openapi":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_order_items_with_zero_quantity_for_e_conomic_export":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_order_items_with_zero_price_for_e_conomic_export":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_keeps_positive_quantity_and_price_items_billable_for_e_conomic_export":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_wires_zero_cost_and_zero_quantity_skip_guard_into_transfer_line_builder":0.048,"P\\Tests\\Unit\\Invoicing\\EconomicInvoiceDraftZeroItemSkipWiringTest::__pest_evaluable_it_skips_zero_cost_and_zero_quantity_items_in_legacy_economic_draft_helper":0.023,"P\\Tests\\Unit\\Invoicing\\EconomicTransferOrderItemSkipTest::__pest_evaluable_it_skips_malformed_order_item_payloads_for_e_conomic_export_safety":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueHardeningTest::__pest_evaluable_it_hardens_transfer_queue_with_type_validation_retry_caps_and_stale_lock_recovery":0.043,"P\\Tests\\Unit\\Router\\AutoloadRedisCacheValidationTest::__pest_evaluable_it_validates_cached_autoload_paths_before_returning_and_clears_stale_cache_entries":0.008,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_applies_created__at_bounds_directly_in_SQL_when_filtering_orders_by_registration_number":0.001,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_rejects_an_inverted_date_range_for_registration_lookups":0,"P\\Tests\\Unit\\Orders\\OrdersRegistrationDateRangeQueryTest::__pest_evaluable_it_returns_early_when_registration_number_is_blank":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueCronIntegrationTest::__pest_evaluable_it_wires_queue_worker_class_loading_for_CLI_queue_action":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_all_economic_invoice_queue_endpoints_before_constructing_queue_service":0.012,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_all_collected_invoice_queue_endpoints_before_constructing_queue_service":0.011,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_missing_queue_dependencies":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_gracefully_handles_unavailable_queue_dependencies_on_collected_invoice_queue_endpoints":0.005,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_returns_the_queue_job_id_in_POST__collected_invoices_economic_enqueue_response":0.204,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_requires_id_and_at_least_one_mutable_field_for_PUT__collected_invoices_in_user_route":0.019,"P\\Tests\\Unit\\Invoicing\\UserCollectedInvoiceUpdateRouteValidationTest::__pest_evaluable_it_supports_independent_po__number_and_closed__at_updates_for_PUT__collected_invoices_in_user_route":0.008,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_returns_queued_contract_for_POST__collected_invoices_stripe_book":0.002,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_keeps_order_draft_export_route_queue_only":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_keeps_collected_invoice_draft_producing_routes_queue_only_in_orderInvoicesRoute":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_guards_collected_invoice_and_stripe_draft_producing_endpoints_before_constructing_queue_service":0.004,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_unavailable_queue_dependency_responses_for_async_economic_transfer_endpoints":0.007,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_normalizes_order_payloads_to_strict_positive_integer_ids":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_normalizes_collected_invoice_payload_booleans_to_strict_bool_values":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueuePayloadValidationTest::__pest_evaluable_it_rejects_invalid_transfer_payloads_before_enqueue_write_attempts":0,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_queued_transfer_jobs_to_completion":0.016,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_deduplicates_active_jobs_per_transfer_target":0.016,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_rejects_invalid_payloads_without_inserting_queue_rows":0.013,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_supports_fail_retry_and_reprocess_lifecycle_transitions":0.014,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_guards_on_economic_invoice_queue_status_and_retry_routes":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_supports_synchronous_fallback_branches_before_queue_enqueue_on_economic_invoice_export_routes":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_keeps_queue_status_endpoints_guarded_while_collected_invoice_export_routes_support_synchronous_fallback":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueAvailabilityGuardTest::__pest_evaluable_it_uses_a_consistent_unavailable_service_contract_for_queue_status_lifecycle_endpoints":0.057,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_supports_synchronous_fallback_and_queued_processing_for_order_draft_export_route":0.006,"P\\Tests\\Unit\\Invoicing\\EconomicDraftQueueOnlyRouteBehaviorTest::__pest_evaluable_it_supports_synchronous_fallback_and_queued_processing_for_collected_invoice_draft_producing_routes":0.006,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_documents_both_synchronous_fallback_and_queued_response_contracts_for_POST__collected_invoices_economic":0.165,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceEconomicQueueResponseContractTest::__pest_evaluable_it_documents_both_synchronous_fallback_and_queued_response_contracts_for_POST__collected_invoices_stripe_book":0.018,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_200_fallback_plus_202_queue_contracts_for_export_endpoints_and_keeps_503_on_queue_lifecycle_endpoints":0.009,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_returns_pagination_metadata_and_strict_status_handling_for_collected_invoice_queue_list":0.006,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_enforces_retry_constraints_for_collected_invoice_queue_jobs_before_retry_execution":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_collected_queue_list_metadata_and_strict_status_filter_enum_in_openapi":0,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_builds_a_completed_collected_invoice_queue_summary_from_payload_and_result":0.029,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_prefers_queue_error_messages_for_failed_jobs_and_keeps_null_safe_outcome_fields":0,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_uses_deterministic_status_message_fallback_when_no_explicit_message_exists":0,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_handles_object_payload_result_values_and_malformed_fields_without_throwing":0,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_collected_invoice_transfer_queue_from_queue_list_and_status_routes":0.008,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_ticks_order_transfer_queue_from_draft_and_invoice_status_routes":0.009,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_marks_queued_transactions_and_clears_requires__action_when_all_actionable_work_is_already_queued":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_keeps_requires__action_true_when_a_customer_still_has_unqueued_actionable_transactions":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_blocks_fixed_pricing_or_subscription_customers_with_no_transactions_when_a_relevant_queue_job_exists":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_queues_admin_commands__exposes_agent_poll_result_handlers__and_keeps_heartbeats_from_mutating_discovery_state":0.003,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_defines_the_dispatchable_gateway_guard_on_the_loaded_manager_class":0.009,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"recent heartbeat stays online\"\"":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"late heartbeat degrades after one minute\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"stale heartbeat goes offline after five minutes\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"explicit offline reports stay offline even when heartbeat is fresh\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_effective_gateway_status_from_heartbeat_freshness with data set \"dataset \"missing heartbeat is treated as offline\"\"":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_marks_ready_discovery_as_stale_when_the_gateway_heartbeat_has_expired":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_edge_gateway_management_REST_endpoints":0.021,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_public_installer__claim__heartbeat__command_polling__and_internal_broker_auth_endpoints":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeBrokerClientConfigTest::__pest_evaluable_it_uses_the_same_default_broker_url_and_shared_secret_fallback_as_the_docker_stack":0.267,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_forwarded_https_scheme_when_proxied":0.336,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_appends_forwarded_ports_when_the_forwarded_host_omits_them":0.002,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_infers_https_for_the_staging_api_host_when_only_the_https_port_is_present":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured":0.003,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_normalizes_public_broker_overrides_to_https_and_browser_shell_urls_to_wss":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_keeps_localhost_broker_overrides_on_plain_http_and_ws_for_local_development":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_includes_node_pty_build_prerequisites_in_the_generated_install_script":0.007,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_prefers_EDGE__PUBLIC__API__URL_when_explicitly_configured_and_derives_the_broker_from_the_api_origin":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_normalizes_public_broker_overrides_to_https__strips_paths__and_browser_shell_urls_to_wss":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_merges_incoming_heartbeat_metadata_with_existing_gateway_metadata":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_the_v2_operator_facing_edge_gateway_routes":0.002,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayRouteWiringTest::__pest_evaluable_it_registers_PHP_edge_agent_routes_for_operations_and_legacy_relay_command_polling":0.002,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_defines_the_v2_edge_gateway_schema_bootstrap_tables":0.002,"P\\Tests\\Unit\\Selfserve\\EdgeGatewaySchemaBootstrapTest::__pest_evaluable_it_stores_operation_metadata_and_event_timelines_for_management_workflows":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_PHP_agent_artifacts_and_management_polling_config":0.011,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__and_operation_endpoints_without_shell_transport_wiring":0.013,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_keeps_relay_dispatch_and_discovery_queueing_on_the_edge_gateway_manager":0.003,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerCommandQueueTest::__pest_evaluable_it_loads_relay_command_helpers_on_the_manager_and_gateway_operations_on_the_dedicated_service":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_derives_relay_fallback_and_transport_health_details_without_shell_or_update_runtime_state":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_the_source_tree_layout":0.445,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_includes_the_container_mounted_artifact_directory_as_a_candidate":0.021,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_reads_install_artifacts_through_the_shared_locator":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_builds_update_payloads_with_checksums_from_resolved_artifact_paths":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_resolves_edge_agent_artifacts_from_a_supported_runtime_layout":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_PHP_agent_artifacts_and_forwarded_https_scheme":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_explains_the_legacy_dist_mount_mismatch_when_php_artifacts_are_unavailable":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_mounted_and_baked_in_artifact_directories_before_repo_fallbacks":0.022,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_falls_back_to_baked_in_artifacts_when_the_mount_path_is_absent":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayArtifactLocatorTest::__pest_evaluable_it_prioritizes_router_resources_before_mounted_and_baked_in_artifact_directories":0,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_orders_for_an_admin_scoped_user_and_limits_the_results_to_the_permitted_departments":1.109,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_lists_only_the_targeted_customer_orders_for_subuser_sessions":2.935,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_returns_the_current_auth_and_permission_failures_when_order_listing_is_not_allowed":1.375,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_creates_orders_through_the_real_endpoint":0.982,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_creation_requests":3.423,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_primary_endpoint":1.13,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_reassigns_invoice_collections_when_changing_an_order_across_the_draft_customer_boundary":1.615,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_primary_endpoint":5.592,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_primary_order_endpoint":1.29,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_updates_orders_through_the_legacy_alias_endpoint":1.517,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_supports_legacy_field_value_metadata_updates_through_the_alias_endpoint":4.136,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_updates_through_the_legacy_alias_endpoint":0.512,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_unsupported_legacy_field_value_updates_on_both_update_endpoints":0.965,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_deletes_orders_through_the_real_endpoint":1.045,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_rejects_invalid_order_delete_requests":1.64,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_when_certificate_metadata_changes_through_the_primary_endpoint":3.683,"P\\Tests\\Api\\OrdersApiTest::__pest_evaluable_it_regenerates_attached_wash_certificates_for_legacy_field_value_updates_through_the_alias_endpoint":3.194,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayOperationLegacySchemaCompatibilityTest::__pest_evaluable_it_keeps_the_legacy_operation__type_column_compatible_with_v2_operation_queueing":0.002,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_builds_deterministic_keys_for_equivalent_contexts":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_stores_and_retrieves_full_order_bookings_payloads":0.001,"P\\Tests\\Unit\\Bookings\\OrderBookingsListCacheTest::__pest_evaluable_it_ignores_malformed_cached_payloads_and_clears_order_bookings_list_caches":0.001,"P\\Tests\\Unit\\Bookings\\OrderBookingsRouteCacheWiringTest::__pest_evaluable_it_caches_the_paginated_order_bookings_list_response_and_invalidates_it_on_booking_changes":0.051,"P\\Tests\\Unit\\Bookings\\VehicleSearchBookedMetadataRouteContractTest::__pest_evaluable_it_keeps_booked_vehicle_search_metadata_aligned_with_filtered_pending_order_bookings":0.052,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_clamps_negative_ttl_to_zero":0.001,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_builds_deterministic_keys_for_equivalent_count_contexts":0.039,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_stores_and_retrieves_normalized_booking_counts":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsCacheTest::__pest_evaluable_it_ignores_malformed_payloads_and_clears_order_bookings_count_caches":0,"P\\Tests\\Unit\\Bookings\\OrderBookingsCountsRouteWiringTest::__pest_evaluable_it_adds_a_cached_order_bookings_counts_endpoint_and_invalidates_it_on_booking_changes":0.04,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayFleetUsageStatisticsTest::__pest_evaluable_it_summarizes_fleet_usage_statistics_for_the_dashboard_landing_view":0.001,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_every_selected_API_operation_covered_by_happy_path_and_failure_tests":0.271,"P\\Tests\\Api\\ApiCoverageManifestTest::__pest_evaluable_it_keeps_the_OpenAPI_manifest_entries_aligned_with_the_API_spec":0.097,"P\\Tests\\Api\\ApiFixturesCleanupTest::__pest_evaluable_it_removes_generated_customer_traces_during_fixture_cleanup":8.099,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_in_with_valid_customer_credentials":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_login_payloads_and_credentials":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_returns_the_cached_auth_session_payload_for_a_valid_token":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_includes_economic_runtime_config_for_uncached_auth_sessions":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_auth_session_tokens":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_the_token_for_future_session_calls":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_logs_out_and_invalidates_cached_subuser_sessions":0,"P\\Tests\\Api\\AuthApiTest::__pest_evaluable_it_rejects_invalid_logout_tokens":0,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_the_raw_202_gather_webhook_contract_over_HTTP":0.788,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_still_prompts_for_department_selection_when_only_one_department_is_eligible":0.732,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_accepts_the_legacy_initial_webhook_body_with_top_level_call_identifiers":0.692,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_native_flow_gather_data_after_a_top_level_department_selection_when_distinct_gate_choices_exist":1.515,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_opens_the_gate_immediately_after_a_top_level_department_selection_when_entrance_and_exit_share_the_same_gate":1.719,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_uses_a_multi_digit_gather_contract_when_10_departments_are_eligible":0.587,"P\\Tests\\Api\\BirdVoiceWebhookApiTest::__pest_evaluable_it_returns_a_raw_400_transport_error_for_malformed_webhook_payloads":0.419,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_only_visible_departments_and_can_return_a_single_department_with_the_slack_webhook":1.048,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_department_listing_when_the_permission_is_missing":0.378,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_creates_departments_through_the_real_endpoint":0.59,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_create_requests":1.554,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_updates_departments_through_the_real_endpoint":0.788,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_update_requests":1.552,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_lists_department_categories_for_a_department":1.006,"P\\Tests\\Api\\DepartmentsApiTest::__pest_evaluable_it_rejects_invalid_department_category_requests":1.191,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_lists_the_draft_customer_config_entry_in_economic_config_responses":0,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_draft_customer_config_value_through_economic_config_updates":0,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_order_draft_exports_for_the_configured_draft_customer":0,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_booked_invoice_exports_for_the_configured_draft_customer":0,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_rejects_collected_invoice_exports_for_the_configured_draft_customer":0,"P\\Tests\\Api\\PingApiTest::__pest_evaluable_it_returns_the_ping_contract":0.877,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_department_terminal_readers_are_requested_without_terminal_setup":1.281,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_sends_a_Stripe_invoice_by_email_and_persists_the_hosted_invoice_association":5.434,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_conflict_when_a_Stripe_hosted_invoice_is_already_active_for_the_order":4.756,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_allows_sending_a_new_Stripe_hosted_invoice_when_the_existing_association_is_already_terminal":3.943,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_voids_an_unpaid_Stripe_hosted_invoice_and_clears_the_local_order_association":3.746,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_refuses_to_cancel_a_paid_Stripe_hosted_invoice":4.131,"P\\Tests\\Api\\StripeApiTest::__pest_evaluable_it_returns_a_setup_required_error_when_creating_a_payment_intent_for_a_department_without_terminal_setup":0.726,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_the_newest_vehicle_last__order__id_that_still_has_order_items":1.326,"P\\Tests\\Api\\VehiclesApiTest::__pest_evaluable_it_returns_a_null_vehicle_last__order__id_when_no_order_with_items_exists":1.159,"P\\Tests\\Unit\\Users\\EconomicCustomerModelParsingTest::__pest_evaluable_it_parses_cached_economic_customer_payloads_that_use_snake__case_customer__number":0,"P\\Tests\\Unit\\Users\\EconomicCustomerModelParsingTest::__pest_evaluable_it_leaves_the_economic_customer_model_empty_when_no_valid_customer_number_is_present":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayFleetUsageStatisticsTest::__pest_evaluable_it_derives_fleet_usage_directly_from_cached_gateway_row_summaries":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_install_script_urls_with_the_compose_edge_gateway_artifacts_and_forwarded_https_scheme":0.008,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayMetadataUpdateContractTest::__pest_evaluable_it_adds_a_gateway_metadata_update_endpoint_with_label_and_primary_assignment_fields":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayMetadataUpdateContractTest::__pest_evaluable_it_reassigns_department_primary_gateways_through_dedicated_manager_helpers":0.002,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayShellPollingTransportTest::__pest_evaluable_it_removes_shell_access_from_the_edge_gateway_HTTP_contracts":0.004,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_builds_the_installer_around_the_compose_stack_artifacts_and_management_polling_config":0.009,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_uses_sane_ttl_defaults_and_deterministic_cache_keys":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_stores_and_retrieves_cached_list_and_detail_payloads":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_syncs_gateway_snapshots_into_cached_list_payloads_and_refreshes_fleet_usage":0.002,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayViewCacheTest::__pest_evaluable_it_removes_deleted_gateways_from_cached_list_and_detail_payloads":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayUpdateLifecycleTest::__pest_evaluable_it_exposes_update_payload__credential_rotation__cancel_endpoints__and_operation_endpoints_without_shell_transport_wiring":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_module_scoped_edge_gateway_operator_routes":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_edge_gateway_module_config_endpoints":0.006,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_edge_gateway_config_endpoints_from_the_module_route_directory":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_keeps_only_the_module_facade_in_the_global_classes_directory_and_conditionally_loads_module_routes":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_caps_install_session_diagnostics_and_events_while_preserving_the_first_start_timestamp":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_clears_terminal_failure_details_after_a_successful_claim_update":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayInstallSessionLifecycleTest::__pest_evaluable_it_marks_expired_non_terminal_install_sessions_as_terminal_when_read_back":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_websocket_broker_urls_on_the_traefik_broker_path":0.003,"P\\Tests\\Unit\\Selfserve\\DepartmentGateConfigRelayTest::__pest_evaluable_it_validates_relay_gate_configs_and_keeps_relay_specific_fields_in_the_payload":0,"P\\Tests\\Unit\\Selfserve\\DepartmentGateConfigRelayTest::__pest_evaluable_it_rejects_relay_gate_configs_without_a_logical_relay_id":0,"P\\Tests\\Unit\\Bird\\DepartmentGatesRelayOpenTest::__pest_evaluable_it_dispatches_relay_backed_gates_through_the_edge_gateway_relay_manager":0,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayDepartmentWorkspaceContractTest::__pest_evaluable_it_defines_the_department_hardware_workspace_service_payload_surface":0.001,"P\\Tests\\Unit\\Selfserve\\PlateScannerWorkspaceContractTest::__pest_evaluable_it_adds_lane_aware_scanner_management_and_a_dedicated_rotate_key_action":0.001,"P\\Tests\\Unit\\Selfserve\\PlateScannerWorkspaceContractTest::__pest_evaluable_it_uses_the_scanner_default_lane_before_requiring_an_explicit_lane__id_in_machine_button_webhooks":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_maps_gateway_relay_status_responses_into_the_Shelly_cloud_payload_shape":0.001,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_maps_gateway_relay_switch_responses_into_the_Shelly_cloud_payload_shape":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_requires_a_valid_department_id_for_gateway_transport_requests":0.001,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_rejects_unsupported_gateway_transport_endpoints":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_surfaces_binding_lookup_failures_while_resolving_relay_state_through_the_gateway_transport":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_surfaces_offline_gateway_failures_while_dispatching_relay_switch_commands":0,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_returns_the_updated_lane_id_after_editing_a_scanner_whose_null_lane_was_already_cached":21.835,"P\\Tests\\Api\\PlateScannersApiTest::__pest_evaluable_it_rejects_plate_scanner_edits_when_the_permission_is_missing":7.837,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_normalizes_owned_Shelly_devices_into_relay_select_options":0.001,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_fails_fast_when_Shelly_inventory_does_not_include_owned_devices_status":0,"P\\Tests\\Unit\\Selfserve\\DepartmentLaneRelayOptionsRouteWiringTest::__pest_evaluable_it_registers_a_department_lane_relay_options_endpoint_backed_by_Shelly_inventory":0.001,"P\\Tests\\Unit\\Selfserve\\DepartmentLaneRelayNullificationRouteWiringTest::__pest_evaluable_it_nullifies_department_lane_relay_fields_when_blank_select_values_are_submitted":0.001,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_serves_installer_artifacts_and_recovers_gateway_runtime_status_after_fresh_heartbeats":109.487,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_polls_operations_and_commands__submits_results__and_records_broker_presence_for_task_pages":229.768,"P\\Tests\\Api\\EdgeGatewayAgentApiTest::__pest_evaluable_it_rejects_missing_and_invalid_edge_agent_tokens":12.815,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_validates_broker_sessions_and_ingests_presence__telemetry__logs__and_shell_lifecycle_data":180.867,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_builds_broker_backlog_and_completes_gateway_operations_through_broker_endpoints":147.749,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_invalid_edge_broker_shared_secrets":6.832,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_creates_install_tokens__tracks_installer_status__and_exposes_claimed_gateway_detail_to_authorized_operators":134.744,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_manages_edge_gateway_metadata__bindings__operations__sessions__rotation__cutover__and_deletion":272.219,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_rejects_operator_edge_routes_when_module_permission_or_department_access_is_missing":46.681,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_persists_install_session_updates_and_derives_gateway_runtime_status_from_heartbeats":0.015,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_assembles_tasks__logs__statistics__operations__commands__and_shell_lifecycle_state_from_persisted_records":0.019,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_builds_localhost_websocket_broker_urls_on_the_local_traefik_api_prefix":0.003,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerUrlTest::__pest_evaluable_it_keeps_root_host_api_urls_unprefixed_when_the_request_is_not_under_the_local_api_alias":0.003,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_imports_a_matching_e_conomic_customer_into_the_local_system_when_no_local_record_exists":0.001,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_reports_when_the_local_customer_already_has_a_login_account":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_creates_a_new_e_conomic_customer_and_returns_a_created_result_for_new_rows":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_creates_the_economic_record_for_an_existing_local_account_when_no_matching_upstream_customer_exists":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_rejects_CVR_conflicts_when_the_upstream_customer_number_does_not_match_the_submitted_phone_number":0,"P\\Tests\\Unit\\Customers\\CustomerMassImportServiceTest::__pest_evaluable_it_registers_the_customer_import_route_and_wires_it_through_the_mass_import_service":0.009,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_builds_customer_name_cache_payloads_from_economic_data_or_display_name_fallbacks":0,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_guards_bulk_customer_name_cache_writes_behind_a_resolved_payload_check":0.003,"P\\Tests\\Api\\EdgeGatewayOperatorApiTest::__pest_evaluable_it_ignores_and_soft_deletes_edge_gateways_whose_department_no_longer_exists":35.946,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_only_trusts_broker_presence_while_the_broker_heartbeat_is_fresh":0.005,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayManagerHeartbeatStatusTest::__pest_evaluable_it_refreshes_broker_presence_from_broker_telemetry_heartbeats":0,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_resolves_the_injected_gateway_transport_when_a_department_is_in_gateway_mode":0,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_resolves_the_injected_cloud_transport_when_a_department_is_in_cloud_mode":0,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_lets_relay_tests_override_the_department_transport_without_changing_department_mode":0,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_falls_back_to_local_device_and_control_names_when_Shelly_cloud_list_metadata_is_unavailable":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_uses_local_only_gateway_dispatch_for_explicit_local_transport_overrides":0,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_marks_non_injected_local_overrides_as_local_only_gateway_transport":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_exit_port_by_switching_relay__out__id_on":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_opens_entrance_port_by_switching_relay__in__id_on":0,"P\\Tests\\Unit\\Selfserve\\GatewayShellyTransportTest::__pest_evaluable_it_forwards_Shelly_toggle__after_timers_to_gateway_relay_switches":0,"P\\Tests\\Unit\\Selfserve\\ShellyTransportResolverTest::__pest_evaluable_it_marks_non_injected_local_and_gateway_overrides_as_local_only_gateway_transport":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_preserves_local_gateway_diagnostic_metadata_on_relay_status_snapshots":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_includes_positive_relay_timers_in_Shelly_switch_payloads":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_applies_Shelly_transport_overrides_across_self_serve_relay_side_effect_routes":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayLegacyRouteShimTest::__pest_evaluable_it_keeps_guarded_legacy_root_shims_for_moved_edge_gateway_routes":0.001,"P\\Tests\\Integration\\EdgeGateway\\EdgeGatewayBackendIntegrationTest::__pest_evaluable_it_persists_gateway_cutover_relay_bindings_used_by_self_serve_Shelly_dispatch":0.015,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_passes_explicit_timer_values_when_opening_lane_gates":0,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_keeps_Shelly_1_Mini_Gen3_type__model__and_generation_aligned_with_Shelly_metadata":0,"P\\Tests\\Api\\EdgeGatewayBrokerApiTest::__pest_evaluable_it_rejects_shell_session_creation_while_broker_presence_is_unavailable":23.503,"P\\Tests\\Unit\\Selfserve\\EdgeGatewayModuleRouteWiringTest::__pest_evaluable_it_registers_broker_settings_as_editable_edge_gateway_module_config":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_self_serve_session_management_endpoints_and_OpenAPI_coverage":0.005,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_self_serve_force_stop_distinct_from_normal_STOP_relay_and_gate_behavior":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_keeps_read_only_self_serve_preview_and_summary_refreshes_from_touching_relay_hardware":0,"P\\Tests\\Unit\\Selfserve\\SelfserveWashFlowMachineAllowedWiringTest::__pest_evaluable_it_separates_session_synchronization_from_relay_hardware_synchronization":0.001,"P\\Tests\\Unit\\Selfserve\\ShellyRealRequestGuardTest::__pest_evaluable_it_blocks_and_records_test_mode_Shelly_POST_requests_before_cURL_can_run":0.002,"P\\Tests\\Unit\\Selfserve\\ShellyRealRequestGuardTest::__pest_evaluable_it_blocks_and_records_test_mode_Shelly_GET_requests_before_cURL_can_run":0.001,"P\\Tests\\Unit\\Selfserve\\ZZZShellyGuardSafetyMetaTest::__pest_evaluable_it_did_not_record_any_real_Shelly_request_attempts_during_self_serve_tests":0.001,"P\\Tests\\Api\\SelfserveFixtureApiTest::__pest_evaluable_it_creates_a_comprehensive_self_serve_API_scenario_with_demo_relays":0.171,"P\\Tests\\Api\\SelfserveZZZShellyGuardApiTest::__pest_evaluable_it_did_not_record_any_real_Shelly_request_attempts_during_self_serve_API_tests":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_serializes_questions__conditions__tasks__scopes__and_gateways_into_one_graph":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_derives_studio_vehicle_type_lookup_rows_from_selectable_wash_products":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_applies_saved_layout_without_changing_graph_semantics":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_keeps_layout_loading_compatible_with_native_PDO_named_placeholders":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_builds_guided_simulator_debug_payload_with_blockers_and_canvas_annotations":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_resolves_simulator_gateway_service_bindings_from_lane_relay_slots":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_persists_allowed_services_without_relay_writes_for_pre_start_wash_setup":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_the_all_in_one_self_serve_studio_replacement_endpoints":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_continues_start_when_entrance_relay_dispatch_times_out_ambiguously":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_still_fails_start_for_non_timeout_entrance_relay_errors":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_parses_deferred_relay_side_effects_on_start_command_arguments":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_skips_cleaner_and_machine_relay_side_effects_when_start_asks_to_defer_them":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_keeps_cleaner_and_machine_relay_side_effects_for_normal_start_commands":0,"P\\Tests\\Unit\\Selfserve\\SelfservePropertyGatePermissionBypassTest::__pest_evaluable_it_allows_property_gate_commands_for_customers_with_an_active_wash_in_the_target_department":0,"P\\Tests\\Unit\\Selfserve\\SelfservePropertyGatePermissionBypassTest::__pest_evaluable_it_does_not_bypass_property_gate_permissions_without_a_positive_customer_number":0,"P\\Tests\\Unit\\Selfserve\\SelfservePropertyGatePermissionBypassTest::__pest_evaluable_it_does_not_bypass_property_gate_permissions_when_the_customer_has_no_active_wash_in_the_target_department":0,"P\\Tests\\Unit\\Selfserve\\SelfserveOpenApiSpecTest::__pest_evaluable_it_documents_the_all_in_one_self_serve_studio_replacement_API":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveNonOwnedVehicleWashAccessTest::__pest_evaluable_it_allows_own_permission_customers_to_preview_borrowed_registration_plates_without_ownership_checks":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveNonOwnedVehicleWashAccessTest::__pest_evaluable_it_allows_customer_scoped_answers_to_be_stored_for_borrowed_registration_plates":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveNonOwnedVehicleWashAccessTest::__pest_evaluable_it_does_not_apply_saved_answers_from_another_customer_for_the_same_registration_plate":0.027,"P\\Tests\\Unit\\Selfserve\\SelfserveNonOwnedVehicleWashAccessTest::__pest_evaluable_it_scopes_saved_self_serve_answers_by_customer_number_and_registration_plate":0,"P\\Tests\\Unit\\Selfserve\\SelfserveNonOwnedVehicleWashAccessTest::__pest_evaluable_it_loads_saved_answers_from_the_authenticated_customer_context_instead_of_the_plate_owner":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_does_not_count_shifts_without_punches_when_checkIn_checkOut_are_null":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_overtime_minutes_when_a_saved_shift_end_extends_past_the_approved_original_end":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_does_not_count_removed_approved_time_when_a_saved_shift_end_is_shortened":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_caps_current_slot_hours_to_elapsed_minutes_and_zeroes_future_slots":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_counts_checked_in_shifts_without_checkOut_up_to_occurredUntil":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_keeps_the_main_period_response_local_only_for_booked_state_and_customer_names":0.024,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_streams_the_main_period_response_instead_of_encoding_the_full_payload_at_once":0.033,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_maps_batched_period_transaction_rows_to_the_legacy_transaction_response_shape":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_uses_batched_period_transactions_and_keyed_customer_maps_in_the_main_period_route":0.033,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodRouteGuardsTest::__pest_evaluable_it_falls_back_to_configured_e_conomic_default_department_for_missing_customer_default_department_in_distributions":0.021,"P\\Tests\\Api\\EconomicDraftCustomerApiTest::__pest_evaluable_it_round_trips_the_default_distribution_department_config_value_through_economic_config_updates":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_computes_MySQL_GTID_interval_counts_and_coverage_percentages":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_reports_empty_source_GTID_sets_as_caught_up":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_computes_Redis_offset_percentages_safely":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_computes_MariaDB_GTID_coverage_by_domain_sequence":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_normalizes_public_replication_kind_aliases":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_supports_MariaDB_prerequisites_without_requiring_Oracle_MySQL_variables":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_reports_MariaDB_specific_blockers_when_GTID_or_binary_logging_prerequisites_are_missing":0,"P\\Tests\\Unit\\Replication\\ReplicationSecretBoxTest::__pest_evaluable_it_encrypts_replication_secrets_without_storing_plaintext":0.002,"P\\Tests\\Unit\\Replication\\ReplicationSecretBoxTest::__pest_evaluable_it_builds_active_database_and_redis_config_from_encrypted_bootstrap_snapshots":0,"P\\Tests\\Unit\\Replication\\SuperuserReplicationRouteWiringTest::__pest_evaluable_it_registers_superuser_replication_endpoints_and_permissions":0.019,"P\\Tests\\Unit\\Replication\\SuperuserReplicationRouteWiringTest::__pest_evaluable_it_documents_replication_management_in_openapi":0.016,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_generates_replication_ready_MariaDB_compose_templates_without_embedding_secrets":0.001,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_generates_Redis_replica_compose_templates_with_primary_connection_placeholders":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_does_not_require_replica_SQL_threads_before_database_provisioning_configures_them":0.006,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_creates_the_generated_replication_user_on_the_primary_during_provisioning":0.007,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_detects_missing_database_tables_before_provisioning_a_preseeded_replica":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_allows_failed_replicas_to_be_removed_without_allowing_primary_or_healthy_replica_removal":0.033,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_seeds_MariaDB_replicas_in_place_instead_of_requiring_container_recreation":0.024,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_keeps_replication_operation_progress_schema_idempotent_for_existing_installs":0.039,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_limits_MariaDB_log_table_seeding_to_the_last_month":0.002,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_skips_log_table_data_during_MariaDB_seeding_and_replication":0.003,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_keeps_operational_log_tables_schema_only_during_MariaDB_seeding_and_replication":0.005,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_provisions_Redis_replicas_after_a_connectivity_only_preflight_and_reports_sync_progress":0.015,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_keeps_Redis_promotion_caught_up__durable__and_metadata_safe":0.007,"P\\Tests\\Unit\\Auth\\CreateTokenTest::__pest_evaluable_it_creates_auth_tokens_and_reports_missing_customer_users_clearly":0.271,"P\\Tests\\Unit\\Auth\\EconomicCreateCustomerResponseTest::__pest_evaluable_it_returns_the_raw_upstream_create_response_and_preserves_the_requested_payload":0,"P\\Tests\\Unit\\Auth\\RegisterCvrLegacyScriptTest::__pest_evaluable_it_keeps_the_legacy_register_cvr_route_harness_passing":0.043,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_raw_202_gather_response_for_initial_department_selection":0.205,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_accepts_legacy_initial_webhook_payloads_with_top_level_call_identifiers":0.005,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_flow_data_gather_payload_after_department_selection_in_native_flow_mode_when_distinct_gate_choices_exist":0.002,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_opens_the_gate_immediately_after_department_selection_when_entrance_and_exit_resolve_to_the_same_gate_in_native_flow_mode":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_flow_data_completion_payload_after_gate_confirmation_in_native_flow_mode":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_second_stage_raw_202_gather_response_after_department_selection_when_distinct_gate_choices_exist":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_opens_the_shared_gate_immediately_after_department_selection_in_raw_command_mode":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_opens_the_selected_gate_and_clears_redis_state_on_final_selection":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_reprompts_with_invalid_selection_while_keeping_webhook_state":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_uses_fallback_dtmf_extraction_when_event_gather_keys_are_missing":0.001,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_prompts_for_department_selection_even_when_only_one_eligible_department_exists":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_prompts_for_a_single_available_gate_type_and_opens_only_after_explicit_confirmation":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_supports_multi_digit_department_selections_before_gate_confirmation":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_direct_raw_200_completion_when_no_departments_are_eligible":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_continues_with_the_first_gather_prompt_when_backend_call_acceptance_fails":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteCallLifecycleTest::__pest_evaluable_it_returns_a_business_failure_raw_200_response_when_gate_opening_fails":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_deterministic_department_digit_map_without_capping_options":0.009,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_compact_gate_option_maps_and_resolves_selected_gate_type_by_digit":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_builds_department_prompts_with_multi_digit_guidance_and_compact_gate_prompts":0,"P\\Tests\\Unit\\Bird\\BirdVoiceWebhooksRouteIvrTest::__pest_evaluable_it_normalizes_menu_digit_input_from_Bird_dtmf_payload_values":0,"P\\Tests\\Unit\\Bird\\DepartmentGatesPhoneCallOpenTest::__pest_evaluable_it_forwards_phone_number_and_call_duration_threshold_to_the_Bird_gate_helper":0.002,"P\\Tests\\Unit\\Bird\\DepartmentGatesPhoneCallOpenTest::__pest_evaluable_it_wraps_Bird_helper_failures_and_reports_them_to_Slack":0,"P\\Tests\\Unit\\Bookings\\NonPosBookingCompletionRemovalTest::__pest_evaluable_it_unregisters_legacy_booking_completion_forms":0.13,"P\\Tests\\Unit\\Bookings\\NonPosBookingCompletionRemovalTest::__pest_evaluable_it_keeps_legacy_wash_certificate_downloads_but_disables_generation_and_completion":0.166,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsComplaintsOpenApiSpecTest::__pest_evaluable_it_documents_the_daily_report_complaints_CRUD_and_customer_lookup_endpoints_in_openapi":0.011,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsComplaintsRouteContractTest::__pest_evaluable_it_wires_complaint_create__lookup__list__edit__and_delete_routes_with_validation_and_parsing":0.01,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOutsideHoursOpenApiSpecTest::__pest_evaluable_it_documents_outside_hours_summary_and_trend_schemas_in_openapi":0.016,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOutsideHoursRouteContractTest::__pest_evaluable_it_wires_outside_hours_summary_and_trend_endpoints_through_the_dedicated_statistics_service":0.007,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOutsideHoursRouteContractTest::__pest_evaluable_it_initializes_the_outside_hours_statistics_service_before_building_the_transaction_count_summary_payload":0.006,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewOpenApiSpecTest::__pest_evaluable_it_documents_the_daily_report_overview_endpoint_and_reusable_schemas_in_openapi":0.013,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_builds_the_overview_payload_from_batched_repository_data_with_deterministic_tile_states":0.013,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_marks_overtime_unavailable_when_not_every_selected_department_can_be_mapped_to_workfeed":0,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_normalizes_department_id_input_from_csv_strings_and_nested_values":0,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_limits_overtime_counting_to_the_selected_reporting_range":0,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_does_not_count_negative_approved_overtime_when_a_saved_end_shortens_the_shift":0,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_ignores_late_unapproved_administrative_edits_when_calculating_overtime":0,"P\\Tests\\Unit\\DailyReports\\DepartmentDailyReportsOverviewRouteTest::__pest_evaluable_it_wires_the_overview_route_to_batched_repository_methods_and_overview_path":0.013,"P\\Tests\\Unit\\DailyReports\\DepartmentOutsideHoursStatisticsServiceTest::__pest_evaluable_it_counts_only_outside_hours_washes_and_flags_missing_opening_hours_without_counting_them_as_closed":0.002,"P\\Tests\\Unit\\DailyReports\\DepartmentOutsideHoursStatisticsServiceTest::__pest_evaluable_it_deduplicates_linked_washes_with_self_serve_first__then_xlvask__then_orders":0,"P\\Tests\\Unit\\DailyReports\\DepartmentOutsideHoursStatisticsServiceTest::__pest_evaluable_it_builds_daily_trend_points_with_per_day_missing_hours_diagnostics":0.001,"P\\Tests\\Unit\\Database\\DbObjectRedisNamespaceSafetyTest::__pest_evaluable_it_keeps_db_object_Redis_access_namespace_safe":0.008,"P\\Tests\\Unit\\DynamicImages\\DepartmentLaneDynamicImageRouteTest::__pest_evaluable_it_allows_studio_lane_dynamic_image_previews_to_override_the_saved_image_id":0.012,"P\\Tests\\Unit\\DynamicImages\\DepartmentLaneDynamicImageRouteTest::__pest_evaluable_it_accepts_ordered_dynamic_image_button_tokens_including_reset_start_and_zero":0.003,"P\\Tests\\Unit\\DynamicImages\\DepartmentLaneDynamicImageRouteTest::__pest_evaluable_it_renders_machine_one_dynamic_image_steps_from_the_ordered_button_payload":0.014,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueDetailsSummaryBuilderTest::__pest_evaluable_it_uses_queued_job_payload_customer_context_before_result_data_exists":0,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_exposes_collected_invoice_queue_monitor_and_per_user_terminal_clear_routes":0.008,"P\\Tests\\Unit\\Invoicing\\CollectedInvoiceQueueRouteHardeningTest::__pest_evaluable_it_runs_collected_invoice_queue_batches_through_an_explicit_manual_endpoint":0.026,"P\\Tests\\Unit\\Invoicing\\EconomicAuthTokenFallbackTest::__pest_evaluable_it_bounds_e_conomic_curl_calls_below_the_PHP_request_timeout":0.01,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersDiscountFallbackTest::__pest_evaluable_it_falls_back_to_a_later_customer_template_product_when_earlier_probes_fail_on_missing_currency_prices":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersDiscountFallbackTest::__pest_evaluable_it_returns_zero_when_every_customer_template_lookup_fails_due_to_missing_currency_prices":0,"P\\Tests\\Unit\\Invoicing\\EconomicCustomersDiscountFallbackTest::__pest_evaluable_it_rethrows_unrelated_discount_lookup_failures":0,"P\\Tests\\Unit\\Invoicing\\EconomicDraftCustomerOpenApiSpecTest::__pest_evaluable_it_documents_transaction_draft_customer_config_and_auth_runtime_fields_in_all_tracked_openapi_copies":0.306,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueCronEntrypointWiringTest::__pest_evaluable_it_wires_root_cron_entrypoint_to_the_full_cron_scheduler_with_queue_worker_tasks":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueOpenApiSpecTest::__pest_evaluable_it_documents_additive_collected_invoice_queue_pagination_metadata_and_retry_conflict_semantics":0.009,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_exposes_an_explicit_collected_invoice_transfer_queue_run_route_instead_of_ticking_read_endpoints":0.013,"P\\Tests\\Unit\\Invoicing\\EconomicTransferQueueWorkerTickRouteTest::__pest_evaluable_it_keeps_order_transfer_queue_status_routes_read_only":0.005,"P\\Tests\\Unit\\Invoicing\\EconomicV2BookedDepartment75DistributionTest::__pest_evaluable_it_assigns_classified_booked_department_75_amounts_to_fallback_when_no_monthly_basis_exists":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_fixed_pricing_using_the_configured_fallback_department":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_falls_back_to_system_orders_for_wash_subscriptions_using_the_configured_fallback_department":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_uses_the_configured_fallback_department_when_a_subscription_has_no_customer_department_basis":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_excludes_orphaned_customer_traces_from_fixed_pricing_and_customer_price_distributions":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceFallbackTest::__pest_evaluable_it_excludes_orphaned_customers_from_subscription_fallback_versions":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceOrderOverrideTest::__pest_evaluable_it_inherits_department_eligibility_when_no_order_override_is_set":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceOrderOverrideTest::__pest_evaluable_it_allows_an_order_level_include_override_to_overrule_department_exclusion":0,"P\\Tests\\Unit\\Invoicing\\EconomicV2DistributionServiceOrderOverrideTest::__pest_evaluable_it_allows_an_order_level_exclude_override_to_overrule_department_inclusion":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_builds_deterministic_automatic_flag_fingerprints_and_interactive_price_message_parts":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_builds_interactive_message_parts_for_order_and_wash_certificate_warnings":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_includes_order_item_preview_context_for_required_order_field_warnings":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_allows_tank_cleaning_products_for_only_tank_cleaning_customers":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_does_not_flag_interior_wash_variants_as_historical_primary_product_mismatches":0.001,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_does_not_report_duplicate_primary_vehicle_products_from_duplicated_detector_rows_for_the_same_order_item":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_uses_attached_wash_certificate_documents_instead_of_safety_seal_text_for_certificate_presence":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_loads_wash_certificate_attachment_presence_from_order_attachment_content":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_uses_the_highest_customer_specific_discount_in_expected_price_breakdowns":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_uses_a_preloaded_e_conomic_global_discount_in_expected_price_breakdowns":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_does_not_report_a_price_mismatch_when_a_product_specific_discount_makes_the_expected_price_zero":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_preloads_and_caches_missing_e_conomic_discounts_before_price_mismatch_detection":0.04,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_seeds_order_item_preview_cache_from_period_rows":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_sorts_manual_flags_before_automatic_warnings_and_preserves_legacy_circle_indicators_without_flags":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_scopes_invoice_period_flags_to_the_customer_card_that_can_render_them":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_keeps_order_item_preview_context_compact_for_the_period_response":0,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_formats_stored_manual_flags_with_the_creating_superuser_display_name":0.003,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_validates_supported_manual_flag_fields_by_target_type":0.136,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_wires_invoice_period_flag_routes_with_explicit_list_create_and_update_permissions":0.043,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_uses_the_users_display__name_column_in_detector_queries":0.115,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_aggregates_customer_price_overrides_by_customer_number_for_price_mismatch_detection":0.115,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_guards_optional_customer_vehicle_deleted__at_filtering_behind_a_column_check":0.097,"P\\Tests\\Unit\\Invoicing\\InvoicePeriodFlagServiceTest::__pest_evaluable_it_limits_historical_primary_product_lookup_to_current_period_registrations":0.08,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_provides_a_batched_plain_row_transaction_query_for_invoicing_period_responses":0.11,"P\\Tests\\Unit\\Invoicing\\InvoicingOrdersCalculationsHardeningTest::__pest_evaluable_it_adds_guarded_composite_indexes_for_invoicing_period_lookups":0.155,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_blocks_invoicing_when_all_actionable_transactions_are_backed_by_valid_e_conomic_drafts":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_keeps_invoicing_available_when_valid_drafts_only_cover_part_of_the_actionable_work":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_excludes_errored__booked__deleted__and_missing_external_id_invoice_collections_at_query_time":0.027,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_still_checks_valid_drafts_when_the_collection_table_has_no_deleted_marker_column":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_blocks_fixed_pricing_and_subscription_customer_level_work_when_a_relevant_valid_draft_exists":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodDraftOverlayTest::__pest_evaluable_it_keeps_queue_blocking_ahead_of_the_draft_label_when_all_work_is_covered_by_queue_or_draft_state":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_detects_paginated_period_mode_only_when_pagination_parameters_are_present":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_normalizes_period_pagination_options_and_clamps_invalid_page_and_limit_values":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_slices_only_the_active_period_view_and_keeps_exact_full_result_type_counts":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_returns_the_entire_active_period_view_when_the_limit_is_all":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_searches_customer_fields_and_order_fields_at_the_customer_card_level":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodPaginationTest::__pest_evaluable_it_applies_requires_action_and_booked_visibility_filters_before_counting_and_slicing":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_normalizes_targeted_customer_number_filters_from_comma_separated_or_repeated_values":0,"P\\Tests\\Unit\\Invoicing\\InvoicingPeriodQueueOverlayTest::__pest_evaluable_it_filters_period_customer_number_candidates_to_targeted_customers_only":0,"P\\Tests\\Unit\\MotorApi\\MotorApiCachedResultTest::__pest_evaluable_it_only_writes_cached_MotorAPI_metadata_when_a_response_object_exists":0,"P\\Tests\\Unit\\Orders\\OrderBookingsCompletionDedupTest::__pest_evaluable_it_attaches_and_emails_a_wash_certificate_when_a_booking_is_already_linked_to_a_pos_order_without_one":0,"P\\Tests\\Unit\\Orders\\OrderBookingsCompletionDedupTest::__pest_evaluable_it_does_not_create_or_email_a_duplicate_wash_certificate_when_a_linked_pos_order_already_has_one":0,"P\\Tests\\Unit\\Orders\\OrderBookingsCompletionDedupTest::__pest_evaluable_it_keeps_standalone_booking_completion_behavior_unchanged_for_wash_certificates":0,"P\\Tests\\Unit\\Orders\\OrdersAutoWashCertificateCompletionTest::__pest_evaluable_it_auto_attaches_a_wash_certificate_on_order_completion_when_a_wash_certificate_item_is_present":0.001,"P\\Tests\\Unit\\Orders\\OrdersAutoWashCertificateCompletionTest::__pest_evaluable_it_keeps_order_completion_idempotent_when_a_wash_certificate_is_already_attached":0,"P\\Tests\\Unit\\Orders\\OrdersAutoWashCertificateCompletionTest::__pest_evaluable_it_allows_blank_safety_seal_values_when_auto_attaching_a_wash_certificate_on_completion":0,"P\\Tests\\Unit\\Orders\\OrdersIncludeInInvoiceOverrideTest::__pest_evaluable_it_lets_the_order_level_override_include_an_otherwise_excluded_order":0,"P\\Tests\\Unit\\Orders\\OrdersIncludeInInvoiceOverrideTest::__pest_evaluable_it_lets_the_order_level_override_exclude_an_otherwise_included_order":0,"P\\Tests\\Unit\\Orders\\OrdersIncludeInInvoiceOverrideTest::__pest_evaluable_it_falls_back_to_the_department_invoicing_rule_when_the_override_is_null":0,"P\\Tests\\Unit\\Orders\\OrdersIncludeInInvoiceOverrideTest::__pest_evaluable_it_serializes_both_raw_and_effective_include__in__invoice_values":0,"P\\Tests\\Unit\\Orders\\OrdersInputNormalizerTest::__pest_evaluable_it_normalizes_sql_and_datetime_local_created__at_values":0,"P\\Tests\\Unit\\Orders\\OrdersInputNormalizerTest::__pest_evaluable_it_rejects_invalid_created__at_values":0,"P\\Tests\\Unit\\Orders\\OrdersInputNormalizerTest::__pest_evaluable_it_normalizes_include__in__invoice_tri_state_inputs":0,"P\\Tests\\Unit\\Orders\\OrdersInputNormalizerTest::__pest_evaluable_it_rejects_invalid_include__in__invoice_values":0,"P\\Tests\\Unit\\Orders\\OrdersRouteSettingsUpdateWiringTest::__pest_evaluable_it_wires_order_create_and_update_routes_through_the_settings_normalizers":0.035,"P\\Tests\\Unit\\Orders\\OrdersRouteSettingsUpdateWiringTest::__pest_evaluable_it_keeps_line_item_invoice_filtering_in_the_order_net_amount_calculation":0.004,"P\\Tests\\Unit\\Orders\\OrdersRouteStripePaymentIntentLifecycleWiringTest::__pest_evaluable_it_wires_mobile_stripe_payment_intent_routes_to_normalized_lifecycle_handling":0.008,"P\\Tests\\Unit\\Orders\\StripePaymentIntentsPersistenceWiringTest::__pest_evaluable_it_wires_stripe_payment_intent_persistence_to_prune_duplicates_and_clear_reader_state_safely":0.104,"P\\Tests\\Unit\\Redis\\RedisAtomicReservationTest::__pest_evaluable_it_does_not_send_empty_mget_commands_to_redis":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_generates_MinIO_replica_compose_templates_without_embedding_secrets":0.001,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_computes_MinIO_free_space_and_catch_up_math_safely":0.001,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_wires_MinIO_replication_through_routes_and_bootstrap_snapshots":0.07,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_nested_v2_ALL_and_ANY_expression_trees_with_trace_output":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_v2_if__else_if__and_else_condition_branches_in_order":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_evaluates_v2_case_expressions_against_question_values":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConditionEvaluatorTest::__pest_evaluable_it_returns_false_and_traces_v2_condition_expression_cycles":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_fails_validation_when_nested_conditions_form_cycles":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_migrates_legacy_AND_and_OR_rules_into_grouped_v2_condition_expressions":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_repairs_legacy_defaulted_always_task_gates_during_v2_normalization":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_does_not_let_legacy_defaulted_always_task_gates_bypass_validation":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_rejects_unsupported_legacy_task_target_rules_after_migration":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_validates_v2_expressions_for_empty_used_conditions__missing_refs__invalid_operators__and_cycles":0,"P\\Tests\\Unit\\Selfserve\\SelfserveConfigVersioningTest::__pest_evaluable_it_validates_nested_v2_branch_and_case_expressions":0,"P\\Tests\\Unit\\Selfserve\\SelfserveInProgressWashAccessTest::__pest_evaluable_it_keeps_own_in_progress_self_serve_wash_details_visible_to_the_customer":0,"P\\Tests\\Unit\\Selfserve\\SelfserveInProgressWashAccessTest::__pest_evaluable_it_redacts_another_customers_in_progress_wash_details_during_customer_lane_polling":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_the_physical_machine_ON_signal_was_recorded__then_turns_off_cleaner_and_machine_relays":0.012,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_skips_vehicle_type_product_add_when_no_physical_machine_ON_signal_was_recorded_and_only_disables_configured_relays":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_does_not_use_selector_relay_online_status_as_machine_wash_billing_evidence":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_continues_STOP_when_exit_relay_dispatch_times_out_ambiguously":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_still_fails_STOP_for_non_timeout_exit_relay_errors":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveMachineSignalTest::__pest_evaluable_it_normalizes_Shelly_input_toggle_ON_events_as_machine_start_signals":0,"P\\Tests\\Unit\\Selfserve\\SelfserveMachineSignalTest::__pest_evaluable_it_normalizes_Shelly_switch_ON_events_and_nested_status_payloads":0,"P\\Tests\\Unit\\Selfserve\\SelfserveMachineSignalTest::__pest_evaluable_it_recognizes_Shelly_OFF_events_but_does_not_treat_them_as_billable_machine_starts":0,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_local_edge_gateway_machine_ON_signal_monitor_endpoints":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_lane_level_self_serve_toggles_through_lane_APIs__guest_payloads__and_edge_workspace_readiness":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_returns_authoritative_allowed_service_state_from_self_serve_session_summaries":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_filters_machine_button_tasks_out_of_self_serve_snapshots_when_MACHINE_is_not_allowed":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_blocks_new_self_serve_eligibility_and_session_sync_for_disabled_lanes":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_adds_lane_level_self_serve_enablement_for_existing_department_lanes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_creates_canvas_only_self_serve_studio_layout_storage":0,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_uses_mysql_safe_identifiers_for_self_serve_studio_virtual_hardware_storage":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_serializes_configurable_studio_actions_with_event__gate__scope__and_ordering_edges":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_validates_action_configuration_and_keeps_warnings_non_blocking":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_serializes_v2_condition_expressions_without_standalone_rule_nodes":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_serializes_branch_and_case_condition_expression_dependencies":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_keeps_runtime_on_published_v2_configs_and_leaves_draft_JSON_as_the_studio_edit_surface":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_surfaces_task_attachments_in_studio_graph__simulator__and_flow_responses":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_exposes_dynamic_images_and_referenced_machine_types_as_studio_lookup_choices":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_keeps_lane_management_fields_on_lane_scope_nodes":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_routes_studio_lane_graph_operations_through_department__lanes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_projects_visible_question_answer_paths_into_grouped_task_service_and_signal_outcomes":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_truncates_path_outcome_projection_when_the_state_cap_is_reached":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_returns_complete_terminal_path_results_for_wide_question_trees_and_reports_progress":0.364,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_generates_and_merges_virtual_hardware_as_studio_only_relay_coverage":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_renders_virtual_gateway_nodes_and_task_service_edges_in_the_studio_graph":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_inserts_configured_action_signals_into_the_simulator_timeline_in_runtime_order":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_simulates_lane_scoped_wash_start_actions_for_property_gates_and_lane_entrance_ports":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_adds_ordered_simulator_signal_timeline_rows_for_virtual_hardware_dry_runs":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveWashFlowMachineAllowedWiringTest::__pest_evaluable_it_infers_legacy_defaulted_always_task_gates_from_condition__id_at_runtime":0,"P\\Tests\\Unit\\Selfserve\\SelfserveWashSessionStateTest::__pest_evaluable_it_treats_terminal_self_serve_wash_session_statuses_as_closed":0,"P\\Tests\\Unit\\Selfserve\\SelfserveWashSessionStateTest::__pest_evaluable_it_freezes_elapsed_self_serve_wash_minutes_at_completion_time":0,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_exposes_chauffeur_management_endpoints_on_the_subusers_route":0.728,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_includes_grant_management_fields_in_the_subusers_payload_builder":0.014,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_links_grant_disable_operations_to_SUBUSERS__DELETE_for_own_customer_managers":0.022,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_prevents_own_customer_managers_from_editing_driver_owned_account_profiles":0.018,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_only_allows_invite_resend_while_setup_is_still_pending":0.028,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusOpenApiSpecTest::__pest_evaluable_it_documents_the_superuser_system_status_snapshot_endpoint_in_openapi":0.008,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusOpenApiSpecTest::__pest_evaluable_it_defines_the_reusable_system_status_schemas_and_enums":0.006,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusRouteWiringTest::__pest_evaluable_it_registers_the_aggregated_superuser_system_status_endpoint_and_permission":0.006,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusRouteWiringTest::__pest_evaluable_it_keeps_the_legacy_database_status_endpoint_wired_through_the_shared_snapshot_service":0.004,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_reduces_overall_status_using_down_and_degraded_precedence":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_runtime_usage_percentages_consistently":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_reuses_cached_module_probes_only_when_the_ttl_is_still_valid_and_force_is_false":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"success\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"unauthorized\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"forbidden\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"rate limited\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"server error\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_authenticated_http_probe_responses_conservatively with data set \"dataset \"no response\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_classifies_transport_errors_as_down":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_normalizes_and_deduplicates_warning_entries_for_snapshots":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_interprets_recaptcha_probe_payloads_safely with data set \"dataset \"dummy token rejected but credentials valid\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_interprets_recaptcha_probe_payloads_safely with data set \"dataset \"invalid secret is down\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_interprets_recaptcha_probe_payloads_safely with data set \"dataset \"unexpected validation errors degrade\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"recaptcha\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"email\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"motorapi\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"fxratesapi\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"weatherapi\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"workfeed\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"gatewayapi\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"xlvask\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"limble\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"license plate recognizer\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_the_expected_http_probe_requests_for_newly_supported_modules with data set \"dataset \"bird\"\"":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_uses_runtime_economic_credentials_for_the_economic_probe":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_returns_down_without_attempting_economic_http_calls_when_runtime_credentials_are_missing":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_reports_backup_probe_failures_from_local_validation":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_returns_configured_for_shelly_when_no_known_device_id_is_available_for_probing":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_builds_an_authenticated_shelly_status_probe_when_a_known_device_id_exists":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_validates_selfserve_schema_and_minute_product_configuration":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_reports_invalid_selfserve_minute_configuration_before_touching_the_schema":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_reports_missing_selfserve_minute_products":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_surfaces_selfserve_bootstrap_failures":0,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_adds_localization_metadata_for_disabled_and_missing_config_modules":40.262,"P\\Tests\\Unit\\SystemStatus\\SuperuserSystemStatusServiceTest::__pest_evaluable_it_marks_newly_supported_modules_as_probe_backed_and_leaves_only_truly_unsupported_modules_as_configuration_only":38.499,"P\\Tests\\Unit\\SystemStatus\\SystemSessionActivityTrackerTest::__pest_evaluable_it_detects_device_types_from_common_user_agents":0,"P\\Tests\\Unit\\SystemStatus\\SystemSessionActivityTrackerTest::__pest_evaluable_it_treats_recent_sessions_as_active_within_the_configured_activity_window":0,"P\\Tests\\Unit\\SystemStatus\\SystemSessionActivityTrackerTest::__pest_evaluable_it_converts_database_utc_datetimes_into_timezone_aware_iso_strings":0,"P\\Tests\\Unit\\SystemStatus\\SystemSessionActivityTrackerTest::__pest_evaluable_it_treats_timezone_aware_iso_timestamps_as_active_using_absolute_time":0,"P\\Tests\\Unit\\Tooling\\LegacyTestInventoryTest::__pest_evaluable_it_keeps_every_legacy_PHP_test_accounted_for_in_the_manifest":0.489,"P\\Tests\\Unit\\Tooling\\MySqlSchemaCompatibilityTest::__pest_evaluable_it_keeps_schema_bootstrap_SQL_compatible_with_the_MySQL_runner":6.55,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_allows_callers_to_resolve_customer_names_without_e_conomic_fallback":0.003,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_returns_an_empty_customer_name_map_without_touching_cache_for_empty_input":0,"P\\Tests\\Unit\\Users\\UsersCustomerNamesCacheTest::__pest_evaluable_it_returns_no_rows_for_empty_array_field_filters":0,"P\\Tests\\Unit\\Users\\UsersRedisNamespaceSafetyTest::__pest_evaluable_it_keeps_users_Redis_access_namespace_safe":0.005,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherCacheRuntimeBehaviorTest::__pest_evaluable_it_builds_department_weather_preload_targets_in_cli_without_a_request_uri":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherPreloadCronWiringTest::__pest_evaluable_it_registers_and_implements_cron_warming_for_workfeed_employee_name_cache":0.007,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_multi_department_slot_statuses_using_worst_severity_when_any_department_is_unhealthy":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_aggregates_all_unhealthy_multi_department_slot_statuses_as_unhealthy":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_returns_unknown_when_aggregated_multi_department_slot_targets_are_missing":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_returns_unknown_when_aggregated_multi_department_slot_has_no_evaluable_hours":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherStatusTargetsTest::__pest_evaluable_it_returns_unknown_when_aggregated_multi_department_slot_has_not_started_yet":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherTargetsRouteWiringTest::__pest_evaluable_it_registers_department_weather_hour_details_route_with_weather_read_and_department_access_checks":0.007,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_weather_hour_contributions_grouped_per_employee_for_a_slot":0.001,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_calculates_weather_hour_contributions_for_canonical_nested_workfeed_employee_schema":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_extracts_weather_employee_identity_from_supported_shift_payload_shapes":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_prefers_canonical_workfeed_employee_schema_fields_over_generic_employee_names":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_does_not_use_workfeed_schema_name_fields_as_employee_ids":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_returns_a_null_employee_name_when_no_workfeed_employee_name_is_available":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_resolves_missing_workfeed_employee_names_from_the_employees_endpoint":0.042,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_filters_employee_hour_rows_that_cannot_be_resolved_to_a_workfeed_schema_name":0,"P\\Tests\\Unit\\Workfeed\\DepartmentWeatherWorkfeedHoursTest::__pest_evaluable_it_resolves_employee_display_name_from_cache_when_shift_payload_lacks_a_name":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedEmployeeNameFormatterTest::__pest_evaluable_it_formats_workfeed_employee_display_names_from_the_documented_firstname_lastname_schema":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedEmployeeNameFormatterTest::__pest_evaluable_it_prefers_workfeed_schema_names_over_generic_display_name_fields":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedEmployeeNameFormatterTest::__pest_evaluable_it_falls_back_to_legacy_display_name_fields_when_schema_names_are_absent":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedEmployeeNameFormatterTest::__pest_evaluable_it_ignores_placeholder_workfeed_display_names":0,"P\\Tests\\Unit\\Workfeed\\WorkfeedEmployeeNameFormatterTest::__pest_evaluable_it_ignores_employee_id_placeholder_display_names_when_the_id_is_known":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_normalizes_registrations_for_XL_Vask_automation_signatures":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_builds_stable_XL_Vask_automation_item_signatures":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_normalizes_persisted_XL_Vask_usage_log_rows_before_helper_hydration":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_builds_stable_OpenAI_cache_keys_for_identical_automation_input":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_changes_OpenAI_cache_keys_when_automation_eligibility_input_changes":0,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_declares_a_persistent_OpenAI_cache_table_for_XL_Vask_automation":0.005,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_declares_cached_amount_summary_columns_for_XL_Vask_usage_logs":0.012,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_scores_same_day_orders_with_matching_XL_Vask_products_and_extra_add_ons_as_attach_suggestions":0.003,"P\\Tests\\Unit\\XLVask\\XLVaskAutomationServiceTest::__pest_evaluable_it_does_not_score_an_order_with_only_the_primary_product_as_a_matching_add_on_attachment":0,"P\\Tests\\Unit\\XLVask\\XLVaskUsageLogHelperTest::__pest_evaluable_it_accepts_persisted_ignore_metadata_from_xlvask_usage_log_rows":0.019,"P\\Tests\\Unit\\XLVask\\XLVaskUsageLogHelperTest::__pest_evaluable_it_calculates_XL_Vask_amount_summaries_without_hydrating_order_item_previews":0.006,"P\\Tests\\Unit\\XLVask\\XLVaskUsageRouteContractTest::__pest_evaluable_it_exposes_direct_linked_order_metadata_on_XL_Vask_usage_order_rows":0.003,"P\\Tests\\Unit\\XLVask\\XLVaskUsageRouteContractTest::__pest_evaluable_it_returns_cached_amount_summaries_on_XL_Vask_usage_order_rows_without_widening_the_usage_log_object_payload":0.003,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_counts_complaint_rows_by_department_and_created__at_reporting_range":0.284,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_updates_and_deletes_complaint_rows":0.005,"P\\Tests\\Integration\\DailyReports\\DepartmentDailyReportComplaintsIntegrationTest::__pest_evaluable_it_parses_created__by__name_from_the_users_table":0.005,"P\\Tests\\Integration\\DailyReports\\DepartmentOutsideHoursStatisticsServiceIntegrationTest::__pest_evaluable_it_integrates_orders__xlvask__and_self_serve_into_one_outside_hours_summary_with_missing_hours_diagnostics":0.016,"P\\Tests\\Integration\\Invoicing\\EconomicTransferQueueIntegrationTest::__pest_evaluable_it_processes_only_collected_invoice_jobs_and_respects_the_manual_batch_limit":0.014,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_the_configured_database_in_integration_mode":0,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_redis_in_integration_mode_when_configured":0,"P\\Tests\\Integration\\SystemStatus\\SuperuserSystemStatusInfrastructureProbeTest::__pest_evaluable_it_can_probe_minio_in_integration_mode_when_configured":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_redacts_sensitive_release_timeline_payload_fields_recursively":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_verifies_GitHub_sha256_webhook_signatures":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_normalizes_GitHub_repository_identifiers_for_private_repository_access_checks":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_defines_release_manager_schema__routes__permissions__and_system_status_integration_hooks":0.575,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_summarizes_failed_deployments_and_blocks_promotion_until_a_deployment_succeeds":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_uses_the_selected_Coolify_project_and_resolves_server_UUID_from_the_instance_default":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_supports_isolated_stack_mode_and_names_new_Coolify_services_explicitly":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_creates_Coolify_service_payloads_from_raw_compose_without_a_service_type":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_normalizes_Coolify_API_base_URLs_to_the_v1_API_root":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_parses_generated_env_files_for_Coolify_service_env_bulk_updates":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_prefers_public_Coolify_server_hosts_over_Docker_local_addresses":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_blocks_planned_downtime_operations_against_active_replication_primaries":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_allows_failed_Coolify_replica_targets_to_be_removed_after_the_service_disappears":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_retries_Coolify_maintenance_while_linked_replication_provisioning_is_still_incomplete":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_plans_Hetzner_load_balancer_target_and_service_drift_without_mutating_state":0.24,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_does_not_plan_removal_of_the_last_Hetzner_load_balancer_target":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_plans_removal_only_for_disabled_or_deleted_Hetzner_load_balancer_targets":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_defines_Coolify_schema__route_permissions__and_replication_integration_hooks":0.418,"P\\Tests\\Unit\\ErrorReports\\ErrorReportTest::__pest_evaluable_it_redacts_sensitive_error_report_payload_fields_recursively":0.001,"P\\Tests\\Unit\\ErrorReports\\ErrorReportTest::__pest_evaluable_it_validates_supported_screenshot_data_uris":0,"P\\Tests\\Unit\\ErrorReports\\ErrorReportTest::__pest_evaluable_it_defines_error_report_schema__routes__permissions__storage__and_OpenAPI_docs":0.04,"P\\Tests\\Unit\\Http\\ResponseRequestParametersTest::__pest_evaluable_it_reads_JSON_payloads_for_DELETE_request_parameter_arrays":0,"P\\Tests\\Unit\\Http\\ResponseRequestParametersTest::__pest_evaluable_it_keeps_DELETE_query_parameters_when_no_JSON_body_is_present":0,"P\\Tests\\Unit\\Infrastructure\\CorsReleaseHeadersTest::__pest_evaluable_it_allows_release_telemetry_headers_at_PHP_served_CORS_entry_points":0.424,"P\\Tests\\Unit\\Orders\\OrderBookingsCompletionDedupTest::__pest_evaluable_it_uses_the_linked_pos_order_wash_certificate_item_added_during_mobile_completion":0,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_normalizes_failover_config_defaults_and_per_kind_enablement":0,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_requires_strict_fresh_100_percent_replica_status_for_candidates":0,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_selects_the_freshest_eligible_replica_for_failover":0,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_promotes_enabled_startup_dependencies_from_snapshot_in_dependency_order":0.004,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_does_not_promote_a_disabled_dependency_during_startup_failover":0.001,"P\\Tests\\Unit\\Replication\\ReplicaFailoverManagerTest::__pest_evaluable_it_wires_the_failover_module_config_endpoint_and_promotion_paths":0.312,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_can_embed_primary_admin_credentials_in_generated_MariaDB_replica_env_files":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_keeps_operational_and_derived_tables_schema_only_during_MariaDB_seeding_and_replication":0.021,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_supports_metadata_only_replication_host_renames":0.005,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_keeps_MinIO_backup_replicas_bounded_to_the_recent_backup_window":0.014,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_prefills_MinIO_replica_compose_primary_values_from_current_config_when_available":0.001,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_allows_the_MinIO_client_binary_to_be_configured_explicitly":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_supports_MinIO_client_runtime_fallback_configuration":0,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_extracts_host_specific_MariaDB_replication_account_denials":0.001,"P\\Tests\\Unit\\Replication\\ReplicationManagerStatusTest::__pest_evaluable_it_identifies_stopped_database_replication_threads_as_a_restartable_status":0,"P\\Tests\\Unit\\Scanner\\ModuleScannerRouteTest::__pest_evaluable_it_returns_no_plate_LPR_results_without_a_failed_HTTP_status":0.046,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_does_not_invent_GHCR_images_for_Coolify_service_payloads":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_keeps_release_branch_services_out_of_the_production_Coolify_environment_except_beta":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_creates_Coolify_GitHub_App_application_payloads_so_pulls_use_the_app_token":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_does_not_treat_an_existing_Coolify_service_as_an_application_just_because_a_GitHub_App_UUID_is_stored":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_can_use_the_Coolify_instance_default_GitHub_App_when_source_targets_do_not_store_it_yet":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_updates_existing_frontend_Coolify_applications_away_from_legacy_Nixpacks_detection":0,"P\\Tests\\Unit\\Auth\\EconomicCreateCustomerResponseTest::__pest_evaluable_it_adds_supported_CVR_company_fields_to_the_e_conomic_customer_payload":0.014,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_keeps_release_channel_runtime_availability_independent_from_channel_URLs":0.007,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_chooses_a_requested_runtime_channel_only_when_it_is_available_to_the_principal":0.199,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_normalizes_release_assignment_subject_suggestions_without_leaking_private_fields":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_keeps_GitHub_commit_timestamps_in_public_release_manager_commit_payloads":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_requires_non_default_release_channel_runtime_URLs_and_preserves_load_balancer_paths":0.105,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_exposes_release_version_git_commit_metadata_for_runtime_channel_cards":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_builds_gateway_API_auto_provision_context_for_connected_Coolify_servers":0.001,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_adds_explicit_Coolify_application_route_labels_for_gateway_API_domains":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_builds_explicit_Coolify_application_route_labels_for_release_API_targets":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_uses_the_self_contained_Coolify_API_Dockerfile_for_API_applications":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_isolates_and_restores_Hetzner_load_balancer_IP_targets_for_gateway_certificate_bootstrap":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_requires_gateway_ping_probes_to_return_the_API_ping_contract":0,"P\\Tests\\Unit\\Tooling\\ComposerEntrypointTest::__pest_evaluable_it_checks_PSR_HTTP_message_interfaces_before_trusting_a_Composer_vendor_tree":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_marks_a_channel_ready_when_all_release_services_are_healthy":0.001,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_reports_non_default_channels_missing_bundles__versions__and_URLs_as_blocking_missing_values":0.024,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_surfaces_failed_latest_deployments_as_critical_promotion_blockers":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_flags_isolated_stacks_that_are_missing_database_Redis_and_MinIO_services":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_maps_degraded_Coolify_targets_and_reconcile_failures_to_release_service_issues":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_plans_Hetzner_load_balancer_service_health_check_drift_updates":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_returns_structured_errors_for_failed_gateway_certificate_bootstrap_and_verification":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_captures_release_request_context_from_headers_and_runtime_query_parameters":0.004,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_normalizes_channel_prefixed_API_ingress_paths_before_route_dispatch":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_creates_frontend_Coolify_GitHub_App_application_payloads_with_the_release_Dockerfile":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_builds_gateway_frontend_auto_provision_context_with_the_release_Dockerfile":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_allows_explicit_runtime_selection_of_any_enabled_release_channel":0.289,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_chooses_requested_runtime_channels_from_available_channels_or_enabled_channel_slugs":0,"P\\Tests\\Unit\\Coolify\\CoolifyManagerTest::__pest_evaluable_it_normalizes_gateway_probe_paths_for_release_gateway_health_checks":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_resolves_release_deployment_endpoints_from_manual_overrides__URLs__health_checks__and_gateway_defaults":0.001,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_does_not_report_frontend_or_API_URLs_missing_when_target_auto_endpoints_are_resolvable":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_offers_a_release_bundle_action_when_exactly_one_deployed_bundle_is_eligible":0.008,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_offers_application_target_preparation_for_path_routed_Coolify_failures":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_maps_the_public_master_API_prefix_to_the_stable_release_channel":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_uses_master_as_the_public_route_slug_for_the_stable_release_channel":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_does_not_block_channels_on_unhealthy_data_targets_when_data_services_are_production_shared":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_ignores_missing_legacy_bundles_but_still_blocks_on_missing_versions_and_URLs":0.001,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_marks_a_branch_based_channel_ready_without_a_release_bundle_when_app_versions_and_URLs_exist":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_does_not_surface_legacy_release_bundle_actions_as_readiness_blockers":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_adds_exact_hidden_question__skipped_action__signal__and_button_decision_causes":0,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_rejects_standalone_order_booking_completion_outside_POS":5.621,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_allows_linked_POS_order_booking_completion_for_mobile_POS_compatibility":4.121,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_accepts_numeric_safety_seal_strings_when_completing_a_linked_POS_order_booking":4.366,"P\\Tests\\Api\\OrderBookingsCompletionApiTest::__pest_evaluable_it_disables_the_legacy_complete_wash_without_certificate_route":1.122,"P\\Tests\\Api\\OrderBookingsUpdateApiTest::__pest_evaluable_it_detaches_an_order_booking_and_clears_the_matching_order_link":5.559,"P\\Tests\\Api\\OrderBookingsUpdateApiTest::__pest_evaluable_it_keeps_the_linked_order_when_order__id_is_omitted_from_an_order_booking_update":5.22,"P\\Tests\\Unit\\DynamicImages\\DepartmentLaneDynamicImageRouteTest::__pest_evaluable_it_accepts_ordered_dynamic_image_button_tokens_including_program_picker_reset_start_and_zero":0.007,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_adds_program_picker_before_mapped_machine_buttons_in_simulator_debug_decisions":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_verifies_CI_release_gate_bearer_tokens_from_dedicated_release_credentials":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_only_chooses_requested_runtime_channels_from_channels_available_to_the_principal":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_ignores_explicit_runtime_selection_for_channels_outside_the_principal_channel_set":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_auto_prepares_path_routed_release_targets_for_Coolify_application_creation":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_offers_application_target_preparation_for_missing_Coolify_service_creation_failures":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_builds_API_Coolify_runtime_environment_from_allowed_process_variables":0.001,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_normalizes_URL_like_CORS_entries_to_origins":0,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_merges_required_release_and_existing_frontend_origins_into_configured_CORS":0,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_builds_credential_safe_normal_CORS_response_headers_for_allowed_origins":0,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_builds_preflight_CORS_response_headers_for_api_v2_release_URLs":0,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_rejects_unknown_CORS_origins":0,"P\\Tests\\Unit\\Infrastructure\\CorsPolicyTest::__pest_evaluable_it_reflects_the_request_origin_for_wildcard_CORS_instead_of_sending_credentialed_wildcard_headers":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_allows_customers_with_own_self_serve_permission_to_use_enabled_self_serve_lanes":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_blocks_customer_lane_mutations_without_own_self_serve_permission":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_blocks_customer_lane_mutations_when_the_lane_is_not_operationally_enabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_allows_active_wash_operations_when_the_lane_runtime_belongs_to_the_customer":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_falls_back_to_active_department_sessions_for_customer_active_wash_operations":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_blocks_active_wash_operations_for_other_customers":0,"P\\Tests\\Unit\\Selfserve\\SelfservePropertyGatePermissionBypassTest::__pest_evaluable_it_does_not_bypass_property_gate_permissions_without_customer_self_serve_permission":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_keeps_active_wash_operations_available_if_a_lane_is_disabled_after_start":0,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_requires_authentication_before_checking_in_progress_wash_permissions":0.05,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_reports_both_elevated_and_customer_self_serve_permissions_when_lane_polling_is_not_allowed":0.133,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_allows_customer_self_serve_permission_to_view_their_own_in_progress_wash_details":0.287,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_redacts_another_customers_in_progress_wash_from_customer_self_serve_lane_polling":0.319,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_keeps_beta_API_runtime_environment_on_production_database_target":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_treats_attach_existing_service_sets_without_data_target_ids_as_production_shared_ready":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_rejects_beta_release_bundles_that_resolve_to_isolated_cloned_or_fresh_data_services":0.01,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_detects_explicit_data_target_ids_so_beta_service_sets_can_stay_data_only":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_resolves_backend_commit_sha_from_API_runtime_environment_in_priority_order":0.009,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_injects_selected_API_commit_into_Coolify_runtime_env_unless_explicitly_set":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_allows_beta_production_service_bundles_only_when_data_services_stay_production_shared":0,"P\\Tests\\Unit\\ReleaseManager\\ReleaseManagerTest::__pest_evaluable_it_keeps_release_branch_services_out_of_the_production_Coolify_environment":0,"P\\Tests\\Unit\\Release\\ReleaseManagerStatusOverviewTest::__pest_evaluable_it_marks_beta_ready_from_the_production_frontend_and_API_services":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_uses_program_picker_button_numbers_as_thumb_selectors_in_simulator_debug_decisions":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_upserts_path_editor_answers_into_generated_condition_and_task_config_rows":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_marks_projected_path_confirmations_confirmed_or_stale_by_stable_signatures":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveSchemaBootstrapCompatibilityTest::__pest_evaluable_it_creates_self_serve_studio_path_confirmation_storage":0,"P\\Tests\\Unit\\Subusers\\SubusersRouteManagementContractTest::__pest_evaluable_it_resolves_subuser_customer_names_without_external_lookups_during_list_requests":0.208,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_treats_null_path_confirmation_rows_as_an_empty_confirmation_set":0,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioGraphTest::__pest_evaluable_it_applies_default_caps_for_wide_question_trees_and_reports_progress":0.07,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_wires_dashboard_lane_machine_status_and_Dognvask_toggle_endpoints":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveRouteWiringTest::__pest_evaluable_it_classifies_self_serve_lane_command_route_authorization_by_customer_product_behavior":0.003,"P\\Tests\\Unit\\Selfserve\\EdgeBrokerClientConfigTest::__pest_evaluable_it_uses_default_broker_url_but_requires_explicit_shared_secret_configuration":0.001,"P\\Tests\\Unit\\Selfserve\\EdgeBrokerClientConfigTest::__pest_evaluable_it_fails_closed_when_no_broker_shared_secret_is_configured":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_denies_customer_self_serve_command_fallback_when_the_self_serve_module_is_disabled":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_returns_deterministic_forbidden_permissions_when_disabled_module_blocks_customer_self_serve_command_fallback":0,"P\\Tests\\Unit\\Selfserve\\SelfserveCustomerLaneAccessTest::__pest_evaluable_it_continues_allowing_operator_self_serve_commands_when_the_self_serve_module_is_disabled":0,"P\\Tests\\Unit\\Selfserve\\SelfserveEligibilityLaneAccessTest::__pest_evaluable_it_authorizes_customer_eligibility_preview_lanes_before_returning_task_attachments":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceModeBillingTest::__pest_evaluable_it_creates_self_serve_invoice_orders_for_the_actual_lane_customer_when_a_draft_customer_is_configured":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneInvoiceModeBillingTest::__pest_evaluable_it_keeps_the_real_billing_customer_as_the_authoritative_order_customer_in_the_invoice_context":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveLanePortControllerTest::__pest_evaluable_it_caps_excessive_timer_values_when_opening_lane_gates":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_hard_MACHINE_relay_helper_targets_the_configured_MACHINE_relay":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneRelayShellyBatchingTest::__pest_evaluable_it_blocks_setMachineRelayStatus_from_enabling_MACHINE_when_MACHINE_is_not_allowed":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartRaceLockWiringTest::__pest_evaluable_it_locks_and_marks_a_self_serve_start_occupied_before_opening_the_entrance_relay":0.002,"P\\Tests\\Unit\\Selfserve\\SelfserveStartCleanerRelayWiringTest::__pest_evaluable_it_does_not_enable_cleaner_relay_before_deferred_start_relay_side_effects_are_checked":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveStudioActionRunnerTest::__pest_evaluable_it_does_not_match_condition_gated_actions_when_condition_results_are_missing":0.001,"P\\Tests\\Unit\\Selfserve\\SelfserveWashCompletionRelayWiringTest::__pest_evaluable_it_always_dispatches_completion_relay_off_for_configured_machine_relays_without_a_status_precheck":0,"P\\Tests\\Unit\\Selfserve\\ShellyRelayInventoryTest::__pest_evaluable_it_only_includes_local_IP_addresses_for_internal_relay_option_lookups":0.001,"P\\Tests\\Api\\SelfserveFixtureApiTest::__pest_evaluable_it_creates_self_serve_invoice_orders_for_the_lane_customer_with_draft_customer_and_driver_metadata_attached":0.283,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_allows_customer_self_serve_permission_to_execute_START_without_department_access_when_department_and_lane_are_enabled":2.214,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_denies_customer_START_when_department_self_serve_is_disabled":0.255,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_denies_customer_START_when_lane_self_serve_is_disabled":0.769,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_denies_a_customer_STOP_for_another_customers_active_lane":0.31,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_still_allows_elevated_operators_with_department_access_to_execute_lane_commands":5.98,"P\\Tests\\Api\\SelfserveLaneCommandApiTest::__pest_evaluable_it_keeps_operator_only_commands_elevated_only_for_customers_and_reports_command_permissions":0.26,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_requires_authentication_before_checking_the_current_customers_active_self_serve_wash":0.048,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_requires_customer_self_serve_permission_before_checking_my_active_wash":0.127,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_returns_the_authenticated_customers_active_self_serve_wash_without_requiring_a_lane_id":0.294,"P\\Tests\\Api\\SelfserveLaneWashInProgressApiTest::__pest_evaluable_it_returns_404_when_the_authenticated_customer_has_no_active_self_serve_wash":30.237,"P\\Tests\\Unit\\Selfserve\\ModuleConfigVariableDatabaseConfigTest::__pest_evaluable_it_reads_debug_database_configuration_when_the_debug_target_is_selected":0.001,"P\\Tests\\Unit\\Selfserve\\ModuleConfigVariableDatabaseConfigTest::__pest_evaluable_it_keeps_live_database_configuration_as_the_default_target":0,"P\\Tests\\Api\\SelfserveCustomerStartApiTest::__pest_evaluable_it_allows_the_customer_self_serve_start_sequence_without_department_access":13.663,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_skips_cleaner__program_picker_and_machine_relay_side_effects_when_start_asks_to_defer_them":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStartEntranceTimeoutTest::__pest_evaluable_it_keeps_cleaner__program_picker_and_machine_relay_side_effects_in_order_for_normal_start_commands":0,"P\\Tests\\Unit\\Selfserve\\SelfserveLaneStopFlowTest::__pest_evaluable_it_adds_vehicle_type_product_on_STOP_when_the_physical_machine_ON_signal_was_recorded__after_turning_relays_off_before_exit":0.012,"P\\Tests\\Unit\\Selfserve\\SelfservePublishedConfigLaneWildcardTest::__pest_evaluable_it_applies_department_product_rows_with_lane_zero_to_all_lanes_in_published_v2_configs":0,"P\\Tests\\Api\\SelfserveCustomerStartApiTest::__pest_evaluable_it_derives_allowed_services_from_v2_session_task_snapshots_when_task_rows_are_not_legacy_records":0.259}} \ No newline at end of file diff --git a/services/nginx/app/build/logs/api-server.err.log b/services/nginx/app/build/logs/api-server.err.log index 094e7aaf..e8ea6dc1 100644 --- a/services/nginx/app/build/logs/api-server.err.log +++ b/services/nginx/app/build/logs/api-server.err.log @@ -12204,3 +12204,251 @@ [Tue May 26 09:31:07 2026] 127.0.0.1:38284 Closing [Tue May 26 09:31:08 2026] 127.0.0.1:38290 Accepted [Tue May 26 09:31:12 2026] 127.0.0.1:38290 Closing +[Tue Jun 2 12:55:52 2026] PHP 8.2.15 Development Server (http://127.0.0.1:45377) started +[Tue Jun 2 12:55:52 2026] 127.0.0.1:52720 Accepted +[Tue Jun 2 12:55:52 2026] 127.0.0.1:52720 Closing +[Tue Jun 2 12:55:52 2026] 127.0.0.1:52734 Accepted +[Tue Jun 2 12:55:52 2026] 127.0.0.1:52734 Closing +[Tue Jun 2 12:55:52 2026] 127.0.0.1:52742 Accepted +[Tue Jun 2 12:55:52 2026] 127.0.0.1:52742 Closing +[Tue Jun 2 12:55:52 2026] 127.0.0.1:52750 Accepted +[Tue Jun 2 12:55:52 2026] 127.0.0.1:52750 Closing +[Tue Jun 2 12:55:52 2026] 127.0.0.1:52766 Accepted +[Tue Jun 2 12:55:52 2026] 127.0.0.1:52766 Closing +[Tue Jun 2 12:55:53 2026] 127.0.0.1:52770 Accepted +[Tue Jun 2 12:55:53 2026] 127.0.0.1:52770 Closing +[Tue Jun 2 12:55:53 2026] 127.0.0.1:52784 Accepted +[Tue Jun 2 12:55:53 2026] 127.0.0.1:52784 Closing +[Tue Jun 2 12:55:53 2026] 127.0.0.1:52792 Accepted +[Tue Jun 2 12:55:53 2026] 127.0.0.1:52792 Closing +[Tue Jun 2 12:55:53 2026] 127.0.0.1:52802 Accepted +[Tue Jun 2 12:55:53 2026] 127.0.0.1:52802 Closing +[Tue Jun 2 12:59:15 2026] PHP 8.2.15 Development Server (http://127.0.0.1:42651) started +[Tue Jun 2 12:59:15 2026] 127.0.0.1:41826 Accepted +[Tue Jun 2 12:59:15 2026] 127.0.0.1:41826 Closing +[Tue Jun 2 12:59:15 2026] 127.0.0.1:41842 Accepted +[Tue Jun 2 12:59:15 2026] 127.0.0.1:41842 Closing +[Tue Jun 2 12:59:15 2026] 127.0.0.1:41850 Accepted +[Tue Jun 2 12:59:15 2026] 127.0.0.1:41850 Closing +[Tue Jun 2 12:59:15 2026] 127.0.0.1:41860 Accepted +[Tue Jun 2 12:59:15 2026] 127.0.0.1:41860 Closing +[Tue Jun 2 12:59:15 2026] 127.0.0.1:41874 Accepted +[Tue Jun 2 12:59:15 2026] 127.0.0.1:41874 Closing +[Tue Jun 2 12:59:16 2026] 127.0.0.1:41884 Accepted +[Tue Jun 2 12:59:16 2026] 127.0.0.1:41884 Closing +[Tue Jun 2 12:59:16 2026] 127.0.0.1:41894 Accepted +[Tue Jun 2 12:59:16 2026] 127.0.0.1:41894 Closing +[Tue Jun 2 12:59:16 2026] 127.0.0.1:41902 Accepted +[Tue Jun 2 12:59:16 2026] 127.0.0.1:41902 Closing +[Tue Jun 2 12:59:16 2026] 127.0.0.1:41916 Accepted +[Tue Jun 2 12:59:37 2026] 127.0.0.1:41916 Closing +[Tue Jun 2 13:02:13 2026] PHP 8.2.15 Development Server (http://127.0.0.1:38777) started +[Tue Jun 2 13:02:13 2026] 127.0.0.1:37238 Accepted +[Tue Jun 2 13:02:13 2026] 127.0.0.1:37238 Closing +[Tue Jun 2 13:02:13 2026] 127.0.0.1:37252 Accepted +[Tue Jun 2 13:02:13 2026] 127.0.0.1:37252 Closing +[Tue Jun 2 13:02:13 2026] 127.0.0.1:37256 Accepted +[Tue Jun 2 13:02:13 2026] 127.0.0.1:37256 Closing +[Tue Jun 2 13:02:15 2026] 127.0.0.1:35516 Accepted +[Tue Jun 2 13:02:15 2026] 127.0.0.1:35516 Closing +[Tue Jun 2 13:02:15 2026] 127.0.0.1:35518 Accepted +[Tue Jun 2 13:02:15 2026] 127.0.0.1:35518 Closing +[Tue Jun 2 13:02:15 2026] 127.0.0.1:35528 Accepted +[Tue Jun 2 13:02:15 2026] 127.0.0.1:35528 Closing +[Tue Jun 2 13:02:16 2026] 127.0.0.1:35544 Accepted +[Tue Jun 2 13:02:16 2026] 127.0.0.1:35544 Closing +[Tue Jun 2 13:02:16 2026] 127.0.0.1:35552 Accepted +[Tue Jun 2 13:02:16 2026] 127.0.0.1:35552 Closing +[Tue Jun 2 13:02:16 2026] 127.0.0.1:35568 Accepted +[Tue Jun 2 13:02:16 2026] 127.0.0.1:35568 Closing +[Tue Jun 2 13:02:16 2026] 127.0.0.1:35582 Accepted +[Tue Jun 2 13:02:16 2026] 127.0.0.1:35582 Closing +[Tue Jun 2 13:02:16 2026] 127.0.0.1:35586 Accepted +[Tue Jun 2 13:02:17 2026] 127.0.0.1:35586 Closing +[Tue Jun 2 13:02:17 2026] 127.0.0.1:35588 Accepted +[Tue Jun 2 13:02:17 2026] 127.0.0.1:35588 Closing +[Tue Jun 2 13:02:19 2026] 127.0.0.1:35596 Accepted +[Tue Jun 2 13:02:20 2026] 127.0.0.1:35596 Closing +[Tue Jun 2 13:02:20 2026] 127.0.0.1:35600 Accepted +[Tue Jun 2 13:02:20 2026] 127.0.0.1:35600 Closing +[Tue Jun 2 13:02:20 2026] 127.0.0.1:35612 Accepted +[Tue Jun 2 13:02:20 2026] 127.0.0.1:35612 Closing +[Tue Jun 2 13:02:46 2026] PHP 8.2.15 Development Server (http://127.0.0.1:39573) started +[Tue Jun 2 13:02:46 2026] 127.0.0.1:43488 Accepted +[Tue Jun 2 13:02:46 2026] 127.0.0.1:43488 Closing +[Tue Jun 2 13:02:46 2026] 127.0.0.1:43494 Accepted +[Tue Jun 2 13:02:47 2026] 127.0.0.1:43494 Closing +[Tue Jun 2 13:02:47 2026] 127.0.0.1:43502 Accepted +[Tue Jun 2 13:02:47 2026] 127.0.0.1:43502 Closing +[Tue Jun 2 13:02:47 2026] 127.0.0.1:43504 Accepted +[Tue Jun 2 13:02:47 2026] 127.0.0.1:43504 Closing +[Tue Jun 2 13:02:47 2026] 127.0.0.1:43516 Accepted +[Tue Jun 2 13:02:47 2026] 127.0.0.1:43516 Closing +[Tue Jun 2 13:02:53 2026] 127.0.0.1:43530 Accepted +[Tue Jun 2 13:02:53 2026] 127.0.0.1:43530 Closing +[Tue Jun 2 13:02:53 2026] 127.0.0.1:43540 Accepted +[Tue Jun 2 13:02:53 2026] 127.0.0.1:43540 Closing +[Tue Jun 2 13:02:53 2026] 127.0.0.1:43550 Accepted +[Tue Jun 2 13:02:53 2026] 127.0.0.1:43550 Closing +[Tue Jun 2 13:02:53 2026] 127.0.0.1:43562 Accepted +[Tue Jun 2 13:02:53 2026] 127.0.0.1:43562 Closing +[Tue Jun 2 13:02:53 2026] 127.0.0.1:43578 Accepted +[Tue Jun 2 13:02:53 2026] 127.0.0.1:43578 Closing +[Tue Jun 2 13:02:54 2026] 127.0.0.1:51950 Accepted +[Tue Jun 2 13:02:54 2026] 127.0.0.1:51950 Closing +[Tue Jun 2 13:02:54 2026] 127.0.0.1:51952 Accepted +[Tue Jun 2 13:02:54 2026] 127.0.0.1:51952 Closing +[Tue Jun 2 13:02:54 2026] 127.0.0.1:51964 Accepted +[Tue Jun 2 13:02:54 2026] 127.0.0.1:51964 Closing +[Tue Jun 2 13:02:54 2026] 127.0.0.1:51978 Accepted +[Tue Jun 2 13:02:54 2026] 127.0.0.1:51978 Closing +[Tue Jun 2 13:02:55 2026] 127.0.0.1:51994 Accepted +[Tue Jun 2 13:02:55 2026] 127.0.0.1:51994 Closing +[Tue Jun 2 13:25:35 2026] PHP 8.2.15 Development Server (http://127.0.0.1:40811) started +[Tue Jun 2 13:25:35 2026] 127.0.0.1:43736 Accepted +[Tue Jun 2 13:25:35 2026] 127.0.0.1:43736 Closing +[Tue Jun 2 13:25:35 2026] 127.0.0.1:43740 Accepted +[Tue Jun 2 13:25:35 2026] 127.0.0.1:43740 Closing +[Tue Jun 2 13:25:35 2026] 127.0.0.1:43754 Accepted +[Tue Jun 2 13:25:35 2026] 127.0.0.1:43754 Closing +[Tue Jun 2 13:25:36 2026] 127.0.0.1:43768 Accepted +[Tue Jun 2 13:25:36 2026] 127.0.0.1:43768 Closing +[Tue Jun 2 13:25:36 2026] 127.0.0.1:43776 Accepted +[Tue Jun 2 13:25:36 2026] 127.0.0.1:43776 Closing +[Tue Jun 2 13:25:52 2026] 127.0.0.1:57442 Accepted +[Tue Jun 2 13:25:52 2026] 127.0.0.1:57442 Closing +[Tue Jun 2 13:25:52 2026] 127.0.0.1:57452 Accepted +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57452 Closing +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57460 Accepted +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57460 Closing +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57472 Accepted +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57472 Closing +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57486 Accepted +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57486 Closing +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57492 Accepted +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57492 Closing +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57508 Accepted +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57508 Closing +[Tue Jun 2 13:25:53 2026] 127.0.0.1:57522 Accepted +[Tue Jun 2 13:25:54 2026] 127.0.0.1:57522 Closing +[Tue Jun 2 13:25:54 2026] 127.0.0.1:60940 Accepted +[Tue Jun 2 13:25:54 2026] 127.0.0.1:60940 Closing +[Tue Jun 2 13:25:54 2026] 127.0.0.1:60950 Accepted +[Tue Jun 2 13:25:54 2026] 127.0.0.1:60950 Closing +[Tue Jun 2 13:44:42 2026] PHP 8.2.15 Development Server (http://127.0.0.1:37125) started +[Tue Jun 2 13:44:42 2026] 127.0.0.1:45382 Accepted +[Tue Jun 2 13:44:42 2026] 127.0.0.1:45382 Closing +[Tue Jun 2 13:44:42 2026] 127.0.0.1:45388 Accepted +[Tue Jun 2 13:44:42 2026] 127.0.0.1:45388 Closing +[Tue Jun 2 13:44:42 2026] 127.0.0.1:45398 Accepted +[Tue Jun 2 13:44:43 2026] 127.0.0.1:45398 Closing +[Tue Jun 2 13:44:43 2026] 127.0.0.1:45410 Accepted +[Tue Jun 2 13:44:46 2026] 127.0.0.1:45410 Closing +[Tue Jun 2 13:44:46 2026] 127.0.0.1:53928 Accepted +[Tue Jun 2 13:44:46 2026] 127.0.0.1:53928 Closing +[Tue Jun 2 13:44:51 2026] PHP 8.2.15 Development Server (http://127.0.0.1:34643) started +[Tue Jun 2 13:44:51 2026] 127.0.0.1:46776 Accepted +[Tue Jun 2 13:44:51 2026] 127.0.0.1:46776 Closing +[Tue Jun 2 13:44:51 2026] 127.0.0.1:46782 Accepted +[Tue Jun 2 13:44:51 2026] 127.0.0.1:46782 Closing +[Tue Jun 2 13:44:51 2026] 127.0.0.1:46796 Accepted +[Tue Jun 2 13:44:51 2026] 127.0.0.1:46796 Closing +[Tue Jun 2 13:44:51 2026] 127.0.0.1:46806 Accepted +[Tue Jun 2 13:44:51 2026] 127.0.0.1:46806 Closing +[Tue Jun 2 13:44:51 2026] 127.0.0.1:46816 Accepted +[Tue Jun 2 13:44:51 2026] 127.0.0.1:46816 Closing +[Tue Jun 2 13:44:52 2026] 127.0.0.1:46824 Accepted +[Tue Jun 2 13:44:52 2026] 127.0.0.1:46824 Closing +[Tue Jun 2 13:44:53 2026] 127.0.0.1:46836 Accepted +[Tue Jun 2 13:44:53 2026] 127.0.0.1:46836 Closing +[Tue Jun 2 13:44:53 2026] 127.0.0.1:46846 Accepted +[Tue Jun 2 13:44:53 2026] 127.0.0.1:46846 Closing +[Tue Jun 2 13:44:53 2026] 127.0.0.1:46848 Accepted +[Tue Jun 2 13:44:53 2026] 127.0.0.1:46848 Closing +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45254 Accepted +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45254 Closing +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45264 Accepted +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45264 Closing +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45276 Accepted +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45276 Closing +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45282 Accepted +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45282 Closing +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45288 Accepted +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45288 Closing +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45296 Accepted +[Tue Jun 2 13:44:54 2026] 127.0.0.1:45296 Closing +[Tue Jun 2 13:44:55 2026] 127.0.0.1:45312 Accepted +[Tue Jun 2 13:44:55 2026] 127.0.0.1:45312 Closing +[Tue Jun 2 13:44:55 2026] 127.0.0.1:45314 Accepted +[Tue Jun 2 13:44:55 2026] 127.0.0.1:45314 Closing +[Tue Jun 2 13:44:55 2026] 127.0.0.1:45328 Accepted +[Tue Jun 2 13:44:55 2026] 127.0.0.1:45328 Closing +[Tue Jun 2 13:44:55 2026] 127.0.0.1:45330 Accepted +[Tue Jun 2 13:44:55 2026] 127.0.0.1:45330 Closing +[Tue Jun 2 14:14:22 2026] PHP 8.2.15 Development Server (http://127.0.0.1:41283) started +[Tue Jun 2 14:14:22 2026] 127.0.0.1:54804 Accepted +[Tue Jun 2 14:14:22 2026] 127.0.0.1:54804 Closing +[Tue Jun 2 14:14:22 2026] 127.0.0.1:54812 Accepted +[Tue Jun 2 14:14:22 2026] 127.0.0.1:54812 Closing +[Tue Jun 2 14:14:22 2026] 127.0.0.1:54816 Accepted +[Tue Jun 2 14:14:22 2026] 127.0.0.1:54816 Closing +[Tue Jun 2 14:14:22 2026] 127.0.0.1:54826 Accepted +[Tue Jun 2 14:14:23 2026] 127.0.0.1:54826 Closing +[Tue Jun 2 14:14:23 2026] 127.0.0.1:54828 Accepted +[Tue Jun 2 14:14:25 2026] 127.0.0.1:54828 Closing +[Tue Jun 2 14:14:25 2026] 127.0.0.1:45644 Accepted +[Tue Jun 2 14:14:25 2026] 127.0.0.1:45644 Closing +[Tue Jun 2 14:14:42 2026] PHP 8.2.15 Development Server (http://127.0.0.1:40157) started +[Tue Jun 2 14:14:42 2026] 127.0.0.1:46410 Accepted +[Tue Jun 2 14:14:42 2026] 127.0.0.1:46410 Closing +[Tue Jun 2 14:14:42 2026] 127.0.0.1:46414 Accepted +[Tue Jun 2 14:14:42 2026] 127.0.0.1:46414 Closing +[Tue Jun 2 14:14:42 2026] 127.0.0.1:46424 Accepted +[Tue Jun 2 14:14:42 2026] 127.0.0.1:46424 Closing +[Tue Jun 2 14:14:42 2026] 127.0.0.1:46440 Accepted +[Tue Jun 2 14:14:42 2026] 127.0.0.1:46440 Closing +[Tue Jun 2 14:14:42 2026] 127.0.0.1:46442 Accepted +[Tue Jun 2 14:14:42 2026] 127.0.0.1:46442 Closing +[Tue Jun 2 14:14:43 2026] 127.0.0.1:46458 Accepted +[Tue Jun 2 14:14:43 2026] 127.0.0.1:46458 Closing +[Tue Jun 2 14:16:10 2026] PHP 8.2.15 Development Server (http://127.0.0.1:38915) started +[Tue Jun 2 14:16:10 2026] 127.0.0.1:54470 Accepted +[Tue Jun 2 14:16:10 2026] 127.0.0.1:54470 Closing +[Tue Jun 2 14:16:10 2026] 127.0.0.1:54482 Accepted +[Tue Jun 2 14:16:11 2026] 127.0.0.1:54482 Closing +[Tue Jun 2 14:16:11 2026] 127.0.0.1:54492 Accepted +[Tue Jun 2 14:16:11 2026] 127.0.0.1:54492 Closing +[Tue Jun 2 14:16:11 2026] 127.0.0.1:54498 Accepted +[Tue Jun 2 14:16:11 2026] 127.0.0.1:54498 Closing +[Tue Jun 2 14:16:11 2026] 127.0.0.1:54508 Accepted +[Tue Jun 2 14:16:11 2026] 127.0.0.1:54508 Closing +[Tue Jun 2 14:16:24 2026] 127.0.0.1:48044 Accepted +[Tue Jun 2 14:16:24 2026] 127.0.0.1:48044 Closing +[Tue Jun 2 14:16:25 2026] 127.0.0.1:48060 Accepted +[Tue Jun 2 14:16:25 2026] 127.0.0.1:48060 Closing +[Tue Jun 2 14:16:27 2026] 127.0.0.1:48072 Accepted +[Tue Jun 2 14:16:27 2026] 127.0.0.1:48072 Closing +[Tue Jun 2 14:16:27 2026] 127.0.0.1:48088 Accepted +[Tue Jun 2 14:16:28 2026] 127.0.0.1:48088 Closing +[Tue Jun 2 14:16:28 2026] 127.0.0.1:48094 Accepted +[Tue Jun 2 14:16:28 2026] 127.0.0.1:48094 Closing +[Tue Jun 2 14:16:34 2026] 127.0.0.1:55000 Accepted +[Tue Jun 2 14:16:34 2026] 127.0.0.1:55000 Closing +[Tue Jun 2 14:16:34 2026] 127.0.0.1:55006 Accepted +[Tue Jun 2 14:16:34 2026] 127.0.0.1:55006 Closing +[Tue Jun 2 14:16:34 2026] 127.0.0.1:55016 Accepted +[Tue Jun 2 14:16:34 2026] 127.0.0.1:55016 Closing +[Tue Jun 2 14:16:34 2026] 127.0.0.1:55018 Accepted +[Tue Jun 2 14:16:34 2026] 127.0.0.1:55018 Closing +[Tue Jun 2 14:16:35 2026] 127.0.0.1:55022 Accepted +[Tue Jun 2 14:16:35 2026] 127.0.0.1:55022 Closing +[Tue Jun 2 14:16:35 2026] 127.0.0.1:55032 Accepted +[Tue Jun 2 14:16:35 2026] 127.0.0.1:55032 Closing +[Tue Jun 2 14:16:35 2026] 127.0.0.1:55048 Accepted +[Tue Jun 2 14:16:35 2026] 127.0.0.1:55048 Closing +[Tue Jun 2 14:16:35 2026] 127.0.0.1:55060 Accepted +[Tue Jun 2 14:16:35 2026] 127.0.0.1:55060 Closing +[Tue Jun 2 14:16:35 2026] 127.0.0.1:55074 Accepted +[Tue Jun 2 14:16:35 2026] 127.0.0.1:55074 Closing +[Tue Jun 2 14:17:06 2026] 127.0.0.1:34490 Accepted +[Tue Jun 2 14:17:06 2026] 127.0.0.1:34490 Closing diff --git a/services/nginx/app/modules/selfserve/classes/selfserve_wash_flow.php b/services/nginx/app/modules/selfserve/classes/selfserve_wash_flow.php index cf90eca1..9312019b 100644 --- a/services/nginx/app/modules/selfserve/classes/selfserve_wash_flow.php +++ b/services/nginx/app/modules/selfserve/classes/selfserve_wash_flow.php @@ -2962,7 +2962,7 @@ class selfserve_wash_flow implements selfserve_wash_flow_i return array_values(array_filter($questions, static function (array $question) use ($departmentId, $laneId, $vehicleTypeId): bool { return (int)($question['department'] ?? 0) === $departmentId - && (int)($question['lane'] ?? 0) === $laneId + && ((int)($question['lane'] ?? 0) === 0 || (int)($question['lane'] ?? 0) === $laneId) && (int)($question['product'] ?? 0) === $vehicleTypeId; })); } @@ -3005,7 +3005,7 @@ class selfserve_wash_flow implements selfserve_wash_flow_i return array_values(array_filter($conditions, static function (array $condition) use ($departmentId, $laneId, $vehicleTypeId): bool { return (int)($condition['machine_type_id'] ?? 0) === 0 && (int)($condition['department'] ?? 0) === $departmentId - && (int)($condition['lane'] ?? 0) === $laneId + && ((int)($condition['lane'] ?? 0) === 0 || (int)($condition['lane'] ?? 0) === $laneId) && (int)($condition['product'] ?? 0) === $vehicleTypeId; })); } @@ -3049,7 +3049,7 @@ class selfserve_wash_flow implements selfserve_wash_flow_i return array_values(array_filter($tasks, static function (array $task) use ($departmentId, $laneId, $vehicleTypeId): bool { return (int)($task['machine_type_id'] ?? 0) === 0 && (int)($task['department'] ?? 0) === $departmentId - && (int)($task['lane'] ?? 0) === $laneId + && ((int)($task['lane'] ?? 0) === 0 || (int)($task['lane'] ?? 0) === $laneId) && (int)($task['product'] ?? 0) === $vehicleTypeId; })); } diff --git a/services/nginx/app/modules/selfserve/traits/selfserve_lane_command_t.php b/services/nginx/app/modules/selfserve/traits/selfserve_lane_command_t.php index 825f16ba..5f8b9edc 100644 --- a/services/nginx/app/modules/selfserve/traits/selfserve_lane_command_t.php +++ b/services/nginx/app/modules/selfserve/traits/selfserve_lane_command_t.php @@ -176,8 +176,7 @@ trait selfserve_lane_command_t if (!$this->isRelayConfigured(selfserve_lane_relay::MACHINE)) { return; } - $active_wash = new selfserve_wash_flow(); - if ($active_wash->isMachineAllowedToStartWash($this->id)) { + if ($this->isMachineWashSelectedAndAvailableForStart()) { try { $this->setMachineRelayStatusHard(true); } catch (\Throwable) { @@ -193,6 +192,57 @@ trait selfserve_lane_command_t } } + /** + * Keep the program picker relay aligned with the selected wash mode at START. + * It is ON only when the active self-serve session is allowed to start machine wash. + */ + protected function setProgramPickerRelayStatusForWashStart(): void + { + if (!$this->isRelayConfigured(selfserve_lane_relay::MACHINE_PROGRAM_PICKER)) { + return; + } + + try { + $shouldEnable = $this->isMachineWashSelectedAndAvailableForStart(); + $this->setMachineProgramPickerRelayStatusHard($shouldEnable); + } catch (\Throwable) { + // Best effort only; wash start must continue. + } + } + + protected function isMachineWashSelectedAndAvailableForStart(): bool + { + if (!$this->isMachineServiceSelectedForWashStart()) { + return false; + } + + try { + return (new selfserve_wash_flow())->isMachineAllowedToStartWash((int)$this->id); + } catch (\Throwable) { + return false; + } + } + + protected function isMachineServiceSelectedForWashStart(): bool + { + try { + if (method_exists($this, 'getLaneCache') && defined(self::class . '::CACHE_SELFSERVE_LANE_KEY_ALLOWED_SERVICES')) { + $services = $this->getLaneCache((int)$this->id, self::CACHE_SELFSERVE_LANE_KEY_ALLOWED_SERVICES); + if (is_array($services)) { + foreach ($services as $service) { + if (strtoupper((string)$service) === 'MACHINE') { + return true; + } + } + } + } + } catch (\Throwable) { + // Fall through to fail-closed when the selected service cache is unavailable. + } + + return false; + } + protected function openEntrancePortForWashStart(): void { try { @@ -277,27 +327,15 @@ trait selfserve_lane_command_t return; } - // Ensure cleaner relay is enabled whenever wash starts. $this->turnOnCleanerRelayForWashStart(); - // Ensure the machine relay is ON when a wash starts, when it is allowed. + $this->setProgramPickerRelayStatusForWashStart(); $this->setMachineRelayStatusForWashStart(); } protected function resolveSelfServeActionWashModeForStart(): string { - try { - if (method_exists($this, 'getLaneCache') && defined(self::class . '::CACHE_SELFSERVE_LANE_KEY_ALLOWED_SERVICES')) { - $services = $this->getLaneCache((int)$this->id, self::CACHE_SELFSERVE_LANE_KEY_ALLOWED_SERVICES); - if (is_array($services)) { - foreach ($services as $service) { - if (strtoupper((string)$service) === 'MACHINE') { - return selfserve_studio_actions::MODE_MACHINE; - } - } - } - } - } catch (\Throwable) { - // Fall through to manual mode when the cached service set is unavailable. + if ($this->isMachineServiceSelectedForWashStart()) { + return selfserve_studio_actions::MODE_MACHINE; } return selfserve_studio_actions::MODE_MANUAL; @@ -382,14 +420,16 @@ trait selfserve_lane_command_t } /** - * Disable relays after STOP in deterministic order: + * Disable relays before opening exit gates in deterministic order: * 1. Cleaner relay - * 2. Machine relay + * 2. Program picker relay + * 3. Machine relay */ protected function turnOffRelaysAfterStop(): void { $relays = [ selfserve_lane_relay::MACHINE_CLEANER, + selfserve_lane_relay::MACHINE_PROGRAM_PICKER, selfserve_lane_relay::MACHINE, ]; @@ -563,8 +603,17 @@ trait selfserve_lane_command_t // Set the customer number and license plate $this->setCustomerNumber($customer_number); $this->setLicensePlate($license_plate); - // Mark the lane occupied before any physical entrance relay side effects. + // Mark the lane occupied before any physical relay or gate side effects. $this->setLaneStatus(selfserve_lane_status::OCCUPIED); + $this->runRelaySideEffectsForWashStart($arguments); + $this->runPublishedStudioActions( + selfserve_studio_actions::EVENT_WASH_START_COMMAND, + $this->resolveSelfServeActionWashModeForStart(), + [ + 'customer_number' => (int)$customer_number, + 'reg' => $license_plate, + ] + ); try { // Gateway timeouts are ambiguous because the relay may already have received // the pulse, so openEntrancePortForWashStart() reports them and continues. @@ -580,15 +629,6 @@ trait selfserve_lane_command_t $this->setLaneState(selfserve_lane_state::IN_WASH); // Start the wash timer $this->setWashStartTime(time()); - $this->runPublishedStudioActions( - selfserve_studio_actions::EVENT_WASH_START_COMMAND, - $this->resolveSelfServeActionWashModeForStart(), - [ - 'customer_number' => (int)$customer_number, - 'reg' => $license_plate, - ] - ); - $this->runRelaySideEffectsForWashStart($arguments); // Log the lane start event $this->logLaneAction(selfserve_lane_log_action::START_WASH); } finally { @@ -604,6 +644,8 @@ trait selfserve_lane_command_t } // Snapshot the physical machine ON signal before session completion/reset. $machine_start_triggered = $this->hasMachineStartSignalForStop(); + // Turn off relays before any configured or default exit gate opens. + $this->turnOffRelaysAfterStop(); $this->runPublishedStudioActions( selfserve_studio_actions::EVENT_WASH_STOP_COMMAND, $machine_start_triggered ? selfserve_studio_actions::MODE_MACHINE : selfserve_studio_actions::MODE_MANUAL, @@ -616,8 +658,6 @@ trait selfserve_lane_command_t // Open the exit port. Gateway timeouts are ambiguous because // the relay may already have received the pulse. $this->openExitPortForWashStop(); - // Turn off relays in deterministic order after STOP - $this->turnOffRelaysAfterStop(); // Log the lane stop event $this->logLaneAction(selfserve_lane_log_action::STOP_WASH); // Invoice the customer diff --git a/services/nginx/app/routes/departmentSelfserveVehicleConditionsRoute.php b/services/nginx/app/routes/departmentSelfserveVehicleConditionsRoute.php index 4c1e4935..0d2cc9fc 100644 --- a/services/nginx/app/routes/departmentSelfserveVehicleConditionsRoute.php +++ b/services/nginx/app/routes/departmentSelfserveVehicleConditionsRoute.php @@ -13,6 +13,7 @@ use objects\customer_vehicles_o; use objects\department_lanes_o; use objects\department_selfserve_tasks_o; use objects\department_selfserve_vehicle_conditions_o; +use objects\departments_o; use objects\logs_o; use traits\route_t; @@ -131,9 +132,9 @@ class departmentSelfserveVehicleConditionsRoute $lane_id = (int)self::getParameter('lane_id'); $reg = selfserve::standardize_registration((string)self::getParameter('reg')); - $lane = $this->assertLaneAccess($user, $lane_id); + $lane = $this->assertLaneAccess($user, $lane_id, $has_global, $has_own); $customer_number = null; - if (!$has_global && $has_own) { + if ($has_own && (!$has_global || !$this->userHasLaneDepartmentAccess($user, $lane))) { $customer_number = $this->requireAuthenticatedCustomerNumber($user, 'list_department_selfserve_vehicle_conditions'); } $vehicle_type_id = $this->resolveVehicleTypeIdFromQuery(); @@ -171,7 +172,7 @@ class departmentSelfserveVehicleConditionsRoute try { if (self::isParametersSet(['session_id'])) { $summary = $flow->getSessionSummary((int)self::getParameter('session_id')); - $this->assertSummaryAccess($user, $summary, $has_global, 'list_department_selfserve_vehicle_conditions'); + $this->assertSummaryAccess($user, $summary, $has_global, $has_own, 'list_department_selfserve_vehicle_conditions'); if ($this->shouldRefreshSummaryForVehicleType($summary, $vehicle_type_id)) { $summary = $flow->synchronizeSession( @@ -193,9 +194,9 @@ class departmentSelfserveVehicleConditionsRoute $lane_id = (int)self::getParameter('lane_id'); $reg = selfserve::standardize_registration((string)self::getParameter('reg')); - $this->assertLaneAccess($user, $lane_id); + $lane = $this->assertLaneAccess($user, $lane_id, $has_global, $has_own); $customer_number = null; - if (!$has_global && $has_own) { + if ($has_own && (!$has_global || !$this->userHasLaneDepartmentAccess($user, $lane))) { $customer_number = $this->requireAuthenticatedCustomerNumber($user, 'list_department_selfserve_vehicle_conditions'); } @@ -204,7 +205,7 @@ class departmentSelfserveVehicleConditionsRoute } else { $summary = $flow->getLatestSessionSummary($lane_id, $reg); } - $this->assertSummaryAccess($user, $summary, $has_global, 'list_department_selfserve_vehicle_conditions'); + $this->assertSummaryAccess($user, $summary, $has_global, $has_own, 'list_department_selfserve_vehicle_conditions'); $response->success($summary); } catch (\RuntimeException $e) { $response->error($e->getMessage(), 404); @@ -527,7 +528,13 @@ class departmentSelfserveVehicleConditionsRoute return $default; } - private function assertLaneAccess(object $user, int $laneId): department_lanes_o + private function assertLaneAccess( + object $user, + int $laneId, + bool $hasGlobalPermission = true, + bool $hasOwnPermission = false, + string $elevatedPermission = 'list_department_selfserve_vehicle_conditions' + ): department_lanes_o { global $response; @@ -536,17 +543,77 @@ class departmentSelfserveVehicleConditionsRoute $response->error('Department lane not found', 404); } + if ($hasGlobalPermission && $this->userHasLaneDepartmentAccess($user, $lane)) { + return $lane; + } + + if ($hasOwnPermission && $this->isCustomerSelfServeLaneEnabled($lane)) { + return $lane; + } + + if ($hasGlobalPermission) { + $lane_department_id = (int)$lane->department->value(); + $this->forbidDepartmentAccess($lane_department_id); + } + + $response->forbidden([$elevatedPermission]); + } + + private function userHasLaneDepartmentAccess(object $user, department_lanes_o $lane): bool + { $lane_department_id = (int)$lane->department->value(); $authorized_department_ids = array_values(array_filter( array_map('intval', (array)$user->getGroup()->getDepartments()), static fn(int $department_id): bool => $department_id > 0 )); - if (!in_array($lane_department_id, $authorized_department_ids, true)) { - $this->forbidDepartmentAccess($lane_department_id); + return in_array($lane_department_id, $authorized_department_ids, true); + } + + private function isCustomerSelfServeLaneEnabled(department_lanes_o $lane): bool + { + try { + if (!$lane->isSelfServeEnabled()) { + return false; + } + + $department = (new departments_o())->select((int)$lane->department->value()); + return $department->exists() && $department->getSelfServeEnabled(); + } catch (\Throwable) { + return false; + } + } + + private function summaryBelongsToCustomer(object $user, array $summary): bool + { + $session_customer_number = $summary['session']['customer_number'] ?? null; + if ($session_customer_number !== null && (int)$session_customer_number === (int)$user->customer_number->value()) { + return true; } - return $lane; + $reg = (string)($summary['session']['reg'] ?? ''); + $vehicle_o = (new customer_vehicles_o())->selectByPlate($reg); + return $vehicle_o->exists() && (int)$vehicle_o->customer_id->value() === (int)$user->customer_number->value(); + } + + private function summaryDepartmentId(array $summary): int + { + return (int)($summary['lane']['department'] ?? $summary['session']['department_id'] ?? 0); + } + + private function userHasSummaryDepartmentAccess(object $user, array $summary): bool + { + $lane_department = $this->summaryDepartmentId($summary); + if ($lane_department <= 0) { + return false; + } + + $authorized_department_ids = array_values(array_filter( + array_map('intval', (array)$user->getGroup()->getDepartments()), + static fn(int $department_id): bool => $department_id > 0 + )); + + return in_array($lane_department, $authorized_department_ids, true); } private function requireAuthenticatedCustomerNumber(object $user, string $elevatedPermission): int @@ -561,28 +628,26 @@ class departmentSelfserveVehicleConditionsRoute return $customer_number; } - private function assertSummaryAccess(object $user, array $summary, bool $hasGlobalPermission, string $elevatedPermission): void + private function assertSummaryAccess( + object $user, + array $summary, + bool $hasGlobalPermission, + bool $hasOwnPermission, + string $elevatedPermission + ): void { global $response; + if ($hasGlobalPermission && $this->userHasSummaryDepartmentAccess($user, $summary)) { + return; + } + + if ($hasOwnPermission && $this->summaryBelongsToCustomer($user, $summary)) { + return; + } + if ($hasGlobalPermission) { - $authorized_department_ids = $user->getGroup()->getDepartments(); - $lane_department = (int)($summary['lane']['department'] ?? 0); - if (!in_array($lane_department, $authorized_department_ids, true)) { - $this->forbidDepartmentAccess($lane_department); - } - return; - } - - $session_customer_number = $summary['session']['customer_number'] ?? null; - if ($session_customer_number !== null && (int)$session_customer_number === (int)$user->customer_number->value()) { - return; - } - - $reg = (string)($summary['session']['reg'] ?? ''); - $vehicle_o = (new customer_vehicles_o())->selectByPlate($reg); - if ($vehicle_o->exists() && (int)$vehicle_o->customer_id->value() === (int)$user->customer_number->value()) { - return; + $this->forbidDepartmentAccess($this->summaryDepartmentId($summary)); } $response->forbidden([$elevatedPermission]); diff --git a/services/nginx/app/routes/moduleSelfServeRoute.php b/services/nginx/app/routes/moduleSelfServeRoute.php index ec7a51e6..a97cbfc2 100644 --- a/services/nginx/app/routes/moduleSelfServeRoute.php +++ b/services/nginx/app/routes/moduleSelfServeRoute.php @@ -22,6 +22,7 @@ use objects\logs_o; use objects\orders_o; use objects\customer_vehicles_o; use objects\selfserve_wash_sessions_o; +use objects\selfserve_wash_session_tasks_o; use objects\stripe_module_customers_o; use objects\users_o; use traits\route_t; @@ -630,23 +631,59 @@ class moduleSelfServeRoute // Build allowed services from provided tasks $lane = $selfserve->lane($lane_id); $customer_number = $this->resolveEffectiveCustomerNumber(); - self::requirePermission('modules_selfserve_lane_services_set_allowed'); + $this->requireSelfServeLaneAccess( + $lane, + $customer_number === null ? 0 : (int)$customer_number, + ['modules_selfserve_lane_services_set_allowed'], + false + ); + $session_task_services = []; + $latest_session = (new selfserve_wash_sessions_o())->selectLatestOpenByLane( + $lane_id, + $customer_number === null || (int)$customer_number <= 0 ? null : (int)$customer_number + ); + if (!$latest_session->exists() && $customer_number !== null && (int)$customer_number > 0) { + $latest_session = (new selfserve_wash_sessions_o())->selectLatestOpenByLane($lane_id); + } + if ($latest_session->exists()) { + foreach ((new selfserve_wash_session_tasks_o())->listBySession((int)$latest_session->id) as $session_task) { + $task_id = (int)($session_task['task_id'] ?? 0); + if ($task_id > 0) { + $services = $session_task['services'] ?? []; + if (is_string($services)) { + $decoded_services = json_decode($services, true); + $services = json_last_error() === JSON_ERROR_NONE && is_array($decoded_services) + ? $decoded_services + : []; + } + $session_task_services[$task_id] = is_array($services) ? $services : []; + } + } + } + $allowed_services = []; - foreach ($task_ids as $tid) { - if ($tid <= 0) continue; - $t = new \objects\department_selfserve_tasks_o(); - $t->select($tid); - if (!$t->exists()) continue; // ignore unknown ids - // Validate the task belongs to the same lane - if ((int)$t->lane->value() !== $lane_id) continue; - // Merge services (if any) - $services = (array)$t->services->value(); + $merge_services = static function (array $services) use (&$allowed_services): void { foreach ($services as $srv) { $name = strtoupper((string)$srv); if (!in_array($name, $allowed_services, true)) { $allowed_services[] = $name; } } + }; + foreach ($task_ids as $tid) { + if ($tid <= 0) continue; + if (array_key_exists($tid, $session_task_services)) { + $merge_services($session_task_services[$tid]); + continue; + } + + $t = new \objects\department_selfserve_tasks_o(); + $t->select($tid); + if (!$t->exists()) continue; // ignore unknown ids + // Validate the task belongs to the same lane + if ((int)$t->lane->value() !== $lane_id) continue; + // Merge services (if any) + $merge_services((array)$t->services->value()); } // Persist on lane cache (overwrites previous allowed services) try { diff --git a/services/nginx/app/tests/Api/SelfserveCustomerStartApiTest.php b/services/nginx/app/tests/Api/SelfserveCustomerStartApiTest.php new file mode 100644 index 00000000..572919bf --- /dev/null +++ b/services/nginx/app/tests/Api/SelfserveCustomerStartApiTest.php @@ -0,0 +1,130 @@ + getenv('REDIS_CONFIG_HOST') ?: getenv('REDIS_CONFIG_DEBUG_HOST') ?: 'redis', + 'user' => getenv('REDIS_CONFIG_USER') ?: getenv('REDIS_CONFIG_DEBUG_USER') ?: 'default', + 'database' => getenv('REDIS_CONFIG_DATABASE') ?: getenv('REDIS_CONFIG_DEBUG_DATABASE') ?: '0', + 'password' => getenv('REDIS_CONFIG_PASSWORD') ?: getenv('REDIS_CONFIG_DEBUG_PASSWORD') ?: '', + 'port' => getenv('REDIS_CONFIG_PORT') ?: getenv('REDIS_CONFIG_DEBUG_PORT') ?: '6379', + ]; + + define('redis', (new \classes\redis())->connect()); +} + +function selfserve_customer_start_make_available(int $laneId): void +{ + selfserve_customer_start_ensure_legacy_redis_constant(); + + $lane = (new \classes\selfserve())->lane($laneId); + $lane->setLaneStatus(\modules\selfserve\helpers\selfserve_lane_status::AVAILABLE); + $lane->setLaneState(\modules\selfserve\helpers\selfserve_lane_state::IDLE); + $lane->setCustomerNumber(0); + $lane->setLicensePlate(''); + $lane->setWashStartTime(0); +} + +it('allows the customer self-serve start sequence without department access', function (): void { + $group = api_fixtures()->createGroup([], [ + 'list_own_department_selfserve_vehicle_conditions', + ]); + $scenario = api_fixtures()->createSelfServeScenario([ + 'customer' => ['group_id' => $group['id']], + 'department_selfserve_enabled' => true, + 'lane_selfserve_enabled' => true, + ]); + $headers = api_fixtures()->bearerHeaders( + api_fixtures()->createAuthToken((int)$scenario['customer']['id']) + ); + $laneId = (int)$scenario['lane']['id']; + $reg = (string)$scenario['vehicle']['reg']; + + selfserve_customer_start_make_available($laneId); + + api_client() + ->get('/department/selfserve/vehicle/allowed?lane_id=' . $laneId . '®=' . urlencode($reg), $headers) + ->assertStatus(200) + ->assertSuccess(true); + + $summaryResponse = api_client() + ->get('/department/selfserve/washes/summary?lane_id=' . $laneId . '®=' . urlencode($reg), $headers) + ->assertStatus(200) + ->assertSuccess(true); + + expect($summaryResponse->data()['session']['customer_number'] ?? null) + ->toBe((int)$scenario['customer']['customer_number']); + + api_client() + ->post('/modules/self-serve/lane/services/allowed', [ + 'lane_id' => $laneId, + 'task_ids' => [(int)$scenario['tasks'][1]['id']], + ], $headers) + ->assertStatus(200) + ->assertSuccess(true); + + $startResponse = api_client() + ->post('/modules/self-serve/lane/command', [ + 'lane_id' => $laneId, + 'command' => 'START', + 'license_plate' => $reg, + 'defer_relay_side_effects' => true, + ], $headers) + ->assertStatus(200) + ->assertSuccess(true); + + expect($startResponse->data()['status'] ?? null)->toBe('OCCUPIED') + ->and($startResponse->data()['customer_number'] ?? null) + ->toBe((int)$scenario['customer']['customer_number']); +}); + +it('derives allowed services from v2 session task snapshots when task rows are not legacy records', function (): void { + $group = api_fixtures()->createGroup([], [ + 'list_own_department_selfserve_vehicle_conditions', + ]); + $scenario = api_fixtures()->createSelfServeScenario([ + 'customer' => ['group_id' => $group['id']], + 'department_selfserve_enabled' => true, + 'lane_selfserve_enabled' => true, + ]); + $headers = api_fixtures()->bearerHeaders( + api_fixtures()->createAuthToken((int)$scenario['customer']['id']) + ); + $laneId = (int)$scenario['lane']['id']; + $v2TaskId = 900000 + $laneId; + + $sessionTask = (new \objects\selfserve_wash_session_tasks_o())->addSnapshot( + (int)$scenario['session']['id'], + $v2TaskId, + 'V2 path editor machine task', + 'Task exists only in the session snapshot.', + ['MACHINE', 'PROGRAM_PICKER'], + ['program_picker', 6, 'start'], + (int)$scenario['product']['id'], + ); + + try { + $response = api_client() + ->post('/modules/self-serve/lane/services/allowed', [ + 'lane_id' => $laneId, + 'task_ids' => [$v2TaskId], + ], $headers) + ->assertStatus(200) + ->assertSuccess(true); + + expect($response->data()['allowed_services'] ?? [])->toBe([ + 'MACHINE', + 'PROGRAM_PICKER', + ]); + } finally { + $sessionTask->delete(); + } +}); diff --git a/services/nginx/app/tests/Unit/Selfserve/ModuleConfigVariableDatabaseConfigTest.php b/services/nginx/app/tests/Unit/Selfserve/ModuleConfigVariableDatabaseConfigTest.php new file mode 100644 index 00000000..b2dce9d6 --- /dev/null +++ b/services/nginx/app/tests/Unit/Selfserve/ModuleConfigVariableDatabaseConfigTest.php @@ -0,0 +1,130 @@ +setAccessible(true); + + return $method->invoke(null); +} + +function selfserve_module_config_with_env(array $values, callable $callback): mixed +{ + $keys = [ + 'CONFIG_DB_TARGET', + 'CONFIG_DB_HOST', + 'CONFIG_DB_USER', + 'CONFIG_DB_PASSWORD', + 'CONFIG_DB_DATABASE', + 'CONFIG_DB_PORT', + 'CONFIG_DB_SSL_MODE', + 'CONFIG_DB_DEBUG_HOST', + 'CONFIG_DB_DEBUG_USER', + 'CONFIG_DB_DEBUG_PASSWORD', + 'CONFIG_DB_DEBUG_DATABASE', + 'CONFIG_DB_DEBUG_PORT', + 'CONFIG_DB_DEBUG_SSL_MODE', + ]; + $previous = []; + + foreach ($keys as $key) { + $previous[$key] = [ + 'env' => getenv($key), + 'has_env' => array_key_exists($key, $_ENV), + 'super_env' => $_ENV[$key] ?? null, + 'has_server' => array_key_exists($key, $_SERVER), + 'server' => $_SERVER[$key] ?? null, + ]; + putenv($key); + unset($_ENV[$key], $_SERVER[$key]); + } + + try { + foreach ($values as $key => $value) { + putenv($key . '=' . (string)$value); + $_ENV[$key] = (string)$value; + $_SERVER[$key] = (string)$value; + } + + return $callback(); + } finally { + foreach ($previous as $key => $state) { + $state['env'] === false + ? putenv($key) + : putenv($key . '=' . $state['env']); + + if ($state['has_env']) { + $_ENV[$key] = $state['super_env']; + } else { + unset($_ENV[$key]); + } + + if ($state['has_server']) { + $_SERVER[$key] = $state['server']; + } else { + unset($_SERVER[$key]); + } + } + } +} + +it('reads debug database configuration when the debug target is selected', function (): void { + $config = selfserve_module_config_with_env([ + 'CONFIG_DB_TARGET' => 'debug', + 'CONFIG_DB_HOST' => '', + 'CONFIG_DB_USER' => '', + 'CONFIG_DB_PASSWORD' => '', + 'CONFIG_DB_DATABASE' => '', + 'CONFIG_DB_PORT' => '', + 'CONFIG_DB_SSL_MODE' => '', + 'CONFIG_DB_DEBUG_HOST' => 'mysql-debug', + 'CONFIG_DB_DEBUG_USER' => 'root', + 'CONFIG_DB_DEBUG_PASSWORD' => 'debug_root_password', + 'CONFIG_DB_DEBUG_DATABASE' => 'nnks_db_debug', + 'CONFIG_DB_DEBUG_PORT' => '3306', + 'CONFIG_DB_DEBUG_SSL_MODE' => 'DISABLED', + ], static fn(): array => selfserve_module_config_database_config()); + + expect($config)->toMatchArray([ + 'host' => 'mysql-debug', + 'user' => 'root', + 'password' => 'debug_root_password', + 'database' => 'nnks_db_debug', + 'port' => 3306, + 'ssl_mode' => 'DISABLED', + ]); +}); + +it('keeps live database configuration as the default target', function (): void { + $config = selfserve_module_config_with_env([ + 'CONFIG_DB_HOST' => 'live-db', + 'CONFIG_DB_USER' => 'live-user', + 'CONFIG_DB_PASSWORD' => 'live-password', + 'CONFIG_DB_DATABASE' => 'live-database', + 'CONFIG_DB_PORT' => '3307', + 'CONFIG_DB_SSL_MODE' => 'REQUIRED', + 'CONFIG_DB_DEBUG_HOST' => 'mysql-debug', + 'CONFIG_DB_DEBUG_USER' => 'root', + 'CONFIG_DB_DEBUG_PASSWORD' => 'debug_root_password', + 'CONFIG_DB_DEBUG_DATABASE' => 'nnks_db_debug', + 'CONFIG_DB_DEBUG_PORT' => '3306', + 'CONFIG_DB_DEBUG_SSL_MODE' => 'DISABLED', + ], static fn(): array => selfserve_module_config_database_config()); + + expect($config)->toMatchArray([ + 'host' => 'live-db', + 'user' => 'live-user', + 'password' => 'live-password', + 'database' => 'live-database', + 'port' => 3307, + 'ssl_mode' => 'REQUIRED', + ]); +}); diff --git a/services/nginx/app/tests/Unit/Selfserve/SelfserveEligibilityLaneAccessTest.php b/services/nginx/app/tests/Unit/Selfserve/SelfserveEligibilityLaneAccessTest.php index b9943bc8..ad075f84 100644 --- a/services/nginx/app/tests/Unit/Selfserve/SelfserveEligibilityLaneAccessTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/SelfserveEligibilityLaneAccessTest.php @@ -43,16 +43,17 @@ function selfserve_eligibility_method_block(string $route, string $signature): s it('authorizes customer eligibility preview lanes before returning task attachments', function (): void { $route = selfserve_eligibility_route_source(); $allowedBlock = selfserve_eligibility_route_block($route, 'get', '/department/selfserve/vehicle/allowed'); - $assertBlock = selfserve_eligibility_method_block($route, 'private function assertLaneAccess(object $user, int $laneId): department_lanes_o'); + $assertBlock = selfserve_eligibility_method_block($route, 'private function assertLaneAccess('); - expect($allowedBlock)->toContain('$lane = $this->assertLaneAccess($user, $lane_id);') + expect($allowedBlock)->toContain('$lane = $this->assertLaneAccess($user, $lane_id, $has_global, $has_own);') ->and($allowedBlock)->toContain('previewVehicleEligibility($lane_id, $reg, $customer_number, $vehicle_type_id)') - ->and(strpos($allowedBlock, '$lane = $this->assertLaneAccess($user, $lane_id);')) + ->and(strpos($allowedBlock, '$lane = $this->assertLaneAccess($user, $lane_id, $has_global, $has_own);')) ->toBeLessThan(strpos($allowedBlock, 'previewVehicleEligibility($lane_id, $reg, $customer_number, $vehicle_type_id)')); - expect($assertBlock)->toContain('$authorized_department_ids = array_values(array_filter(') - ->and($assertBlock)->toContain('array_map(\'intval\', (array)$user->getGroup()->getDepartments())') - ->and($assertBlock)->toContain('if (!in_array($lane_department_id, $authorized_department_ids, true))') + expect($assertBlock)->toContain('bool $hasGlobalPermission = true') + ->and($assertBlock)->toContain('bool $hasOwnPermission = false') + ->and($assertBlock)->toContain('if ($hasGlobalPermission && $this->userHasLaneDepartmentAccess($user, $lane))') + ->and($assertBlock)->toContain('if ($hasOwnPermission && $this->isCustomerSelfServeLaneEnabled($lane))') ->and($assertBlock)->toContain('$this->forbidDepartmentAccess($lane_department_id);') - ->and($assertBlock)->not->toContain('if ($hasGlobalPermission)'); + ->and($assertBlock)->toContain('$response->forbidden([$elevatedPermission]);'); }); diff --git a/services/nginx/app/tests/Unit/Selfserve/SelfserveLaneStartEntranceTimeoutTest.php b/services/nginx/app/tests/Unit/Selfserve/SelfserveLaneStartEntranceTimeoutTest.php index 178a5795..10ef5cab 100644 --- a/services/nginx/app/tests/Unit/Selfserve/SelfserveLaneStartEntranceTimeoutTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/SelfserveLaneStartEntranceTimeoutTest.php @@ -21,7 +21,10 @@ class SelfserveLaneStartEntranceTimeoutHarness public ?\Throwable $reportedTimeout = null; public ?selfserve_lane_state $laneState = null; public int $cleanerRelayCalls = 0; + public int $programPickerRelayCalls = 0; public int $machineRelayCalls = 0; + /** @var array */ + public array $relayEvents = []; public function open(selfserve_lane_port $port, ?int $toggle_after_seconds = null): bool { @@ -47,11 +50,19 @@ class SelfserveLaneStartEntranceTimeoutHarness protected function turnOnCleanerRelayForWashStart(): void { $this->cleanerRelayCalls++; + $this->relayEvents[] = 'cleaner:on'; + } + + protected function setProgramPickerRelayStatusForWashStart(): void + { + $this->programPickerRelayCalls++; + $this->relayEvents[] = 'program_picker:sync'; } protected function setMachineRelayStatusForWashStart(): void { $this->machineRelayCalls++; + $this->relayEvents[] = 'machine:sync'; } public function runEntranceOpenForStart(): void @@ -98,20 +109,28 @@ it('parses deferred relay side effects on start command arguments', function (): expect($arguments->defer_relay_side_effects)->toBeTrue(); }); -it('skips cleaner and machine relay side effects when start asks to defer them', function (): void { +it('skips cleaner, program picker and machine relay side effects when start asks to defer them', function (): void { $lane = new SelfserveLaneStartEntranceTimeoutHarness(); $lane->runStartRelaySideEffects(true); expect($lane->cleanerRelayCalls)->toBe(0); + expect($lane->programPickerRelayCalls)->toBe(0); expect($lane->machineRelayCalls)->toBe(0); + expect($lane->relayEvents)->toBe([]); }); -it('keeps cleaner and machine relay side effects for normal start commands', function (): void { +it('keeps cleaner, program picker and machine relay side effects in order for normal start commands', function (): void { $lane = new SelfserveLaneStartEntranceTimeoutHarness(); $lane->runStartRelaySideEffects(false); expect($lane->cleanerRelayCalls)->toBe(1); + expect($lane->programPickerRelayCalls)->toBe(1); expect($lane->machineRelayCalls)->toBe(1); + expect($lane->relayEvents)->toBe([ + 'cleaner:on', + 'program_picker:sync', + 'machine:sync', + ]); }); diff --git a/services/nginx/app/tests/Unit/Selfserve/SelfserveLaneStopFlowTest.php b/services/nginx/app/tests/Unit/Selfserve/SelfserveLaneStopFlowTest.php index f0993c7b..4cebff87 100644 --- a/services/nginx/app/tests/Unit/Selfserve/SelfserveLaneStopFlowTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/SelfserveLaneStopFlowTest.php @@ -63,6 +63,8 @@ class SelfserveLaneStopFlowHarness public array $openedPorts = []; /** @var selfserve_lane_relay[] */ public array $turnedOffRelays = []; + /** @var array */ + public array $events = []; private selfserve_lane_status $laneStatus; private selfserve_lane_mode $laneMode; @@ -182,6 +184,7 @@ class SelfserveLaneStopFlowHarness public function open(selfserve_lane_port $port): bool { $this->openedPorts[] = $port; + $this->events[] = 'open:' . $port->name; if ($this->openThrowable !== null) { throw $this->openThrowable; } @@ -192,6 +195,7 @@ class SelfserveLaneStopFlowHarness public function turnOffRelay(selfserve_lane_relay $relay): bool { $this->turnedOffRelays[] = $relay; + $this->events[] = 'relay:' . $relay->name . ':off'; return true; } @@ -199,6 +203,7 @@ class SelfserveLaneStopFlowHarness { if ($on === false) { $this->turnedOffRelays[] = $relay; + $this->events[] = 'relay:' . $relay->name . ':off'; } return true; } @@ -229,7 +234,7 @@ class SelfserveLaneStopFlowHarness } } -it('adds vehicle type product on STOP when the physical machine ON signal was recorded, then turns off cleaner and machine relays', function (): void { +it('adds vehicle type product on STOP when the physical machine ON signal was recorded, after turning relays off before exit', function (): void { $lane = new SelfserveLaneStopFlowHarness(machineStartTriggered: true); $args = (new selfserve_lane_command_arguments())->setCustomerNumber(1234); @@ -243,8 +248,15 @@ it('adds vehicle type product on STOP when the physical machine ON signal was re expect($lane->openedPorts)->toBe([selfserve_lane_port::EXIT]); expect($lane->turnedOffRelays)->toBe([ selfserve_lane_relay::MACHINE_CLEANER, + selfserve_lane_relay::MACHINE_PROGRAM_PICKER, selfserve_lane_relay::MACHINE, ]); + expect($lane->events)->toBe([ + 'relay:MACHINE_CLEANER:off', + 'relay:MACHINE_PROGRAM_PICKER:off', + 'relay:MACHINE:off', + 'open:EXIT', + ]); expect($lane->getLaneStatus())->toBe(selfserve_lane_status::AVAILABLE); }); @@ -266,8 +278,14 @@ it('skips vehicle type product add when no physical machine ON signal was record expect($lane->lastVehicleTypeProductDecision)->toBeFalse(); expect($lane->programSelectorStatusReads)->toBe(0); expect($lane->turnedOffRelays)->toBe([ + selfserve_lane_relay::MACHINE_PROGRAM_PICKER, selfserve_lane_relay::MACHINE, ]); + expect($lane->events)->toBe([ + 'relay:MACHINE_PROGRAM_PICKER:off', + 'relay:MACHINE:off', + 'open:EXIT', + ]); }); it('does not use selector relay online status as machine-wash billing evidence', function (): void { @@ -301,8 +319,15 @@ it('continues STOP when exit relay dispatch times out ambiguously', function (): expect($lane->vehicleTypeProductAddCalls)->toBe(1); expect($lane->turnedOffRelays)->toBe([ selfserve_lane_relay::MACHINE_CLEANER, + selfserve_lane_relay::MACHINE_PROGRAM_PICKER, selfserve_lane_relay::MACHINE, ]); + expect($lane->events)->toBe([ + 'relay:MACHINE_CLEANER:off', + 'relay:MACHINE_PROGRAM_PICKER:off', + 'relay:MACHINE:off', + 'open:EXIT', + ]); expect($lane->getLaneStatus())->toBe(selfserve_lane_status::AVAILABLE); }); diff --git a/services/nginx/app/tests/Unit/Selfserve/SelfservePublishedConfigLaneWildcardTest.php b/services/nginx/app/tests/Unit/Selfserve/SelfservePublishedConfigLaneWildcardTest.php new file mode 100644 index 00000000..948ecc9a --- /dev/null +++ b/services/nginx/app/tests/Unit/Selfserve/SelfservePublishedConfigLaneWildcardTest.php @@ -0,0 +1,50 @@ +loadQuestions($departmentId, $laneId, $vehicleTypeId, $config); + } + + public function conditionsFor(int $departmentId, int $laneId, int $vehicleTypeId, array $config): array + { + return $this->loadConditions($departmentId, $laneId, $vehicleTypeId, null, $config); + } + + public function tasksFor(int $departmentId, int $laneId, int $vehicleTypeId, array $config): array + { + return $this->loadTasks($departmentId, $laneId, $vehicleTypeId, null, $config); + } +} + +it('applies department product rows with lane zero to all lanes in published v2 configs', function (): void { + $flow = new SelfservePublishedConfigLaneWildcardHarness(); + $config = [ + 'schema_version' => 2, + 'questions' => [ + ['id' => 1, 'department' => 6, 'lane' => 0, 'product' => 1, 'question' => 'Wildcard question'], + ['id' => 2, 'department' => 6, 'lane' => 99, 'product' => 1, 'question' => 'Other lane question'], + ], + 'conditions' => [ + ['id' => 11, 'department' => 6, 'lane' => 0, 'product' => 1, 'machine_type_id' => null, 'expression' => ['type' => 'predicate', 'subject_type' => 'question', 'subject_id' => 1, 'operator' => 'IS_TRUE']], + ['id' => 12, 'department' => 6, 'lane' => 99, 'product' => 1, 'machine_type_id' => null, 'expression' => ['type' => 'predicate', 'subject_type' => 'question', 'subject_id' => 2, 'operator' => 'IS_TRUE']], + ], + 'tasks' => [ + ['id' => 21, 'department' => 6, 'lane' => 0, 'product' => 1, 'machine_type_id' => null, 'task' => 'Wildcard task', 'services' => ['MACHINE'], 'buttons' => [], 'gate_type' => 'ALWAYS', 'gate_ref_id' => null], + ['id' => 22, 'department' => 6, 'lane' => 99, 'product' => 1, 'machine_type_id' => null, 'task' => 'Other lane task', 'services' => ['MACHINE'], 'buttons' => [], 'gate_type' => 'ALWAYS', 'gate_ref_id' => null], + ], + ]; + + expect(array_column($flow->questionsFor(6, 12, 1, $config), 'id'))->toBe([1]); + expect(array_column($flow->conditionsFor(6, 12, 1, $config), 'id'))->toBe([11]); + expect(array_column($flow->tasksFor(6, 12, 1, $config), 'id'))->toBe([21]); +}); diff --git a/services/nginx/app/tests/Unit/Selfserve/SelfserveRouteWiringTest.php b/services/nginx/app/tests/Unit/Selfserve/SelfserveRouteWiringTest.php index a895f77f..a5fe6791 100644 --- a/services/nginx/app/tests/Unit/Selfserve/SelfserveRouteWiringTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/SelfserveRouteWiringTest.php @@ -240,6 +240,9 @@ it('wires allowed services route through machine relay visibility sync', functio expect($moduleSelfServeRoute)->not->toBeFalse(); expect($moduleSelfServeRoute)->toContain('/modules/self-serve/lane/services/allowed'); + expect($moduleSelfServeRoute)->toContain('selfserve_wash_session_tasks_o'); + expect($moduleSelfServeRoute)->toContain('selectLatestOpenByLane'); + expect($moduleSelfServeRoute)->toContain('$session_task_services[$task_id]'); expect($moduleSelfServeRoute)->toContain('setAllowedServicesFromVisibleTasks($allowed_services)'); expect($moduleSelfServeRoute)->not->toContain('syncMachineRelayFromVisibleServices($allowed_services, true)'); expect($moduleSelfServeRoute)->toContain("'relay_sync' => \$relay_sync"); diff --git a/services/nginx/app/traits/module_config_variable_t.php b/services/nginx/app/traits/module_config_variable_t.php index 72ef8fca..bfed8146 100644 --- a/services/nginx/app/traits/module_config_variable_t.php +++ b/services/nginx/app/traits/module_config_variable_t.php @@ -276,7 +276,7 @@ trait module_config_variable private static function readDatabaseConfigFromEnvironment(): array { $readEnv = static function (string $key, string $default = ''): string { - $value = $_ENV[$key] ?? getenv($key); + $value = $_ENV[$key] ?? $_SERVER[$key] ?? getenv($key); if ($value === false || $value === null) { return $default; } @@ -284,9 +284,25 @@ trait module_config_variable return trim((string)$value); }; - $host = $readEnv('CONFIG_DB_HOST'); - $user = $readEnv('CONFIG_DB_USER'); - $database = $readEnv('CONFIG_DB_DATABASE'); + $dbTarget = strtolower(trim($readEnv('CONFIG_DB_TARGET', 'live'))); + if ($dbTarget !== 'live' && $dbTarget !== 'debug') { + $dbTarget = 'live'; + } + + $resolveDbValue = static function (string $key) use ($dbTarget, $readEnv): string { + $liveValue = $readEnv('CONFIG_DB_' . $key); + $debugValue = $readEnv('CONFIG_DB_DEBUG_' . $key); + + if ($dbTarget === 'debug' && $debugValue !== '') { + return $debugValue; + } + + return $liveValue; + }; + + $host = $resolveDbValue('HOST'); + $user = $resolveDbValue('USER'); + $database = $resolveDbValue('DATABASE'); if ($host === '' || $user === '' || $database === '') { return []; @@ -295,10 +311,10 @@ trait module_config_variable return [ 'host' => $host, 'user' => $user, - 'password' => $readEnv('CONFIG_DB_PASSWORD'), + 'password' => $resolveDbValue('PASSWORD'), 'database' => $database, - 'port' => (int)($readEnv('CONFIG_DB_PORT', '3306') ?: '3306'), - 'ssl_mode' => $readEnv('CONFIG_DB_SSL_MODE', 'DISABLED') ?: 'DISABLED', + 'port' => (int)($resolveDbValue('PORT') ?: '3306'), + 'ssl_mode' => $resolveDbValue('SSL_MODE') ?: 'DISABLED', ]; } diff --git a/services/traefik/dynamic.yml b/services/traefik/dynamic.yml index ec86c6a9..47aa95c1 100644 --- a/services/traefik/dynamic.yml +++ b/services/traefik/dynamic.yml @@ -49,6 +49,18 @@ http: certResolver: le # Dashboard routers are declared via labels; middlewares are defined below. + local: + rule: Host(`localhost`) + entryPoints: [web] + middlewares: [secure-headers] + service: caddy-local + + local-api: + rule: Host(`localhost`) && PathPrefix(`/api`) + entryPoints: [web] + middlewares: [strip-api-prefix, secure-headers] + service: caddy-local + priority: 100 middlewares: redirect-to-https: @@ -125,6 +137,10 @@ http: loadBalancer: servers: - url: "http://94.130.142.41:11000" + caddy-local: + loadBalancer: + servers: + - url: "http://caddy" tls: options: