#!/usr/bin/env php ')) { fwrite( STDERR, sprintf( 'PHPUnit 13.0.5 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.0.5.phar'); Phar::mapPhar('phpunit-13.0.5.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\\InvalidArgumentException' => '/php-code-coverage/Exception/InvalidArgumentException.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\\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\\OpenClover' => '/php-code-coverage/Report/OpenClover.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\PHP' => '/php-code-coverage/Report/PHP.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\\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/Target/Class_.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ClassesThatExtendClass' => '/php-code-coverage/Target/ClassesThatExtendClass.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ClassesThatImplementInterface' => '/php-code-coverage/Target/ClassesThatImplementInterface.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Function_' => '/php-code-coverage/Target/Function_.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\InvalidCodeCoverageTargetException' => '/php-code-coverage/Exception/InvalidCodeCoverageTargetException.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\MapBuilder' => '/php-code-coverage/Target/MapBuilder.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Mapper' => '/php-code-coverage/Target/Mapper.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Method' => '/php-code-coverage/Target/Method.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Namespace_' => '/php-code-coverage/Target/Namespace_.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Target' => '/php-code-coverage/Target/Target.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollection' => '/php-code-coverage/Target/TargetCollection.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollectionIterator' => '/php-code-coverage/Target/TargetCollectionIterator.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollectionValidator' => '/php-code-coverage/Target/TargetCollectionValidator.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Trait_' => '/php-code-coverage/Target/Trait_.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationFailure' => '/php-code-coverage/Target/ValidationFailure.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationResult' => '/php-code-coverage/Target/ValidationResult.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationSuccess' => '/php-code-coverage/Target/ValidationSuccess.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\Known' => '/php-code-coverage/TestSize/Known.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\Large' => '/php-code-coverage/TestSize/Large.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\Medium' => '/php-code-coverage/TestSize/Medium.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\Small' => '/php-code-coverage/TestSize/Small.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\TestSize' => '/php-code-coverage/TestSize/TestSize.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\Unknown' => '/php-code-coverage/TestSize/Unknown.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus\\Failure' => '/php-code-coverage/TestStatus/Failure.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus\\Known' => '/php-code-coverage/TestStatus/Known.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus\\Success' => '/php-code-coverage/TestStatus/Success.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus\\TestStatus' => '/php-code-coverage/TestStatus/TestStatus.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus\\Unknown' => '/php-code-coverage/TestStatus/Unknown.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\\Filesystem' => '/php-code-coverage/Util/Filesystem.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\\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\\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\\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\\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\\IsolatedTestRunner' => '/phpunit/Framework/TestRunner/IsolatedTestRunner.php', 'PHPUnit\\Framework\\IsolatedTestRunnerRegistry' => '/phpunit/Framework/TestRunner/IsolatedTestRunnerRegistry.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\\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\\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\\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\\InfrastructureInformationProvider' => '/phpunit/Logging/OpenTestReporting/InfrastructureInformationProvider.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\\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\\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\\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\\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\\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\\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\\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\\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\\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\\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\\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\\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\\DefaultJobRunner' => '/phpunit/Util/PHP/DefaultJobRunner.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\\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.0.5.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\\InvalidArgumentException' => '/php-code-coverage/Exception/InvalidArgumentException.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\\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\\OpenClover' => '/php-code-coverage/Report/OpenClover.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Report\\PHP' => '/php-code-coverage/Report/PHP.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\\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/Target/Class_.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ClassesThatExtendClass' => '/php-code-coverage/Target/ClassesThatExtendClass.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ClassesThatImplementInterface' => '/php-code-coverage/Target/ClassesThatImplementInterface.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Function_' => '/php-code-coverage/Target/Function_.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\InvalidCodeCoverageTargetException' => '/php-code-coverage/Exception/InvalidCodeCoverageTargetException.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\MapBuilder' => '/php-code-coverage/Target/MapBuilder.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Mapper' => '/php-code-coverage/Target/Mapper.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Method' => '/php-code-coverage/Target/Method.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Namespace_' => '/php-code-coverage/Target/Namespace_.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Target' => '/php-code-coverage/Target/Target.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollection' => '/php-code-coverage/Target/TargetCollection.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollectionIterator' => '/php-code-coverage/Target/TargetCollectionIterator.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollectionValidator' => '/php-code-coverage/Target/TargetCollectionValidator.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\Trait_' => '/php-code-coverage/Target/Trait_.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationFailure' => '/php-code-coverage/Target/ValidationFailure.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationResult' => '/php-code-coverage/Target/ValidationResult.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\Target\\ValidationSuccess' => '/php-code-coverage/Target/ValidationSuccess.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\Known' => '/php-code-coverage/TestSize/Known.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\Large' => '/php-code-coverage/TestSize/Large.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\Medium' => '/php-code-coverage/TestSize/Medium.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\Small' => '/php-code-coverage/TestSize/Small.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\TestSize' => '/php-code-coverage/TestSize/TestSize.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestSize\\Unknown' => '/php-code-coverage/TestSize/Unknown.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus\\Failure' => '/php-code-coverage/TestStatus/Failure.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus\\Known' => '/php-code-coverage/TestStatus/Known.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus\\Success' => '/php-code-coverage/TestStatus/Success.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus\\TestStatus' => '/php-code-coverage/TestStatus/TestStatus.php', 'PHPUnitPHAR\\SebastianBergmann\\CodeCoverage\\Test\\TestStatus\\Unknown' => '/php-code-coverage/TestStatus/Unknown.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\\Filesystem' => '/php-code-coverage/Util/Filesystem.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\\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\\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\\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\\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\\IsolatedTestRunner' => '/phpunit/Framework/TestRunner/IsolatedTestRunner.php', 'PHPUnit\\Framework\\IsolatedTestRunnerRegistry' => '/phpunit/Framework/TestRunner/IsolatedTestRunnerRegistry.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\\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\\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\\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\\InfrastructureInformationProvider' => '/phpunit/Logging/OpenTestReporting/InfrastructureInformationProvider.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\\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\\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\\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\\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\\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\\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\\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\\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\\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\\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\\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\\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\\DefaultJobRunner' => '/phpunit/Util/PHP/DefaultJobRunner.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\\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.0.5.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.0.5.phar composer.lockKö#³•iKöÙû¯À¤ manifest.txtÄ#³•iÄL=àx¤'myclabs-deep-copy/DeepCopy/DeepCopy.php@!#³•i@!në=¤7myclabs-deep-copy/DeepCopy/Exception/CloneException.phpŠ#³•iŠJDéȤ:myclabs-deep-copy/DeepCopy/Exception/PropertyException.phpƒ#³•iƒo‘¼#¤5myclabs-deep-copy/DeepCopy/Filter/ChainableFilter.phpË#³•iË–=(e¤Gmyclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.phpL#³•iL6b]U¤Lmyclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php%#³•i%Œd²-¤Bmyclabs-deep-copy/DeepCopy/Filter/Doctrine/DoctrineProxyFilter.phpª#³•iªfQc_¤,myclabs-deep-copy/DeepCopy/Filter/Filter.phph#³•ih¸ß½¤0myclabs-deep-copy/DeepCopy/Filter/KeepFilter.php#³•iÿ7#¤3myclabs-deep-copy/DeepCopy/Filter/ReplaceFilter.phpÙ#³•iÙ²{C¤3myclabs-deep-copy/DeepCopy/Filter/SetNullFilter.php.#³•i.~ð^¤Dmyclabs-deep-copy/DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php‹#³•i‹ ‹3ä¤.myclabs-deep-copy/DeepCopy/Matcher/Matcher.phpá#³•iáÈfËä6myclabs-deep-copy/DeepCopy/Matcher/PropertyMatcher.phpº#³•iºÝÀA^¤:myclabs-deep-copy/DeepCopy/Matcher/PropertyNameMatcher.php#³•iÑì¡P¤:myclabs-deep-copy/DeepCopy/Matcher/PropertyTypeMatcher.phpn#³•inm$Ãu¤:myclabs-deep-copy/DeepCopy/Reflection/ReflectionHelper.php9#³•i91•¦†¤Amyclabs-deep-copy/DeepCopy/TypeFilter/Date/DateIntervalFilter.php“#³•i“[‚ã¤?myclabs-deep-copy/DeepCopy/TypeFilter/Date/DatePeriodFilter.php`#³•i`m9£œ¤7myclabs-deep-copy/DeepCopy/TypeFilter/ReplaceFilter.php#³•i»8;¤;myclabs-deep-copy/DeepCopy/TypeFilter/ShallowCopyFilter.phpë#³•iëF_e ¤?myclabs-deep-copy/DeepCopy/TypeFilter/Spl/ArrayObjectFilter.phpð#³•ið£Ø©¤Amyclabs-deep-copy/DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php¼#³•i¼K픤Gmyclabs-deep-copy/DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php*#³•i*L-Ø ¤4myclabs-deep-copy/DeepCopy/TypeFilter/TypeFilter.phpÎ#³•iÎÔŠ‡¤6myclabs-deep-copy/DeepCopy/TypeMatcher/TypeMatcher.phpÞ#³•iÞû×$¤(myclabs-deep-copy/DeepCopy/deep_copy.php¥#³•i¥¢WÈ•¤myclabs-deep-copy/LICENSE5#³•i5Ê­Ë„¤nikic-php-parser/LICENSEð#³•ið¥ä”*¤&nikic-php-parser/PhpParser/Builder.php×#³•i×’[ṳ1nikic-php-parser/PhpParser/Builder/ClassConst.php;#³•i;(kïü¤-nikic-php-parser/PhpParser/Builder/Class_.phpk#³•ikÓÞQ¤2nikic-php-parser/PhpParser/Builder/Declaration.phpþ#³•iþ`X:¤/nikic-php-parser/PhpParser/Builder/EnumCase.phpÖ#³•iÖȸÚ¤,nikic-php-parser/PhpParser/Builder/Enum_.phpà #³•ià ÅUfƒ¤3nikic-php-parser/PhpParser/Builder/FunctionLike.php9#³•i9B¹ã¤0nikic-php-parser/PhpParser/Builder/Function_.php‹#³•i‹¥33A¤1nikic-php-parser/PhpParser/Builder/Interface_.phph #³•ih £‹·|¤-nikic-php-parser/PhpParser/Builder/Method.php§#³•i§Ú·t„¤1nikic-php-parser/PhpParser/Builder/Namespace_.phpu#³•iu Öî¤,nikic-php-parser/PhpParser/Builder/Param.php¬#³•i¬_먊¤/nikic-php-parser/PhpParser/Builder/Property.phpx#³•ixVÆnâ¤/nikic-php-parser/PhpParser/Builder/TraitUse.php¼#³•i¼!rѤ9nikic-php-parser/PhpParser/Builder/TraitUseAdaptation.phpú#³•iúŒ0¤-nikic-php-parser/PhpParser/Builder/Trait_.php4 #³•i4 ëѬZ¤+nikic-php-parser/PhpParser/Builder/Use_.php,#³•i,K,g¤-nikic-php-parser/PhpParser/BuilderFactory.php)#³•i) –Ò½¤-nikic-php-parser/PhpParser/BuilderHelpers.phpl%#³•il%‚^Š[¤&nikic-php-parser/PhpParser/Comment.php#³•iVUG¤*nikic-php-parser/PhpParser/Comment/Doc.php€#³•i€Í袤;nikic-php-parser/PhpParser/ConstExprEvaluationException.php}#³•i}ÍÞO¤1nikic-php-parser/PhpParser/ConstExprEvaluator.php&#³•i&V7=å¤$nikic-php-parser/PhpParser/Error.php]#³•i]×:¸¤+nikic-php-parser/PhpParser/ErrorHandler.php9#³•i9–yo¤6nikic-php-parser/PhpParser/ErrorHandler/Collecting.php•#³•i•HÏr(¤4nikic-php-parser/PhpParser/ErrorHandler/Throwing.php˜#³•i˜Îr¾£¤0nikic-php-parser/PhpParser/Internal/DiffElem.php #³•i à_P¤.nikic-php-parser/PhpParser/Internal/Differ.phpÇ#³•iÇd;v,¤Anikic-php-parser/PhpParser/Internal/PrintableNewAnonClassNode.phpe #³•ie ²G×o¤5nikic-php-parser/PhpParser/Internal/TokenPolyfill.php·$#³•i·$wdz®¤3nikic-php-parser/PhpParser/Internal/TokenStream.php£##³•i£#GzÙ¤*nikic-php-parser/PhpParser/JsonDecoder.php® #³•i®  øn¤$nikic-php-parser/PhpParser/Lexer.php(#³•i(&Àì¤.nikic-php-parser/PhpParser/Lexer/Emulative.phpû #³•iû YÃøI¤Tnikic-php-parser/PhpParser/Lexer/TokenEmulator/AsymmetricVisibilityTokenEmulator.php² #³•i² ÑÆÍ¤Dnikic-php-parser/PhpParser/Lexer/TokenEmulator/AttributeEmulator.phpÏ#³•iÏæ g$¤Dnikic-php-parser/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php¾#³•i¾¿¾¤Hnikic-php-parser/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php#³•iHU¨j¤Bnikic-php-parser/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php2#³•i2$ÐG­¤Enikic-php-parser/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.phpÈ#³•iÈÂ9æG¤Hnikic-php-parser/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php-#³•i-[SŤGnikic-php-parser/PhpParser/Lexer/TokenEmulator/PipeOperatorEmulator.php€#³•i€÷uMߤHnikic-php-parser/PhpParser/Lexer/TokenEmulator/PropertyTokenEmulator.php×#³•i×ü4"Ù¤Pnikic-php-parser/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.phpõ#³•iõÜP“ΤHnikic-php-parser/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.phpd#³•id/Cê¤Bnikic-php-parser/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php#³•iï—‚Ù¤@nikic-php-parser/PhpParser/Lexer/TokenEmulator/TokenEmulator.phpW#³•iW3˜ù¤Cnikic-php-parser/PhpParser/Lexer/TokenEmulator/VoidCastEmulator.php* #³•i* q ô„¤(nikic-php-parser/PhpParser/Modifiers.phpF #³•iF `ؤ*nikic-php-parser/PhpParser/NameContext.php &#³•i & 8ÄÕ¤#nikic-php-parser/PhpParser/Node.php#³•i¶h¦m¤'nikic-php-parser/PhpParser/Node/Arg.php #³•i #Eªˆ¤-nikic-php-parser/PhpParser/Node/ArrayItem.phpÞ#³•iÞ¸ªÙݤ-nikic-php-parser/PhpParser/Node/Attribute.php`#³•i`–v¤2nikic-php-parser/PhpParser/Node/AttributeGroup.php¨#³•i¨Gãiʤ.nikic-php-parser/PhpParser/Node/ClosureUse.phpî#³•iî\±jt¤/nikic-php-parser/PhpParser/Node/ComplexType.php[#³•i[š0Us¤*nikic-php-parser/PhpParser/Node/Const_.phpë#³•iëT¼=y¤/nikic-php-parser/PhpParser/Node/DeclareItem.php #³•i ¸o#¤(nikic-php-parser/PhpParser/Node/Expr.php#³•i|Å)¬¤6nikic-php-parser/PhpParser/Node/Expr/ArrayDimFetch.phpW#³•iWSé!¤/nikic-php-parser/PhpParser/Node/Expr/Array_.phpr#³•ir§sG¤6nikic-php-parser/PhpParser/Node/Expr/ArrowFunction.php> #³•i> «ÚM¤/nikic-php-parser/PhpParser/Node/Expr/Assign.php'#³•i'0)œ ¤1nikic-php-parser/PhpParser/Node/Expr/AssignOp.phpô#³•iô¢Œb/¤<nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php#³•iÆ?Q¤;nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseOr.php#³•i)Þñ¤<nikic-php-parser/PhpParser/Node/Expr/AssignOp/BitwiseXor.php#³•i&ÉTþ¤:nikic-php-parser/PhpParser/Node/Expr/AssignOp/Coalesce.php#³•i9˜·¤¤8nikic-php-parser/PhpParser/Node/Expr/AssignOp/Concat.phpÿ#³•iÿGÅ3¤5nikic-php-parser/PhpParser/Node/Expr/AssignOp/Div.phpù#³•iùÍÔ/¤7nikic-php-parser/PhpParser/Node/Expr/AssignOp/Minus.phpý#³•iý¦„¶c¤5nikic-php-parser/PhpParser/Node/Expr/AssignOp/Mod.phpù#³•iùÃjŒ¤5nikic-php-parser/PhpParser/Node/Expr/AssignOp/Mul.phpù#³•iùY:Å;¤6nikic-php-parser/PhpParser/Node/Expr/AssignOp/Plus.phpû#³•iûKÍã]¤5nikic-php-parser/PhpParser/Node/Expr/AssignOp/Pow.phpù#³•iùߊÍA¤;nikic-php-parser/PhpParser/Node/Expr/AssignOp/ShiftLeft.php#³•i–(?¤<nikic-php-parser/PhpParser/Node/Expr/AssignOp/ShiftRight.php#³•i®·íâ¤2nikic-php-parser/PhpParser/Node/Expr/AssignRef.phpX#³•iX[—·¤1nikic-php-parser/PhpParser/Node/Expr/BinaryOp.phpd#³•idñ`˜­¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.phpV#³•iVNVD¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseOr.phpT#³•iTÝŸ¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BitwiseXor.phpV#³•iVà3$¶¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BooleanAnd.phpW#³•iWú€Ýÿ¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/BooleanOr.phpU#³•iU‰¡G¤:nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Coalesce.phpS#³•iS¯/à¤8nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Concat.phpN#³•iN¶€¤5nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Div.phpH#³•iH¨A+¤7nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Equal.phpM#³•iMá$3¤9nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Greater.phpP#³•iPX‡Š¤@nikic-php-parser/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php_#³•i_³Âå ¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Identical.phpV#³•iV´Ðã¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalAnd.phpX#³•iXFü—=¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalOr.phpU#³•iU-”š3¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/LogicalXor.phpX#³•iXÞÁŠé¤7nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Minus.phpL#³•iL"7®æ¤5nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Mod.phpH#³•iHÓ ñ¤5nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Mul.phpH#³•iH œt¤:nikic-php-parser/PhpParser/Node/Expr/BinaryOp/NotEqual.phpS#³•iS¨½£Í¤>nikic-php-parser/PhpParser/Node/Expr/BinaryOp/NotIdentical.php\#³•i\õc_¤6nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Pipe.phpK#³•iKuõ$¤6nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Plus.phpJ#³•iJcm¤5nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Pow.phpI#³•iI­Þ,ô¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/ShiftLeft.phpU#³•iUC”Xe¤<nikic-php-parser/PhpParser/Node/Expr/BinaryOp/ShiftRight.phpW#³•iWü;‘¤9nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Smaller.phpP#³•iPT—å¤@nikic-php-parser/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php_#³•i_èJ³¤;nikic-php-parser/PhpParser/Node/Expr/BinaryOp/Spaceship.phpV#³•iVã”Ex¤3nikic-php-parser/PhpParser/Node/Expr/BitwiseNot.php­#³•i­}lMˤ3nikic-php-parser/PhpParser/Node/Expr/BooleanNot.php­#³•i­sÂ7Þ¤1nikic-php-parser/PhpParser/Node/Expr/CallLike.php#³•iö$‘b¤-nikic-php-parser/PhpParser/Node/Expr/Cast.phpU#³•iU¼ö³ð¤4nikic-php-parser/PhpParser/Node/Expr/Cast/Array_.phpî#³•iîȯ¾š¤3nikic-php-parser/PhpParser/Node/Expr/Cast/Bool_.php#³•iux å¤4nikic-php-parser/PhpParser/Node/Expr/Cast/Double.php·#³•i·S(Û¤2nikic-php-parser/PhpParser/Node/Expr/Cast/Int_.php{#³•i{ú{¤5nikic-php-parser/PhpParser/Node/Expr/Cast/Object_.phpð#³•ið\­‘°¤5nikic-php-parser/PhpParser/Node/Expr/Cast/String_.php…#³•i…Øú{Ƥ4nikic-php-parser/PhpParser/Node/Expr/Cast/Unset_.phpî#³•iîÉ”™Ô¤3nikic-php-parser/PhpParser/Node/Expr/Cast/Void_.phpì#³•iìšõ±d¤8nikic-php-parser/PhpParser/Node/Expr/ClassConstFetch.php#³•i2å¤/nikic-php-parser/PhpParser/Node/Expr/Clone_.phpž#³•iž™×¤0nikic-php-parser/PhpParser/Node/Expr/Closure.phpj #³•ij òI¶¤3nikic-php-parser/PhpParser/Node/Expr/ConstFetch.phpØ#³•iØs>6¤/nikic-php-parser/PhpParser/Node/Expr/Empty_.php¡#³•i¡¸¨Ý¤.nikic-php-parser/PhpParser/Node/Expr/Error.php#³•i$ŸLŒ¤6nikic-php-parser/PhpParser/Node/Expr/ErrorSuppress.php·#³•i·Î &¤.nikic-php-parser/PhpParser/Node/Expr/Eval_.phpž#³•ižA[¤.nikic-php-parser/PhpParser/Node/Expr/Exit_.php#³•igÝí¼¤1nikic-php-parser/PhpParser/Node/Expr/FuncCall.php#³•i@"]¤1nikic-php-parser/PhpParser/Node/Expr/Include_.phpÍ#³•iÍ—ÀÊ ¤4nikic-php-parser/PhpParser/Node/Expr/Instanceof_.php•#³•i•.§B ¤/nikic-php-parser/PhpParser/Node/Expr/Isset_.php£#³•i£ò>:¤.nikic-php-parser/PhpParser/Node/Expr/List_.php£#³•i£2ò¿)¤/nikic-php-parser/PhpParser/Node/Expr/Match_.php;#³•i;hü¤3nikic-php-parser/PhpParser/Node/Expr/MethodCall.phpQ#³•iQOD¥å¤-nikic-php-parser/PhpParser/Node/Expr/New_.php•#³•i•<~h¤;nikic-php-parser/PhpParser/Node/Expr/NullsafeMethodCall.phph#³•ihk[˜S¤>nikic-php-parser/PhpParser/Node/Expr/NullsafePropertyFetch.php#³•ik*¢¤0nikic-php-parser/PhpParser/Node/Expr/PostDec.php #³•i Ph@¤0nikic-php-parser/PhpParser/Node/Expr/PostInc.php #³•i dÞ‡¤/nikic-php-parser/PhpParser/Node/Expr/PreDec.php#³•iÍmB'¤/nikic-php-parser/PhpParser/Node/Expr/PreInc.php#³•iÔ·$x¤/nikic-php-parser/PhpParser/Node/Expr/Print_.php¡#³•i¡U¤óô¤6nikic-php-parser/PhpParser/Node/Expr/PropertyFetch.phpê#³•iê:%g¤2nikic-php-parser/PhpParser/Node/Expr/ShellExec.phpH#³•iHedü¤3nikic-php-parser/PhpParser/Node/Expr/StaticCall.php\#³•i\©ÁP¼¤<nikic-php-parser/PhpParser/Node/Expr/StaticPropertyFetch.php;#³•i;ç.½ ¤0nikic-php-parser/PhpParser/Node/Expr/Ternary.phpè#³•iè:X(¤/nikic-php-parser/PhpParser/Node/Expr/Throw_.php½#³•i½#‚6¢¤3nikic-php-parser/PhpParser/Node/Expr/UnaryMinus.php­#³•i­¾*C‰¤2nikic-php-parser/PhpParser/Node/Expr/UnaryPlus.phpª#³•iªF!Ĥ1nikic-php-parser/PhpParser/Node/Expr/Variable.phpž#³•ižìEk¤2nikic-php-parser/PhpParser/Node/Expr/YieldFrom.php»#³•i»ôBß ¤/nikic-php-parser/PhpParser/Node/Expr/Yield_.phpo#³•io‘Æ´¤0nikic-php-parser/PhpParser/Node/FunctionLike.phpï#³•iïÊj¸¤.nikic-php-parser/PhpParser/Node/Identifier.phpR#³•iR¦œú¤:nikic-php-parser/PhpParser/Node/InterpolatedStringPart.phpr#³•irkGþn¤4nikic-php-parser/PhpParser/Node/IntersectionType.php¯#³•i¯€”u«¤,nikic-php-parser/PhpParser/Node/MatchArm.php¹#³•i¹›Q\¤¤(nikic-php-parser/PhpParser/Node/Name.phpÙ!#³•iÙ!ÿ6Vˤ7nikic-php-parser/PhpParser/Node/Name/FullyQualified.phpÂ#³•iÂø 2¤1nikic-php-parser/PhpParser/Node/Name/Relative.php¿#³•i¿‰8½V¤0nikic-php-parser/PhpParser/Node/NullableType.phpÈ#³•iÈÕä¤)nikic-php-parser/PhpParser/Node/Param.phpë#³•iër @ž¤0nikic-php-parser/PhpParser/Node/PropertyHook.phpÉ #³•iÉ \üBA¤0nikic-php-parser/PhpParser/Node/PropertyItem.php\#³•i\¦`º¤*nikic-php-parser/PhpParser/Node/Scalar.phpo#³•io­¦þ=¤1nikic-php-parser/PhpParser/Node/Scalar/Float_.phpW#³•iWj©Æ¤/nikic-php-parser/PhpParser/Node/Scalar/Int_.phpø #³•iø Ÿ‘¤=nikic-php-parser/PhpParser/Node/Scalar/InterpolatedString.phpÝ#³•iÝ?à Z¤5nikic-php-parser/PhpParser/Node/Scalar/MagicConst.phpx#³•ix÷Ï®÷¤<nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Class_.phpZ#³•iZÁÆÓ5¤9nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Dir.phpS#³•iSrÙfɤ:nikic-php-parser/PhpParser/Node/Scalar/MagicConst/File.phpV#³•iV6›Q¤?nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Function_.phpc#³•ic—5¤¤:nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Line.phpV#³•iVèDEš¤<nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Method.php\#³•i\Ë2 N¤@nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Namespace_.phpf#³•if‹Ãq¤>nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Property.phpb#³•ib0º«¤<nikic-php-parser/PhpParser/Node/Scalar/MagicConst/Trait_.phpZ#³•iZ˵ݤ2nikic-php-parser/PhpParser/Node/Scalar/String_.phpÀ#³•iÀ‰–ƒË¤-nikic-php-parser/PhpParser/Node/StaticVar.php#³•iñT>¤(nikic-php-parser/PhpParser/Node/Stmt.php#³•i«yþ¤.nikic-php-parser/PhpParser/Node/Stmt/Block.php§#³•i§×j¤/nikic-php-parser/PhpParser/Node/Stmt/Break_.phpÛ#³•iÛmj–¤.nikic-php-parser/PhpParser/Node/Stmt/Case_.php†#³•i†ݸO/¤/nikic-php-parser/PhpParser/Node/Stmt/Catch_.phpy#³•iy{é^}¤3nikic-php-parser/PhpParser/Node/Stmt/ClassConst.phpS#³•iS/꾬¤2nikic-php-parser/PhpParser/Node/Stmt/ClassLike.php #³•i üÄsݤ4nikic-php-parser/PhpParser/Node/Stmt/ClassMethod.php÷#³•i÷ #c¤/nikic-php-parser/PhpParser/Node/Stmt/Class_.php¸ #³•i¸ Æ1è?¤/nikic-php-parser/PhpParser/Node/Stmt/Const_.phpÊ#³•iÊ ¤2nikic-php-parser/PhpParser/Node/Stmt/Continue_.phpê#³•iêÇò¥€¤1nikic-php-parser/PhpParser/Node/Stmt/Declare_.php½#³•i½5‹`ä¤,nikic-php-parser/PhpParser/Node/Stmt/Do_.phpT#³•iT%ú0¤.nikic-php-parser/PhpParser/Node/Stmt/Echo_.php´#³•i´±°`)¤0nikic-php-parser/PhpParser/Node/Stmt/ElseIf_.php[#³•i[bE·Ñ¤.nikic-php-parser/PhpParser/Node/Stmt/Else_.php·#³•i·&ô¡Á¤1nikic-php-parser/PhpParser/Node/Stmt/EnumCase.php»#³•i»w4m¤.nikic-php-parser/PhpParser/Node/Stmt/Enum_.phpJ#³•iJ›Œï?¤3nikic-php-parser/PhpParser/Node/Stmt/Expression.php÷#³•i÷ À¤1nikic-php-parser/PhpParser/Node/Stmt/Finally_.php¿#³•i¿8ååå¤-nikic-php-parser/PhpParser/Node/Stmt/For_.php¼#³•i¼€‚½+¤1nikic-php-parser/PhpParser/Node/Stmt/Foreach_.phpÐ#³•iе0–פ2nikic-php-parser/PhpParser/Node/Stmt/Function_.php¬ #³•i¬ f*키0nikic-php-parser/PhpParser/Node/Stmt/Global_.phpÇ#³•iÇPo6¤.nikic-php-parser/PhpParser/Node/Stmt/Goto_.php"#³•i"ÐX –¤1nikic-php-parser/PhpParser/Node/Stmt/GroupUse.php^#³•i^€¦7Ѥ5nikic-php-parser/PhpParser/Node/Stmt/HaltCompiler.php!#³•i!˜×y¤,nikic-php-parser/PhpParser/Node/Stmt/If_.php‘#³•i‘4‡o¤3nikic-php-parser/PhpParser/Node/Stmt/InlineHTML.php´#³•i´oûȇ¤3nikic-php-parser/PhpParser/Node/Stmt/Interface_.phpN#³•iN™yáÆ¤.nikic-php-parser/PhpParser/Node/Stmt/Label.phpü#³•iüŸäJ¤3nikic-php-parser/PhpParser/Node/Stmt/Namespace_.phpÝ#³•iÝSvEj¤,nikic-php-parser/PhpParser/Node/Stmt/Nop.phpF#³•iF$6¿Ø¤1nikic-php-parser/PhpParser/Node/Stmt/Property.phpÑ #³•iÑ rݦ¥¤0nikic-php-parser/PhpParser/Node/Stmt/Return_.phpÈ#³•iÈ|M¤0nikic-php-parser/PhpParser/Node/Stmt/Static_.phpþ#³•iþ’ٜޤ0nikic-php-parser/PhpParser/Node/Stmt/Switch_.phpI#³•iIiËÇü¤1nikic-php-parser/PhpParser/Node/Stmt/TraitUse.phpš#³•iš?óô\¤;nikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation.php=#³•i={:ФAnikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php1#³•i1b Ö¤Fnikic-php-parser/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php>#³•i>¶Ñÿ ¤/nikic-php-parser/PhpParser/Node/Stmt/Trait_.phpQ#³•iQËEøQ¤1nikic-php-parser/PhpParser/Node/Stmt/TryCatch.php6#³•i6‚ã2.¤/nikic-php-parser/PhpParser/Node/Stmt/Unset_.php¿#³•i¿:VÉɤ-nikic-php-parser/PhpParser/Node/Stmt/Use_.phpÔ#³•iÔ Ç|¤/nikic-php-parser/PhpParser/Node/Stmt/While_.phpW#³•iWQ/£×¤-nikic-php-parser/PhpParser/Node/UnionType.php»#³•i»’Hš­¤+nikic-php-parser/PhpParser/Node/UseItem.phpÇ#³•iÇ73Uƒ¤5nikic-php-parser/PhpParser/Node/VarLikeIdentifier.php#³•iy.¤7nikic-php-parser/PhpParser/Node/VariadicPlaceholder.php¯#³•i¯mäWè¤+nikic-php-parser/PhpParser/NodeAbstract.php7#³•i7ë¾i‚¤)nikic-php-parser/PhpParser/NodeDumper.phpû'#³•iû'ŒÍO ¤)nikic-php-parser/PhpParser/NodeFinder.phpW #³•iW ¥¹^‘¤,nikic-php-parser/PhpParser/NodeTraverser.php«&#³•i«&ñ†øm¤5nikic-php-parser/PhpParser/NodeTraverserInterface.phpa#³•ia½©ìð¤*nikic-php-parser/PhpParser/NodeVisitor.phpX#³•iXÝp}ª¤9nikic-php-parser/PhpParser/NodeVisitor/CloningVisitor.php#³•iî"Û¤Cnikic-php-parser/PhpParser/NodeVisitor/CommentAnnotatingVisitor.php¶ #³•i¶ ªÉ^µ¤9nikic-php-parser/PhpParser/NodeVisitor/FindingVisitor.php¥#³•i¥í1A¤>nikic-php-parser/PhpParser/NodeVisitor/FirstFindingVisitor.php#³•i~Ĭ*¤7nikic-php-parser/PhpParser/NodeVisitor/NameResolver.phpA(#³•iA(x_Á ¤@nikic-php-parser/PhpParser/NodeVisitor/NodeConnectingVisitor.php$ #³•i$ Vü¤Bnikic-php-parser/PhpParser/NodeVisitor/ParentConnectingVisitor.phpk#³•ik[>¤2nikic-php-parser/PhpParser/NodeVisitorAbstract.phpÙ#³•iÙ¡¿é~¤%nikic-php-parser/PhpParser/Parser.php #³•i œ0@¤*nikic-php-parser/PhpParser/Parser/Php7.phpåŽ#³•i厩?/}¤*nikic-php-parser/PhpParser/Parser/Php8.phpm#³•imÁ†Dʤ-nikic-php-parser/PhpParser/ParserAbstract.phpÇ#³•iÇ.€m©¤,nikic-php-parser/PhpParser/ParserFactory.phpÖ#³•iÖ(ŸÉc¤)nikic-php-parser/PhpParser/PhpVersion.php—#³•i—ªþßj¤,nikic-php-parser/PhpParser/PrettyPrinter.php¸#³•i¸>¹—´¤5nikic-php-parser/PhpParser/PrettyPrinter/Standard.php Ï#³•i Ï­Û'{¤4nikic-php-parser/PhpParser/PrettyPrinterAbstract.php #³•i 8f(¤$nikic-php-parser/PhpParser/Token.phpû#³•iûÇã ̤3nikic-php-parser/PhpParser/compatibility_tokens.php1 #³•i1 ¬”‚ɤobject-enumerator/LICENSEû#³•iûÏÜpŸ¤object-reflector/LICENSEû#³•iûûO«¤phar-io-manifest/LICENSE`#³•i`÷þp¤+phar-io-manifest/ManifestDocumentMapper.phpë#³•ië^DŒï¤#phar-io-manifest/ManifestLoader.phpÿ#³•iÿÙX©j¤'phar-io-manifest/ManifestSerializer.phpÏ#³•iÏ?jª'¤:phar-io-manifest/exceptions/ElementCollectionException.php#³•iIn‡¤)phar-io-manifest/exceptions/Exception.phpÓ#³•iÓֽФ?phar-io-manifest/exceptions/InvalidApplicationNameException.php<#³•i<°°¯W¤5phar-io-manifest/exceptions/InvalidEmailException.php#³•i)Ϫ}¤3phar-io-manifest/exceptions/InvalidUrlException.php #³•i x᳤9phar-io-manifest/exceptions/ManifestDocumentException.php#³•i/úï"¤@phar-io-manifest/exceptions/ManifestDocumentLoadingException.php~#³•i~H}»¤?phar-io-manifest/exceptions/ManifestDocumentMapperException.php#³•iJ¯R1¤8phar-io-manifest/exceptions/ManifestElementException.php#³•iÌæ¤7phar-io-manifest/exceptions/ManifestLoaderException.phpä#³•iäÍl ½¤7phar-io-manifest/exceptions/NoEmailAddressException.php#³•iáÁü¤'phar-io-manifest/values/Application.php #³•i ;Äk¤+phar-io-manifest/values/ApplicationName.php…#³•i…á”ù¤"phar-io-manifest/values/Author.php#³•i÷x•ü¤,phar-io-manifest/values/AuthorCollection.php-#³•i-àÍá¤4phar-io-manifest/values/AuthorCollectionIterator.php¡#³•i¡¨Ðªe¤,phar-io-manifest/values/BundledComponent.phpd#³•id7õõ¤6phar-io-manifest/values/BundledComponentCollection.php¹#³•i¹·æߤ>phar-io-manifest/values/BundledComponentCollectionIterator.php#³•i _»¤0phar-io-manifest/values/CopyrightInformation.phpp#³•ip‚“æP¤!phar-io-manifest/values/Email.php¦#³•i¦«S·¤%phar-io-manifest/values/Extension.phpÅ#³•iÅF {¤#phar-io-manifest/values/Library.php#³•i±ýžv¤#phar-io-manifest/values/License.php#³•i4Êýç¤$phar-io-manifest/values/Manifest.php& #³•i& ¾øüú¤3phar-io-manifest/values/PhpExtensionRequirement.php¼#³•i¼²Pη¤1phar-io-manifest/values/PhpVersionRequirement.phpA#³•iAÄñi‰¤'phar-io-manifest/values/Requirement.php´#³•i´ ŸïU¤1phar-io-manifest/values/RequirementCollection.phps#³•is6ý•M¤9phar-io-manifest/values/RequirementCollectionIterator.phpÝ#³•iÝUޤ phar-io-manifest/values/Type.phpÔ#³•iÔܲ3«¤phar-io-manifest/values/Url.phpÁ#³•iÁëO©ƒ¤&phar-io-manifest/xml/AuthorElement.phpð#³•iðÎÊÂÚ¤0phar-io-manifest/xml/AuthorElementCollection.phpM#³•iMj£·¤'phar-io-manifest/xml/BundlesElement.phpt#³•it]Y´‹¤)phar-io-manifest/xml/ComponentElement.php™#³•i™”na¤3phar-io-manifest/xml/ComponentElementCollection.phpV#³•iVú¥?¤(phar-io-manifest/xml/ContainsElement.phpŒ#³•iŒl8è¤)phar-io-manifest/xml/CopyrightElement.phpó#³•ió¹hDp¤*phar-io-manifest/xml/ElementCollection.phpÂ#³•iÂ<^ÉÞ¤#phar-io-manifest/xml/ExtElement.php*#³•i*^º×¤-phar-io-manifest/xml/ExtElementCollection.phpD#³•iDβSó¤)phar-io-manifest/xml/ExtensionElement.php#³•i€ JŒ¤'phar-io-manifest/xml/LicenseElement.php#³•ivâ/!¤)phar-io-manifest/xml/ManifestDocument.phpƒ #³•iƒ ™Åi_¤(phar-io-manifest/xml/ManifestElement.phpÝ#³•iÝ#¨=¤#phar-io-manifest/xml/PhpElement.php#³•iYʤ(phar-io-manifest/xml/RequiresElement.phpE#³•iEdwʤ!phar-io-version/BuildMetaData.phpã#³•iã3A(*¤phar-io-version/LICENSE&#³•i&Òª ¤$phar-io-version/PreReleaseSuffix.php#³•i8^æ¤phar-io-version/Version.phpñ#³•iñ‘¬¤+phar-io-version/VersionConstraintParser.phpN #³•iN n­%ˤ*phar-io-version/VersionConstraintValue.phpA #³•iA ²fi™¤!phar-io-version/VersionNumber.phpµ#³•iµKp‘_¤9phar-io-version/constraints/AbstractVersionConstraint.phpÁ#³•iÁ42ƒo¤9phar-io-version/constraints/AndVersionConstraintGroup.phpé#³•iékO•¤4phar-io-version/constraints/AnyVersionConstraint.phpT#³•iT¸v¤6phar-io-version/constraints/ExactVersionConstraint.phpÖ#³•iÖgÉÐq¤Ephar-io-version/constraints/GreaterThanOrEqualToVersionConstraint.php‰#³•i‰©ÞÚ_¤8phar-io-version/constraints/OrVersionConstraintGroup.php#³•i£¥ƒ6¤Fphar-io-version/constraints/SpecificMajorAndMinorVersionConstraint.phpÌ#³•iÌBº”,¤>phar-io-version/constraints/SpecificMajorVersionConstraint.php #³•i êÒé¤1phar-io-version/constraints/VersionConstraint.phpø#³•iøï¾dã¤(phar-io-version/exceptions/Exception.php³#³•i³ôÓ<²¤?phar-io-version/exceptions/InvalidPreReleaseSuffixException.php›#³•i›Ë[–¤6phar-io-version/exceptions/InvalidVersionException.php¡#³•i¡·ðy¤7phar-io-version/exceptions/NoBuildMetaDataException.php“#³•i“+${¡¤:phar-io-version/exceptions/NoPreReleaseSuffixException.php–#³•i–º"Ï÷¤Dphar-io-version/exceptions/UnsupportedVersionConstraintException.phpß#³•iߤ´æ¨¤"php-code-coverage/CodeCoverage.phpêI#³•iêIä’3¤6php-code-coverage/Data/ProcessedBranchCoverageData.php§ #³•i§ ”qô–¤-php-code-coverage/Data/ProcessedClassType.php##³•i#£M~k¤4php-code-coverage/Data/ProcessedCodeCoverageData.php—"#³•i—"Ћ¤8php-code-coverage/Data/ProcessedFunctionCoverageData.php¨ #³•i¨ ß p¤0php-code-coverage/Data/ProcessedFunctionType.php˜#³•i˜MvÕ·¤.php-code-coverage/Data/ProcessedMethodType.php’#³•i’ö3c—¤4php-code-coverage/Data/ProcessedPathCoverageData.phpµ#³•iµi*€¤-php-code-coverage/Data/ProcessedTraitType.php##³•i#³í-1¤.php-code-coverage/Data/RawCodeCoverageData.php‰##³•i‰#kºk¤#php-code-coverage/Driver/Driver.phpÿ#³•iÿ“j £¤'php-code-coverage/Driver/PcovDriver.php¢#³•i¢X^‰¹¤%php-code-coverage/Driver/Selector.php(#³•i(ƒ¹Ú¤)php-code-coverage/Driver/XdebugDriver.php/#³•i/Ž0|:¤Jphp-code-coverage/Exception/BranchAndPathCoverageNotSupportedException.phpÇ#³•iÇz¤Cphp-code-coverage/Exception/DirectoryCouldNotBeCreatedException.phpÿ#³•iÿ<î6'¤)php-code-coverage/Exception/Exception.php#³•i+’ËQ¤>php-code-coverage/Exception/FileCouldNotBeWrittenException.php»#³•i»£ó’¤8php-code-coverage/Exception/InvalidArgumentException.php¨#³•i¨lÕ~ФBphp-code-coverage/Exception/InvalidCodeCoverageTargetException.phpÃ#³•iÃyد¤Fphp-code-coverage/Exception/NoCodeCoverageDriverAvailableException.php3#³•i35oYC¤]php-code-coverage/Exception/NoCodeCoverageDriverWithPathCoverageSupportAvailableException.phpe#³•ie®X3Ÿ¤/php-code-coverage/Exception/ParserException.php¬#³•i¬pÏêÚ¤Dphp-code-coverage/Exception/PathExistsButIsNotDirectoryException.phpd#³•id±@¿¤9php-code-coverage/Exception/PcovNotAvailableException.phpi#³•iiÁq¤3php-code-coverage/Exception/ReflectionException.php°#³•i°ö`¤?php-code-coverage/Exception/ReportAlreadyFinalizedException.php>#³•i>ÒmU=¤Iphp-code-coverage/Exception/StaticAnalysisCacheNotConfiguredException.phpÆ#³•iÆÛpé¤6php-code-coverage/Exception/TestIdMissingException.php#³•i3ÄOê¤Cphp-code-coverage/Exception/UnintentionallyCoveredCodeException.phpÒ#³•iÒ[‹ã¤=php-code-coverage/Exception/WriteOperationFailedException.phpO#³•iOHç‰"¤;php-code-coverage/Exception/XdebugNotAvailableException.phpm#³•imí{F¤9php-code-coverage/Exception/XdebugNotEnabledException.php³#³•i³J]0¤Bphp-code-coverage/Exception/XdebugVersionNotSupportedException.phpò#³•iòØÝ2¤,php-code-coverage/Exception/XmlException.php©#³•i©0)ƒR¤php-code-coverage/Filter.phpˆ#³•iˆSÿѤphp-code-coverage/LICENSEû#³•iû„+•K¤'php-code-coverage/Node/AbstractNode.php #³•i -nP‡¤"php-code-coverage/Node/Builder.phpâ#³•iâ½à¢8¤$php-code-coverage/Node/CrapIndex.phpÂ#³•iÂWx\´¤$php-code-coverage/Node/Directory.php'#³•i'Y¤>ù¤php-code-coverage/Node/File.php«P#³•i«Pü„Ù»¤#php-code-coverage/Node/Iterator.php3#³•i3lŽÎ¤#php-code-coverage/Report/Clover.phpK%#³•iK%äI¸¤&php-code-coverage/Report/Cobertura.phpo/#³•io/ŠT·|¤#php-code-coverage/Report/Crap4j.phpY#³•iYÊáʤ(php-code-coverage/Report/Html/Colors.phpš#³•išÖ]­ÿ¤/php-code-coverage/Report/Html/CustomCssFile.php5#³•i5©ZÇ0¤(php-code-coverage/Report/Html/Facade.php{#³•i{†Þ~¤*php-code-coverage/Report/Html/Renderer.php%!#³•i%!ɰ~9¤4php-code-coverage/Report/Html/Renderer/Dashboard.php'#³•i' ÃÔ¤4php-code-coverage/Report/Html/Renderer/Directory.phpK#³•iK¹88a¤/php-code-coverage/Report/Html/Renderer/File.php‰#³•i‰<îv¤Bphp-code-coverage/Report/Html/Renderer/Template/branches.html.distô#³•iôh2+¤Fphp-code-coverage/Report/Html/Renderer/Template/coverage_bar.html.dist/#³•i/ÕchÁ¤Mphp-code-coverage/Report/Html/Renderer/Template/coverage_bar_branch.html.dist/#³•i/ÕchÁ¤Ephp-code-coverage/Report/Html/Renderer/Template/css/billboard.min.cssu#³•iuÃ(Zœ¤Ephp-code-coverage/Report/Html/Renderer/Template/css/bootstrap.min.cssRŠ#³•iRŠ Ìý¤>php-code-coverage/Report/Html/Renderer/Template/css/custom.css#³•i¤@php-code-coverage/Report/Html/Renderer/Template/css/octicons.cssX#³•iX'#ï¤=php-code-coverage/Report/Html/Renderer/Template/css/style.css#³•i¦{n§¤Cphp-code-coverage/Report/Html/Renderer/Template/dashboard.html.distv#³•iv,©Rt¤Jphp-code-coverage/Report/Html/Renderer/Template/dashboard_branch.html.dist#³•i«ŒÅϤCphp-code-coverage/Report/Html/Renderer/Template/directory.html.distö#³•iöÎÕ†á¤Jphp-code-coverage/Report/Html/Renderer/Template/directory_branch.html.dist”#³•i”n2]¤Hphp-code-coverage/Report/Html/Renderer/Template/directory_item.html.distA#³•iAds¤Ophp-code-coverage/Report/Html/Renderer/Template/directory_item_branch.html.dist;#³•i;ªm½Û¤>php-code-coverage/Report/Html/Renderer/Template/file.html.distö#³•iö9Á¤Ephp-code-coverage/Report/Html/Renderer/Template/file_branch.html.dist“ #³•i“ ûu ¤Cphp-code-coverage/Report/Html/Renderer/Template/file_item.html.distr#³•iréð/y¤Jphp-code-coverage/Report/Html/Renderer/Template/file_item_branch.html.distl#³•il¡-°÷¤Cphp-code-coverage/Report/Html/Renderer/Template/icons/file-code.svg0#³•i0ÙQUU¤Hphp-code-coverage/Report/Html/Renderer/Template/icons/file-directory.svgê#³•iêýÚZÿ¤Hphp-code-coverage/Report/Html/Renderer/Template/js/billboard.pkgd.min.js·#³•i·‰4E”¤Jphp-code-coverage/Report/Html/Renderer/Template/js/bootstrap.bundle.min.jsg;#³•ig;âOê$¤:php-code-coverage/Report/Html/Renderer/Template/js/file.jsÈ#³•iÈ 5-¤@php-code-coverage/Report/Html/Renderer/Template/js/jquery.min.jsìU#³•iìU¥ŸGœ¤>php-code-coverage/Report/Html/Renderer/Template/line.html.distÃ#³•i÷ä´_¤?php-code-coverage/Report/Html/Renderer/Template/lines.html.diste#³•iedf ¤Ephp-code-coverage/Report/Html/Renderer/Template/method_item.html.dist«#³•i«‹jפLphp-code-coverage/Report/Html/Renderer/Template/method_item_branch.html.dist¥#³•i¥yÄŽk¤?php-code-coverage/Report/Html/Renderer/Template/paths.html.distò#³•iòã*'ݤ'php-code-coverage/Report/OpenClover.phpý/#³•iý/O󩦤 php-code-coverage/Report/PHP.phpo#³•ioÊ4n’¤!php-code-coverage/Report/Text.phpÊ&#³•iÊ&BjL¤'php-code-coverage/Report/Thresholds.phpH#³•iH™¡^}¤1php-code-coverage/Report/Xml/BuildInformation.phpC#³•iCÍ—½¤)php-code-coverage/Report/Xml/Coverage.phpS#³•iS`à[¤*php-code-coverage/Report/Xml/Directory.phpí#³•ií ôFn¤'php-code-coverage/Report/Xml/Facade.phpp&#³•ip&p§?q¤%php-code-coverage/Report/Xml/File.php¢#³•i¢ü³8¤'php-code-coverage/Report/Xml/Method.php#³•ic‚¾á¤%php-code-coverage/Report/Xml/Node.phpþ#³•iþ¢[3é¤(php-code-coverage/Report/Xml/Project.php’#³•i’±J¬¤'php-code-coverage/Report/Xml/Report.php] #³•i] 6½â1¤'php-code-coverage/Report/Xml/Source.phpø#³•iøò] ‚¤&php-code-coverage/Report/Xml/Tests.phpø#³•iøpt !¤'php-code-coverage/Report/Xml/Totals.php: #³•i: ìx8w¤%php-code-coverage/Report/Xml/Unit.phpï#³•iï­££J¤0php-code-coverage/StaticAnalysis/CacheWarmer.php±#³•i±PZu$¤:php-code-coverage/StaticAnalysis/CachingSourceAnalyser.php5 #³•i5 T—ó.¤1php-code-coverage/StaticAnalysis/FileAnalyser.phpA#³•iAá7ܤ:php-code-coverage/StaticAnalysis/ParsingSourceAnalyser.phpâ#³•iâF¹_Y¤3php-code-coverage/StaticAnalysis/SourceAnalyser.phpÄ#³•iÄ_›n¤9php-code-coverage/StaticAnalysis/Value/AnalysisResult.phpÄ #³•iÄ P»‚’¤1php-code-coverage/StaticAnalysis/Value/Class_.phpÔ#³•iÔ}×¼`¤4php-code-coverage/StaticAnalysis/Value/Function_.phpŽ #³•iŽ fw¨¤5php-code-coverage/StaticAnalysis/Value/Interface_.phpv #³•iv ™ 6=¤6php-code-coverage/StaticAnalysis/Value/LinesOfCode.phpP#³•iPé8,|¤1php-code-coverage/StaticAnalysis/Value/Method.phpè#³•iè(¤1php-code-coverage/StaticAnalysis/Value/Trait_.phpË #³•iË ÕÂ;¤5php-code-coverage/StaticAnalysis/Value/Visibility.phpI#³•iIÌ**¤Mphp-code-coverage/StaticAnalysis/Visitor/AttributeParentConnectingVisitor.php #³•i Dùö»¤Cphp-code-coverage/StaticAnalysis/Visitor/CodeUnitFindingVisitor.phpZ,#³•iZ,Ÿ“Á¤Jphp-code-coverage/StaticAnalysis/Visitor/ExecutableLinesFindingVisitor.php +#³•i +±‹Z¤Gphp-code-coverage/StaticAnalysis/Visitor/IgnoredLinesFindingVisitor.php[#³•i[¢ájþ¤#php-code-coverage/Target/Class_.phpG#³•iGæLÁå¤3php-code-coverage/Target/ClassesThatExtendClass.php‹#³•i‹“!x¤:php-code-coverage/Target/ClassesThatImplementInterface.phpÇ#³•iÇ\<x¤&php-code-coverage/Target/Function_.phpv#³•iv”½'¤'php-code-coverage/Target/MapBuilder.php$#³•i$©ñá¤#php-code-coverage/Target/Mapper.phpd #³•id d#ø¤#php-code-coverage/Target/Method.php¤#³•i¤î f£¤'php-code-coverage/Target/Namespace_.phpb#³•ibʾ!¤#php-code-coverage/Target/Target.phpÕ #³•iÕ EÂ̤-php-code-coverage/Target/TargetCollection.phpî#³•iî3aª?¤5php-code-coverage/Target/TargetCollectionIterator.phpò#³•iòÛ÷M¤6php-code-coverage/Target/TargetCollectionValidator.php#³•iŠ>Sy¤#php-code-coverage/Target/Trait_.phpF#³•iFüWà ¤.php-code-coverage/Target/ValidationFailure.php#³•i™¬md¤-php-code-coverage/Target/ValidationResult.php\#³•i\T¼¤.php-code-coverage/Target/ValidationSuccess.phpt#³•it!Ãb¤$php-code-coverage/TestSize/Known.php#³•i”ñQ¤$php-code-coverage/TestSize/Large.php‰#³•i‰88çq¤%php-code-coverage/TestSize/Medium.php‹#³•i‹û›¤$php-code-coverage/TestSize/Small.php}#³•i}O¾Dä¤'php-code-coverage/TestSize/TestSize.phpš#³•išfSúv¤&php-code-coverage/TestSize/Unknown.php*#³•i*T4Uv¤(php-code-coverage/TestStatus/Failure.php)#³•i)%$¤&php-code-coverage/TestStatus/Known.phpà#³•iàsŒ¤(php-code-coverage/TestStatus/Success.php)#³•i)ë²!¤+php-code-coverage/TestStatus/TestStatus.phpÐ#³•iÐÄñyå¤(php-code-coverage/TestStatus/Unknown.php.#³•i.Xæl¤%php-code-coverage/Util/Filesystem.phpý#³•iýd2A¤%php-code-coverage/Util/Percentage.phpU#³•iUwªfÀ¤php-code-coverage/Util/Xml.php•#³•i•W‹¨¤php-code-coverage/Version.php¯#³•i¯dû,¤%php-file-iterator/ExcludeIterator.phpõ#³•iõC 5ë¤php-file-iterator/Facade.php•#³•i•Í…!Z¤php-file-iterator/Factory.phps#³•is3áø¤php-file-iterator/Iterator.php8 #³•i8 °*çó¤php-file-iterator/LICENSEû#³•iû„+•K¤php-invoker/Invoker.php7#³•i7>(6ʤ$php-invoker/exceptions/Exception.phpv#³•iv'P=¤Dphp-invoker/exceptions/ProcessControlExtensionNotLoadedException.phpÑ#³•iÑed e¤+php-invoker/exceptions/TimeoutException.php¢#³•i¢—tJï¤php-text-template/LICENSEû#³•iû„+•K¤php-text-template/Template.phpà #³•ià iªÕ–¤*php-text-template/exceptions/Exception.php}#³•i}Áã`"¤9php-text-template/exceptions/InvalidArgumentException.php¤#³•i¤ô¼¸Â¤1php-text-template/exceptions/RuntimeException.php¹#³•i¹Ö]Mp¤php-timer/Duration.php #³•i }h#¤php-timer/LICENSEû#³•iûw¶-&¤$php-timer/ResourceUsageFormatter.php#³•i°”vø¤php-timer/Timer.phpŠ#³•iŠCHì¤"php-timer/exceptions/Exception.phpr#³•ir˜›<¤/php-timer/exceptions/NoActiveTimerException.php #³•i *®õ¤Ephp-timer/exceptions/TimeSinceStartOfRequestNotAvailableException.phpº#³•iºÐ.ñ¤ phpunit.xsd²N#³•i²NßÑ­R¤1phpunit/Event/Dispatcher/CollectingDispatcher.php#³•iØ­:¤0phpunit/Event/Dispatcher/DeferringDispatcher.php¢#³•i¢MW°‰¤-phpunit/Event/Dispatcher/DirectDispatcher.php#³•iÐ$"e¤'phpunit/Event/Dispatcher/Dispatcher.php}#³•i};G`œ¤3phpunit/Event/Dispatcher/SubscribableDispatcher.php#³•i»>òL¤,phpunit/Event/Emitter/DispatchingEmitter.php‰#³•i‰5yܤ!phpunit/Event/Emitter/Emitter.php0#³•i0µ‡¾¤-phpunit/Event/Events/Application/Finished.php¨#³•i¨9ÒsS¤7phpunit/Event/Events/Application/FinishedSubscriber.php6#³•i6Íþ)÷¤,phpunit/Event/Events/Application/Started.php¦#³•i¦ëó0Á¤6phpunit/Event/Events/Application/StartedSubscriber.php4#³•i4JÜ'¤phpunit/Event/Events/Event.php:#³•i:¾ûké¤(phpunit/Event/Events/EventCollection.phpJ#³•iJ·æI¤0phpunit/Event/Events/EventCollectionIterator.php #³•i Rn¤;phpunit/Event/Events/Test/AdditionalInformationProvided.phpw#³•iw†—x†¤Ephpunit/Event/Events/Test/AdditionalInformationProvidedSubscriber.phpR#³•iRj6ü¤2phpunit/Event/Events/Test/ComparatorRegistered.phpv#³•ivEø¤<phpunit/Event/Events/Test/ComparatorRegisteredSubscriber.php@#³•i@Ú­êö¤<phpunit/Event/Events/Test/CustomTestMethodInvocationUsed.php?#³•i?¯È¤Fphpunit/Event/Events/Test/CustomTestMethodInvocationUsedSubscriber.phpT#³•iT~'¤Bphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodCalled.php­#³•i­q€+0¤Lphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodCalledSubscriber.phpJ#³•iJ‘Éü ¤Cphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodErrored.php+#³•i+æP¤Mphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodErroredSubscriber.phpL#³•iLø¿¤Bphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFailed.php)#³•i)ujµ‘¤Lphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFailedSubscriber.phpJ#³•iJ ¶0¤Dphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFinished.php˜#³•i˜몠 ¤Nphpunit/Event/Events/Test/HookMethod/AfterLastTestMethodFinishedSubscriber.phpN#³•iNwœàK¤>phpunit/Event/Events/Test/HookMethod/AfterTestMethodCalled.php¼#³•i¼?±ï¤Hphpunit/Event/Events/Test/HookMethod/AfterTestMethodCalledSubscriber.phpB#³•iB£R‘ÿ¤?phpunit/Event/Events/Test/HookMethod/AfterTestMethodErrored.php:#³•i:'<ߤIphpunit/Event/Events/Test/HookMethod/AfterTestMethodErroredSubscriber.phpD#³•iD%?±ò¤>phpunit/Event/Events/Test/HookMethod/AfterTestMethodFailed.php8#³•i8”(%h¤Hphpunit/Event/Events/Test/HookMethod/AfterTestMethodFailedSubscriber.phpB#³•iBÞÙŽ¤@phpunit/Event/Events/Test/HookMethod/AfterTestMethodFinished.php§#³•i§&1·¤Jphpunit/Event/Events/Test/HookMethod/AfterTestMethodFinishedSubscriber.phpF#³•iF–^‰_¤Dphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalled.php±#³•i±ë @½¤Nphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalledSubscriber.phpN#³•iNeÚäu¤Ephpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodErrored.php/#³•i/«ÍÖÚ¤Ophpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodErroredSubscriber.phpP#³•iPñ¨¥²¤Dphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailed.php-#³•i-Ú1ÇÛ¤Nphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailedSubscriber.phpN#³•iNæõ¤Fphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinished.phpœ#³•iœæå3¼¤Pphpunit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinishedSubscriber.phpR#³•iR½Á“\¤?phpunit/Event/Events/Test/HookMethod/BeforeTestMethodCalled.php¾#³•i¾î €¦¤Iphpunit/Event/Events/Test/HookMethod/BeforeTestMethodCalledSubscriber.phpD#³•iD¿þƾ¤@phpunit/Event/Events/Test/HookMethod/BeforeTestMethodErrored.php<#³•i<‘Ož¤Jphpunit/Event/Events/Test/HookMethod/BeforeTestMethodErroredSubscriber.phpF#³•iF¦ó„0¤?phpunit/Event/Events/Test/HookMethod/BeforeTestMethodFailed.php:#³•i:½Âça¤Iphpunit/Event/Events/Test/HookMethod/BeforeTestMethodFailedSubscriber.phpD#³•iD}&°ö¤Aphpunit/Event/Events/Test/HookMethod/BeforeTestMethodFinished.php©#³•i©ÕéÄj¤Kphpunit/Event/Events/Test/HookMethod/BeforeTestMethodFinishedSubscriber.phpH#³•iHx—ŠS¤<phpunit/Event/Events/Test/HookMethod/PostConditionCalled.php¾#³•i¾â~*û¤Fphpunit/Event/Events/Test/HookMethod/PostConditionCalledSubscriber.php>#³•i>b*¤=phpunit/Event/Events/Test/HookMethod/PostConditionErrored.php<#³•i<² ç¤Gphpunit/Event/Events/Test/HookMethod/PostConditionErroredSubscriber.php@#³•i@qhÀ÷¤<phpunit/Event/Events/Test/HookMethod/PostConditionFailed.php:#³•i:Ή¥L¤Fphpunit/Event/Events/Test/HookMethod/PostConditionFailedSubscriber.php>#³•i>åàœ¤>phpunit/Event/Events/Test/HookMethod/PostConditionFinished.php©#³•i©Te_¤Hphpunit/Event/Events/Test/HookMethod/PostConditionFinishedSubscriber.phpB#³•iBWXF“¤;phpunit/Event/Events/Test/HookMethod/PreConditionCalled.php¼#³•i¼[š7<¤Ephpunit/Event/Events/Test/HookMethod/PreConditionCalledSubscriber.php<#³•i<u8O&¤<phpunit/Event/Events/Test/HookMethod/PreConditionErrored.php:#³•i:³wÉa¤Fphpunit/Event/Events/Test/HookMethod/PreConditionErroredSubscriber.php>#³•i>‘§¤;phpunit/Event/Events/Test/HookMethod/PreConditionFailed.php8#³•i8òÈsƒ¤Ephpunit/Event/Events/Test/HookMethod/PreConditionFailedSubscriber.php<#³•i<>Äw¤=phpunit/Event/Events/Test/HookMethod/PreConditionFinished.php§#³•i§”¤Gphpunit/Event/Events/Test/HookMethod/PreConditionFinishedSubscriber.php@#³•i@¡µX¤3phpunit/Event/Events/Test/Issue/ConsideredRisky.phpô#³•iôë1Ÿ ¤=phpunit/Event/Events/Test/Issue/ConsideredRiskySubscriber.php6#³•i6S%LT¤8phpunit/Event/Events/Test/Issue/DeprecationTriggered.phpx#³•ix¼ÿö¤Bphpunit/Event/Events/Test/Issue/DeprecationTriggeredSubscriber.php@#³•i@ö†“¤2phpunit/Event/Events/Test/Issue/ErrorTriggered.phpÚ #³•iÚ ¼W”¤<phpunit/Event/Events/Test/Issue/ErrorTriggeredSubscriber.php4#³•i4R¹Â5¤3phpunit/Event/Events/Test/Issue/NoticeTriggered.php #³•i m©ÓX¤=phpunit/Event/Events/Test/Issue/NoticeTriggeredSubscriber.php6#³•i6'T$ž¤;phpunit/Event/Events/Test/Issue/PhpDeprecationTriggered.phpC #³•iC Šr„¤Ephpunit/Event/Events/Test/Issue/PhpDeprecationTriggeredSubscriber.phpF#³•iFˆs†¤6phpunit/Event/Events/Test/Issue/PhpNoticeTriggered.php #³•i Í-ž+¤@phpunit/Event/Events/Test/Issue/PhpNoticeTriggeredSubscriber.php<#³•i<M¥s¤7phpunit/Event/Events/Test/Issue/PhpWarningTriggered.php #³•i fð2û¤Aphpunit/Event/Events/Test/Issue/PhpWarningTriggeredSubscriber.php>#³•i>« d¤?phpunit/Event/Events/Test/Issue/PhpunitDeprecationTriggered.phpi#³•ii¨ªa/¤Iphpunit/Event/Events/Test/Issue/PhpunitDeprecationTriggeredSubscriber.phpN#³•iNlp®¤9phpunit/Event/Events/Test/Issue/PhpunitErrorTriggered.phpv#³•iviÎÙ¤Cphpunit/Event/Events/Test/Issue/PhpunitErrorTriggeredSubscriber.phpB#³•iB°Ÿ³;¤:phpunit/Event/Events/Test/Issue/PhpunitNoticeTriggered.phpx#³•ixdSS8¤Dphpunit/Event/Events/Test/Issue/PhpunitNoticeTriggeredSubscriber.phpD#³•iD —¤;phpunit/Event/Events/Test/Issue/PhpunitWarningTriggered.php¿#³•i¿)ŽߤEphpunit/Event/Events/Test/Issue/PhpunitWarningTriggeredSubscriber.phpF#³•iF¶²â¤4phpunit/Event/Events/Test/Issue/WarningTriggered.php #³•i üæÐ¤>phpunit/Event/Events/Test/Issue/WarningTriggeredSubscriber.php8#³•i8£®Z{¤@phpunit/Event/Events/Test/Lifecycle/DataProviderMethodCalled.phpF#³•iFŸ?åR¤Jphpunit/Event/Events/Test/Lifecycle/DataProviderMethodCalledSubscriber.phpH#³•iHë~-r¤Bphpunit/Event/Events/Test/Lifecycle/DataProviderMethodFinished.php#³•i¯(ín¤Lphpunit/Event/Events/Test/Lifecycle/DataProviderMethodFinishedSubscriber.phpL#³•iL Ç?¤0phpunit/Event/Events/Test/Lifecycle/Finished.php8#³•i8<ï4¤:phpunit/Event/Events/Test/Lifecycle/FinishedSubscriber.php(#³•i(.͵P¤:phpunit/Event/Events/Test/Lifecycle/PreparationErrored.php#³•i’ÐͤDphpunit/Event/Events/Test/Lifecycle/PreparationErroredSubscriber.php<#³•i<‰ê¯€¤9phpunit/Event/Events/Test/Lifecycle/PreparationFailed.php #³•i 7+%¤Cphpunit/Event/Events/Test/Lifecycle/PreparationFailedSubscriber.php:#³•i:ØÌ"»¤:phpunit/Event/Events/Test/Lifecycle/PreparationStarted.php“#³•i“k¹Ý¤Dphpunit/Event/Events/Test/Lifecycle/PreparationStartedSubscriber.php<#³•i<&Uep¤0phpunit/Event/Events/Test/Lifecycle/Prepared.php~#³•i~Öîj¤:phpunit/Event/Events/Test/Lifecycle/PreparedSubscriber.php(#³•i(ħK”¤-phpunit/Event/Events/Test/Outcome/Errored.php#³•iŽÈx8¤7phpunit/Event/Events/Test/Outcome/ErroredSubscriber.php&#³•i&èd3¤,phpunit/Event/Events/Test/Outcome/Failed.php¸#³•i¸Ù²!¤6phpunit/Event/Events/Test/Outcome/FailedSubscriber.php$#³•i$À\*¤6phpunit/Event/Events/Test/Outcome/MarkedIncomplete.php$#³•i$þ^ߤ@phpunit/Event/Events/Test/Outcome/MarkedIncompleteSubscriber.php8#³•i8 6‹¤,phpunit/Event/Events/Test/Outcome/Passed.phpz#³•izÒü—¤6phpunit/Event/Events/Test/Outcome/PassedSubscriber.php$#³•i$ÂÐ:y¤-phpunit/Event/Events/Test/Outcome/Skipped.php´#³•i´ÞÔ-¤7phpunit/Event/Events/Test/Outcome/SkippedSubscriber.php&#³•i&{ªdz¤5phpunit/Event/Events/Test/PrintedUnexpectedOutput.php4#³•i4D ¤?phpunit/Event/Events/Test/PrintedUnexpectedOutputSubscriber.phpF#³•iF¾4¾­¤:phpunit/Event/Events/Test/TestDouble/MockObjectCreated.php#³•iì[~¤Dphpunit/Event/Events/Test/TestDouble/MockObjectCreatedSubscriber.php:#³•i:E¨'á¤Uphpunit/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreated.phpj#³•ij’Œ¤_phpunit/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreatedSubscriber.phpp#³•ip-¤Aphpunit/Event/Events/Test/TestDouble/PartialMockObjectCreated.php3#³•i3ÓE„¤Kphpunit/Event/Events/Test/TestDouble/PartialMockObjectCreatedSubscriber.phpH#³•iHøþ¡£¤8phpunit/Event/Events/Test/TestDouble/TestStubCreated.php#³•i·ÚÅû¤Bphpunit/Event/Events/Test/TestDouble/TestStubCreatedSubscriber.php6#³•i6íà ¤Sphpunit/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreated.phpf#³•if¥“Ƈ¤]phpunit/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreatedSubscriber.phpl#³•ilŠªR¤5phpunit/Event/Events/TestRunner/BootstrapFinished.php#³•iySóž¤?phpunit/Event/Events/TestRunner/BootstrapFinishedSubscriber.phpF#³•iF€2¸=¤7phpunit/Event/Events/TestRunner/ChildProcessErrored.php¯#³•i¯œR[ª¤Aphpunit/Event/Events/TestRunner/ChildProcessErroredSubscriber.phpJ#³•iJ@$$¤8phpunit/Event/Events/TestRunner/ChildProcessFinished.phpé#³•iéO†º¤Bphpunit/Event/Events/TestRunner/ChildProcessFinishedSubscriber.phpL#³•iL`¨&¤7phpunit/Event/Events/TestRunner/ChildProcessStarted.php¯#³•i¯°ýÙg¤Aphpunit/Event/Events/TestRunner/ChildProcessStartedSubscriber.phpJ#³•iJ"4¤.phpunit/Event/Events/TestRunner/Configured.php¡#³•i¡nTúФ8phpunit/Event/Events/TestRunner/ConfiguredSubscriber.php8#³•i8ÍL¿Ï¤8phpunit/Event/Events/TestRunner/DeprecationTriggered.php'#³•i'Ù¾ˆ¤Bphpunit/Event/Events/TestRunner/DeprecationTriggeredSubscriber.phpL#³•iLöñ`2¤5phpunit/Event/Events/TestRunner/EventFacadeSealed.php«#³•i«j̾¤?phpunit/Event/Events/TestRunner/EventFacadeSealedSubscriber.phpF#³•iF$¬v^¤4phpunit/Event/Events/TestRunner/ExecutionAborted.php´#³•i´uÓ-¤>phpunit/Event/Events/TestRunner/ExecutionAbortedSubscriber.phpD#³•iD²sl|¤5phpunit/Event/Events/TestRunner/ExecutionFinished.php¶#³•i¶¶"Àq¤?phpunit/Event/Events/TestRunner/ExecutionFinishedSubscriber.phpF#³•iFÓ¾ñ¤4phpunit/Event/Events/TestRunner/ExecutionStarted.php#³•iÞ#<ü¤>phpunit/Event/Events/TestRunner/ExecutionStartedSubscriber.phpD#³•iDÿ.¤9phpunit/Event/Events/TestRunner/ExtensionBootstrapped.phpr#³•ir ½)¼¤Cphpunit/Event/Events/TestRunner/ExtensionBootstrappedSubscriber.phpN#³•iNÃ¥³¤;phpunit/Event/Events/TestRunner/ExtensionLoadedFromPhar.phps#³•isR롤Ephpunit/Event/Events/TestRunner/ExtensionLoadedFromPharSubscriber.phpR#³•iRA‹Æ¾¤,phpunit/Event/Events/TestRunner/Finished.php£#³•i£p™¤6phpunit/Event/Events/TestRunner/FinishedSubscriber.php4#³•i4[Ixé¤=phpunit/Event/Events/TestRunner/GarbageCollectionDisabled.phpÇ#³•iÇA\¤Gphpunit/Event/Events/TestRunner/GarbageCollectionDisabledSubscriber.phpV#³•iVy ÃW¤<phpunit/Event/Events/TestRunner/GarbageCollectionEnabled.phpÅ#³•iŇ­M«¤Fphpunit/Event/Events/TestRunner/GarbageCollectionEnabledSubscriber.phpT#³•iTyÄ ¤>phpunit/Event/Events/TestRunner/GarbageCollectionTriggered.phpÉ#³•iÉ4†”d¤Hphpunit/Event/Events/TestRunner/GarbageCollectionTriggeredSubscriber.phpX#³•iX€Jz¤3phpunit/Event/Events/TestRunner/NoticeTriggered.phpˆ#³•iˆð¤=phpunit/Event/Events/TestRunner/NoticeTriggeredSubscriber.phpB#³•iB¾Ðò¤+phpunit/Event/Events/TestRunner/Started.php¡#³•i¡[i¶W¤5phpunit/Event/Events/TestRunner/StartedSubscriber.php2#³•i2}ÃRp¤Iphpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinished.php²#³•i²€œRÖ¤Sphpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinishedSubscriber.phpn#³•inöÏLû¤Hphpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStarted.phpÔ#³•iÔFCàò¤Rphpunit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStartedSubscriber.phpl#³•ilêÙ§Ó¤4phpunit/Event/Events/TestRunner/WarningTriggered.php#³•i_Ìò¤>phpunit/Event/Events/TestRunner/WarningTriggeredSubscriber.phpD#³•iDʉú±¤+phpunit/Event/Events/TestSuite/Filtered.php#³•iñ˜_Õ¤5phpunit/Event/Events/TestSuite/FilteredSubscriber.php2#³•i2™?¾Ë¤+phpunit/Event/Events/TestSuite/Finished.php3#³•i38 ›ó¤5phpunit/Event/Events/TestSuite/FinishedSubscriber.php2#³•i2JVˆ8¤)phpunit/Event/Events/TestSuite/Loaded.php#³•i ¤3phpunit/Event/Events/TestSuite/LoadedSubscriber.php.#³•i.˜š)¤*phpunit/Event/Events/TestSuite/Skipped.php•#³•i•ëÝL¤4phpunit/Event/Events/TestSuite/SkippedSubscriber.php0#³•i0èǤ)phpunit/Event/Events/TestSuite/Sorted.php1#³•i1úl9´¤3phpunit/Event/Events/TestSuite/SortedSubscriber.php.#³•i.ÝIN"¤*phpunit/Event/Events/TestSuite/Started.php1#³•i19ˆǤ4phpunit/Event/Events/TestSuite/StartedSubscriber.php0#³•i0¿Ý.¤9phpunit/Event/Exception/EventAlreadyAssignedException.php #³•i 0•ɤ8phpunit/Event/Exception/EventFacadeIsSealedException.php #³•i J ؤ%phpunit/Event/Exception/Exception.php½#³•i½/7rr¤4phpunit/Event/Exception/InvalidArgumentException.phpù#³•iùÛ䀤1phpunit/Event/Exception/InvalidEventException.php#³•iE>¯¤6phpunit/Event/Exception/InvalidSubscriberException.php#³•iSÜg¤$phpunit/Event/Exception/MapError.phpö#³•iöÕ÷äR¤8phpunit/Event/Exception/NoComparisonFailureException.php#³•iâ{k ¤>phpunit/Event/Exception/NoDataSetFromDataProviderException.php'#³•i'@~à¤8phpunit/Event/Exception/NoPreviousThrowableException.php #³•i Ùú¦~¤@phpunit/Event/Exception/NoTestCaseObjectOnCallStackException.phpù#³•iùxs§Ù¤,phpunit/Event/Exception/RuntimeException.phpé#³•iéLƤDphpunit/Event/Exception/SubscriberTypeAlreadyRegisteredException.php#³•iį¨K¤1phpunit/Event/Exception/UnknownEventException.php#³•išÜ}ê¤5phpunit/Event/Exception/UnknownEventTypeException.php#³•i/<ˆ¡¤6phpunit/Event/Exception/UnknownSubscriberException.php#³•i ²Éˤ:phpunit/Event/Exception/UnknownSubscriberTypeException.php #³•i &'ý*¤phpunit/Event/Facade.phpO$#³•iO$¶©°¤phpunit/Event/Subscriber.php£#³•i£dlkû¤phpunit/Event/Tracer.phpî#³•iî€Úm¤phpunit/Event/TypeMap.php&#³•i&j}J¤#phpunit/Event/Value/ClassMethod.phpj#³•ijý¢—¤)phpunit/Event/Value/ComparisonFailure.phpË#³•iËŠ6IQ¤0phpunit/Event/Value/ComparisonFailureBuilder.php^#³•i^Õ?`Ÿ¤/phpunit/Event/Value/Runtime/OperatingSystem.php¢#³•i¢Âá—÷¤#phpunit/Event/Value/Runtime/PHP.phpÄ#³•iĆƒÖ½¤'phpunit/Event/Value/Runtime/PHPUnit.php^#³•i^ 7:á¤'phpunit/Event/Value/Runtime/Runtime.php´#³•i´Ë&TŒ¤*phpunit/Event/Value/Telemetry/Duration.phpÑ #³•iÑ ëØ`†¤8phpunit/Event/Value/Telemetry/GarbageCollectorStatus.phpÞ #³•iÞ Ó5ƒ¤@phpunit/Event/Value/Telemetry/GarbageCollectorStatusProvider.phpp#³•ipr Ù¤(phpunit/Event/Value/Telemetry/HRTime.php #³•i mÖž¥¤&phpunit/Event/Value/Telemetry/Info.php #³•i fÔ ‹¤-phpunit/Event/Value/Telemetry/MemoryMeter.php¤#³•i¤'ìä}¤-phpunit/Event/Value/Telemetry/MemoryUsage.php^#³•i^Übi¤*phpunit/Event/Value/Telemetry/Snapshot.php…#³•i…âš‹ø¤+phpunit/Event/Value/Telemetry/StopWatch.phpL#³•iLQØ¡6¤(phpunit/Event/Value/Telemetry/System.php•#³•i•öȈɤFphpunit/Event/Value/Telemetry/SystemGarbageCollectorStatusProvider.phpR#³•iRÃRH¤3phpunit/Event/Value/Telemetry/SystemMemoryMeter.phpç#³•iç>ÿ¤1phpunit/Event/Value/Telemetry/SystemStopWatch.phpc#³•icý‚÷H¤;phpunit/Event/Value/Telemetry/SystemStopWatchWithOffset.php½#³•i½‹'^L¤'phpunit/Event/Value/Test/Issue/Code.php #³•i Õ9 ¤/phpunit/Event/Value/Test/Issue/IssueTrigger.php¨#³•i¨C™,ø¤!phpunit/Event/Value/Test/Phpt.php#³•i3{ÞY¤!phpunit/Event/Value/Test/Test.phpÓ#³•iÓÙ[U¼¤+phpunit/Event/Value/Test/TestCollection.php"#³•i"¨>Ƥ3phpunit/Event/Value/Test/TestCollectionIterator.php#³•i‘9•¤:phpunit/Event/Value/Test/TestData/DataFromDataProvider.phpÅ#³•iÅöÆ¥¤<phpunit/Event/Value/Test/TestData/DataFromTestDependency.php°#³•i°8åçˤ.phpunit/Event/Value/Test/TestData/TestData.phpÄ#³•iÄ æ·¤8phpunit/Event/Value/Test/TestData/TestDataCollection.php#³•i'¬ ¤@phpunit/Event/Value/Test/TestData/TestDataCollectionIterator.php)#³•i)£ì˜¤$phpunit/Event/Value/Test/TestDox.phpò#³•iòb°oФ+phpunit/Event/Value/Test/TestDoxBuilder.phpÇ#³•iÇRçò^¤'phpunit/Event/Value/Test/TestMethod.php: #³•i: Œ&úe¤.phpunit/Event/Value/Test/TestMethodBuilder.php4 #³•i4 1Á¤+phpunit/Event/Value/TestSuite/TestSuite.php^#³•i^Ó,[Ф2phpunit/Event/Value/TestSuite/TestSuiteBuilder.phpl #³•il •š÷¤7phpunit/Event/Value/TestSuite/TestSuiteForTestClass.php5#³•i5ÞÞmP¤Hphpunit/Event/Value/TestSuite/TestSuiteForTestMethodWithDataProvider.phpÙ#³•iÙ.^¤3phpunit/Event/Value/TestSuite/TestSuiteWithName.phpD#³•iDjW;¤!phpunit/Event/Value/Throwable.php #³•i W¾¼¤(phpunit/Event/Value/ThrowableBuilder.php‹#³•i‹CΓ¤phpunit/Exception.php½#³•i½ÐA-¤phpunit/Framework/Assert.php´V#³•i´VB4½Ê¤&phpunit/Framework/Assert/Functions.php Ï#³•i Ï)6¤&phpunit/Framework/Attributes/After.phpÎ#³•iÎw§¤+phpunit/Framework/Attributes/AfterClass.phpÓ#³•iÓ9Á ±¤Dphpunit/Framework/Attributes/AllowMockObjectsWithoutExpectations.php7#³•i75>%¤.phpunit/Framework/Attributes/BackupGlobals.phpé#³•iém4B·¤7phpunit/Framework/Attributes/BackupStaticProperties.phpò#³•iòy !„¤'phpunit/Framework/Attributes/Before.phpÏ#³•iÏŠNÌ2¤,phpunit/Framework/Attributes/BeforeClass.phpÔ#³•iÔ· Gå¤,phpunit/Framework/Attributes/CoversClass.php„#³•i„T^ù§¤=phpunit/Framework/Attributes/CoversClassesThatExtendClass.php•#³•i•ÚæšŽ¤Dphpunit/Framework/Attributes/CoversClassesThatImplementInterface.php¸#³•i¸£Ã¤/phpunit/Framework/Attributes/CoversFunction.php¨#³•i¨u®ôK¤-phpunit/Framework/Attributes/CoversMethod.phpÅ#³•iÅþ¨So¤0phpunit/Framework/Attributes/CoversNamespace.php”#³•i”wQdʤ.phpunit/Framework/Attributes/CoversNothing.php!#³•i!z3Ф,phpunit/Framework/Attributes/CoversTrait.php„#³•i„ã®¶¤-phpunit/Framework/Attributes/DataProvider.php‘#³•i‘•¾Œ¤5phpunit/Framework/Attributes/DataProviderExternal.phpÆ#³•iÆGÓU¤(phpunit/Framework/Attributes/Depends.php”#³•i”¶6"¤0phpunit/Framework/Attributes/DependsExternal.phpÉ#³•iÉ·¶Q¤>phpunit/Framework/Attributes/DependsExternalUsingDeepClone.php×#³•i׌QU,¤Aphpunit/Framework/Attributes/DependsExternalUsingShallowClone.phpÚ#³•iÚÃuI¤/phpunit/Framework/Attributes/DependsOnClass.phpˆ#³•iˆ£‡Ó¤=phpunit/Framework/Attributes/DependsOnClassUsingDeepClone.php–#³•i–•#kû¤@phpunit/Framework/Attributes/DependsOnClassUsingShallowClone.php™#³•i™fùÕ¤6phpunit/Framework/Attributes/DependsUsingDeepClone.php¢#³•i¢«&…á¤9phpunit/Framework/Attributes/DependsUsingShallowClone.php¥#³•i¥r@P¤Kphpunit/Framework/Attributes/DisableReturnValueGenerationForTestDoubles.php##³•i#Y¿tE¤9phpunit/Framework/Attributes/DoesNotPerformAssertions.php,#³•i,a¡¤@phpunit/Framework/Attributes/ExcludeGlobalVariableFromBackup.phpþ#³•iþ ¡ým¤@phpunit/Framework/Attributes/ExcludeStaticPropertyFromBackup.php#³•i…çðò¤&phpunit/Framework/Attributes/Group.php‚#³•i‚à㟤3phpunit/Framework/Attributes/IgnoreDeprecations.phpË#³•iËç¾ؤ:phpunit/Framework/Attributes/IgnorePhpunitDeprecations.php‰#³•i‰Ç}±ý¤6phpunit/Framework/Attributes/IgnorePhpunitWarnings.php´#³•i´Uܫˤ&phpunit/Framework/Attributes/Large.phpþ#³•iþ¤'phpunit/Framework/Attributes/Medium.phpÿ#³•iÿ`4à¤.phpunit/Framework/Attributes/PostCondition.phpÖ#³•iÖ)[.¤-phpunit/Framework/Attributes/PreCondition.phpÕ#³•iÕ•(y¤4phpunit/Framework/Attributes/PreserveGlobalState.phpï#³•iïrm¿c¤<phpunit/Framework/Attributes/RequiresEnvironmentVariable.php$#³•i$žfX¤1phpunit/Framework/Attributes/RequiresFunction.phpÅ#³•iÅžXê¤/phpunit/Framework/Attributes/RequiresMethod.phpâ#³•iâ0ÐÏš¤8phpunit/Framework/Attributes/RequiresOperatingSystem.phpÔ#³•iÔÑü’Ö¤>phpunit/Framework/Attributes/RequiresOperatingSystemFamily.phpö#³•iöê?Á‡¤,phpunit/Framework/Attributes/RequiresPhp.phpÏ#³•iÏǯo¤5phpunit/Framework/Attributes/RequiresPhpExtension.phpF#³•iF;9°£¤0phpunit/Framework/Attributes/RequiresPhpunit.phpÓ#³•iÓãïc“¤9phpunit/Framework/Attributes/RequiresPhpunitExtension.php#³•irÙ㎤0phpunit/Framework/Attributes/RequiresSetting.phpº#³•iºª_p¿¤5phpunit/Framework/Attributes/RunInSeparateProcess.php#³•iÕ}³¤<phpunit/Framework/Attributes/RunTestsInSeparateProcesses.php#³•iú£Hz¤&phpunit/Framework/Attributes/Small.phpþ#³•iþ˜ ´w¤%phpunit/Framework/Attributes/Test.phpþ#³•iþ77d‹¤(phpunit/Framework/Attributes/TestDox.phpi#³•iiéXL¤1phpunit/Framework/Attributes/TestDoxFormatter.php‚#³•i‚axÇŤ9phpunit/Framework/Attributes/TestDoxFormatterExternal.php·#³•i·EîŤ)phpunit/Framework/Attributes/TestWith.php€#³•i€2Míw¤-phpunit/Framework/Attributes/TestWithJson.php#³•i– á¤'phpunit/Framework/Attributes/Ticket.phpƒ#³•iƒ„,D¤*phpunit/Framework/Attributes/UsesClass.php‚#³•i‚Ä3­¤;phpunit/Framework/Attributes/UsesClassesThatExtendClass.php“#³•i“”<¤Bphpunit/Framework/Attributes/UsesClassesThatImplementInterface.php¶#³•i¶ÿ·¹´¤-phpunit/Framework/Attributes/UsesFunction.php¦#³•i¦=Yï¤+phpunit/Framework/Attributes/UsesMethod.phpÃ#³•iÃ,Ap´¤.phpunit/Framework/Attributes/UsesNamespace.php’#³•i’ξë¤*phpunit/Framework/Attributes/UsesTrait.php‚#³•i‚²4K¼¤8phpunit/Framework/Attributes/WithEnvironmentVariable.phpÅ#³•iÅèÇ£e¤4phpunit/Framework/Attributes/WithoutErrorHandler.php #³•i ñO½¤6phpunit/Framework/Constraint/Array/ArrayComparison.phpŠ#³•iŠr¨L/¤2phpunit/Framework/Constraint/Array/ArrayHasKey.phpy#³•iy8ÓÆ£¤5phpunit/Framework/Constraint/Array/ArraysAreEqual.php#³•iõë÷¤9phpunit/Framework/Constraint/Array/ArraysAreIdentical.phpò#³•iòßÞM¤-phpunit/Framework/Constraint/Array/IsList.phpR#³•iRì!„=¤0phpunit/Framework/Constraint/Boolean/IsFalse.php`#³•i`, µá¤/phpunit/Framework/Constraint/Boolean/IsTrue.php]#³•i]?6þͤ)phpunit/Framework/Constraint/Callback.phpú#³•iú J¢c¤2phpunit/Framework/Constraint/Cardinality/Count.phpY #³•iY º™/¤8phpunit/Framework/Constraint/Cardinality/GreaterThan.php(#³•i( ¥ ¯¤4phpunit/Framework/Constraint/Cardinality/IsEmpty.phpŒ#³•iŒ[c[¤5phpunit/Framework/Constraint/Cardinality/LessThan.php"#³•i"¡°%¤5phpunit/Framework/Constraint/Cardinality/SameSize.phpû#³•iû ™08¤+phpunit/Framework/Constraint/Constraint.php‘##³•i‘#ãn]¤1phpunit/Framework/Constraint/Equality/IsEqual.phpc #³•ic 3ÃÖ¤?phpunit/Framework/Constraint/Equality/IsEqualCanonicalizing.php^ #³•i^ šðY‚¤=phpunit/Framework/Constraint/Equality/IsEqualIgnoringCase.phpd #³•id kîͤ:phpunit/Framework/Constraint/Equality/IsEqualWithDelta.php¸ #³•i¸ ;y6ê¤4phpunit/Framework/Constraint/Exception/Exception.phpé#³•iéX}íÿ¤8phpunit/Framework/Constraint/Exception/ExceptionCode.php0#³•i0~ѤGphpunit/Framework/Constraint/Exception/ExceptionMessageIsOrContains.php$#³•i$x›¤ñ¤Sphpunit/Framework/Constraint/Exception/ExceptionMessageMatchesRegularExpression.php·#³•i·7Ë«F¤;phpunit/Framework/Constraint/Filesystem/DirectoryExists.phpù#³•iù-pˆ¤6phpunit/Framework/Constraint/Filesystem/FileExists.phpô#³•iôÿ+ð÷¤6phpunit/Framework/Constraint/Filesystem/IsReadable.phpô#³•iô“A†¤6phpunit/Framework/Constraint/Filesystem/IsWritable.phpô#³•iôöÆùB¤+phpunit/Framework/Constraint/IsAnything.phpA#³•iAkÒš6¤,phpunit/Framework/Constraint/IsIdentical.phpæ #³•iæ rÚª¤,phpunit/Framework/Constraint/JsonMatches.php #³•i 9~¬8¤.phpunit/Framework/Constraint/Math/IsFinite.phpz#³•izÔŠø¤0phpunit/Framework/Constraint/Math/IsInfinite.php‚#³•i‚íC²¤+phpunit/Framework/Constraint/Math/IsNan.phpn#³•inÇx¤4phpunit/Framework/Constraint/Object/ObjectEquals.phpO#³•iOŽírL¤9phpunit/Framework/Constraint/Object/ObjectHasProperty.phpu#³•iu÷e¥¤8phpunit/Framework/Constraint/Operator/BinaryOperator.php #³•i X‹¤4phpunit/Framework/Constraint/Operator/LogicalAnd.phpY#³•iYÿ‡ý¤4phpunit/Framework/Constraint/Operator/LogicalNot.phpü #³•iü âèRf¤3phpunit/Framework/Constraint/Operator/LogicalOr.php1#³•i1¾ ä¤4phpunit/Framework/Constraint/Operator/LogicalXor.php#³•ix{F¤2phpunit/Framework/Constraint/Operator/Operator.php'#³•i'áJÂ%¤7phpunit/Framework/Constraint/Operator/UnaryOperator.php#³•i5D ¤.phpunit/Framework/Constraint/String/IsJson.phpò #³•iò î–±¤9phpunit/Framework/Constraint/String/RegularExpression.php^#³•i^ŠË¬>¤6phpunit/Framework/Constraint/String/StringContains.php?#³•i?𶩤¤6phpunit/Framework/Constraint/String/StringEndsWith.phpð#³•ið@%õ-¤Mphpunit/Framework/Constraint/String/StringEqualsStringIgnoringLineEndings.php7#³•i7[…J¤Fphpunit/Framework/Constraint/String/StringMatchesFormatDescription.php~#³•i~ðÓ¤8phpunit/Framework/Constraint/String/StringStartsWith.phpø#³•iø™.ÿ¤@phpunit/Framework/Constraint/Traversable/TraversableContains.phpK#³•iK#Ǧ¤Ephpunit/Framework/Constraint/Traversable/TraversableContainsEqual.php!#³•i!×b/¤Iphpunit/Framework/Constraint/Traversable/TraversableContainsIdentical.phpò#³•iòíµÍ#¤Dphpunit/Framework/Constraint/Traversable/TraversableContainsOnly.phpH #³•iH DsÖå¤2phpunit/Framework/Constraint/Type/IsInstanceOf.phpÊ#³•iÊ9 ;>¤,phpunit/Framework/Constraint/Type/IsNull.php\#³•i\a#‡ ¤,phpunit/Framework/Constraint/Type/IsType.phpâ #³•iâ ÃÈÚ°¤+phpunit/Framework/DataProviderTestSuite.php@ #³•i@ E­‹ø¤4phpunit/Framework/Exception/AssertionFailedError.phpþ#³•iþÏ5/¤4phpunit/Framework/Exception/EmptyStringException.phpC#³•iC‹ÖšÍ¤<phpunit/Framework/Exception/ErrorLogNotWritableException.php¹#³•i¹_}¤)phpunit/Framework/Exception/Exception.php› #³•i› ²,Õú¤:phpunit/Framework/Exception/ExpectationFailedException.phpÎ#³•iÎÞ]û»¤>phpunit/Framework/Exception/GeneratorNotSupportedException.php:#³•i:™ j{¤9phpunit/Framework/Exception/Incomplete/IncompleteTest.php,#³•i,_Kª¤>phpunit/Framework/Exception/Incomplete/IncompleteTestError.phpk#³•ik÷›øè¤8phpunit/Framework/Exception/InvalidArgumentException.php;#³•i;÷ñ‹)¤<phpunit/Framework/Exception/InvalidDataProviderException.phpÉ#³•iÉ¥¾ '¤:phpunit/Framework/Exception/InvalidDependencyException.phpo#³•ioi¾Ôí¤9phpunit/Framework/Exception/NoChildTestSuiteException.php9#³•i94´Ý¤Nphpunit/Framework/Exception/ObjectEquals/ActualValueIsNotAnObjectException.php­#³•i­·òW÷¤`phpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotAcceptParameterTypeException.phpW#³•iWŒ‹–½¤bphpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php>#³•i>{ý–¤gphpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareExactlyOneParameterException.phpH#³•iH°t ²¤aphpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareParameterTypeException.phpF#³•iFñ †9¤Rphpunit/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotExistException.php#³•iÝ/]¤8phpunit/Framework/Exception/PhptAssertionFailedError.phpÃ#³•iÃèèy¤9phpunit/Framework/Exception/ProcessIsolationException.php9#³•i9,ÿä3phpunit/Framework/Exception/Skipped/SkippedTest.php)#³•i)Àó¤=phpunit/Framework/Exception/Skipped/SkippedTestSuiteError.phpj#³•ijwÜŠ¤Cphpunit/Framework/Exception/Skipped/SkippedWithMessageException.phpp#³•ipX&º>¤@phpunit/Framework/Exception/UnknownClassOrInterfaceException.phpö#³•iöH nw¤:phpunit/Framework/Exception/UnknownNativeTypeException.phpç#³•içœ%]¤.phpunit/Framework/ExecutionOrderDependency.php#³•iëלð¤3phpunit/Framework/MockObject/ConfigurableMethod.phpï#³•iïÌ^ÉP¤Aphpunit/Framework/MockObject/Exception/BadMethodCallException.phpo#³•ioäÛ!¤Hphpunit/Framework/MockObject/Exception/CannotUseOnlyMethodsException.phpt#³•it™¬ ¤4phpunit/Framework/MockObject/Exception/Exception.php,#³•i,÷Rœ?¤Kphpunit/Framework/MockObject/Exception/IncompatibleReturnValueException.phpå#³•iå2íK]¤Hphpunit/Framework/MockObject/Exception/MatchBuilderNotFoundException.php.#³•i.ú¤´a¤Lphpunit/Framework/MockObject/Exception/MatcherAlreadyRegisteredException.php&#³•i&æÝLphpunit/Framework/MockObject/Exception/MethodCannotBeConfiguredException.phpˆ#³•iˆ7À„3¤Ophpunit/Framework/MockObject/Exception/MethodNameAlreadyConfiguredException.phpò#³•iò<Ú¬>¤Kphpunit/Framework/MockObject/Exception/MethodNameNotConfiguredException.phpê#³•iêªYi¤Uphpunit/Framework/MockObject/Exception/MethodParametersAlreadyConfiguredException.phpû#³•iû¥s¤Hphpunit/Framework/MockObject/Exception/NeverReturningMethodException.phpe#³•ie]M6…¤Qphpunit/Framework/MockObject/Exception/NoMoreParameterSetsConfiguredException.phpò#³•iò°C½Ì¤Pphpunit/Framework/MockObject/Exception/NoMoreReturnValuesConfiguredException.php×#³•i×H]²ò¤Lphpunit/Framework/MockObject/Exception/ReturnValueNotConfiguredException.php¨#³•i¨2’×V¤;phpunit/Framework/MockObject/Exception/RuntimeException.phpc#³•icõ€= ¤Dphpunit/Framework/MockObject/Exception/TestDoubleSealedException.php#³•imy®¤7phpunit/Framework/MockObject/Generator/DoubledClass.php#³•i8¢Àó¤8phpunit/Framework/MockObject/Generator/DoubledMethod.php~)#³•i~)Ò'W±¤;phpunit/Framework/MockObject/Generator/DoubledMethodSet.phpÚ#³•iÚ#0¤Pphpunit/Framework/MockObject/Generator/Exception/ClassIsEnumerationException.phpJ#³•iJ `@ ¤Jphpunit/Framework/MockObject/Generator/Exception/ClassIsFinalException.phpF#³•iFÔƒ¤Mphpunit/Framework/MockObject/Generator/Exception/DuplicateMethodException.phpF#³•iFÂAé¤>phpunit/Framework/MockObject/Generator/Exception/Exception.phpn#³•in½q~•¤Ophpunit/Framework/MockObject/Generator/Exception/InvalidMethodNameException.php<#³•i<×ÓªÙ¤Ophpunit/Framework/MockObject/Generator/Exception/MethodNamedMethodException.phpÃ#³•iÃW²6¶¤Nphpunit/Framework/MockObject/Generator/Exception/NameAlreadyInUseException.phpi#³•iiØ´¤Hphpunit/Framework/MockObject/Generator/Exception/ReflectionException.php…#³•i…"è¤Ephpunit/Framework/MockObject/Generator/Exception/RuntimeException.php‚#³•i‚„Ãø¤Nphpunit/Framework/MockObject/Generator/Exception/UnknownInterfaceException.php;#³•i;¹:yá¤Iphpunit/Framework/MockObject/Generator/Exception/UnknownTypeException.php-#³•i-¨‰V¤4phpunit/Framework/MockObject/Generator/Generator.phpŒb#³•iŒbCCå¤9phpunit/Framework/MockObject/Generator/HookedProperty.php #³•i Ú ¤Bphpunit/Framework/MockObject/Generator/HookedPropertyGenerator.phpI#³•iIσt¤9phpunit/Framework/MockObject/Generator/TemplateLoader.phpÙ#³•iÙˆHU!¤@phpunit/Framework/MockObject/Generator/templates/deprecation.tpl;#³•i;O5øs¤Cphpunit/Framework/MockObject/Generator/templates/doubled_method.tplC#³•iC¡÷Mé¤Jphpunit/Framework/MockObject/Generator/templates/doubled_static_method.tplî#³•iî 4éR¤Aphpunit/Framework/MockObject/Generator/templates/intersection.tplL#³•iL®Ž-X¤Fphpunit/Framework/MockObject/Generator/templates/test_double_class.tpl[#³•i[üj½Ð¤,phpunit/Framework/MockObject/MockBuilder.php" #³•i" (ʳ¤Iphpunit/Framework/MockObject/Runtime/AbstractInvocationImplementation.php¹"#³•i¹"{j¤?phpunit/Framework/MockObject/Runtime/Api/DoubledCloneMethod.php#³•i¥•J%¤3phpunit/Framework/MockObject/Runtime/Api/Method.php)#³•i)ü Šž¤:phpunit/Framework/MockObject/Runtime/Api/MockObjectApi.php?#³•i?á$rÕ¤?phpunit/Framework/MockObject/Runtime/Api/ProxiedCloneMethod.php7#³•i7‰˜Â˜¤4phpunit/Framework/MockObject/Runtime/Api/StubApi.php`#³•i`×±@¬¤<phpunit/Framework/MockObject/Runtime/Api/TestDoubleState.php}#³•i}læ¤Cphpunit/Framework/MockObject/Runtime/Interface/InvocationMocker.php]#³•i]~™þ¤Dphpunit/Framework/MockObject/Runtime/Interface/InvocationStubber.php #³•i h›„O¤=phpunit/Framework/MockObject/Runtime/Interface/MockObject.php‚#³•i‚…6¨A¤Ephpunit/Framework/MockObject/Runtime/Interface/MockObjectInternal.php?#³•i?ŠU@6¤7phpunit/Framework/MockObject/Runtime/Interface/Stub.php‰#³•i‰cvã ¤?phpunit/Framework/MockObject/Runtime/Interface/StubInternal.php9#³•i9 {Æå¤3phpunit/Framework/MockObject/Runtime/Invocation.phpQ #³•iQ ¤€~º¤:phpunit/Framework/MockObject/Runtime/InvocationHandler.phpI#³•iI_s‹¬¤Gphpunit/Framework/MockObject/Runtime/InvocationMockerImplementation.phpw #³•iw Oi¤Hphpunit/Framework/MockObject/Runtime/InvocationStubberImplementation.php§#³•i§’Óü¤0phpunit/Framework/MockObject/Runtime/Matcher.phpÿ#³•iÿ³]«¤=phpunit/Framework/MockObject/Runtime/MethodNameConstraint.php#³•iý/ ƒ¤Ephpunit/Framework/MockObject/Runtime/PropertyHook/PropertyGetHook.php#³•i»Æ6̤Bphpunit/Framework/MockObject/Runtime/PropertyHook/PropertyHook.php5#³•i5NE5Ò¤Ephpunit/Framework/MockObject/Runtime/PropertyHook/PropertySetHook.php#³•i`²>n¤=phpunit/Framework/MockObject/Runtime/ReturnValueGenerator.phpÏ#³•iÏ×í¦ ¤=phpunit/Framework/MockObject/Runtime/Rule/AnyInvokedCount.phpƒ#³•iƒ/d²k¤;phpunit/Framework/MockObject/Runtime/Rule/AnyParameters.php/#³•i/ÿpv¤=phpunit/Framework/MockObject/Runtime/Rule/InvocationOrder.php7#³•i7=€Ä˜¤Aphpunit/Framework/MockObject/Runtime/Rule/InvokedAtLeastCount.php*#³•i*䙆³¤@phpunit/Framework/MockObject/Runtime/Rule/InvokedAtLeastOnce.phpG#³•iGãfËs¤@phpunit/Framework/MockObject/Runtime/Rule/InvokedAtMostCount.php#³•iyÃIޤ:phpunit/Framework/MockObject/Runtime/Rule/InvokedCount.phpÁ #³•iÁ  I¤8phpunit/Framework/MockObject/Runtime/Rule/MethodName.php{#³•i{>Êh¤Bphpunit/Framework/MockObject/Runtime/Rule/OrderedParameterSets.phpH #³•iH ;ã÷¤8phpunit/Framework/MockObject/Runtime/Rule/Parameters.php¯#³•i¯ï)NÁ¤<phpunit/Framework/MockObject/Runtime/Rule/ParametersRule.phpë#³•iëv®Y¤Dphpunit/Framework/MockObject/Runtime/Rule/UnorderedParameterSets.php" #³•i" ¬dýï¤>phpunit/Framework/MockObject/Runtime/Stub/ConsecutiveCalls.php #³•i ËdRY¤7phpunit/Framework/MockObject/Runtime/Stub/Exception.php¦#³•i¦áëK¶¤<phpunit/Framework/MockObject/Runtime/Stub/ReturnArgument.phpŸ#³•iŸrjc¤<phpunit/Framework/MockObject/Runtime/Stub/ReturnCallback.phpÔ#³•iÔ2à¶Q¤=phpunit/Framework/MockObject/Runtime/Stub/ReturnReference.phpf#³•if¦ÿ¬Ó¤8phpunit/Framework/MockObject/Runtime/Stub/ReturnSelf.phpE#³•iE“”DѤ8phpunit/Framework/MockObject/Runtime/Stub/ReturnStub.phpT#³•iTå{ÈŠ¤<phpunit/Framework/MockObject/Runtime/Stub/ReturnValueMap.phpl#³•il$}S¤2phpunit/Framework/MockObject/Runtime/Stub/Stub.phpé#³•iéŽÓ±Ê¤2phpunit/Framework/MockObject/TestDoubleBuilder.php¢#³•i¢âH-d¤0phpunit/Framework/MockObject/TestStubBuilder.phpª#³•iª‚B<\¤ phpunit/Framework/NativeType.php&#³•i&|Ñgç¤!phpunit/Framework/Reorderable.phpø#³•iø€¶çö¤$phpunit/Framework/SelfDescribing.phpy#³•iy;Å;¤phpunit/Framework/Test.phpã#³•iã­ñ9¤!phpunit/Framework/TestBuilder.php )#³•i )„v”¤phpunit/Framework/TestCase.php2'#³•i2'¡i_¤<phpunit/Framework/TestRunner/ChildProcessResultProcessor.php8 #³•i8 =¾;ì¤3phpunit/Framework/TestRunner/IsolatedTestRunner.php‚#³•i‚Ú×í¤;phpunit/Framework/TestRunner/IsolatedTestRunnerRegistry.php/#³•i/˜¥Ú¤:phpunit/Framework/TestRunner/SeparateProcessTestRunner.phpà#³•ià'gĤ+phpunit/Framework/TestRunner/TestRunner.phpÕ,#³•iÕ,DŸ]Á¤1phpunit/Framework/TestRunner/templates/method.tplŠ#³•iŠ:àÏb¤$phpunit/Framework/TestSize/Known.phpØ#³•iد½R¤$phpunit/Framework/TestSize/Large.phpb#³•ib;qç¤%phpunit/Framework/TestSize/Medium.phpd#³•idTA¦Ñ¤$phpunit/Framework/TestSize/Small.phpV#³•iVX♤'phpunit/Framework/TestSize/TestSize.php¤#³•i¤ÅìHѤ&phpunit/Framework/TestSize/Unknown.phpç#³•içfÚœ¤,phpunit/Framework/TestStatus/Deprecation.php3#³•i3‡mÐ|¤&phpunit/Framework/TestStatus/Error.php!#³•i!ÊXP>¤(phpunit/Framework/TestStatus/Failure.php'#³•i'µgö%¤+phpunit/Framework/TestStatus/Incomplete.php0#³•i0Üqöq¤&phpunit/Framework/TestStatus/Known.phpŸ#³•iŸ‘–¤'phpunit/Framework/TestStatus/Notice.php$#³•i$«¥!H¤&phpunit/Framework/TestStatus/Risky.php!#³•i!t E¤(phpunit/Framework/TestStatus/Skipped.php'#³•i'Ž<¤(phpunit/Framework/TestStatus/Success.php'#³•i'Þa&¥¤+phpunit/Framework/TestStatus/TestStatus.phpÀ#³•iÀ+ u¤(phpunit/Framework/TestStatus/Unknown.php-#³•i-FuXN¤(phpunit/Framework/TestStatus/Warning.php'#³•i'Ž=â¤phpunit/Framework/TestSuite.phpK#³•iK‰O·j¤'phpunit/Framework/TestSuiteIterator.phpç#³•iç%Nî¤phpunit/Logging/EventLogger.phpI#³•iIcïµ¾¤(phpunit/Logging/JUnit/JunitXmlLogger.php¹1#³•i¹1µÿW¤/phpunit/Logging/JUnit/Subscriber/Subscriber.php=#³•i=ôýxÛ¤:phpunit/Logging/JUnit/Subscriber/TestErroredSubscriber.php}#³•i}£Šá¤9phpunit/Logging/JUnit/Subscriber/TestFailedSubscriber.phpw#³•iw†€¤;phpunit/Logging/JUnit/Subscriber/TestFinishedSubscriber.phpƒ#³•iƒ"^—¤Cphpunit/Logging/JUnit/Subscriber/TestMarkedIncompleteSubscriber.php³#³•i³5ÝTY¤Ephpunit/Logging/JUnit/Subscriber/TestPreparationErroredSubscriber.php¹#³•i¹ñDy‰¤Dphpunit/Logging/JUnit/Subscriber/TestPreparationFailedSubscriber.php³#³•i³ºÉ£Å¤Ephpunit/Logging/JUnit/Subscriber/TestPreparationStartedSubscriber.php¿#³•i¿$†‘2¤;phpunit/Logging/JUnit/Subscriber/TestPreparedSubscriber.php}#³•i}ñý»‡¤Jphpunit/Logging/JUnit/Subscriber/TestPrintedUnexpectedOutputSubscriber.phpy#³•iy÷Öú¤Jphpunit/Logging/JUnit/Subscriber/TestRunnerExecutionFinishedSubscriber.phpQ#³•iQ2õ÷÷¤:phpunit/Logging/JUnit/Subscriber/TestSkippedSubscriber.php}#³•i}¿I©¤@phpunit/Logging/JUnit/Subscriber/TestSuiteFinishedSubscriber.php-#³•i- Cö¶¤?phpunit/Logging/JUnit/Subscriber/TestSuiteStartedSubscriber.php-#³•i-}‰£€¤Pphpunit/Logging/OpenTestReporting/Exception/CannotOpenUriForWritingException.phpÅ#³•iÅΗip¤9phpunit/Logging/OpenTestReporting/Exception/Exception.php`#³•i`Tç>i¤Gphpunit/Logging/OpenTestReporting/InfrastructureInformationProvider.phph#³•ihJ>¤2phpunit/Logging/OpenTestReporting/OtrXmlLogger.phpß>#³•iß>á¡ ³¤,phpunit/Logging/OpenTestReporting/Status.php³#³•i³|Ü"£¤Uphpunit/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodErroredSubscriber.php,#³•i,wÖ¤Tphpunit/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodFailedSubscriber.php%#³•i%ë£õ¤Wphpunit/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodErroredSubscriber.php8#³•i8–£¤Vphpunit/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodFailedSubscriber.php1#³•i1r¤™¤;phpunit/Logging/OpenTestReporting/Subscriber/Subscriber.phpg#³•ig†€!{¤Fphpunit/Logging/OpenTestReporting/Subscriber/TestAbortedSubscriber.phpÀ#³•iÀþsE¤Fphpunit/Logging/OpenTestReporting/Subscriber/TestErroredSubscriber.php•#³•i•RO(¤Ephpunit/Logging/OpenTestReporting/Subscriber/TestFailedSubscriber.php#³•i#ݤGphpunit/Logging/OpenTestReporting/Subscriber/TestFinishedSubscriber.php•#³•i•Hœ¤Qphpunit/Logging/OpenTestReporting/Subscriber/TestPreparationErroredSubscriber.phpÍ#³•iͦ£Ø¾¤Pphpunit/Logging/OpenTestReporting/Subscriber/TestPreparationFailedSubscriber.phpÈ#³•iÈu„µ¤Gphpunit/Logging/OpenTestReporting/Subscriber/TestPreparedSubscriber.php›#³•i›ÙÁ7²¤Mphpunit/Logging/OpenTestReporting/Subscriber/TestRunnerFinishedSubscriber.phpÑ#³•iÑùów…¤Lphpunit/Logging/OpenTestReporting/Subscriber/TestRunnerStartedSubscriber.php©#³•i©Òy¡Æ¤Fphpunit/Logging/OpenTestReporting/Subscriber/TestSkippedSubscriber.php•#³•i•iÏIr¤Lphpunit/Logging/OpenTestReporting/Subscriber/TestSuiteFinishedSubscriber.php©#³•i©¡ÐɤKphpunit/Logging/OpenTestReporting/Subscriber/TestSuiteSkippedSubscriber.php©#³•i©@*E¤Kphpunit/Logging/OpenTestReporting/Subscriber/TestSuiteStartedSubscriber.php©#³•i©­E@p¤2phpunit/Logging/TeamCity/Subscriber/Subscriber.phpI#³•iIŒt¶“¤Ephpunit/Logging/TeamCity/Subscriber/TestConsideredRiskySubscriber.php³#³•i³åÎF¤=phpunit/Logging/TeamCity/Subscriber/TestErroredSubscriber.phpƒ#³•iƒ¯y»ˆ¤<phpunit/Logging/TeamCity/Subscriber/TestFailedSubscriber.php}#³•i}°ôå¤>phpunit/Logging/TeamCity/Subscriber/TestFinishedSubscriber.php‰#³•i‰ÍT¸›¤Fphpunit/Logging/TeamCity/Subscriber/TestMarkedIncompleteSubscriber.php¹#³•i¹¾T»b¤>phpunit/Logging/TeamCity/Subscriber/TestPreparedSubscriber.php%#³•i%ÿ`c+¤Mphpunit/Logging/TeamCity/Subscriber/TestRunnerExecutionFinishedSubscriber.phpW#³•iWã)Ê®¤=phpunit/Logging/TeamCity/Subscriber/TestSkippedSubscriber.phpƒ#³•iƒÁNÇH¤Wphpunit/Logging/TeamCity/Subscriber/TestSuiteBeforeFirstTestMethodErroredSubscriber.php#³•iïʹj¤Cphpunit/Logging/TeamCity/Subscriber/TestSuiteFinishedSubscriber.php9#³•i9¬(s³¤Bphpunit/Logging/TeamCity/Subscriber/TestSuiteSkippedSubscriber.php—#³•i—5²B;¤Bphpunit/Logging/TeamCity/Subscriber/TestSuiteStartedSubscriber.php3#³•i3±Ò“¤+phpunit/Logging/TeamCity/TeamCityLogger.php’*#³•i’**é]4¤(phpunit/Logging/TestDox/HtmlRenderer.php· #³•i· ¹O!‘¤*phpunit/Logging/TestDox/NamePrettifier.php/0#³•i/0t[õ¤-phpunit/Logging/TestDox/PlainTextRenderer.php„#³•i„NÅô¤<phpunit/Logging/TestDox/TestResult/Subscriber/Subscriber.phpf#³•if7kC¤Ophpunit/Logging/TestDox/TestResult/Subscriber/TestConsideredRiskySubscriber.phpP#³•iP»J'ž¤Gphpunit/Logging/TestDox/TestResult/Subscriber/TestErroredSubscriber.php #³•i t8¤Fphpunit/Logging/TestDox/TestResult/Subscriber/TestFailedSubscriber.php#³•iñä;À¤Hphpunit/Logging/TestDox/TestResult/Subscriber/TestFinishedSubscriber.phpŠ#³•iŠMÉ~£¤Pphpunit/Logging/TestDox/TestResult/Subscriber/TestMarkedIncompleteSubscriber.phpV#³•iV]ùó¤Fphpunit/Logging/TestDox/TestResult/Subscriber/TestPassedSubscriber.php#³•iÔBº¤Hphpunit/Logging/TestDox/TestResult/Subscriber/TestPreparedSubscriber.php&#³•i&ÚÈé¤Gphpunit/Logging/TestDox/TestResult/Subscriber/TestSkippedSubscriber.php #³•i ´Õj¤Tphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.phpn#³•inQ¤Ophpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredNoticeSubscriber.phpP#³•iP°ÔÃ)¤Wphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php€#³•i€˜]¤Rphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.phpb#³•ibae¤Sphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.phph#³•ih¢QF¤[phpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php˜#³•i˜^õ¤Uphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.phpt#³•it‘Gâ°¤Wphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php€#³•i€îk½<¤Pphpunit/Logging/TestDox/TestResult/Subscriber/TestTriggeredWarningSubscriber.phpV#³•iVxÝB\¤1phpunit/Logging/TestDox/TestResult/TestResult.phpf#³•if阵 ¤;phpunit/Logging/TestDox/TestResult/TestResultCollection.phps#³•is¹Ì¤Cphpunit/Logging/TestDox/TestResult/TestResultCollectionIterator.php¼#³•i¼'4%~¤:phpunit/Logging/TestDox/TestResult/TestResultCollector.phpÓ)#³•iÓ)<[Qì¤phpunit/Metadata/After.php9#³•i9àwÀ¤phpunit/Metadata/AfterClass.phpC#³•iCU÷¤8phpunit/Metadata/AllowMockObjectsWithoutExpectations.phpb#³•ibI)¨¤%phpunit/Metadata/Api/CodeCoverage.phpÑ#³•iÑß;ñý¤%phpunit/Metadata/Api/DataProvider.php (#³•i (<Þé8¤%phpunit/Metadata/Api/Dependencies.php†#³•i†Š6Á¾¤phpunit/Metadata/Api/Groups.phpJ#³•iJ%“PU¤$phpunit/Metadata/Api/HookMethods.php#³•iÙE¤%phpunit/Metadata/Api/ProvidedData.phpû#³•iûO „®¤%phpunit/Metadata/Api/Requirements.phpÇ#³•iǹý†º¤"phpunit/Metadata/BackupGlobals.phpF#³•iF´r0õ¤+phpunit/Metadata/BackupStaticProperties.phpX#³•iXX\½w¤phpunit/Metadata/Before.php;#³•i;®‘Y¦¤ phpunit/Metadata/BeforeClass.phpE#³•iE{‰¸¤ phpunit/Metadata/CoversClass.phpß#³•ißš0 ¤1phpunit/Metadata/CoversClassesThatExtendClass.php#³•i@bã¤8phpunit/Metadata/CoversClassesThatImplementInterface.php+#³•i+}¡¯¤#phpunit/Metadata/CoversFunction.php#³•i‹&7¤!phpunit/Metadata/CoversMethod.php!#³•i!³Â8¶¤$phpunit/Metadata/CoversNamespace.phpó#³•ióX‘»»¤"phpunit/Metadata/CoversNothing.php6#³•i6I¥Õ¤ phpunit/Metadata/CoversTrait.phpß#³•iß“³’¤!phpunit/Metadata/DataProvider.php#³•iú®#‡¤#phpunit/Metadata/DependsOnClass.phpG#³•iGASáH¤$phpunit/Metadata/DependsOnMethod.php‰#³•i‰B.T†¤?phpunit/Metadata/DisableReturnValueGenerationForTestDoubles.phpp#³•ip‘ ¤-phpunit/Metadata/DoesNotPerformAssertions.phpL#³•iL{¯T¤(phpunit/Metadata/Exception/Exception.phpÀ#³•iÀälñ¤8phpunit/Metadata/Exception/InvalidAttributeException.phpw#³•iwÒo‡¤Aphpunit/Metadata/Exception/InvalidVersionRequirementException.php#³•i-µ[D¤<phpunit/Metadata/Exception/NoVersionRequirementException.php#³•igÌ®¤4phpunit/Metadata/ExcludeGlobalVariableFromBackup.phpR#³•iR)§™[¤4phpunit/Metadata/ExcludeStaticPropertyFromBackup.phpU#³•iU„Ø£¤phpunit/Metadata/Group.phpß#³•ißï 4i¤'phpunit/Metadata/IgnoreDeprecations.php&#³•i&ˆ†!F¤.phpunit/Metadata/IgnorePhpunitDeprecations.phpª#³•iª(\¤*phpunit/Metadata/IgnorePhpunitWarnings.php,#³•i,ßÎo¤phpunit/Metadata/Level.php¿#³•i¿8VB¤phpunit/Metadata/Metadata.php%y#³•i%yã ¡ð¤'phpunit/Metadata/MetadataCollection.php=7#³•i=7½Ìã¤/phpunit/Metadata/MetadataCollectionIterator.php/#³•i/2¸†Ž¤+phpunit/Metadata/Parser/AttributeParser.php ‡#³•i ‡úHV¤)phpunit/Metadata/Parser/CachingParser.php¯ #³•i¯ ®t¤"phpunit/Metadata/Parser/Parser.php3#³•i3dÝË$¤$phpunit/Metadata/Parser/Registry.php#³•iç˜wR¤"phpunit/Metadata/PostCondition.phpI#³•iIù¤sG¤!phpunit/Metadata/PreCondition.phpG#³•iG†&›È¤(phpunit/Metadata/PreserveGlobalState.phpR#³•iR-¶Ü˜¤0phpunit/Metadata/RequiresEnvironmentVariable.phpm#³•im¼A&Ò¤%phpunit/Metadata/RequiresFunction.php #³•i õ |^¤#phpunit/Metadata/RequiresMethod.php%#³•i%V¢´¤,phpunit/Metadata/RequiresOperatingSystem.php-#³•i-¥_ã¤2phpunit/Metadata/RequiresOperatingSystemFamily.phpc#³•icµÏ§H¤ phpunit/Metadata/RequiresPhp.phpÃ#³•ià ã~P¤)phpunit/Metadata/RequiresPhpExtension.phpž#³•ižÝ7ùJ¤$phpunit/Metadata/RequiresPhpunit.phpË#³•iËo_³¤-phpunit/Metadata/RequiresPhpunitExtension.phpe#³•ieŒÒ-ž¤$phpunit/Metadata/RequiresSetting.phpþ#³•iþÇ£lú¤)phpunit/Metadata/RunInSeparateProcess.phpD#³•iDÿŸi‹¤0phpunit/Metadata/RunTestsInSeparateProcesses.phpR#³•iRYß­s¤phpunit/Metadata/Test.php$#³•i$1Ñ¡¤phpunit/Metadata/TestDox.phpÀ#³•iÀW½*¤%phpunit/Metadata/TestDoxFormatter.php)#³•i)v߃¤phpunit/Metadata/TestWith.phpò#³•iòÀNñ¤phpunit/Metadata/UsesClass.phpÛ#³•iÛB3Ô¤/phpunit/Metadata/UsesClassesThatExtendClass.phpý#³•iý§ZlI¤6phpunit/Metadata/UsesClassesThatImplementInterface.php'#³•i'ð,¤!phpunit/Metadata/UsesFunction.php#³•iB€h‹¤phpunit/Metadata/UsesMethod.php#³•iê¤"phpunit/Metadata/UsesNamespace.phpë#³•ië^öo¤phpunit/Metadata/UsesTrait.phpÛ#³•iÛr@AĤ2phpunit/Metadata/Version/ComparisonRequirement.phpW#³•iWìÈ–?¤2phpunit/Metadata/Version/ConstraintRequirement.phpž#³•iž^.8¤(phpunit/Metadata/Version/Requirement.phpþ#³•iþ¢âI¿¤,phpunit/Metadata/WithEnvironmentVariable.php #³•i .zu¤(phpunit/Metadata/WithoutErrorHandler.phpB#³•iB%€W­¤.phpunit/Runner/BackedUpEnvironmentVariable.php«#³•i«Ô#{°¤$phpunit/Runner/Baseline/Baseline.phpg#³•igQá<¤Aphpunit/Runner/Baseline/Exception/CannotLoadBaselineException.php~#³•i~=)Sb¤Bphpunit/Runner/Baseline/Exception/CannotWriteBaselineException.php#³•i¶ 4ɤBphpunit/Runner/Baseline/Exception/FileDoesNotHaveLineException.php1#³•i1ü3€¤%phpunit/Runner/Baseline/Generator.phpñ#³•iñ–öÖ¤!phpunit/Runner/Baseline/Issue.php) #³•i) Û<ɤ"phpunit/Runner/Baseline/Reader.phpÖ #³•iÖ ´ÿÀ{¤2phpunit/Runner/Baseline/RelativePathCalculator.phpÎ #³•iÎ íËe¥¤1phpunit/Runner/Baseline/Subscriber/Subscriber.phpH#³•iHÐ43¤Iphpunit/Runner/Baseline/Subscriber/TestTriggeredDeprecationSubscriber.phpû#³•iûü_E¤Dphpunit/Runner/Baseline/Subscriber/TestTriggeredNoticeSubscriber.phpâ#³•iâjâĤLphpunit/Runner/Baseline/Subscriber/TestTriggeredPhpDeprecationSubscriber.php #³•i Âk°±¤Gphpunit/Runner/Baseline/Subscriber/TestTriggeredPhpNoticeSubscriber.phpñ#³•iñÒîL¤Hphpunit/Runner/Baseline/Subscriber/TestTriggeredPhpWarningSubscriber.phpö#³•iö´MФEphpunit/Runner/Baseline/Subscriber/TestTriggeredWarningSubscriber.phpç#³•içàQ̽¤"phpunit/Runner/Baseline/Writer.phpj #³•ij öý†q¤phpunit/Runner/CodeCoverage.php®=#³•i®=9·ûy¤3phpunit/Runner/CodeCoverageInitializationStatus.phpT#³•iT‰52q¤1phpunit/Runner/DeprecationCollector/Collector.phpZ#³•iZì–c¤.phpunit/Runner/DeprecationCollector/Facade.phpô#³•iô&¨ I¤<phpunit/Runner/DeprecationCollector/InIsolationCollector.php"#³•i"óß}Ȥ=phpunit/Runner/DeprecationCollector/Subscriber/Subscriber.php&#³•i&˜¬\¤Iphpunit/Runner/DeprecationCollector/Subscriber/TestPreparedSubscriber.php/#³•i/Kd€I¤Uphpunit/Runner/DeprecationCollector/Subscriber/TestTriggeredDeprecationSubscriber.php}#³•i}Yò¤phpunit/Runner/ErrorHandler.phpR;#³•iR; f±d¤8phpunit/Runner/Exception/ClassCannotBeFoundException.php%#³•i%uëX¤@phpunit/Runner/Exception/ClassDoesNotExtendTestCaseException.phpQ#³•iQκYÀ¤5phpunit/Runner/Exception/ClassIsAbstractException.php'#³•i'ƒìT¤<phpunit/Runner/Exception/CodeCoverageFileExistsException.phpk#³•ik ƒÙŸ¤;phpunit/Runner/Exception/DirectoryDoesNotExistException.php+#³•i+EH¾-¤+phpunit/Runner/Exception/ErrorException.phpD#³•iDi}Ť&phpunit/Runner/Exception/Exception.php#³•iúYŠK¤6phpunit/Runner/Exception/FileDoesNotExistException.phpþ#³•iþdfH!¤2phpunit/Runner/Exception/InvalidOrderException.phpa#³•ia[Èt%¤;phpunit/Runner/Exception/ParameterDoesNotExistException.php#³•iZ­Ÿh¤&phpunit/Runner/Extension/Extension.php…#³•i…sƲ¤2phpunit/Runner/Extension/ExtensionBootstrapper.phpá #³•iá .îÑL¤#phpunit/Runner/Extension/Facade.php‘ #³•i‘ ÇŒ ¤0phpunit/Runner/Extension/ParameterCollection.phpL#³•iLpýñ(¤'phpunit/Runner/Extension/PharLoader.php#³•i¢Ã†s¤4phpunit/Runner/Filter/ExcludeGroupFilterIterator.phpQ#³•iQúFßݤ3phpunit/Runner/Filter/ExcludeNameFilterIterator.php£#³•i£BêÕ¤!phpunit/Runner/Filter/Factory.phpõ #³•iõ Ä1 ¤-phpunit/Runner/Filter/GroupFilterIterator.php#³•iÜßu¤1phpunit/Runner/ResultCache/DefaultResultCache.phpø#³•iø¸ј¤.phpunit/Runner/ResultCache/NullResultCache.php«#³•i«ÿMޤ*phpunit/Runner/ResultCache/ResultCache.phpó#³•ióM¸˜¤1phpunit/Runner/ResultCache/ResultCacheHandler.php$#³•i$®yù…¤,phpunit/Runner/ResultCache/ResultCacheId.php¢#³•i¢,㶤4phpunit/Runner/ResultCache/Subscriber/Subscriber.phpc#³•ic·Ëž¤Gphpunit/Runner/ResultCache/Subscriber/TestConsideredRiskySubscriber.phpT#³•iT­_€¤?phpunit/Runner/ResultCache/Subscriber/TestErroredSubscriber.php$#³•i$“ݘΤ>phpunit/Runner/ResultCache/Subscriber/TestFailedSubscriber.php#³•iÜú…†¤@phpunit/Runner/ResultCache/Subscriber/TestFinishedSubscriber.phpÉ#³•iÉíÎg¤Hphpunit/Runner/ResultCache/Subscriber/TestMarkedIncompleteSubscriber.phpZ#³•iZŸÞ¦v¤@phpunit/Runner/ResultCache/Subscriber/TestPreparedSubscriber.php*#³•i*yѤ?phpunit/Runner/ResultCache/Subscriber/TestSkippedSubscriber.phpÃ#³•iÃà.“ͤEphpunit/Runner/ResultCache/Subscriber/TestSuiteFinishedSubscriber.php8#³•i8Ê×/ý¤Dphpunit/Runner/ResultCache/Subscriber/TestSuiteStartedSubscriber.php2#³•i2ª/ªÂ¤"phpunit/Runner/ShutdownHandler.phpc#³•ic©Çeߤ'phpunit/Runner/TestResult/Collector.php¿L#³•i¿L\L¤$phpunit/Runner/TestResult/Facade.php¼ #³•i¼ U„ûM¤#phpunit/Runner/TestResult/Issue.phpà #³•ià „9×=¤)phpunit/Runner/TestResult/PassedTests.phpÏ #³•iÏ Ì 8¤Nphpunit/Runner/TestResult/Subscriber/AfterTestClassMethodErroredSubscriber.php˜#³•i˜8)xº¤Mphpunit/Runner/TestResult/Subscriber/AfterTestClassMethodFailedSubscriber.php’#³•i’-ÀQR¤Ophpunit/Runner/TestResult/Subscriber/BeforeTestClassMethodErroredSubscriber.php¢#³•i¢U½E2¤Nphpunit/Runner/TestResult/Subscriber/BeforeTestClassMethodFailedSubscriber.phpœ#³•iœ[Æ=„¤Fphpunit/Runner/TestResult/Subscriber/ChildProcessErroredSubscriber.phpV#³•iV-4g­¤Cphpunit/Runner/TestResult/Subscriber/ExecutionStartedSubscriber.php˜#³•i˜XUÕ¤3phpunit/Runner/TestResult/Subscriber/Subscriber.php`#³•i`T¹1{¤Fphpunit/Runner/TestResult/Subscriber/TestConsideredRiskySubscriber.php\#³•i\-ï½4¤>phpunit/Runner/TestResult/Subscriber/TestErroredSubscriber.php,#³•i,ÿ;¦Ô¤=phpunit/Runner/TestResult/Subscriber/TestFailedSubscriber.php&#³•i&×0ˤ?phpunit/Runner/TestResult/Subscriber/TestFinishedSubscriber.php2#³•i2޻݃¤Gphpunit/Runner/TestResult/Subscriber/TestMarkedIncompleteSubscriber.phpb#³•ibC•¬¿¤?phpunit/Runner/TestResult/Subscriber/TestPreparedSubscriber.php,#³•i,<Ú¸G¤Qphpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredDeprecationSubscriber.php’#³•i’šÅÍ<¤Lphpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredNoticeSubscriber.phpt#³•it‚½U"¤Mphpunit/Runner/TestResult/Subscriber/TestRunnerTriggeredWarningSubscriber.phpz#³•izÚ+d¤>phpunit/Runner/TestResult/Subscriber/TestSkippedSubscriber.php,#³•i,Û$ñ¤Dphpunit/Runner/TestResult/Subscriber/TestSuiteFinishedSubscriber.phpF#³•iF2Šá¼¤Cphpunit/Runner/TestResult/Subscriber/TestSuiteSkippedSubscriber.php@#³•i@OU&¤Cphpunit/Runner/TestResult/Subscriber/TestSuiteStartedSubscriber.php@#³•i@ƒˆi¤Kphpunit/Runner/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.phpz#³•iz°|?¤Ephpunit/Runner/TestResult/Subscriber/TestTriggeredErrorSubscriber.phpV#³•iV¶‘Fphpunit/Runner/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php\#³•i\¡AU‹¤Nphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.phpŒ#³•iŒB.XÞ¤Iphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.phpn#³•inE…@¤Jphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.phpt#³•it’ÈS̤Rphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php¤#³•i¤ù‘à/¤Lphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php€#³•i€Ò)i2¤Mphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php†#³•i† lÆä¤Nphpunit/Runner/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.phpŒ#³•iŒ,,ˆŒ¤Gphpunit/Runner/TestResult/Subscriber/TestTriggeredWarningSubscriber.phpb#³•ibÍ8Ux¤(phpunit/Runner/TestResult/TestResult.php‘J#³•i‘Jð¸ôT¤"phpunit/Runner/TestSuiteLoader.php†#³•i†B"phpunit/Runner/TestSuiteSorter.php##³•i#Ϊ|¤phpunit/Runner/Version.php.#³•i.¼ÎVk¤phpunit/TextUI/Application.phpød#³•iød—Lµ¤"phpunit/TextUI/Command/Command.phpH#³•iH"Fò ¤9phpunit/TextUI/Command/Commands/AtLeastVersionCommand.php5#³•i5zд¤@phpunit/TextUI/Command/Commands/CheckPhpConfigurationCommand.phpÑ#³•iѲn2ö¤@phpunit/TextUI/Command/Commands/GenerateConfigurationCommand.php# #³•i# ã2® ¤5phpunit/TextUI/Command/Commands/ListGroupsCommand.php3#³•i3^ؤ8phpunit/TextUI/Command/Commands/ListTestFilesCommand.php×#³•i×eêj%¤9phpunit/TextUI/Command/Commands/ListTestSuitesCommand.php¦ #³•i¦ *¶h¸¤:phpunit/TextUI/Command/Commands/ListTestsAsTextCommand.php$#³•i$ŒeÏš¤9phpunit/TextUI/Command/Commands/ListTestsAsXmlCommand.phpg#³•ig à+¤?phpunit/TextUI/Command/Commands/MigrateConfigurationCommand.php#³•i¦—£#¤3phpunit/TextUI/Command/Commands/ShowHelpCommand.phpš#³•išÿ§x¤6phpunit/TextUI/Command/Commands/ShowVersionCommand.phpÇ#³•iÇ!n˜¤7phpunit/TextUI/Command/Commands/VersionCheckCommand.php] #³•i] `}¤@phpunit/TextUI/Command/Commands/WarmCodeCoverageCacheCommand.phpÅ #³•iÅ Ái¤!phpunit/TextUI/Command/Result.phpÍ#³•iÍP,0Ф0phpunit/TextUI/Configuration/BootstrapLoader.phpr #³•ir b,š£¤(phpunit/TextUI/Configuration/Builder.phpä#³•iäß• 5¤,phpunit/TextUI/Configuration/Cli/Builder.phpZˆ#³•iZˆáؤ2phpunit/TextUI/Configuration/Cli/Configuration.phpò #³•iò ó\tw¤.phpunit/TextUI/Configuration/Cli/Exception.php[#³•i[¨æÎ'¤?phpunit/TextUI/Configuration/Cli/XmlConfigurationFileFinder.phpÌ#³•iÌDý±ü¤;phpunit/TextUI/Configuration/CodeCoverageFilterRegistry.php¾#³•i¾º™ò*¤.phpunit/TextUI/Configuration/Configuration.php¹#³•i¹k’ê¤Ophpunit/TextUI/Configuration/Exception/BootstrapScriptDoesNotExistException.php6#³•i6Ö4Y¤Cphpunit/TextUI/Configuration/Exception/BootstrapScriptException.php€#³•i€{™’Ö¤Dphpunit/TextUI/Configuration/Exception/CannotFindSchemaException.php’#³•i’¸«¢O¤Sphpunit/TextUI/Configuration/Exception/CodeCoverageReportNotConfiguredException.php#³•i©ÙVF¤Nphpunit/TextUI/Configuration/Exception/ConfigurationCannotBeBuiltException.php‹#³•i‹6¯Õ¤4phpunit/TextUI/Configuration/Exception/Exception.php3#³•i3¿l´p¤Gphpunit/TextUI/Configuration/Exception/FilterNotConfiguredException.php„#³•i„´]Ü9¤Hphpunit/TextUI/Configuration/Exception/LoggingNotConfiguredException.php…#³•i…N†¤>phpunit/TextUI/Configuration/Exception/NoBaselineException.php{#³•i{%Iû¤?phpunit/TextUI/Configuration/Exception/NoBootstrapException.php|#³•i|eIÂæ¤Dphpunit/TextUI/Configuration/Exception/NoCacheDirectoryException.php#³•iÍAФGphpunit/TextUI/Configuration/Exception/NoConfigurationFileException.php„#³•i„¡Þ@À¤Lphpunit/TextUI/Configuration/Exception/NoCoverageCacheDirectoryException.php‰#³•i‰æGt½¤Cphpunit/TextUI/Configuration/Exception/NoCustomCssFileException.php€#³•i€¾ÝòΤFphpunit/TextUI/Configuration/Exception/NoDefaultTestSuiteException.phpƒ#³•iƒàÐÿ¤Lphpunit/TextUI/Configuration/Exception/NoPharExtensionDirectoryException.php‰#³•i‰™jà ¤Cphpunit/TextUI/Configuration/Exception/NoTestFilesFileException.php€#³•i€ˆõ-õ¤\phpunit/TextUI/Configuration/Exception/SpecificDeprecationToStopOnNotConfiguredException.php™#³•i™ì+̇¤'phpunit/TextUI/Configuration/Merger.php ¦#³•i ¦éø.¤+phpunit/TextUI/Configuration/PhpHandler.php0#³•i0~ö¡¤)phpunit/TextUI/Configuration/Registry.phph#³•ih~Øó«¤-phpunit/TextUI/Configuration/SourceFilter.phpë#³•iëÜ‚q¶¤-phpunit/TextUI/Configuration/SourceMapper.php8#³•i8 žzµ¤1phpunit/TextUI/Configuration/TestSuiteBuilder.php#³•iÍìwx¤/phpunit/TextUI/Configuration/Value/Constant.php-#³•i-9ⵤ9phpunit/TextUI/Configuration/Value/ConstantCollection.phpŽ#³•iŽš8ṳ̂Aphpunit/TextUI/Configuration/Value/ConstantCollectionIterator.phpY#³•iYÜžBϤ0phpunit/TextUI/Configuration/Value/Directory.php‰#³•i‰nÏØ%¤:phpunit/TextUI/Configuration/Value/DirectoryCollection.phpý#³•iýÛv|¤Bphpunit/TextUI/Configuration/Value/DirectoryCollectionIterator.phpj#³•ijž'6¤9phpunit/TextUI/Configuration/Value/ExtensionBootstrap.php#³•iž„¤Cphpunit/TextUI/Configuration/Value/ExtensionBootstrapCollection.php«#³•i«ŒžI¤Kphpunit/TextUI/Configuration/Value/ExtensionBootstrapCollectionIterator.phpÇ#³•iÇDÒ9Ƥ+phpunit/TextUI/Configuration/Value/File.php#³•i EÁð¤5phpunit/TextUI/Configuration/Value/FileCollection.phpŸ#³•iŸ%- ä=phpunit/TextUI/Configuration/Value/FileCollectionIterator.php-#³•i-(À¤6phpunit/TextUI/Configuration/Value/FilterDirectory.phpY#³•iY'Ùo‘¤@phpunit/TextUI/Configuration/Value/FilterDirectoryCollection.php3#³•i3ÍJ ±¤Hphpunit/TextUI/Configuration/Value/FilterDirectoryCollectionIterator.phpˆ#³•iˆÐÙa¿¤,phpunit/TextUI/Configuration/Value/Group.php…#³•i…šVÛ_¤6phpunit/TextUI/Configuration/Value/GroupCollection.php"#³•i"5ÓnÛ¤>phpunit/TextUI/Configuration/Value/GroupCollectionIterator.php8#³•i8<’ °¤1phpunit/TextUI/Configuration/Value/IniSetting.php #³•i ­E¨Õ¤;phpunit/TextUI/Configuration/Value/IniSettingCollection.php°#³•i°ˆÝn¤Cphpunit/TextUI/Configuration/Value/IniSettingCollectionIterator.phpo#³•io_»`n¤*phpunit/TextUI/Configuration/Value/Php.phpî#³•iîö¦«¤-phpunit/TextUI/Configuration/Value/Source.php=#³•i=bIçå¤4phpunit/TextUI/Configuration/Value/TestDirectory.php‰#³•i‰©TϤ>phpunit/TextUI/Configuration/Value/TestDirectoryCollection.php#³•i:Àë…¤Fphpunit/TextUI/Configuration/Value/TestDirectoryCollectionIterator.php~#³•i~ŸÐ…¤/phpunit/TextUI/Configuration/Value/TestFile.phpL#³•iLø—ìú¤9phpunit/TextUI/Configuration/Value/TestFileCollection.php¿#³•i¿Æo¤Aphpunit/TextUI/Configuration/Value/TestFileCollectionIterator.phpA#³•iAPÙ6¤0phpunit/TextUI/Configuration/Value/TestSuite.phpŠ#³•iŠùÇ»¤:phpunit/TextUI/Configuration/Value/TestSuiteCollection.phpô#³•iô‘d΋¤Bphpunit/TextUI/Configuration/Value/TestSuiteCollectionIterator.phpd#³•id͸“¤/phpunit/TextUI/Configuration/Value/Variable.php«#³•i«'z§3¤9phpunit/TextUI/Configuration/Value/VariableCollection.phpŽ#³•iŽP]y¤Aphpunit/TextUI/Configuration/Value/VariableCollectionIterator.phpY#³•iY1cQH¤>phpunit/TextUI/Configuration/Xml/CodeCoverage/CodeCoverage.php€#³•i€ &¤?phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Clover.php&#³•i&á+­¤Bphpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Cobertura.php)#³•i)±‹ZŤ?phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Crap4j.phpË#³•iËâÌñ¤=phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Html.php #³•i Ô{Oè¤Cphpunit/TextUI/Configuration/Xml/CodeCoverage/Report/OpenClover.php*#³•i*Õ ´/¤<phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Php.php##³•i#Hô3¤=phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Text.phpÎ#³•iÎVÉ^ƒ¤<phpunit/TextUI/Configuration/Xml/CodeCoverage/Report/Xml.php÷#³•i÷xf„¤2phpunit/TextUI/Configuration/Xml/Configuration.php2 #³•i2 ’”¤9phpunit/TextUI/Configuration/Xml/DefaultConfiguration.php] #³•i] {}—u¤.phpunit/TextUI/Configuration/Xml/Exception.php_#³•i_+øg3¤.phpunit/TextUI/Configuration/Xml/Generator.phpÏ#³•iÏb․+phpunit/TextUI/Configuration/Xml/Groups.php½#³•i½mu’¤@phpunit/TextUI/Configuration/Xml/LoadedFromFileConfiguration.phpƒ#³•iƒaAÇr¤+phpunit/TextUI/Configuration/Xml/Loader.php#›#³•i#›)Žéú¤2phpunit/TextUI/Configuration/Xml/Logging/Junit.php#³•iOÙ¤4phpunit/TextUI/Configuration/Xml/Logging/Logging.php #³•i Y8Œ•¤0phpunit/TextUI/Configuration/Xml/Logging/Otr.php#³•i±4.€¤5phpunit/TextUI/Configuration/Xml/Logging/TeamCity.php#³•i&Sk¤9phpunit/TextUI/Configuration/Xml/Logging/TestDox/Html.php #³•i *IòŒ¤9phpunit/TextUI/Configuration/Xml/Logging/TestDox/Text.php #³•i ¬l¦¤?phpunit/TextUI/Configuration/Xml/Migration/MigrationBuilder.phpƒ#³•iƒýã9¤Aphpunit/TextUI/Configuration/Xml/Migration/MigrationException.phpv#³•ivÛ[–r¤Iphpunit/TextUI/Configuration/Xml/Migration/Migrations/ConvertLogTypes.php#³•i< ëÙ¤Pphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageCloverToReport.phpË#³•i˳b5z¤Pphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageCrap4jToReport.php#³•iˆæ“¤Nphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageHtmlToReport.php#³•il;^©¤Mphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoveragePhpToReport.php¹#³•i¹™c'ǤNphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageTextToReport.php#³•ií*LФMphpunit/TextUI/Configuration/Xml/Migration/Migrations/CoverageXmlToReport.php¾#³•i¾gºŠú¤Zphpunit/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCacheDirectoryAttribute.phpÐ#³•iÐi¬"¤Rphpunit/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCoverageElement.phpU#³•iU Fc¤Nphpunit/TextUI/Configuration/Xml/Migration/Migrations/LogToReportMigration.php¬ #³•i¬ CÜkí¤Cphpunit/TextUI/Configuration/Xml/Migration/Migrations/Migration.php_#³•i_*ÉŸ,¤ephpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php(#³•i(‘,«¤Zphpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromRootToCoverage.phpù#³•iù["ý¤Yphpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveCoverageDirectoriesToSource.php#³•i*Vº¹¤Yphpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistExcludesToCoverage.php6 #³•i6 !„À¤Yphpunit/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistIncludesToCoverage.phpi#³•ii)ì⣤sphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute.php#³•i«ëܤhphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutTodoAnnotatedTestsAttribute.phpá#³•iáP’ƒÅ¤Xphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheResultFileAttribute.php±#³•i± 1§¤Tphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheTokensAttribute.php¥#³•i¥1ªú¤`phpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveConversionToExceptionsAttributes.php€#³•i€¨:o¤fphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementCacheDirectoryAttribute.phpý#³•iý¤ï¯ª¤mphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementProcessUncoveredFilesAttribute.php#³•i ì€>¤Kphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveEmptyFilter.phpî#³•iîåRµƒ¤Iphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveListeners.php›#³•i›Í'6ï¤Hphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveLogTypes.phpÝ#³•i݇tRO¤Ophpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveLoggingElements.php(#³•i('—¤Vphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveNoInteractionAttribute.php«#³•i«n'°.¤Qphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemovePrinterAttributes.php#³•i]ï2/¤xphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute.php#³•i¿ÕW¤Tphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestDoxGroupsElement.phpª#³•iªô×´š¤Yphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestSuiteLoaderAttributes.php;#³•i;)ó†¤Pphpunit/TextUI/Configuration/Xml/Migration/Migrations/RemoveVerboseAttribute.php™#³•i™Õª”±¤_phpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameBackupStaticAttributesAttribute.php˜#³•i˜Ž"Zù¤fphpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameBeStrictAboutCoversAnnotationAttribute.phpÂ#³•iÂuÀˤ^phpunit/TextUI/Configuration/Xml/Migration/Migrations/RenameForceCoversAnnotationAttribute.php–#³•i–ƒ–¢U¤kphpunit/TextUI/Configuration/Xml/Migration/Migrations/ReplaceRestrictDeprecationsWithIgnoreDeprecations.php‰#³•i‰t¯³7¤Nphpunit/TextUI/Configuration/Xml/Migration/Migrations/UpdateSchemaLocation.phpÙ#³•iÙ.P¦Ó¤7phpunit/TextUI/Configuration/Xml/Migration/Migrator.phpÑ#³•iÑÕ+§¼¤?phpunit/TextUI/Configuration/Xml/Migration/SnapshotNodeList.php>#³•i>ý+ ¤,phpunit/TextUI/Configuration/Xml/PHPUnit.phpB#³•iBE}÷¤Ophpunit/TextUI/Configuration/Xml/SchemaDetector/FailedSchemaDetectionResult.php}#³•i}|¥€¤Iphpunit/TextUI/Configuration/Xml/SchemaDetector/SchemaDetectionResult.php#³•i(ù¯¤Bphpunit/TextUI/Configuration/Xml/SchemaDetector/SchemaDetector.phpo#³•ioÐc€ª¤Sphpunit/TextUI/Configuration/Xml/SchemaDetector/SuccessfulSchemaDetectionResult.phpF#³•iFkÚÎw¤1phpunit/TextUI/Configuration/Xml/SchemaFinder.phpy#³•iy)}š3¤4phpunit/TextUI/Configuration/Xml/TestSuiteMapper.php<#³•i<`gý£¤?phpunit/TextUI/Configuration/Xml/Validator/ValidationResult.phpo#³•iof²1¤8phpunit/TextUI/Configuration/Xml/Validator/Validator.phpù#³•iùI‹ö`¤6phpunit/TextUI/Exception/CannotOpenSocketException.php#³•izçá¤&phpunit/TextUI/Exception/Exception.php$#³•i$昤3phpunit/TextUI/Exception/InvalidSocketException.php#³•iÊI ¤-phpunit/TextUI/Exception/RuntimeException.phpG#³•iG¾n V¤;phpunit/TextUI/Exception/TestDirectoryNotFoundException.php#³•iH˲P¤6phpunit/TextUI/Exception/TestFileNotFoundException.phpþ#³•iþ=ƒ|¤phpunit/TextUI/Help.phprD#³•irDìqŒ?¤Aphpunit/TextUI/Output/Default/ProgressPrinter/ProgressPrinter.php<4#³•i<4áÏ:Ö¤cphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/BeforeTestClassMethodErroredSubscriber.phpº#³•iºPÏDפZphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/ChildProcessErroredSubscriber.phpt#³•it¸ O=¤Gphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/Subscriber.php¦#³•i¦%¢¹ß¤Zphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestConsideredRiskySubscriber.phpt#³•itÜb¤Rphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestErroredSubscriber.phpJ#³•iJxmÇ¢¤Qphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFailedSubscriber.php>#³•i>Y'¹‡¤Sphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFinishedSubscriber.phpJ#³•iJzJ–é¤[phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestMarkedIncompleteSubscriber.phpz#³•izÂjø\¤Sphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestPreparedSubscriber.phpJ#³•iJùû¤aphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestRunnerExecutionStartedSubscriber.php˜#³•i˜ê¥j ¤Rphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.phpD#³•iD…訚¤Wphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestSuiteSkippedSubscriber.phpt#³•it‘¨—e¤_phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredDeprecationSubscriber.php˜#³•i˜d¿Vé¤Yphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredErrorSubscriber.phpt#³•ity´‘ѤZphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredNoticeSubscriber.phpz#³•iz­[¾Ó¤bphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpDeprecationSubscriber.phpª#³•iªA ”¤]phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpNoticeSubscriber.phpŒ#³•iŒ¸•‚è¤^phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpWarningSubscriber.php’#³•i’¦Ú+¤fphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php¼#³•i¼?ï>f¤aphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitNoticeSubscriber.phpž#³•ižØMä¤bphpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitWarningSubscriber.phpª#³•iªëuý¤[phpunit/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredWarningSubscriber.php€#³•i€ë Ý´¤/phpunit/TextUI/Output/Default/ResultPrinter.phpxR#³•ixR&7Õv¤9phpunit/TextUI/Output/Default/UnexpectedOutputPrinter.phpØ#³•iØqp‘ ¤ phpunit/TextUI/Output/Facade.php{##³•i{#2XO¤0phpunit/TextUI/Output/Printer/DefaultPrinter.phpˆ #³•iˆ ¯"$¤-phpunit/TextUI/Output/Printer/NullPrinter.php§#³•i§&W„þ¤)phpunit/TextUI/Output/Printer/Printer.php\#³•i\gD“ߤ(phpunit/TextUI/Output/SummaryPrinter.phpÍ#³•iÍ”‰e¿¤/phpunit/TextUI/Output/TestDox/ResultPrinter.phpÛ1#³•iÛ1°3¤*phpunit/TextUI/ShellExitCodeCalculator.phpF#³•iFöë©å¤phpunit/TextUI/TestRunner.php×#³•i×m/$ؤ+phpunit/TextUI/TestSuiteFilterProcessor.phpF #³•iF œî5¶¤phpunit/Util/Color.phpí#³•iíM4“¤$phpunit/Util/Exception/Exception.php"#³•i"ð‘Ò¤4phpunit/Util/Exception/InvalidDirectoryException.php#³•i ¦ç3¤/phpunit/Util/Exception/InvalidJsonException.php\#³•i\÷nt¤:phpunit/Util/Exception/InvalidVersionOperatorException.php#³•ip2ïÙ¤.phpunit/Util/Exception/PhpProcessException.phpm#³•imZž|¤'phpunit/Util/Exception/XmlException.phpf#³•ifÎ;´Q¤phpunit/Util/ExcludeList.php‘#³•i‘{"Þ¤phpunit/Util/Exporter.phpV#³•iVÔMRç¤phpunit/Util/Filesystem.phpR#³•iRñ]â_¤phpunit/Util/Filter.php¦#³•i¦óu¤phpunit/Util/GlobalState.php##³•i#‰Â?¤ phpunit/Util/Http/Downloader.phpt#³•it.Ø=ä#phpunit/Util/Http/PhpDownloader.php #³•i KÃ>Ƥphpunit/Util/Json.php #³•i â¢o¤%phpunit/Util/PHP/DefaultJobRunner.php#³•i—x¤phpunit/Util/PHP/Job.php #³•i QPðޤphpunit/Util/PHP/JobRunner.phpe#³•ieɺ¤schema/12.4.xsdM#³•iMÛ¢ýð¤schema/12.5.xsdXN#³•iXNç#õ¤schema/8.5.xsdÓB#³•iÓB2A[­¤schema/9.0.xsd4B#³•i4B•¨7w¤schema/9.1.xsdÕB#³•iÕBßq'8¤schema/9.2.xsdÜB#³•iÜBc·Á-¤schema/9.3.xsd¼E#³•i¼E¿ùq¤schema/9.4.xsd F#³•i FDOFI¤schema/9.5.xsdDF#³•iDFûùs|¤sebastian-cli-parser/LICENSEû#³•iû¬D¤sebastian-cli-parser/Parser.phpÇ#³•iÇÌ’f’¤<sebastian-cli-parser/exceptions/AmbiguousOptionException.phpÝ#³•iÝ+Mó…¤-sebastian-cli-parser/exceptions/Exception.phpy#³•iy>€±¤Gsebastian-cli-parser/exceptions/OptionDoesNotAllowArgumentException.phpc#³•icŠRjY¤Jsebastian-cli-parser/exceptions/RequiredOptionArgumentMissingException.phpl#³•ilzQ¢¤:sebastian-cli-parser/exceptions/UnknownOptionException.phpv#³•ivëÛÿä¤(sebastian-comparator/ArrayComparator.phpi#³•iicT±_¤*sebastian-comparator/ClosureComparator.phpI#³•iI~6 ¤#sebastian-comparator/Comparator.phpÐ#³•iÐ'bžŸ¤*sebastian-comparator/ComparisonFailure.php“#³•i“›‹ÕD¤*sebastian-comparator/DOMNodeComparator.php #³•i çz~¤+sebastian-comparator/DateTimeComparator.php–#³•i–A@7!¤.sebastian-comparator/EnumerationComparator.php§#³•i§†ß X¤,sebastian-comparator/ExceptionComparator.phpp#³•ip0CW¤ sebastian-comparator/Factory.phpÌ#³•iÌà‚² ¤sebastian-comparator/LICENSEû#³•iû9fo¤-sebastian-comparator/MockObjectComparator.phpÿ#³•iÿ©~¤)sebastian-comparator/NumberComparator.phpj#³•ijF(Ö¤*sebastian-comparator/NumericComparator.phpâ#³•iâ¢ÒO}¤)sebastian-comparator/ObjectComparator.phpY #³•iY Ö©è¤+sebastian-comparator/ResourceComparator.phpi#³•iik€¢¤)sebastian-comparator/ScalarComparator.php›#³•i›”’ü¤3sebastian-comparator/SplObjectStorageComparator.php#³•i¯r÷p¤'sebastian-comparator/TypeComparator.phpm#³•imjÌ-¤-sebastian-comparator/exceptions/Exception.phpø#³•iø)d¹J¤4sebastian-comparator/exceptions/RuntimeException.php#³•i¨âµï¤#sebastian-complexity/Calculator.php #³•i ä}V¤.sebastian-complexity/Complexity/Complexity.php #³•i w¸Š¤8sebastian-complexity/Complexity/ComplexityCollection.php8 #³•i8 íµÔD¤@sebastian-complexity/Complexity/ComplexityCollectionIterator.phpR#³•iR+ÂVù¤,sebastian-complexity/Exception/Exception.phpz#³•izȬˤ3sebastian-complexity/Exception/RuntimeException.php‘#³•i‘¼Ìé¤sebastian-complexity/LICENSEû#³•iû¬D¤=sebastian-complexity/Visitor/ComplexityCalculatingVisitor.php< #³•i< [»aï¤Gsebastian-complexity/Visitor/CyclomaticComplexityCalculatingVisitor.phph#³•ih¨µŸ®¤sebastian-diff/Chunk.php„#³•i„³Á $¤sebastian-diff/Diff.phpH#³•iHƒ¯€æ¤sebastian-diff/Differ.php~#³•i~oýB¤3sebastian-diff/Exception/ConfigurationException.phpQ#³•iQ ®¶T¤&sebastian-diff/Exception/Exception.phpn#³•inšÀ/\¤sebastian-diff/LICENSEû#³•iû9fo¤sebastian-diff/Line.php<#³•i<ïa ¤5sebastian-diff/LongestCommonSubsequenceCalculator.phpô#³•iôep€6¤Dsebastian-diff/MemoryEfficientLongestCommonSubsequenceCalculator.phpê#³•iêK˜º¤4sebastian-diff/Output/AbstractChunkOutputBuilder.php(#³•i(—ž¤/sebastian-diff/Output/DiffOnlyOutputBuilder.phpÕ#³•iÕ|í ¤4sebastian-diff/Output/DiffOutputBuilderInterface.php#³•ipmö¤8sebastian-diff/Output/StrictUnifiedDiffOutputBuilder.phpý(#³•iý(É–¤2sebastian-diff/Output/UnifiedDiffOutputBuilder.php¾#³•i¾?ŽÙ}¤sebastian-diff/Parser.phpÆ #³•iÆ | ·™¤Bsebastian-diff/TimeEfficientLongestCommonSubsequenceCalculator.phpç#³•içi¢šØ¤!sebastian-environment/Console.phpŸ#³•iŸ¨»©¤sebastian-environment/LICENSEû#³•iû§ú»÷¤!sebastian-environment/Runtime.phpy#³•iyMH~¤sebastian-exporter/Exporter.php21#³•i21,p¤sebastian-exporter/LICENSEû#³•iû9fo¤'sebastian-global-state/CodeExporter.php™ #³•i™ l¤¤&sebastian-global-state/ExcludeList.php #³•i Vÿeu¤sebastian-global-state/LICENSEû#³•iûe´È3¤#sebastian-global-state/Restorer.phph#³•ihÏ^o(¤#sebastian-global-state/Snapshot.phpS-#³•iS-»¯âȤ/sebastian-global-state/exceptions/Exception.php}#³•i}¶µâ´¤6sebastian-global-state/exceptions/RuntimeException.php”#³•i”#Ú™¤#sebastian-lines-of-code/Counter.phpä#³•iäõd²®¤/sebastian-lines-of-code/Exception/Exception.php~#³•i~%>²ú¤>sebastian-lines-of-code/Exception/IllogicalValuesException.php®#³•i®Êårÿ¤6sebastian-lines-of-code/Exception/RuntimeException.php•#³•i•Ñ)Ϲ¤sebastian-lines-of-code/LICENSEû#³•iû¬D¤/sebastian-lines-of-code/LineCountingVisitor.phpï#³•iïòuóù¤'sebastian-lines-of-code/LinesOfCode.php| #³•i| LSèý¤*sebastian-object-enumerator/Enumerator.phpO#³•iO'ßìX¤.sebastian-object-reflector/ObjectReflector.phpû#³•iûŸŸMl¤'sebastian-recursion-context/Context.phpX#³•iX·:uë¤#sebastian-recursion-context/LICENSEû#³•iû9fo¤sebastian-type/LICENSEû#³•iû¢ºj¤sebastian-type/Parameter.php¦#³•i¦ÓòR7¤#sebastian-type/ReflectionMapper.php©#³•i©G™Ü¤sebastian-type/TypeName.php= #³•i= `Y/m¤&sebastian-type/exception/Exception.phpä#³•iä}¥«¤-sebastian-type/exception/RuntimeException.phpû#³•iûÃu†¤$sebastian-type/type/CallableType.php´#³•i´wRt\¤!sebastian-type/type/FalseType.phpÂ#³•i³X ]¤)sebastian-type/type/GenericObjectType.phpy#³•iy‰#¸„¤(sebastian-type/type/IntersectionType.phpJ #³•iJ VÜD¤$sebastian-type/type/IterableType.phpI#³•iIZ«ŸÀ¤!sebastian-type/type/MixedType.php­#³•i­ jÿ¦¤!sebastian-type/type/NeverType.php7#³•i7}‘š¤ sebastian-type/type/NullType.php§#³•i§#² n¤"sebastian-type/type/ObjectType.phpŒ#³•iŒ"Ç?Õ¤"sebastian-type/type/SimpleType.phpP#³•iPgË·»¤"sebastian-type/type/StaticType.php"#³•i"Oaг¤ sebastian-type/type/TrueType.php½#³•i½,šiú¤sebastian-type/type/Type.phpÍ#³•iÍøe¤!sebastian-type/type/UnionType.php& #³•i& _€â[¤#sebastian-type/type/UnknownType.phpŸ#³•iŸyWk=¤ sebastian-type/type/VoidType.php3#³•i3õó¤sebastian-version/LICENSEû#³•iû+ƒz¤sebastian-version/Version.php #³•i ÎZ¦¤$staabm-side-effects-detector/LICENSE-#³•i-ßâj-¤+staabm-side-effects-detector/SideEffect.phpF#³•iFpפ4staabm-side-effects-detector/SideEffectsDetector.phpÒ$#³•iÒ$ÅÌÅ©¤1staabm-side-effects-detector/functionMetadata.phpŸs#³•iŸsÔä!s¤theseer-tokenizer/Exception.phpr#³•irÊÂmœ¤theseer-tokenizer/LICENSEü#³•iüïR (¤"theseer-tokenizer/NamespaceUri.phps#³•is¯c岤+theseer-tokenizer/NamespaceUriException.php}#³•i}aÕ“¤theseer-tokenizer/Token.php—#³•i—K•`¤%theseer-tokenizer/TokenCollection.phpt#³•itê»Ñ¤.theseer-tokenizer/TokenCollectionException.php€#³•i€5ɤtheseer-tokenizer/Tokenizer.php‚ #³•i‚ b䕤#theseer-tokenizer/XMLSerializer.phpZ #³•iZ ”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": "efcffb01d63d6a8a77320b50ca07079d", "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": "13.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", "reference": "a8b58fde2f4fbc69a064e1f80ff917607cf7737c" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/a8b58fde2f4fbc69a064e1f80ff917607cf7737c", "reference": "a8b58fde2f4fbc69a064e1f80ff917607cf7737c", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", "nikic/php-parser": "^5.7.0", "php": ">=8.4", "phpunit/php-file-iterator": "^7.0", "phpunit/php-text-template": "^6.0", "sebastian/complexity": "^6.0", "sebastian/environment": "^9.0", "sebastian/lines-of-code": "^5.0", "sebastian/version": "^7.0", "theseer/tokenizer": "^2.0.1" }, "require-dev": { "phpunit/phpunit": "^13.0" }, "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": "13.0.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/13.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/phpunit/php-code-coverage", "type": "tidelift" } ], "time": "2026-02-06T06:05:15+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.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", "reference": "29b232ddc29c2b114c0358c69b3084e7c3da0d58" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/29b232ddc29c2b114c0358c69b3084e7c3da0d58", "reference": "29b232ddc29c2b114c0358c69b3084e7c3da0d58", "shasum": "" }, "require": { "ext-dom": "*", "ext-mbstring": "*", "php": ">=8.4", "sebastian/diff": "^8.0", "sebastian/exporter": "^8.0" }, "require-dev": { "phpunit/phpunit": "^13.0" }, "suggest": { "ext-bcmath": "For comparing BcMath\\Number objects" }, "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": "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.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/comparator", "type": "tidelift" } ], "time": "2026-02-06T04:40:39+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.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", "reference": "a2b6d09d7729ee87d605a439469f9dcc39be5ea3" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/a2b6d09d7729ee87d605a439469f9dcc39be5ea3", "reference": "a2b6d09d7729ee87d605a439469f9dcc39be5ea3", "shasum": "" }, "require": { "php": ">=8.4" }, "require-dev": { "phpunit/phpunit": "^13.0", "symfony/process": "^7.2" }, "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": "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.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/diff", "type": "tidelift" } ], "time": "2026-02-06T04:42:27+00:00" }, { "name": "sebastian/environment", "version": "9.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", "reference": "bb64d08145b021b67d5f253308a498b73ab0461e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/bb64d08145b021b67d5f253308a498b73ab0461e", "reference": "bb64d08145b021b67d5f253308a498b73ab0461e", "shasum": "" }, "require": { "php": ">=8.4" }, "require-dev": { "phpunit/phpunit": "^13.0" }, "suggest": { "ext-posix": "*" }, "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": "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.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/environment", "type": "tidelift" } ], "time": "2026-02-06T04:43:29+00:00" }, { "name": "sebastian/exporter", "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", "reference": "dc31f1f8e0186c8f0bb3e48fd4d51421d8905fea" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/dc31f1f8e0186c8f0bb3e48fd4d51421d8905fea", "reference": "dc31f1f8e0186c8f0bb3e48fd4d51421d8905fea", "shasum": "" }, "require": { "ext-mbstring": "*", "php": ">=8.4", "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" }, { "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.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/exporter", "type": "tidelift" } ], "time": "2026-02-06T04:44: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.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", "reference": "4f21bb7768e1c997722ccc7efb1d6b5c11bfd471" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/4f21bb7768e1c997722ccc7efb1d6b5c11bfd471", "reference": "4f21bb7768e1c997722ccc7efb1d6b5c11bfd471", "shasum": "" }, "require": { "nikic/php-parser": "^5.0", "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 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.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/lines-of-code", "type": "tidelift" } ], "time": "2026-02-06T04:45:54+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.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", "reference": "42412224607bd3931241bbd17f38e0f972f5a916" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/42412224607bd3931241bbd17f38e0f972f5a916", "reference": "42412224607bd3931241bbd17f38e0f972f5a916", "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": "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.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/type", "type": "tidelift" } ], "time": "2026-02-06T04:52:09+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.0.5 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: 13.0.1 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.0.0 sebastian/complexity: 6.0.0 sebastian/diff: 8.0.0 sebastian/environment: 9.0.0 sebastian/exporter: 8.0.0 sebastian/global-state: 9.0.0 sebastian/lines-of-code: 5.0.0 sebastian/object-enumerator: 8.0.0 sebastian/object-reflector: 6.0.0 sebastian/recursion-context: 8.0.0 sebastian/type: 7.0.0 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_diff; use function array_diff_key; use function array_flip; use function array_keys; use function array_merge; use function array_unique; use function count; use function explode; use function is_file; use function sort; use ReflectionClass; 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\TestSize; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestStatus\TestStatus; /** * Provides collection functionality for PHP code coverage information. * * @phpstan-type TestType array{size: string, status: string, time: float} * @phpstan-type TargetedLines array> */ 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(); } public function __serialize(): array { $prefix = "\x00" . self::class . "\x00"; return [ // Configuration $prefix . 'cacheDirectory' => $this->cacheDirectory, $prefix . 'checkForUnintentionallyCoveredCode' => $this->checkForUnintentionallyCoveredCode, $prefix . 'includeUncoveredFiles' => $this->includeUncoveredFiles, $prefix . 'ignoreDeprecatedCode' => $this->ignoreDeprecatedCode, $prefix . 'parentClassesExcludedFromUnintentionallyCoveredCodeCheck' => $this->parentClassesExcludedFromUnintentionallyCoveredCodeCheck, $prefix . 'useAnnotationsForIgnoringCode' => $this->useAnnotationsForIgnoringCode, $prefix . 'filter' => $this->filter, // Data $prefix . 'data' => $this->data, $prefix . 'tests' => $this->tests, ]; } /** * Returns the code coverage information as a graph of node objects. */ public function getReport(): Directory { if ($this->cachedReport === null) { $this->cachedReport = (new Builder($this->analyser()))->build($this); } 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; $this->applyFilter($rawData); $this->applyExecutableLinesFilter($rawData); if ($this->useAnnotationsForIgnoringCode) { $this->applyIgnoredLinesFilter($rawData); } $this->data->initializeUnseenData($rawData); if (!$append) { return; } if ($id === self::UNCOVERED_FILES) { return; } $linesToBeCovered = \false; $linesToBeUsed = []; if ($covers !== \false) { $linesToBeCovered = $this->targetMapper()->mapTargets($covers); } if ($linesToBeCovered !== \false) { $linesToBeUsed = $this->targetMapper()->mapTargets($uses); } $this->applyCoversAndUsesFilter($rawData, $linesToBeCovered, $linesToBeUsed, $size); if ($rawData->lineCoverage() === []) { return; } $this->tests[$id] = ['size' => $size->asString(), 'status' => $status->asString(), 'time' => $time]; $this->data->markCodeAsExecutedByTestCase($id, $rawData); } /** * Merges the data from another instance. */ 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); } /** * @internal */ public function driverIsPcov(): bool { /** @phpstan-ignore isset.initializedProperty */ return isset($this->driver) && $this->driver->isPcov(); } /** * @internal */ public function driverIsXdebug(): bool { /** @phpstan-ignore isset.initializedProperty */ return isset($this->driver) && $this->driver->isXdebug(); } /** * @param false|TargetedLines $linesToBeCovered * @param TargetedLines $linesToBeUsed * * @throws ReflectionException * @throws UnintentionallyCoveredCodeException */ private function applyCoversAndUsesFilter(RawCodeCoverageData $rawData, array|false $linesToBeCovered, array $linesToBeUsed, TestSize $size): void { if ($linesToBeCovered === \false) { $rawData->clear(); return; } if ($linesToBeCovered === []) { return; } if ($this->checkForUnintentionallyCoveredCode && !$size->isMedium() && !$size->isLarge()) { $this->performUnintentionallyCoveredCodeCheck($rawData, $linesToBeCovered, $linesToBeUsed); } $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); } } private function applyFilter(RawCodeCoverageData $data): void { if (!$this->filter->isEmpty()) { foreach (array_keys($data->lineCoverage()) as $filename) { if ($this->filter->isExcluded($filename)) { $data->removeCoverageDataForFile($filename); } } } $data->skipEmptyLines(); } private function applyExecutableLinesFilter(RawCodeCoverageData $data): void { foreach (array_keys($data->lineCoverage()) as $filename) { if (!$this->filter->isFile($filename)) { continue; } $linesToBranchMap = $this->analyser()->analyse($filename)->executableLines(); $data->keepLineCoverageDataOnlyForLines($filename, array_keys($linesToBranchMap)); $data->markExecutableLineByBranch($filename, $linesToBranchMap); } } private function applyIgnoredLinesFilter(RawCodeCoverageData $data): void { foreach (array_keys($data->lineCoverage()) as $filename) { if (!$this->filter->isFile($filename)) { continue; } $data->removeCoverageDataForLines($filename, $this->analyser()->analyse($filename)->ignoredLines()); } } /** * @throws UnintentionallyCoveredCodeException */ private function addUncoveredFilesFromFilter(): void { $uncoveredFiles = array_diff($this->filter->files(), $this->data->coveredFiles()); foreach ($uncoveredFiles as $uncoveredFile) { if (is_file($uncoveredFile)) { $this->append(RawCodeCoverageData::fromUncoveredFile($uncoveredFile, $this->analyser()), self::UNCOVERED_FILES); } } } /** * @param TargetedLines $linesToBeCovered * @param TargetedLines $linesToBeUsed * * @throws ReflectionException * @throws UnintentionallyCoveredCodeException */ private function performUnintentionallyCoveredCodeCheck(RawCodeCoverageData $data, array $linesToBeCovered, array $linesToBeUsed): void { $allowedLines = $this->getAllowedLines($linesToBeCovered, $linesToBeUsed); $unintentionallyCoveredUnits = []; foreach ($data->lineCoverage() as $file => $_data) { foreach ($_data as $line => $flag) { if ($flag === 1 && !isset($allowedLines[$file][$line])) { $unintentionallyCoveredUnits[] = $this->targetMapper->lookup($file, $line); } } } $unintentionallyCoveredUnits = $this->processUnintentionallyCoveredUnits($unintentionallyCoveredUnits); if ($unintentionallyCoveredUnits !== []) { throw new UnintentionallyCoveredCodeException($unintentionallyCoveredUnits); } } /** * @param TargetedLines $linesToBeCovered * @param TargetedLines $linesToBeUsed * * @return TargetedLines */ private function getAllowedLines(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; } /** * @param list $unintentionallyCoveredUnits * * @throws ReflectionException * * @return list */ private function processUnintentionallyCoveredUnits(array $unintentionallyCoveredUnits): 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 ($this->parentClassesExcludedFromUnintentionallyCoveredCodeCheck as $parentClass) { if ($class->isSubclassOf($parentClass)) { continue 2; } } } catch (\ReflectionException $e) { throw new ReflectionException($e->getMessage(), $e->getCode(), $e); } $processed[] = $tmp[0]; } $processed = array_unique($processed); sort($processed); return $processed; } 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 PHPUnitPHAR\NoDiscard; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\XdebugDriver; /** * @internal This class is 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 */ 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; public function __construct( string $className, string $namespace, /** * @var array */ 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 * * @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. * * @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 PHPUnitPHAR\NoDiscard; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\XdebugDriver; /** * @internal This class is 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 */ 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 */ 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 PHPUnitPHAR\NoDiscard; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Driver\XdebugDriver; /** * @internal This class is 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 */ 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; public function __construct( string $traitName, string $namespace, /** * @var array */ 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 * * @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[] $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 */ 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; } public function isPcov(): bool { return \false; } public function isXdebug(): bool { return \false; } abstract public function nameAndVersion(): string; 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 */ 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 nameAndVersion(): string { return 'PCOV ' . phpversion('pcov'); } public function isPcov(): true { return \true; } /** * @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; 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 * * @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 nameAndVersion(): string { return 'Xdebug ' . phpversion('xdebug'); } public function isXdebug(): true { return \true; } /** * @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; 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; 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; 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\CodeCoverage; use RuntimeException; 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; 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; 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; use RuntimeException; 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; 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; 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; 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; 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; use RuntimeException; 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; 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; use RuntimeException; 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; 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; 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; use function sprintf; use RuntimeException; 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; 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; 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; 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; 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; 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 === []; } } 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 */ 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 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 array_shift; use function basename; use function count; use function dirname; use function explode; use function implode; use function is_file; use function sha1_file; use function str_ends_with; use function str_replace; use function str_starts_with; use function substr; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedCodeCoverageData; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser; /** * @internal This class is 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; } public function build(CodeCoverage $coverage): Directory { $data = clone $coverage->getData(); // clone because path munging is destructive to the original data $commonPath = $this->reducePaths($data); $root = new Directory($commonPath, null); $this->addItems($root, $this->buildDirectoryStructure($data), $coverage->getTests()); return $root; } /** * @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())); } } 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 $data): array { $result = []; $lineCoverage = $data->lineCoverage(); $functionCoverage = $data->functionCoverage(); foreach ($data->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; } /** * Reduces the paths by cutting the longest common start path. * * For instance, * * * Array * ( * [/home/sb/Money/Money.php] => Array * ( * ... * ) * * [/home/sb/Money/MoneyBag.php] => Array * ( * ... * ) * ) * * * is reduced to * * * Array * ( * [Money.php] => Array * ( * ... * ) * * [MoneyBag.php] => Array * ( * ... * ) * ) * */ private function reducePaths(ProcessedCodeCoverageData $coverage): string { $coveredFiles = $coverage->coveredFiles(); if ($coveredFiles === []) { return '.'; } $commonPath = ''; $paths = $coveredFiles; if (count($paths) === 1) { $commonPath = dirname($paths[0]) . DIRECTORY_SEPARATOR; $coverage->renameFile($paths[0], basename($paths[0])); return $commonPath; } $max = count($paths); for ($i = 0; $i < $max; $i++) { // strip phar:// prefixes 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; } } $done = \false; $max = count($paths); 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]); } } } $original = $coveredFiles; $max = count($original); for ($i = 0; $i < $max; $i++) { $coverage->renameFile($original[$i], implode(DIRECTORY_SEPARATOR, $paths[$i])); } 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\Node; use function sprintf; /** * @internal This class is 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 */ 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 $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 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\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 * * @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; 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 ?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 $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) { parent::__construct($name, $parent); $this->sha1 = $sha1; $this->lineCoverageData = $lineCoverageData; $this->functionCoverageData = $functionCoverageData; $this->testData = $testData; $this->linesOfCode = $linesOfCode; $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; } 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 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->numTestedClasses++; } } 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 */ 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\CodeCoverage; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Xml; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\WriteOperationFailedException; final class Clover { /** * @param null|non-empty-string $target * @param null|non-empty-string $name * * @throws WriteOperationFailedException */ public function process(CodeCoverage $coverage, ?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', $name); } $xmlCoverage->appendChild($xmlProject); $packages = []; $report = $coverage->getReport(); foreach ($report as $item) { if (!$item instanceof File) { continue; } /* @var File $item */ $xmlFile = $xmlDocument->createElement('file'); $xmlFile->setAttribute('name', $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', $className); $xmlClass->setAttribute('namespace', $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', $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', $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 DOMImplementation; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Xml; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\WriteOperationFailedException; final class Cobertura { /** * @param null|non-empty-string $target * * @throws WriteOperationFailedException */ public function process(CodeCoverage $coverage, ?string $target = null): string { $time = (string) time(); $report = $coverage->getReport(); $implementation = new DOMImplementation(); $documentType = $implementation->createDocumentType('coverage', '', 'http://cobertura.sourceforge.net/xml/coverage-04.dtd'); $document = $implementation->createDocument('', '', $documentType); $document->xmlVersion = '1.0'; $document->encoding = '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', $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', 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', $className); $classElement->setAttribute('filename', 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', $methodName); $methodElement->setAttribute('signature', $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', basename($item->pathAsString())); $classElement->setAttribute('filename', 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', $functionName); $methodElement->setAttribute('signature', $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\CodeCoverage; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Xml; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\WriteOperationFailedException; final readonly class Crap4j { 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(CodeCoverage $coverage, ?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) ? $name : ''); $root->appendChild($project); $root->appendChild($document->createElement('timestamp', date('Y-m-d H:i:s'))); $stats = $document->createElement('stats'); $methodsNode = $document->createElement('methods'); $report = $coverage->getReport(); unset($coverage); $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', $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', $namespace)); $methodNode->appendChild($document->createElement('className', $className)); $methodNode->appendChild($document->createElement('methodName', $methodName)); $methodNode->appendChild($document->createElement('methodSignature', htmlspecialchars($method->signature))); $methodNode->appendChild($document->createElement('fullMethod', htmlspecialchars($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\Html; /** * @immutable */ final readonly class Colors { private string $successLow; private string $successMedium; private string $successHigh; private string $warning; private string $danger; public static function default(): self { return new self('#dff0d8', '#c3e3b5', '#99cb84', '#fcf8e3', '#f2dede'); } public static function from(string $successLow, string $successMedium, string $successHigh, string $warning, string $danger): self { return new self($successLow, $successMedium, $successHigh, $warning, $danger); } private function __construct(string $successLow, string $successMedium, string $successHigh, string $warning, string $danger) { $this->successLow = $successLow; $this->successMedium = $successMedium; $this->successHigh = $successHigh; $this->warning = $warning; $this->danger = $danger; } public function successLow(): string { return $this->successLow; } public function successMedium(): string { return $this->successMedium; } public function successHigh(): string { return $this->successHigh; } public function warning(): string { return $this->warning; } public function danger(): string { return $this->danger; } } * * 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 */ 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\CodeCoverage; 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; 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(CodeCoverage $coverage, string $target): void { $target = $this->directory($target); $report = $coverage->getReport(); $date = date('D M j G:i:s T Y'); $hasBranchCoverage = $coverage->getData(\true)->functionCoverage() !== []; $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/billboard.min.css', $dir . 'billboard.min.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/billboard.pkgd.min.js', $dir . 'billboard.pkgd.min.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(['success-low' => $this->colors->successLow(), 'success-medium' => $this->colors->successMedium(), 'success-high' => $this->colors->successHigh(), 'warning' => $this->colors->warning(), 'danger' => $this->colors->danger()]); 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 */ 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'; } if ($data['numExecutablePaths'] > 0) { $pathsLevel = $this->colorLevel($data['pathsExecutedPercent']); $pathsNumber = $data['numExecutedPaths'] . $numSeparator . $data['numExecutablePaths']; $pathsBar = $this->coverageBar($data['pathsExecutedPercent']); } 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']); } 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 function array_values; use function asort; use function assert; use function count; use function explode; use function floor; use function json_encode; use function sprintf; use function str_replace; use function uasort; use function usort; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedClassType; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedMethodType; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Data\ProcessedTraitType; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\FileCouldNotBeWrittenException; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\AbstractNode; 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 */ 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() . '/'; $complexity = $this->complexity($classes, $baseLink); $coverageDistribution = $this->coverageDistribution($classes); $insufficientCoverage = $this->insufficientCoverage($classes, $baseLink); $projectRisks = $this->projectRisks($classes, $baseLink); $template->setVar(['insufficient_coverage_classes' => $insufficientCoverage['class'], 'insufficient_coverage_methods' => $insufficientCoverage['method'], 'project_risks_classes' => $projectRisks['class'], 'project_risks_methods' => $projectRisks['method'], 'complexity_class' => $complexity['class'], 'complexity_method' => $complexity['method'], 'class_coverage_distribution' => $coverageDistribution['class'], 'method_coverage_distribution' => $coverageDistribution['method']]); 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 array{class: non-empty-string, method: non-empty-string} */ private function complexity(array $classes, string $baseLink): array { $result = ['class' => [], 'method' => []]; foreach ($classes as $className => $class) { foreach ($class->methods as $methodName => $method) { if ($className !== '*') { $methodName = $className . '::' . $methodName; } $result['method'][] = [$method->coverage, $method->ccn, str_replace($baseLink, '', $method->link), $methodName, $method->crap]; } $result['class'][] = [$class->coverage, $class->ccn, str_replace($baseLink, '', $class->link), $className, $class->crap]; } usort($result['class'], static fn(mixed $a, mixed $b) => $a[0] <=> $b[0]); usort($result['method'], static fn(mixed $a, mixed $b) => $a[0] <=> $b[0]); $class = json_encode($result['class']); assert($class !== \false); $method = json_encode($result['method']); assert($method !== \false); return ['class' => $class, 'method' => $method]; } /** * @param array $classes * * @return array{class: non-empty-string, method: non-empty-string} */ private function coverageDistribution(array $classes): array { $result = ['class' => ['0%' => 0, '0-10%' => 0, '10-20%' => 0, '20-30%' => 0, '30-40%' => 0, '40-50%' => 0, '50-60%' => 0, '60-70%' => 0, '70-80%' => 0, '80-90%' => 0, '90-100%' => 0, '100%' => 0], 'method' => ['0%' => 0, '0-10%' => 0, '10-20%' => 0, '20-30%' => 0, '30-40%' => 0, '40-50%' => 0, '50-60%' => 0, '60-70%' => 0, '70-80%' => 0, '80-90%' => 0, '90-100%' => 0, '100%' => 0]]; foreach ($classes as $class) { foreach ($class->methods as $method) { if ($method->coverage === 0) { $result['method']['0%']++; } elseif ($method->coverage === 100) { $result['method']['100%']++; } else { $key = floor($method->coverage / 10) * 10; $key = $key . '-' . ($key + 10) . '%'; $result['method'][$key]++; } } if ($class->coverage === 0) { $result['class']['0%']++; } elseif ($class->coverage === 100) { $result['class']['100%']++; } else { $key = floor($class->coverage / 10) * 10; $key = $key . '-' . ($key + 10) . '%'; $result['class'][$key]++; } } $class = json_encode(array_values($result['class'])); assert($class !== \false); $method = json_encode(array_values($result['method'])); assert($method !== \false); return ['class' => $class, 'method' => $method]; } /** * @param array $classes * * @return array{class: string, method: string} */ private function insufficientCoverage(array $classes, string $baseLink): array { $leastTestedClasses = []; $leastTestedMethods = []; $result = ['class' => '', 'method' => '']; foreach ($classes as $className => $class) { foreach ($class->methods as $methodName => $method) { if ($method->coverage < $this->thresholds->highLowerBound()) { $key = $methodName; if ($className !== '*') { $key = $className . '::' . $methodName; } $leastTestedMethods[$key] = $method->coverage; } } if ($class->coverage < $this->thresholds->highLowerBound()) { $leastTestedClasses[$className] = $class->coverage; } } asort($leastTestedClasses); asort($leastTestedMethods); foreach ($leastTestedClasses as $className => $coverage) { $result['class'] .= sprintf(' %s%d%%' . "\n", str_replace($baseLink, '', $classes[$className]->link), $className, $coverage); } foreach ($leastTestedMethods as $methodName => $coverage) { [$class, $method] = explode('::', $methodName); $result['method'] .= sprintf(' %s%d%%' . "\n", str_replace($baseLink, '', $classes[$class]->methods[$method]->link), $methodName, $method, $coverage); } return $result; } /** * @param array $classes * * @return array{class: string, method: string} */ private function projectRisks(array $classes, string $baseLink): array { $classRisks = []; $methodRisks = []; $result = ['class' => '', 'method' => '']; foreach ($classes as $className => $class) { foreach ($class->methods as $methodName => $method) { if ($method->coverage < $this->thresholds->highLowerBound() && $method->ccn > 1) { $key = $methodName; if ($className !== '*') { $key = $className . '::' . $methodName; } $methodRisks[$key] = $method; } } if ($class->coverage < $this->thresholds->highLowerBound() && $class->ccn > count($class->methods)) { $classRisks[$className] = $class; } } uasort($classRisks, static function (ProcessedClassType|ProcessedTraitType $a, ProcessedClassType|ProcessedTraitType $b) { return ((int) $a->crap <=> (int) $b->crap) * -1; }); uasort($methodRisks, static function (ProcessedMethodType $a, ProcessedMethodType $b) { return ((int) $a->crap <=> (int) $b->crap) * -1; }); foreach ($classRisks as $className => $class) { $result['class'] .= sprintf(' %s%.1f%%%d%d' . "\n", str_replace($baseLink, '', $classes[$className]->link), $className, $class->coverage, $class->ccn, $class->crap); } foreach ($methodRisks as $methodName => $methodVals) { [$class, $method] = explode('::', $methodName); $result['method'] .= sprintf(' %s%.1f%%%d%d' . "\n", str_replace($baseLink, '', $classes[$class]->methods[$method]->link), $methodName, $method, $methodVals->coverage, $methodVals->ccn, $methodVals->crap); } 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\Report\Html; use function count; use function sprintf; use function str_repeat; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\FileCouldNotBeWrittenException; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\AbstractNode as Node; 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 */ 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); foreach ($node->directories() as $item) { $items .= $this->renderItem($item); } foreach ($node->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()]; 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 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_PROTECTED; use const T_PUBLIC; 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 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 file_get_contents; use function htmlspecialchars; use function is_string; use function ksort; use function range; use function sort; use function sprintf; use function str_ends_with; use function str_replace; use function token_get_all; use function trim; 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\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 */ final class File extends Renderer { /** * @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_PROTECTED => \true, T_PUBLIC => \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 $formattedSourceCache = []; 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->loadFile($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->loadFile($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->loadFile($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->loadFile($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 */ 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->loadFile($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 */ 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(); } /** * @param non-empty-string $file * * @return list */ private function loadFile(string $file): array { if (isset(self::$formattedSourceCache[$file])) { return self::$formattedSourceCache[$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::$formattedSourceCache[$file] = $result; return $result; } 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; } 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)); } 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]); } }

      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}})
      /*! * Copyright (c) 2017 ~ present NAVER Corp. * billboard.js project is licensed under the MIT license * * billboard.js, JavaScript chart library * https://naver.github.io/billboard.js/ * * @version 3.15.1 */ .bb svg{font:10px sans-serif;-webkit-tap-highlight-color:rgba(0,0,0,0)}.bb path,.bb line{fill:none;stroke:#000}.bb text,.bb .bb-button{-webkit-user-select:none;-moz-user-select:none;user-select:none}.bb-legend-item-tile,.bb-xgrid-focus,.bb-ygrid-focus,.bb-ygrid{shape-rendering:crispEdges}.bb-chart-arcs .bb-needle,.bb-chart-arc .bb-gauge-value{fill:#000}.bb-chart-arc path{stroke:#fff}.bb-chart-arc rect{stroke:#fff;stroke-width:1}.bb-chart-arc text{fill:#fff;font-size:13px}.bb-chart-funnels path{stroke-width:0}.bb-chart-funnels+.bb-chart-texts text{font-size:13px;fill:#fff}.bb-axis{shape-rendering:crispEdges}.bb-axis .bb-axis-x-tooltip,.bb-axis .bb-axis-y-tooltip,.bb-axis .bb-axis-y2-tooltip{font-size:1em;fill:#fff;white-space:nowrap}.bb-grid{pointer-events:none}.bb-grid line{stroke:#aaa}.bb-grid text{fill:#aaa}.bb-xgrid,.bb-ygrid{stroke-dasharray:3 3}.bb-text.bb-empty{fill:gray;font-size:2em}.bb-line{stroke-width:1px}.bb-circle._expanded_{stroke-width:1px;stroke:#fff}.bb-selected-circle{fill:#fff;stroke-width:2px}.bb-bar{stroke-width:0}.bb-bar._expanded_{fill-opacity:.75}.bb-candlestick{stroke-width:1px}.bb-candlestick._expanded_{fill-opacity:.75}.bb-target.bb-focused,.bb-circles.bb-focused{opacity:1}.bb-target.bb-focused path.bb-line,.bb-target.bb-focused path.bb-step,.bb-circles.bb-focused path.bb-line,.bb-circles.bb-focused path.bb-step{stroke-width:2px}.bb-target.bb-defocused,.bb-circles.bb-defocused{opacity:.3!important}.bb-target.bb-defocused .text-overlapping,.bb-circles.bb-defocused .text-overlapping{opacity:.05!important}.bb-region{fill:#4682b4}.bb-region rect{fill-opacity:.1}.bb-zoom-brush,.bb-brush .extent{fill-opacity:.1}.bb-legend-item{font-size:12px;user-select:none}.bb-legend-item-hidden{opacity:.15}.bb-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.bb-title{font:14px sans-serif}.bb-chart-treemaps rect{stroke:#fff;stroke-width:1px}.bb-tooltip-container{z-index:10;user-select:none}.bb-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;opacity:.9;box-shadow:7px 7px 12px -9px #777;white-space:nowrap}.bb-tooltip tr{border:1px solid #CCC}.bb-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#fff}.bb-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.bb-tooltip td>span,.bb-tooltip td>svg{display:inline-block;width:10px;height:10px;margin-right:6px}.bb-tooltip.value{text-align:right}.bb-area{stroke-width:0;opacity:.2}.bb-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}text.bb-chart-arcs-gauge-title{dominant-baseline:middle;font-size:2.7em}.bb-chart-arcs .bb-chart-arcs-background{fill:#e0e0e0;stroke:#fff}.bb-chart-arcs .bb-chart-arcs-gauge-unit{fill:#000;font-size:16px}.bb-chart-arcs .bb-chart-arcs-gauge-max,.bb-chart-arcs .bb-chart-arcs-gauge-min{fill:#777}.bb-chart-arcs .bb-levels circle{fill:none;stroke:#848282;stroke-width:.5px}.bb-chart-arcs .bb-levels text{fill:#848282}.bb-chart-radars .bb-levels polygon{fill:none;stroke:#848282;stroke-width:.5px}.bb-chart-radars .bb-levels text{fill:#848282}.bb-chart-radars .bb-axis line{stroke:#848282;stroke-width:.5px}.bb-chart-radars .bb-axis text{font-size:1.15em;cursor:default}.bb-chart-radars .bb-shapes polygon{fill-opacity:.2;stroke-width:1px}.bb-button{position:absolute;top:10px;right:10px}.bb-button .bb-zoom-reset{font-size:11px;border:solid 1px #ccc;background-color:#fff;padding:5px;border-radius:5px;cursor:pointer} @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(var(--bs-gray-200), var(--bs-gray-800)); --phpunit-success-bar: light-dark(#28a745 ,#1f8135); --phpunit-success-high: light-dark(#99cb84, #3d5c4e); --phpunit-success-medium: light-dark(#c3e3b5,#3c6051); --phpunit-success-low: light-dark(#dff0d8, #2d4431); --phpunit-warning: light-dark(#fcf8e3, #3e3408); --phpunit-warning-bar: light-dark(#ffc107 ,#c19406); --phpunit-danger: light-dark(#f2dede, #42221e); --phpunit-danger-bar: light-dark(#dc3545, #a62633); /* 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 td:first-of-type { padding-left: .75em; padding-right: .75em; } 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; } Dashboard for {{full_path}}

      Classes

      Coverage Distribution

      Complexity

      Insufficient Coverage

      {{insufficient_coverage_classes}}
      Class Coverage

      Project Risks

      {{project_risks_classes}}
      Class Coverage Complexity CRAP

      Methods

      Coverage Distribution

      Complexity

      Insufficient Coverage

      {{insufficient_coverage_methods}}
      Method Coverage

      Project Risks

      {{project_risks_methods}}
      Method Coverage Complexity CRAP
      Dashboard for {{full_path}}

      Classes

      Coverage Distribution

      Complexity

      Insufficient Coverage

      {{insufficient_coverage_classes}}
      Class Coverage

      Project Risks

      {{project_risks_classes}}
      Class CRAP

      Methods

      Coverage Distribution

      Complexity

      Insufficient Coverage

      {{insufficient_coverage_methods}}
      Method Coverage

      Project Risks

      {{project_risks_methods}}
      Method CRAP
      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}}
      /*! * Copyright (c) 2017 ~ present NAVER Corp. * billboard.js project is licensed under the MIT license * * billboard.js, JavaScript chart library * https://naver.github.io/billboard.js/ * * @version 3.15.1 * * All-in-one packaged file for ease use of 'billboard.js' with dependant d3.js modules & polyfills. * - @types/d3-selection ^3.0.11 * - @types/d3-transition ^3.0.9 * - d3-axis ^3.0.0 * - d3-brush ^3.0.0 * - d3-drag ^3.0.0 * - d3-dsv ^3.0.1 * - d3-ease ^3.0.1 * - d3-hierarchy ^3.1.2 * - d3-interpolate ^3.0.1 * - d3-scale ^4.0.2 * - d3-selection ^3.0.0 * - d3-shape ^3.2.0 * - d3-time-format ^4.1.0 * - d3-transition ^3.0.1 * - d3-zoom ^3.0.0 */(function(Xa,zn){if(typeof exports=="object"&&typeof module=="object")module.exports=zn();else if(typeof define=="function"&&define.amd)define([],zn);else{var Ha=zn();for(var x in Ha)(typeof exports=="object"?exports:Xa)[x]=Ha[x]}})(this,function(){return function(){"use strict";var Cs=[function(x,b,r){r(1),r(97),r(98),r(99),r(100),r(101),r(102),r(103),r(104),r(105),r(106),r(107),r(108),r(109),r(110),r(111),r(124),r(126),r(136),r(137),r(139),r(143),r(146),r(148),r(150),r(151),r(152),r(153),r(155),r(156),r(158),r(159),r(161),r(165),r(166),r(167),r(168),r(173),r(174),r(176),r(177),r(178),r(180),r(184),r(185),r(186),r(187),r(188),r(193),r(195),r(196),r(198),r(201),r(202),r(203),r(204),r(205),r(207),r(218),r(220),r(221),r(223),r(224),r(227),r(230),r(236),r(237),r(238),r(239),r(240),r(241),r(245),r(246),r(248),r(249),r(250),r(252),r(253),r(254),r(255),r(256),r(261),r(262),r(263),r(264),r(266),r(267),r(268),r(270),r(271),r(272),r(273),r(93),r(274),r(275),r(283),r(285),r(287),r(288),r(289),r(290),r(291),r(293),r(294),r(295),r(296),r(297),r(298),r(300),r(301),r(302),r(303),r(304),r(305),r(306),r(307),r(311),r(312),r(314),r(316),r(317),r(318),r(319),r(320),r(322),r(324),r(325),r(326),r(327),r(329),r(330),r(332),r(333),r(334),r(335),r(337),r(338),r(339),r(340),r(341),r(342),r(343),r(344),r(345),r(347),r(348),r(349),r(350),r(351),r(352),r(353),r(354),r(355),r(356),r(357),r(359),r(360),r(361),r(362),r(386),r(387),r(388),r(389),r(390),r(391),r(392),r(393),r(394),r(395),r(397),r(398),r(399),r(400),r(401),r(402),r(403),r(404),r(405),r(406),r(413),r(415),r(416),r(418),r(419),r(420),r(421),r(422),r(424),r(434),r(436),r(438),r(440),r(442),r(444),r(446),r(447),r(449),r(452),r(453),r(454),r(455),r(456),r(460),r(461),r(463),r(464),r(465),r(466),r(468),r(469),r(470),r(471),r(472),r(473),r(474),r(476),r(479),r(482),r(485),r(486),r(487),r(488),r(489),r(490),r(491),r(492),r(493),r(494),r(495),r(496),r(497),r(505),r(506),r(507),r(508),r(509),r(510),r(511),r(512),r(513),r(514),r(515),r(516),r(517),r(519),r(520),r(521),r(522),r(523),r(524),r(525),r(526),r(527),r(528),r(529),r(530),r(531),r(532),r(533),r(534),r(535),r(536),r(537),r(538),r(539),r(540),r(541),r(542),r(543),r(544),r(545),r(546),r(549),r(551),r(553),r(554),r(557),r(558),r(560),r(561),r(562),r(566),r(567),r(568),r(569),r(572),r(577),r(578),r(579),r(580),r(581),r(582),r(583),r(80)},function(x,b,r){r(2),r(90),r(92),r(93),r(96)},function(x,b,r){var u=r(3),d=r(4),h=r(8),p=r(14),y=r(36),T=r(6),$=r(26),A=r(7),E=r(38),R=r(24),I=r(46),O=r(12),C=r(18),D=r(68),M=r(11),F=r(71),z=r(73),U=r(57),j=r(75),G=r(66),B=r(5),V=r(44),Y=r(72),Z=r(10),J=r(47),q=r(77),nt=r(34),rt=r(53),_=r(54),tt=r(40),et=r(33),lt=r(78),mt=r(79),gt=r(81),xt=r(82),yt=r(51),Ut=r(83).forEach,Dt=rt("hidden"),Xt="Symbol",Qt="prototype",kt=yt.set,me=yt.getterFor(Xt),ge=Object[Qt],ae=d.Symbol,Mt=ae&&ae[Qt],Ht=d.RangeError,re=d.TypeError,se=d.QObject,ee=B.f,fe=V.f,Pe=j.f,Me=Z.f,$e=p([].push),ce=nt("symbols"),Ae=nt("op-symbols"),Te=nt("wks"),de=!se||!se[Qt]||!se[Qt].findChild,bt=function(It,Pt,Ct){var Nt=ee(ge,Pt);Nt&&delete ge[Pt],fe(It,Pt,Ct),Nt&&It!==ge&&fe(ge,Pt,Nt)},Ft=T&&A(function(){return F(fe({},"a",{get:function(){return fe(this,"a",{value:7}).a}})).a!==7})?bt:fe,Tt=function(It,Pt){var Ct=ce[It]=F(Mt);return kt(Ct,{type:Xt,tag:It,description:Pt}),T||(Ct.description=Pt),Ct},qt=function(Pt,Ct,Nt){Pt===ge&&qt(Ae,Ct,Nt),I(Pt);var Et=C(Ct);return I(Nt),E(ce,Et)?(Nt.enumerable?(E(Pt,Dt)&&Pt[Dt][Et]&&(Pt[Dt][Et]=!1),Nt=F(Nt,{enumerable:M(0,!1)})):(E(Pt,Dt)||fe(Pt,Dt,M(1,F(null))),Pt[Dt][Et]=!0),Ft(Pt,Et,Nt)):fe(Pt,Et,Nt)},te=function(Pt,Ct){I(Pt);var Nt=O(Ct),Et=z(Nt).concat(ut(Nt));return Ut(Et,function(ie){(!T||h(Yt,Nt,ie))&&qt(Pt,ie,Nt[ie])}),Pt},Zt=function(Pt,Ct){return Ct===void 0?F(Pt):te(F(Pt),Ct)},Yt=function(Pt){var Ct=C(Pt),Nt=h(Me,this,Ct);return this===ge&&E(ce,Ct)&&!E(Ae,Ct)?!1:Nt||!E(this,Ct)||!E(ce,Ct)||E(this,Dt)&&this[Dt][Ct]?Nt:!0},Ye=function(Pt,Ct){var Nt=O(Pt),Et=C(Ct);if(!(Nt===ge&&E(ce,Et)&&!E(Ae,Et))){var ie=ee(Nt,Et);return ie&&E(ce,Et)&&!(E(Nt,Dt)&&Nt[Dt][Et])&&(ie.enumerable=!0),ie}},Ze=function(Pt){var Ct=Pe(O(Pt)),Nt=[];return Ut(Ct,function(Et){!E(ce,Et)&&!E(_,Et)&&$e(Nt,Et)}),Nt},ut=function(It){var Pt=It===ge,Ct=Pe(Pt?Ae:O(It)),Nt=[];return Ut(Ct,function(Et){E(ce,Et)&&(!Pt||E(ge,Et))&&$e(Nt,ce[Et])}),Nt};$||(ae=function(){if(R(Mt,this))throw new re("Symbol is not a constructor");var Pt=!arguments.length||arguments[0]===void 0?void 0:D(arguments[0]),Ct=tt(Pt),Nt=function(Et){var ie=this===void 0?d:this;ie===ge&&h(Nt,Ae,Et),E(ie,Dt)&&E(ie[Dt],Ct)&&(ie[Dt][Ct]=!1);var we=M(1,Et);try{Ft(ie,Ct,we)}catch(Rt){if(!(Rt instanceof Ht))throw Rt;bt(ie,Ct,we)}};return T&&de&&Ft(ge,Ct,{configurable:!0,set:Nt}),Tt(Ct,Pt)},Mt=ae[Qt],J(Mt,"toString",function(){return me(this).tag}),J(ae,"withoutSetter",function(It){return Tt(tt(It),It)}),Z.f=Yt,V.f=qt,Y.f=te,B.f=Ye,U.f=j.f=Ze,G.f=ut,lt.f=function(It){return Tt(et(It),It)},T&&(q(Mt,"description",{configurable:!0,get:function(){return me(this).description}}),y||J(ge,"propertyIsEnumerable",Yt,{unsafe:!0}))),u({global:!0,constructor:!0,wrap:!0,forced:!$,sham:!$},{Symbol:ae}),Ut(z(Te),function(It){mt(It)}),u({target:Xt,stat:!0,forced:!$},{useSetter:function(){de=!0},useSimple:function(){de=!1}}),u({target:"Object",stat:!0,forced:!$,sham:!T},{create:Zt,defineProperty:qt,defineProperties:te,getOwnPropertyDescriptor:Ye}),u({target:"Object",stat:!0,forced:!$},{getOwnPropertyNames:Ze}),gt(),xt(ae,Xt),_[Dt]=!0},function(x,b,r){var u=r(4),d=r(5).f,h=r(43),p=r(47),y=r(37),T=r(55),$=r(67);x.exports=function(A,E){var R=A.target,I=A.global,O=A.stat,C,D,M,F,z,U;if(I?D=u:O?D=u[R]||y(R,{}):D=u[R]&&u[R].prototype,D)for(M in E){if(z=E[M],A.dontCallGetSet?(U=d(D,M),F=U&&U.value):F=D[M],C=$(I?M:R+(O?".":"#")+M,A.forced),!C&&F!==void 0){if(typeof z==typeof F)continue;T(z,F)}(A.sham||F&&F.sham)&&h(z,"sham",!0),p(D,M,z,A)}}},function(x){var b=function(r){return r&&r.Math===Math&&r};x.exports=b(typeof globalThis=="object"&&globalThis)||b(typeof window=="object"&&window)||b(typeof self=="object"&&self)||b(typeof global=="object"&&global)||b(typeof this=="object"&&this)||function(){return this}()||Function("return this")()},function(x,b,r){var u=r(6),d=r(8),h=r(10),p=r(11),y=r(12),T=r(18),$=r(38),A=r(41),E=Object.getOwnPropertyDescriptor;b.f=u?E:function(I,O){if(I=y(I),O=T(O),A)try{return E(I,O)}catch(C){}if($(I,O))return p(!d(h.f,I,O),I[O])}},function(x,b,r){var u=r(7);x.exports=!u(function(){return Object.defineProperty({},1,{get:function(){return 7}})[1]!==7})},function(x){x.exports=function(b){try{return!!b()}catch(r){return!0}}},function(x,b,r){var u=r(9),d=Function.prototype.call;x.exports=u?d.bind(d):function(){return d.apply(d,arguments)}},function(x,b,r){var u=r(7);x.exports=!u(function(){var d=function(){}.bind();return typeof d!="function"||d.hasOwnProperty("prototype")})},function(x,b){var r={}.propertyIsEnumerable,u=Object.getOwnPropertyDescriptor,d=u&&!r.call({1:2},1);b.f=d?function(p){var y=u(this,p);return!!y&&y.enumerable}:r},function(x){x.exports=function(b,r){return{enumerable:!(b&1),configurable:!(b&2),writable:!(b&4),value:r}}},function(x,b,r){var u=r(13),d=r(16);x.exports=function(h){return u(d(h))}},function(x,b,r){var u=r(14),d=r(7),h=r(15),p=Object,y=u("".split);x.exports=d(function(){return!p("z").propertyIsEnumerable(0)})?function(T){return h(T)==="String"?y(T,""):p(T)}:p},function(x,b,r){var u=r(9),d=Function.prototype,h=d.call,p=u&&d.bind.bind(h,h);x.exports=u?p:function(y){return function(){return h.apply(y,arguments)}}},function(x,b,r){var u=r(14),d=u({}.toString),h=u("".slice);x.exports=function(p){return h(d(p),8,-1)}},function(x,b,r){var u=r(17),d=TypeError;x.exports=function(h){if(u(h))throw new d("Can't call method on "+h);return h}},function(x){x.exports=function(b){return b==null}},function(x,b,r){var u=r(19),d=r(22);x.exports=function(h){var p=u(h,"string");return d(p)?p:p+""}},function(x,b,r){var u=r(8),d=r(20),h=r(22),p=r(29),y=r(32),T=r(33),$=TypeError,A=T("toPrimitive");x.exports=function(E,R){if(!d(E)||h(E))return E;var I=p(E,A),O;if(I){if(R===void 0&&(R="default"),O=u(I,E,R),!d(O)||h(O))return O;throw new $("Can't convert object to primitive value")}return R===void 0&&(R="number"),y(E,R)}},function(x,b,r){var u=r(21);x.exports=function(d){return typeof d=="object"?d!==null:u(d)}},function(x){var b=typeof document=="object"&&document.all;x.exports=typeof b=="undefined"&&b!==void 0?function(r){return typeof r=="function"||r===b}:function(r){return typeof r=="function"}},function(x,b,r){var u=r(23),d=r(21),h=r(24),p=r(25),y=Object;x.exports=p?function(T){return typeof T=="symbol"}:function(T){var $=u("Symbol");return d($)&&h($.prototype,y(T))}},function(x,b,r){var u=r(4),d=r(21),h=function(p){return d(p)?p:void 0};x.exports=function(p,y){return arguments.length<2?h(u[p]):u[p]&&u[p][y]}},function(x,b,r){var u=r(14);x.exports=u({}.isPrototypeOf)},function(x,b,r){var u=r(26);x.exports=u&&!Symbol.sham&&typeof Symbol.iterator=="symbol"},function(x,b,r){var u=r(27),d=r(7),h=r(4),p=h.String;x.exports=!!Object.getOwnPropertySymbols&&!d(function(){var y=Symbol("symbol detection");return!p(y)||!(Object(y)instanceof Symbol)||!Symbol.sham&&u&&u<41})},function(x,b,r){var u=r(4),d=r(28),h=u.process,p=u.Deno,y=h&&h.versions||p&&p.version,T=y&&y.v8,$,A;T&&($=T.split("."),A=$[0]>0&&$[0]<4?1:+($[0]+$[1])),!A&&d&&($=d.match(/Edge\/(\d+)/),(!$||$[1]>=74)&&($=d.match(/Chrome\/(\d+)/),$&&(A=+$[1]))),x.exports=A},function(x,b,r){var u=r(4),d=u.navigator,h=d&&d.userAgent;x.exports=h?String(h):""},function(x,b,r){var u=r(30),d=r(17);x.exports=function(h,p){var y=h[p];return d(y)?void 0:u(y)}},function(x,b,r){var u=r(21),d=r(31),h=TypeError;x.exports=function(p){if(u(p))return p;throw new h(d(p)+" is not a function")}},function(x){var b=String;x.exports=function(r){try{return b(r)}catch(u){return"Object"}}},function(x,b,r){var u=r(8),d=r(21),h=r(20),p=TypeError;x.exports=function(y,T){var $,A;if(T==="string"&&d($=y.toString)&&!h(A=u($,y))||d($=y.valueOf)&&!h(A=u($,y))||T!=="string"&&d($=y.toString)&&!h(A=u($,y)))return A;throw new p("Can't convert object to primitive value")}},function(x,b,r){var u=r(4),d=r(34),h=r(38),p=r(40),y=r(26),T=r(25),$=u.Symbol,A=d("wks"),E=T?$.for||$:$&&$.withoutSetter||p;x.exports=function(R){return h(A,R)||(A[R]=y&&h($,R)?$[R]:E("Symbol."+R)),A[R]}},function(x,b,r){var u=r(35);x.exports=function(d,h){return u[d]||(u[d]=h||{})}},function(x,b,r){var u=r(36),d=r(4),h=r(37),p="__core-js_shared__",y=x.exports=d[p]||h(p,{});(y.versions||(y.versions=[])).push({version:"3.41.0",mode:u?"pure":"global",copyright:"\xA9 2014-2025 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.41.0/LICENSE",source:"https://github.com/zloirock/core-js"})},function(x){x.exports=!1},function(x,b,r){var u=r(4),d=Object.defineProperty;x.exports=function(h,p){try{d(u,h,{value:p,configurable:!0,writable:!0})}catch(y){u[h]=p}return p}},function(x,b,r){var u=r(14),d=r(39),h=u({}.hasOwnProperty);x.exports=Object.hasOwn||function(y,T){return h(d(y),T)}},function(x,b,r){var u=r(16),d=Object;x.exports=function(h){return d(u(h))}},function(x,b,r){var u=r(14),d=0,h=Math.random(),p=u(1 .toString);x.exports=function(y){return"Symbol("+(y===void 0?"":y)+")_"+p(++d+h,36)}},function(x,b,r){var u=r(6),d=r(7),h=r(42);x.exports=!u&&!d(function(){return Object.defineProperty(h("div"),"a",{get:function(){return 7}}).a!==7})},function(x,b,r){var u=r(4),d=r(20),h=u.document,p=d(h)&&d(h.createElement);x.exports=function(y){return p?h.createElement(y):{}}},function(x,b,r){var u=r(6),d=r(44),h=r(11);x.exports=u?function(p,y,T){return d.f(p,y,h(1,T))}:function(p,y,T){return p[y]=T,p}},function(x,b,r){var u=r(6),d=r(41),h=r(45),p=r(46),y=r(18),T=TypeError,$=Object.defineProperty,A=Object.getOwnPropertyDescriptor,E="enumerable",R="configurable",I="writable";b.f=u?h?function(C,D,M){if(p(C),D=y(D),p(M),typeof C=="function"&&D==="prototype"&&"value"in M&&I in M&&!M[I]){var F=A(C,D);F&&F[I]&&(C[D]=M.value,M={configurable:R in M?M[R]:F[R],enumerable:E in M?M[E]:F[E],writable:!1})}return $(C,D,M)}:$:function(C,D,M){if(p(C),D=y(D),p(M),d)try{return $(C,D,M)}catch(F){}if("get"in M||"set"in M)throw new T("Accessors not supported");return"value"in M&&(C[D]=M.value),C}},function(x,b,r){var u=r(6),d=r(7);x.exports=u&&d(function(){return Object.defineProperty(function(){},"prototype",{value:42,writable:!1}).prototype!==42})},function(x,b,r){var u=r(20),d=String,h=TypeError;x.exports=function(p){if(u(p))return p;throw new h(d(p)+" is not an object")}},function(x,b,r){var u=r(21),d=r(44),h=r(48),p=r(37);x.exports=function(y,T,$,A){A||(A={});var E=A.enumerable,R=A.name!==void 0?A.name:T;if(u($)&&h($,R,A),A.global)E?y[T]=$:p(T,$);else{try{A.unsafe?y[T]&&(E=!0):delete y[T]}catch(I){}E?y[T]=$:d.f(y,T,{value:$,enumerable:!1,configurable:!A.nonConfigurable,writable:!A.nonWritable})}return y}},function(x,b,r){var u=r(14),d=r(7),h=r(21),p=r(38),y=r(6),T=r(49).CONFIGURABLE,$=r(50),A=r(51),E=A.enforce,R=A.get,I=String,O=Object.defineProperty,C=u("".slice),D=u("".replace),M=u([].join),F=y&&!d(function(){return O(function(){},"length",{value:8}).length!==8}),z=String(String).split("String"),U=x.exports=function(j,G,B){C(I(G),0,7)==="Symbol("&&(G="["+D(I(G),/^Symbol\(([^)]*)\).*$/,"$1")+"]"),B&&B.getter&&(G="get "+G),B&&B.setter&&(G="set "+G),(!p(j,"name")||T&&j.name!==G)&&(y?O(j,"name",{value:G,configurable:!0}):j.name=G),F&&B&&p(B,"arity")&&j.length!==B.arity&&O(j,"length",{value:B.arity});try{B&&p(B,"constructor")&&B.constructor?y&&O(j,"prototype",{writable:!1}):j.prototype&&(j.prototype=void 0)}catch(Y){}var V=E(j);return p(V,"source")||(V.source=M(z,typeof G=="string"?G:"")),j};Function.prototype.toString=U(function(){return h(this)&&R(this).source||$(this)},"toString")},function(x,b,r){var u=r(6),d=r(38),h=Function.prototype,p=u&&Object.getOwnPropertyDescriptor,y=d(h,"name"),T=y&&function(){}.name==="something",$=y&&(!u||u&&p(h,"name").configurable);x.exports={EXISTS:y,PROPER:T,CONFIGURABLE:$}},function(x,b,r){var u=r(14),d=r(21),h=r(35),p=u(Function.toString);d(h.inspectSource)||(h.inspectSource=function(y){return p(y)}),x.exports=h.inspectSource},function(x,b,r){var u=r(52),d=r(4),h=r(20),p=r(43),y=r(38),T=r(35),$=r(53),A=r(54),E="Object already initialized",R=d.TypeError,I=d.WeakMap,O,C,D,M=function(j){return D(j)?C(j):O(j,{})},F=function(j){return function(G){var B;if(!h(G)||(B=C(G)).type!==j)throw new R("Incompatible receiver, "+j+" required");return B}};if(u||T.state){var z=T.state||(T.state=new I);z.get=z.get,z.has=z.has,z.set=z.set,O=function(j,G){if(z.has(j))throw new R(E);return G.facade=j,z.set(j,G),G},C=function(j){return z.get(j)||{}},D=function(j){return z.has(j)}}else{var U=$("state");A[U]=!0,O=function(j,G){if(y(j,U))throw new R(E);return G.facade=j,p(j,U,G),G},C=function(j){return y(j,U)?j[U]:{}},D=function(j){return y(j,U)}}x.exports={set:O,get:C,has:D,enforce:M,getterFor:F}},function(x,b,r){var u=r(4),d=r(21),h=u.WeakMap;x.exports=d(h)&&/native code/.test(String(h))},function(x,b,r){var u=r(34),d=r(40),h=u("keys");x.exports=function(p){return h[p]||(h[p]=d(p))}},function(x){x.exports={}},function(x,b,r){var u=r(38),d=r(56),h=r(5),p=r(44);x.exports=function(y,T,$){for(var A=d(T),E=p.f,R=h.f,I=0;IR;)d(E,O=A[R++])&&(~p(I,O)||T(I,O));return I}},function(x,b,r){var u=r(12),d=r(60),h=r(63),p=function(y){return function(T,$,A){var E=u(T),R=h(E);if(R===0)return!y&&-1;var I=d(A,R),O;if(y&&$!==$){for(;R>I;)if(O=E[I++],O!==O)return!0}else for(;R>I;I++)if((y||I in E)&&E[I]===$)return y||I||0;return!y&&-1}};x.exports={includes:p(!0),indexOf:p(!1)}},function(x,b,r){var u=r(61),d=Math.max,h=Math.min;x.exports=function(p,y){var T=u(p);return T<0?d(T+y,0):h(T,y)}},function(x,b,r){var u=r(62);x.exports=function(d){var h=+d;return h!==h||h===0?0:u(h)}},function(x){var b=Math.ceil,r=Math.floor;x.exports=Math.trunc||function(d){var h=+d;return(h>0?r:b)(h)}},function(x,b,r){var u=r(64);x.exports=function(d){return u(d.length)}},function(x,b,r){var u=r(61),d=Math.min;x.exports=function(h){var p=u(h);return p>0?d(p,9007199254740991):0}},function(x){x.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(x,b){b.f=Object.getOwnPropertySymbols},function(x,b,r){var u=r(7),d=r(21),h=/#|\.prototype\./,p=function(E,R){var I=T[y(E)];return I===A?!0:I===$?!1:d(R)?u(R):!!R},y=p.normalize=function(E){return String(E).replace(h,".").toLowerCase()},T=p.data={},$=p.NATIVE="N",A=p.POLYFILL="P";x.exports=p},function(x,b,r){var u=r(69),d=String;x.exports=function(h){if(u(h)==="Symbol")throw new TypeError("Cannot convert a Symbol value to a string");return d(h)}},function(x,b,r){var u=r(70),d=r(21),h=r(15),p=r(33),y=p("toStringTag"),T=Object,$=h(function(){return arguments}())==="Arguments",A=function(E,R){try{return E[R]}catch(I){}};x.exports=u?h:function(E){var R,I,O;return E===void 0?"Undefined":E===null?"Null":typeof(I=A(R=T(E),y))=="string"?I:$?h(R):(O=h(R))==="Object"&&d(R.callee)?"Arguments":O}},function(x,b,r){var u=r(33),d=u("toStringTag"),h={};h[d]="z",x.exports=String(h)==="[object z]"},function(x,b,r){var u=r(46),d=r(72),h=r(65),p=r(54),y=r(74),T=r(42),$=r(53),A=">",E="<",R="prototype",I="script",O=$("IE_PROTO"),C=function(){},D=function(j){return E+I+A+j+E+"/"+I+A},M=function(j){j.write(D("")),j.close();var G=j.parentWindow.Object;return j=null,G},F=function(){var j=T("iframe"),G="java"+I+":",B;return j.style.display="none",y.appendChild(j),j.src=String(G),B=j.contentWindow.document,B.open(),B.write(D("document.F=Object")),B.close(),B.F},z,U=function(){try{z=new ActiveXObject("htmlfile")}catch(G){}U=typeof document!="undefined"?document.domain&&z?M(z):F():M(z);for(var j=h.length;j--;)delete U[R][h[j]];return U()};p[O]=!0,x.exports=Object.create||function(G,B){var V;return G!==null?(C[R]=u(G),V=new C,C[R]=null,V[O]=G):V=U(),B===void 0?V:d.f(V,B)}},function(x,b,r){var u=r(6),d=r(45),h=r(44),p=r(46),y=r(12),T=r(73);b.f=u&&!d?Object.defineProperties:function(A,E){p(A);for(var R=y(E),I=T(E),O=I.length,C=0,D;O>C;)h.f(A,D=I[C++],R[D]);return A}},function(x,b,r){var u=r(58),d=r(65);x.exports=Object.keys||function(p){return u(p,d)}},function(x,b,r){var u=r(23);x.exports=u("document","documentElement")},function(x,b,r){var u=r(15),d=r(12),h=r(57).f,p=r(76),y=typeof window=="object"&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],T=function($){try{return h($)}catch(A){return p(y)}};x.exports.f=function(A){return y&&u(A)==="Window"?T(A):h(d(A))}},function(x,b,r){var u=r(14);x.exports=u([].slice)},function(x,b,r){var u=r(48),d=r(44);x.exports=function(h,p,y){return y.get&&u(y.get,p,{getter:!0}),y.set&&u(y.set,p,{setter:!0}),d.f(h,p,y)}},function(x,b,r){var u=r(33);b.f=u},function(x,b,r){var u=r(80),d=r(38),h=r(78),p=r(44).f;x.exports=function(y){var T=u.Symbol||(u.Symbol={});d(T,y)||p(T,y,{value:h.f(y)})}},function(x,b,r){var u=r(4);x.exports=u},function(x,b,r){var u=r(8),d=r(23),h=r(33),p=r(47);x.exports=function(){var y=d("Symbol"),T=y&&y.prototype,$=T&&T.valueOf,A=h("toPrimitive");T&&!T[A]&&p(T,A,function(E){return u($,this)},{arity:1})}},function(x,b,r){var u=r(44).f,d=r(38),h=r(33),p=h("toStringTag");x.exports=function(y,T,$){y&&!$&&(y=y.prototype),y&&!d(y,p)&&u(y,p,{configurable:!0,value:T})}},function(x,b,r){var u=r(84),d=r(14),h=r(13),p=r(39),y=r(63),T=r(86),$=d([].push),A=function(E){var R=E===1,I=E===2,O=E===3,C=E===4,D=E===6,M=E===7,F=E===5||D;return function(z,U,j,G){for(var B=p(z),V=h(B),Y=y(V),Z=u(U,j),J=0,q=G||T,nt=R?q(z,Y):I||M?q(z,0):void 0,rt,_;Y>J;J++)if((F||J in V)&&(rt=V[J],_=Z(rt,J,B),E))if(R)nt[J]=_;else if(_)switch(E){case 3:return!0;case 5:return rt;case 6:return J;case 2:$(nt,rt)}else switch(E){case 4:return!1;case 7:$(nt,rt)}return D?-1:O||C?C:nt}};x.exports={forEach:A(0),map:A(1),filter:A(2),some:A(3),every:A(4),find:A(5),findIndex:A(6),filterReject:A(7)}},function(x,b,r){var u=r(85),d=r(30),h=r(9),p=u(u.bind);x.exports=function(y,T){return d(y),T===void 0?y:h?p(y,T):function(){return y.apply(T,arguments)}}},function(x,b,r){var u=r(15),d=r(14);x.exports=function(h){if(u(h)==="Function")return d(h)}},function(x,b,r){var u=r(87);x.exports=function(d,h){return new(u(d))(h===0?0:h)}},function(x,b,r){var u=r(88),d=r(89),h=r(20),p=r(33),y=p("species"),T=Array;x.exports=function($){var A;return u($)&&(A=$.constructor,d(A)&&(A===T||u(A.prototype))?A=void 0:h(A)&&(A=A[y],A===null&&(A=void 0))),A===void 0?T:A}},function(x,b,r){var u=r(15);x.exports=Array.isArray||function(h){return u(h)==="Array"}},function(x,b,r){var u=r(14),d=r(7),h=r(21),p=r(69),y=r(23),T=r(50),$=function(){},A=y("Reflect","construct"),E=/^\s*(?:class|function)\b/,R=u(E.exec),I=!E.test($),O=function(M){if(!h(M))return!1;try{return A($,[],M),!0}catch(F){return!1}},C=function(M){if(!h(M))return!1;switch(p(M)){case"AsyncFunction":case"GeneratorFunction":case"AsyncGeneratorFunction":return!1}try{return I||!!R(E,T(M))}catch(F){return!0}};C.sham=!0,x.exports=!A||d(function(){var D;return O(O.call)||!O(Object)||!O(function(){D=!0})||D})?C:O},function(x,b,r){var u=r(3),d=r(23),h=r(38),p=r(68),y=r(34),T=r(91),$=y("string-to-symbol-registry"),A=y("symbol-to-string-registry");u({target:"Symbol",stat:!0,forced:!T},{for:function(E){var R=p(E);if(h($,R))return $[R];var I=d("Symbol")(R);return $[R]=I,A[I]=R,I}})},function(x,b,r){var u=r(26);x.exports=u&&!!Symbol.for&&!!Symbol.keyFor},function(x,b,r){var u=r(3),d=r(38),h=r(22),p=r(31),y=r(34),T=r(91),$=y("symbol-to-string-registry");u({target:"Symbol",stat:!0,forced:!T},{keyFor:function(E){if(!h(E))throw new TypeError(p(E)+" is not a symbol");if(d($,E))return $[E]}})},function(x,b,r){var u=r(3),d=r(23),h=r(94),p=r(8),y=r(14),T=r(7),$=r(21),A=r(22),E=r(76),R=r(95),I=r(26),O=String,C=d("JSON","stringify"),D=y(/./.exec),M=y("".charAt),F=y("".charCodeAt),z=y("".replace),U=y(1 .toString),j=/[\uD800-\uDFFF]/g,G=/^[\uD800-\uDBFF]$/,B=/^[\uDC00-\uDFFF]$/,V=!I||T(function(){var q=d("Symbol")("stringify detection");return C([q])!=="[null]"||C({a:q})!=="{}"||C(Object(q))!=="{}"}),Y=T(function(){return C("\uDF06\uD834")!=='"\\udf06\\ud834"'||C("\uDEAD")!=='"\\udead"'}),Z=function(q,nt){var rt=E(arguments),_=R(nt);if(!(!$(_)&&(q===void 0||A(q))))return rt[1]=function(tt,et){if($(_)&&(et=p(_,this,O(tt),et)),!A(et))return et},h(C,null,rt)},J=function(q,nt,rt){var _=M(rt,nt-1),tt=M(rt,nt+1);return D(G,q)&&!D(B,tt)||D(B,q)&&!D(G,_)?"\\u"+U(F(q,0),16):q};C&&u({target:"JSON",stat:!0,arity:3,forced:V||Y},{stringify:function(nt,rt,_){var tt=E(arguments),et=h(V?Z:C,null,tt);return Y&&typeof et=="string"?z(et,j,J):et}})},function(x,b,r){var u=r(9),d=Function.prototype,h=d.apply,p=d.call;x.exports=typeof Reflect=="object"&&Reflect.apply||(u?p.bind(h):function(){return p.apply(h,arguments)})},function(x,b,r){var u=r(14),d=r(88),h=r(21),p=r(15),y=r(68),T=u([].push);x.exports=function($){if(h($))return $;if(d($)){for(var A=$.length,E=[],R=0;Rj&&R(_,arguments[j]),_});if(J.prototype=Y,B!=="Error"?y?y(J,Z):T(J,Z,{name:!0}):O&&U in V&&($(J,V,U),$(J,V,"prepareStackTrace")),T(J,V),!C)try{Y.name!==B&&h(Y,"name",B),Y.constructor=J}catch(q){}return J}}},function(x,b,r){var u=r(114),d=r(20),h=r(16),p=r(115);x.exports=Object.setPrototypeOf||("__proto__"in{}?function(){var y=!1,T={},$;try{$=u(Object.prototype,"__proto__","set"),$(T,[]),y=T instanceof Array}catch(A){}return function(E,R){return h(E),p(R),d(E)&&(y?$(E,R):E.__proto__=R),E}}():void 0)},function(x,b,r){var u=r(14),d=r(30);x.exports=function(h,p,y){try{return u(d(Object.getOwnPropertyDescriptor(h,p)[y]))}catch(T){}}},function(x,b,r){var u=r(116),d=String,h=TypeError;x.exports=function(p){if(u(p))return p;throw new h("Can't set "+d(p)+" as a prototype")}},function(x,b,r){var u=r(20);x.exports=function(d){return u(d)||d===null}},function(x,b,r){var u=r(44).f;x.exports=function(d,h,p){p in d||u(d,p,{configurable:!0,get:function(){return h[p]},set:function(y){h[p]=y}})}},function(x,b,r){var u=r(21),d=r(20),h=r(113);x.exports=function(p,y,T){var $,A;return h&&u($=y.constructor)&&$!==T&&d(A=$.prototype)&&A!==T.prototype&&h(p,A),p}},function(x,b,r){var u=r(68);x.exports=function(d,h){return d===void 0?arguments.length<2?"":h:u(d)}},function(x,b,r){var u=r(20),d=r(43);x.exports=function(h,p){u(p)&&"cause"in p&&d(h,"cause",p.cause)}},function(x,b,r){var u=r(43),d=r(122),h=r(123),p=Error.captureStackTrace;x.exports=function(y,T,$,A){h&&(p?p(y,T):u(y,"stack",d($,A)))}},function(x,b,r){var u=r(14),d=Error,h=u("".replace),p=function($){return String(new d($).stack)}("zxcasd"),y=/\n\s*at [^:]*:[^\n]*/,T=y.test(p);x.exports=function($,A){if(T&&typeof $=="string"&&!d.prepareStackTrace)for(;A--;)$=h($,y,"");return $}},function(x,b,r){var u=r(7),d=r(11);x.exports=!u(function(){var h=new Error("a");return"stack"in h?(Object.defineProperty(h,"stack",d(1,7)),h.stack!==7):!0})},function(x,b,r){var u=r(47),d=r(125),h=Error.prototype;h.toString!==d&&u(h,"toString",d)},function(x,b,r){var u=r(6),d=r(7),h=r(46),p=r(119),y=Error.prototype.toString,T=d(function(){if(u){var $=Object.create(Object.defineProperty({},"name",{get:function(){return this===$}}));if(y.call($)!=="true")return!0}return y.call({message:1,name:2})!=="2: 1"||y.call({})!=="Error"});x.exports=T?function(){var A=h(this),E=p(A.name,"Error"),R=p(A.message);return E?R?E+": "+R:E:R}:y},function(x,b,r){r(127)},function(x,b,r){var u=r(3),d=r(24),h=r(128),p=r(113),y=r(55),T=r(71),$=r(43),A=r(11),E=r(120),R=r(121),I=r(130),O=r(119),C=r(33),D=C("toStringTag"),M=Error,F=[].push,z=function(G,B){var V=d(U,this),Y;p?Y=p(new M,V?h(this):U):(Y=V?this:T(U),$(Y,D,"Error")),B!==void 0&&$(Y,"message",O(B)),R(Y,z,Y.stack,1),arguments.length>2&&E(Y,arguments[2]);var Z=[];return I(G,F,{that:Z}),$(Y,"errors",Z),Y};p?p(z,M):y(z,M,{name:!0});var U=z.prototype=T(M.prototype,{constructor:A(1,z),message:A(1,""),name:A(1,"AggregateError")});u({global:!0,constructor:!0,arity:2},{AggregateError:z})},function(x,b,r){var u=r(38),d=r(21),h=r(39),p=r(53),y=r(129),T=p("IE_PROTO"),$=Object,A=$.prototype;x.exports=y?$.getPrototypeOf:function(E){var R=h(E);if(u(R,T))return R[T];var I=R.constructor;return d(I)&&R instanceof I?I.prototype:R instanceof $?A:null}},function(x,b,r){var u=r(7);x.exports=!u(function(){function d(){}return d.prototype.constructor=null,Object.getPrototypeOf(new d)!==d.prototype})},function(x,b,r){var u=r(84),d=r(8),h=r(46),p=r(31),y=r(131),T=r(63),$=r(24),A=r(133),E=r(134),R=r(135),I=TypeError,O=function(D,M){this.stopped=D,this.result=M},C=O.prototype;x.exports=function(D,M,F){var z=F&&F.that,U=!!(F&&F.AS_ENTRIES),j=!!(F&&F.IS_RECORD),G=!!(F&&F.IS_ITERATOR),B=!!(F&&F.INTERRUPTED),V=u(M,z),Y,Z,J,q,nt,rt,_,tt=function(lt){return Y&&R(Y,"normal",lt),new O(!0,lt)},et=function(lt){return U?(h(lt),B?V(lt[0],lt[1],tt):V(lt[0],lt[1])):B?V(lt,tt):V(lt)};if(j)Y=D.iterator;else if(G)Y=D;else{if(Z=E(D),!Z)throw new I(p(D)+" is not iterable");if(y(Z)){for(J=0,q=T(D);q>J;J++)if(nt=et(D[J]),nt&&$(C,nt))return nt;return new O(!1)}Y=A(D,Z)}for(rt=j?D.next:Y.next;!(_=d(rt,Y)).done;){try{nt=et(_.value)}catch(lt){R(Y,"throw",lt)}if(typeof nt=="object"&&nt&&$(C,nt))return nt}return new O(!1)}},function(x,b,r){var u=r(33),d=r(132),h=u("iterator"),p=Array.prototype;x.exports=function(y){return y!==void 0&&(d.Array===y||p[h]===y)}},function(x){x.exports={}},function(x,b,r){var u=r(8),d=r(30),h=r(46),p=r(31),y=r(134),T=TypeError;x.exports=function($,A){var E=arguments.length<2?y($):A;if(d(E))return h(u(E,$));throw new T(p($)+" is not iterable")}},function(x,b,r){var u=r(69),d=r(29),h=r(17),p=r(132),y=r(33),T=y("iterator");x.exports=function($){if(!h($))return d($,T)||d($,"@@iterator")||p[u($)]}},function(x,b,r){var u=r(8),d=r(46),h=r(29);x.exports=function(p,y,T){var $,A;d(p);try{if($=h(p,"return"),!$){if(y==="throw")throw T;return T}$=u($,p)}catch(E){A=!0,$=E}if(y==="throw")throw T;if(A)throw $;return d($),T}},function(x,b,r){var u=r(3),d=r(23),h=r(94),p=r(7),y=r(112),T="AggregateError",$=d(T),A=!p(function(){return $([1]).errors[0]!==1})&&p(function(){return $([1],T,{cause:7}).cause!==7});u({global:!0,constructor:!0,arity:2,forced:A},{AggregateError:y(T,function(E){return function(I,O){return h(E,this,arguments)}},A,!0)})},function(x,b,r){var u=r(3),d=r(39),h=r(63),p=r(61),y=r(138);u({target:"Array",proto:!0},{at:function($){var A=d(this),E=h(A),R=p($),I=R>=0?R:E+R;return I<0||I>=E?void 0:A[I]}}),y("at")},function(x,b,r){var u=r(33),d=r(71),h=r(44).f,p=u("unscopables"),y=Array.prototype;y[p]===void 0&&h(y,p,{configurable:!0,value:d(null)}),x.exports=function(T){y[p][T]=!0}},function(x,b,r){var u=r(3),d=r(7),h=r(88),p=r(20),y=r(39),T=r(63),$=r(140),A=r(141),E=r(86),R=r(142),I=r(33),O=r(27),C=I("isConcatSpreadable"),D=O>=51||!d(function(){var z=[];return z[C]=!1,z.concat()[0]!==z}),M=function(z){if(!p(z))return!1;var U=z[C];return U!==void 0?!!U:h(z)},F=!D||!R("concat");u({target:"Array",proto:!0,arity:1,forced:F},{concat:function(U){var j=y(this),G=E(j,0),B=0,V,Y,Z,J,q;for(V=-1,Z=arguments.length;Vr)throw b("Maximum allowed index exceeded");return u}},function(x,b,r){var u=r(6),d=r(44),h=r(11);x.exports=function(p,y,T){u?d.f(p,y,h(0,T)):p[y]=T}},function(x,b,r){var u=r(7),d=r(33),h=r(27),p=d("species");x.exports=function(y){return h>=51||!u(function(){var T=[],$=T.constructor={};return $[p]=function(){return{foo:1}},T[y](Boolean).foo!==1})}},function(x,b,r){var u=r(3),d=r(144),h=r(138);u({target:"Array",proto:!0},{copyWithin:d}),h("copyWithin")},function(x,b,r){var u=r(39),d=r(60),h=r(63),p=r(145),y=Math.min;x.exports=[].copyWithin||function($,A){var E=u(this),R=h(E),I=d($,R),O=d(A,R),C=arguments.length>2?arguments[2]:void 0,D=y((C===void 0?R:d(C,R))-O,R-I),M=1;for(O0;)O in E?E[I]=E[O]:p(E,I),I+=M,O+=M;return E}},function(x,b,r){var u=r(31),d=TypeError;x.exports=function(h,p){if(!delete h[p])throw new d("Cannot delete property "+u(p)+" of "+u(h))}},function(x,b,r){var u=r(3),d=r(83).every,h=r(147),p=h("every");u({target:"Array",proto:!0,forced:!p},{every:function(T){return d(this,T,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(7);x.exports=function(d,h){var p=[][d];return!!p&&u(function(){p.call(null,h||function(){return 1},1)})}},function(x,b,r){var u=r(3),d=r(149),h=r(138);u({target:"Array",proto:!0},{fill:d}),h("fill")},function(x,b,r){var u=r(39),d=r(60),h=r(63);x.exports=function(y){for(var T=u(this),$=h(T),A=arguments.length,E=d(A>1?arguments[1]:void 0,$),R=A>2?arguments[2]:void 0,I=R===void 0?$:d(R,$);I>E;)T[E++]=y;return T}},function(x,b,r){var u=r(3),d=r(83).filter,h=r(142),p=h("filter");u({target:"Array",proto:!0,forced:!p},{filter:function(T){return d(this,T,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(83).find,h=r(138),p="find",y=!0;p in[]&&Array(1)[p](function(){y=!1}),u({target:"Array",proto:!0,forced:y},{find:function($){return d(this,$,arguments.length>1?arguments[1]:void 0)}}),h(p)},function(x,b,r){var u=r(3),d=r(83).findIndex,h=r(138),p="findIndex",y=!0;p in[]&&Array(1)[p](function(){y=!1}),u({target:"Array",proto:!0,forced:y},{findIndex:function($){return d(this,$,arguments.length>1?arguments[1]:void 0)}}),h(p)},function(x,b,r){var u=r(3),d=r(154).findLast,h=r(138);u({target:"Array",proto:!0},{findLast:function(y){return d(this,y,arguments.length>1?arguments[1]:void 0)}}),h("findLast")},function(x,b,r){var u=r(84),d=r(13),h=r(39),p=r(63),y=function(T){var $=T===1;return function(A,E,R){for(var I=h(A),O=d(I),C=p(O),D=u(E,R),M,F;C-- >0;)if(M=O[C],F=D(M,C,I),F)switch(T){case 0:return M;case 1:return C}return $?-1:void 0}};x.exports={findLast:y(0),findLastIndex:y(1)}},function(x,b,r){var u=r(3),d=r(154).findLastIndex,h=r(138);u({target:"Array",proto:!0},{findLastIndex:function(y){return d(this,y,arguments.length>1?arguments[1]:void 0)}}),h("findLastIndex")},function(x,b,r){var u=r(3),d=r(157),h=r(39),p=r(63),y=r(61),T=r(86);u({target:"Array",proto:!0},{flat:function(){var A=arguments.length?arguments[0]:void 0,E=h(this),R=p(E),I=T(E,0);return I.length=d(I,E,E,R,0,A===void 0?1:y(A)),I}})},function(x,b,r){var u=r(88),d=r(63),h=r(140),p=r(84),y=function(T,$,A,E,R,I,O,C){for(var D=R,M=0,F=O?p(O,C):!1,z,U;M0&&u(z)?(U=d(z),D=y(T,$,z,U,D,I-1)-1):(h(D+1),T[D]=z),D++),M++;return D};x.exports=y},function(x,b,r){var u=r(3),d=r(157),h=r(30),p=r(39),y=r(63),T=r(86);u({target:"Array",proto:!0},{flatMap:function(A){var E=p(this),R=y(E),I;return h(A),I=T(E,0),I.length=d(I,E,E,R,0,1,A,arguments.length>1?arguments[1]:void 0),I}})},function(x,b,r){var u=r(3),d=r(160);u({target:"Array",proto:!0,forced:[].forEach!==d},{forEach:d})},function(x,b,r){var u=r(83).forEach,d=r(147),h=d("forEach");x.exports=h?[].forEach:function(y){return u(this,y,arguments.length>1?arguments[1]:void 0)}},function(x,b,r){var u=r(3),d=r(162),h=r(164),p=!h(function(y){Array.from(y)});u({target:"Array",stat:!0,forced:p},{from:d})},function(x,b,r){var u=r(84),d=r(8),h=r(39),p=r(163),y=r(131),T=r(89),$=r(63),A=r(141),E=r(133),R=r(134),I=Array;x.exports=function(C){var D=h(C),M=T(this),F=arguments.length,z=F>1?arguments[1]:void 0,U=z!==void 0;U&&(z=u(z,F>2?arguments[2]:void 0));var j=R(D),G=0,B,V,Y,Z,J,q;if(j&&!(this===I&&y(j)))for(V=M?new this:[],Z=E(D,j),J=Z.next;!(Y=d(J,Z)).done;G++)q=U?p(Z,z,[Y.value,G],!0):Y.value,A(V,G,q);else for(B=$(D),V=M?new this(B):I(B);B>G;G++)q=U?z(D[G],G):D[G],A(V,G,q);return V.length=G,V}},function(x,b,r){var u=r(46),d=r(135);x.exports=function(h,p,y,T){try{return T?p(u(y)[0],y[1]):p(y)}catch($){d(h,"throw",$)}}},function(x,b,r){var u=r(33),d=u("iterator"),h=!1;try{var p=0,y={next:function(){return{done:!!p++}},return:function(){h=!0}};y[d]=function(){return this},Array.from(y,function(){throw 2})}catch(T){}x.exports=function(T,$){try{if(!$&&!h)return!1}catch(R){return!1}var A=!1;try{var E={};E[d]=function(){return{next:function(){return{done:A=!0}}}},T(E)}catch(R){}return A}},function(x,b,r){var u=r(3),d=r(59).includes,h=r(7),p=r(138),y=h(function(){return!Array(1).includes()});u({target:"Array",proto:!0,forced:y},{includes:function($){return d(this,$,arguments.length>1?arguments[1]:void 0)}}),p("includes")},function(x,b,r){var u=r(3),d=r(85),h=r(59).indexOf,p=r(147),y=d([].indexOf),T=!!y&&1/y([1],1,-0)<0,$=T||!p("indexOf");u({target:"Array",proto:!0,forced:$},{indexOf:function(E){var R=arguments.length>1?arguments[1]:void 0;return T?y(this,E,R)||0:h(this,E,R)}})},function(x,b,r){var u=r(3),d=r(88);u({target:"Array",stat:!0},{isArray:d})},function(x,b,r){var u=r(12),d=r(138),h=r(132),p=r(51),y=r(44).f,T=r(169),$=r(172),A=r(36),E=r(6),R="Array Iterator",I=p.set,O=p.getterFor(R);x.exports=T(Array,"Array",function(D,M){I(this,{type:R,target:u(D),index:0,kind:M})},function(){var D=O(this),M=D.target,F=D.index++;if(!M||F>=M.length)return D.target=null,$(void 0,!0);switch(D.kind){case"keys":return $(F,!1);case"values":return $(M[F],!1)}return $([F,M[F]],!1)},"values");var C=h.Arguments=h.Array;if(d("keys"),d("values"),d("entries"),!A&&E&&C.name!=="values")try{y(C,"name",{value:"values"})}catch(D){}},function(x,b,r){var u=r(3),d=r(8),h=r(36),p=r(49),y=r(21),T=r(170),$=r(128),A=r(113),E=r(82),R=r(43),I=r(47),O=r(33),C=r(132),D=r(171),M=p.PROPER,F=p.CONFIGURABLE,z=D.IteratorPrototype,U=D.BUGGY_SAFARI_ITERATORS,j=O("iterator"),G="keys",B="values",V="entries",Y=function(){return this};x.exports=function(Z,J,q,nt,rt,_,tt){T(q,J,nt);var et=function(kt){if(kt===rt&&yt)return yt;if(!U&&kt&&kt in gt)return gt[kt];switch(kt){case G:return function(){return new q(this,kt)};case B:return function(){return new q(this,kt)};case V:return function(){return new q(this,kt)}}return function(){return new q(this)}},lt=J+" Iterator",mt=!1,gt=Z.prototype,xt=gt[j]||gt["@@iterator"]||rt&>[rt],yt=!U&&xt||et(rt),Ut=J==="Array"&>.entries||xt,Dt,Xt,Qt;if(Ut&&(Dt=$(Ut.call(new Z)),Dt!==Object.prototype&&Dt.next&&(!h&&$(Dt)!==z&&(A?A(Dt,z):y(Dt[j])||I(Dt,j,Y)),E(Dt,lt,!0,!0),h&&(C[lt]=Y))),M&&rt===B&&xt&&xt.name!==B&&(!h&&F?R(gt,"name",B):(mt=!0,yt=function(){return d(xt,this)})),rt)if(Xt={values:et(B),keys:_?yt:et(G),entries:et(V)},tt)for(Qt in Xt)(U||mt||!(Qt in gt))&&I(gt,Qt,Xt[Qt]);else u({target:J,proto:!0,forced:U||mt},Xt);return(!h||tt)&>[j]!==yt&&I(gt,j,yt,{name:rt}),C[J]=yt,Xt}},function(x,b,r){var u=r(171).IteratorPrototype,d=r(71),h=r(11),p=r(82),y=r(132),T=function(){return this};x.exports=function($,A,E,R){var I=A+" Iterator";return $.prototype=d(u,{next:h(+!R,E)}),p($,I,!1,!0),y[I]=T,$}},function(x,b,r){var u=r(7),d=r(21),h=r(20),p=r(71),y=r(128),T=r(47),$=r(33),A=r(36),E=$("iterator"),R=!1,I,O,C;[].keys&&(C=[].keys(),"next"in C?(O=y(y(C)),O!==Object.prototype&&(I=O)):R=!0);var D=!h(I)||u(function(){var M={};return I[E].call(M)!==M});D?I={}:A&&(I=p(I)),d(I[E])||T(I,E,function(){return this}),x.exports={IteratorPrototype:I,BUGGY_SAFARI_ITERATORS:R}},function(x){x.exports=function(b,r){return{value:b,done:r}}},function(x,b,r){var u=r(3),d=r(14),h=r(13),p=r(12),y=r(147),T=d([].join),$=h!==Object,A=$||!y("join",",");u({target:"Array",proto:!0,forced:A},{join:function(R){return T(p(this),R===void 0?",":R)}})},function(x,b,r){var u=r(3),d=r(175);u({target:"Array",proto:!0,forced:d!==[].lastIndexOf},{lastIndexOf:d})},function(x,b,r){var u=r(94),d=r(12),h=r(61),p=r(63),y=r(147),T=Math.min,$=[].lastIndexOf,A=!!$&&1/[1].lastIndexOf(1,-0)<0,E=y("lastIndexOf"),R=A||!E;x.exports=R?function(O){if(A)return u($,this,arguments)||0;var C=d(this),D=p(C);if(D===0)return-1;var M=D-1;for(arguments.length>1&&(M=T(M,h(arguments[1]))),M<0&&(M=D+M);M>=0;M--)if(M in C&&C[M]===O)return M||0;return-1}:$},function(x,b,r){var u=r(3),d=r(83).map,h=r(142),p=h("map");u({target:"Array",proto:!0,forced:!p},{map:function(T){return d(this,T,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(7),h=r(89),p=r(141),y=Array,T=d(function(){function $(){}return!(y.of.call($)instanceof $)});u({target:"Array",stat:!0,forced:T},{of:function(){for(var A=0,E=arguments.length,R=new(h(this)?this:y)(E);E>A;)p(R,A,arguments[A++]);return R.length=E,R}})},function(x,b,r){var u=r(3),d=r(39),h=r(63),p=r(179),y=r(140),T=r(7),$=T(function(){return[].push.call({length:4294967296},1)!==4294967297}),A=function(){try{Object.defineProperty([],"length",{writable:!1}).push()}catch(R){return R instanceof TypeError}},E=$||!A();u({target:"Array",proto:!0,arity:1,forced:E},{push:function(I){var O=d(this),C=h(O),D=arguments.length;y(C+D);for(var M=0;M79&&p<83,$=T||!h("reduce");u({target:"Array",proto:!0,forced:$},{reduce:function(E){var R=arguments.length;return d(this,E,R,R>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(30),d=r(39),h=r(13),p=r(63),y=TypeError,T="Reduce of empty array with no initial value",$=function(A){return function(E,R,I,O){var C=d(E),D=h(C),M=p(C);if(u(R),M===0&&I<2)throw new y(T);var F=A?M-1:0,z=A?-1:1;if(I<2)for(;;){if(F in D){O=D[F],F+=z;break}if(F+=z,A?F<0:M<=F)throw new y(T)}for(;A?F>=0:M>F;F+=z)F in D&&(O=R(O,D[F],F,C));return O}};x.exports={left:$(!1),right:$(!0)}},function(x,b,r){var u=r(183);x.exports=u==="NODE"},function(x,b,r){var u=r(4),d=r(28),h=r(15),p=function(y){return d.slice(0,y.length)===y};x.exports=function(){return p("Bun/")?"BUN":p("Cloudflare-Workers")?"CLOUDFLARE":p("Deno/")?"DENO":p("Node.js/")?"NODE":u.Bun&&typeof Bun.version=="string"?"BUN":u.Deno&&typeof Deno.version=="object"?"DENO":h(u.process)==="process"?"NODE":u.window&&u.document?"BROWSER":"REST"}()},function(x,b,r){var u=r(3),d=r(181).right,h=r(147),p=r(27),y=r(182),T=!y&&p>79&&p<83,$=T||!h("reduceRight");u({target:"Array",proto:!0,forced:$},{reduceRight:function(E){return d(this,E,arguments.length,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(14),h=r(88),p=d([].reverse),y=[1,2];u({target:"Array",proto:!0,forced:String(y)===String(y.reverse())},{reverse:function(){return h(this)&&(this.length=this.length),p(this)}})},function(x,b,r){var u=r(3),d=r(88),h=r(89),p=r(20),y=r(60),T=r(63),$=r(12),A=r(141),E=r(33),R=r(142),I=r(76),O=R("slice"),C=E("species"),D=Array,M=Math.max;u({target:"Array",proto:!0,forced:!O},{slice:function(z,U){var j=$(this),G=T(j),B=y(z,G),V=y(U===void 0?G:U,G),Y,Z,J;if(d(j)&&(Y=j.constructor,h(Y)&&(Y===D||d(Y.prototype))?Y=void 0:p(Y)&&(Y=Y[C],Y===null&&(Y=void 0)),Y===D||Y===void 0))return I(j,B,V);for(Z=new(Y===void 0?D:Y)(M(V-B,0)),J=0;B1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(14),h=r(30),p=r(39),y=r(63),T=r(145),$=r(68),A=r(7),E=r(189),R=r(147),I=r(190),O=r(191),C=r(27),D=r(192),M=[],F=d(M.sort),z=d(M.push),U=A(function(){M.sort(void 0)}),j=A(function(){M.sort(null)}),G=R("sort"),B=!A(function(){if(C)return C<70;if(!(I&&I>3)){if(O)return!0;if(D)return D<603;var Z="",J,q,nt,rt;for(J=65;J<76;J++){switch(q=String.fromCharCode(J),J){case 66:case 69:case 70:case 72:nt=3;break;case 68:case 71:nt=4;break;default:nt=2}for(rt=0;rt<47;rt++)M.push({k:q+rt,v:nt})}for(M.sort(function(_,tt){return tt.v-_.v}),rt=0;rt$(q)?1:-1}};u({target:"Array",proto:!0,forced:V},{sort:function(J){J!==void 0&&h(J);var q=p(this);if(B)return J===void 0?F(q):F(q,J);var nt=[],rt=y(q),_,tt;for(tt=0;tt0;)p[E]=p[--E];E!==$++&&(p[E]=A)}else for(var R=d(T/2),I=h(u(p,0,R),y),O=h(u(p,R),y),C=I.length,D=O.length,M=0,F=0;Mj-Y+V;J--)R(U,J-1)}else if(V>Y)for(J=j-Y;J>G;J--)q=J+Y-1,nt=J+V-1,q in U?U[nt]=U[q]:R(U,nt);for(J=0;J2?p:u(h),$=new d(T);T>y;)$[y]=h[y++];return $}},function(x,b,r){var u=r(4);x.exports=function(d,h){var p=u[d],y=p&&p.prototype;return y&&y[h]}},function(x,b,r){var u=r(3),d=r(138),h=r(140),p=r(63),y=r(60),T=r(12),$=r(61),A=Array,E=Math.max,R=Math.min;u({target:"Array",proto:!0},{toSpliced:function(O,C){var D=T(this),M=p(D),F=y(O,M),z=arguments.length,U=0,j,G,B,V;for(z===0?j=G=0:z===1?(j=0,G=M-F):(j=z-2,G=R(E($(C),0),M-F)),B=h(M+j-G),V=A(B);U=A||R<0)throw new h("Incorrect index");for(var I=new y(A),O=0;O>8&255]},se=function(bt){return[bt&255,bt>>8&255,bt>>16&255,bt>>24&255]},ee=function(bt){return bt[3]<<24|bt[2]<<16|bt[1]<<8|bt[0]},fe=function(bt){return ae(D(bt),23,4)},Pe=function(bt){return ae(bt,52,8)},Me=function(bt,Ft,Tt){$(bt[rt],Ft,{configurable:!0,get:function(){return Tt(this)[Ft]}})},$e=function(bt,Ft,Tt,qt){var te=lt(bt),Zt=C(Tt),Yt=!!qt;if(Zt+Ft>te.byteLength)throw new kt(tt);var Ye=te.bytes,Ze=Zt+te.byteOffset,ut=j(Ye,Ze,Ze+Ft);return Yt?ut:ge(ut)},ce=function(bt,Ft,Tt,qt,te,Zt){var Yt=lt(bt),Ye=C(Tt),Ze=qt(+te),ut=!!Zt;if(Ye+Ft>Yt.byteLength)throw new kt(tt);for(var It=Yt.bytes,Pt=Ye+Yt.byteOffset,Ct=0;CtZt)throw new kt("Wrong offset");if(qt=qt===void 0?Zt-Yt:O(qt),Yt+qt>Zt)throw new kt(_);mt(this,{type:nt,buffer:Ft,byteLength:qt,byteOffset:Yt,bytes:te.bytes}),h||(this.buffer=Ft,this.byteLength=qt,this.byteOffset=Yt)},Dt=Ut[rt],h&&(Me(xt,"byteLength",et),Me(Ut,"buffer",lt),Me(Ut,"byteLength",lt),Me(Ut,"byteOffset",lt)),A(Dt,{getInt8:function(Ft){return $e(this,1,Ft)[0]<<24>>24},getUint8:function(Ft){return $e(this,1,Ft)[0]},getInt16:function(Ft){var Tt=$e(this,2,Ft,arguments.length>1?arguments[1]:!1);return(Tt[1]<<8|Tt[0])<<16>>16},getUint16:function(Ft){var Tt=$e(this,2,Ft,arguments.length>1?arguments[1]:!1);return Tt[1]<<8|Tt[0]},getInt32:function(Ft){return ee($e(this,4,Ft,arguments.length>1?arguments[1]:!1))},getUint32:function(Ft){return ee($e(this,4,Ft,arguments.length>1?arguments[1]:!1))>>>0},getFloat32:function(Ft){return Mt($e(this,4,Ft,arguments.length>1?arguments[1]:!1),23)},getFloat64:function(Ft){return Mt($e(this,8,Ft,arguments.length>1?arguments[1]:!1),52)},setInt8:function(Ft,Tt){ce(this,1,Ft,Ht,Tt)},setUint8:function(Ft,Tt){ce(this,1,Ft,Ht,Tt)},setInt16:function(Ft,Tt){ce(this,2,Ft,re,Tt,arguments.length>2?arguments[2]:!1)},setUint16:function(Ft,Tt){ce(this,2,Ft,re,Tt,arguments.length>2?arguments[2]:!1)},setInt32:function(Ft,Tt){ce(this,4,Ft,se,Tt,arguments.length>2?arguments[2]:!1)},setUint32:function(Ft,Tt){ce(this,4,Ft,se,Tt,arguments.length>2?arguments[2]:!1)},setFloat32:function(Ft,Tt){ce(this,4,Ft,fe,Tt,arguments.length>2?arguments[2]:!1)},setFloat64:function(Ft,Tt){ce(this,8,Ft,Pe,Tt,arguments.length>2?arguments[2]:!1)}});else{var Ae=Z&>.name!==q;!E(function(){gt(1)})||!E(function(){new gt(-1)})||E(function(){return new gt,new gt(1.5),new gt(NaN),gt.length!==1||Ae&&!J})?(xt=function(Ft){return R(this,yt),G(new gt(C(Ft)),this,xt)},xt[rt]=yt,yt.constructor=xt,B(xt,gt)):Ae&&J&&T(gt,"name",q),z&&F(Dt)!==Xt&&z(Dt,Xt);var Te=new Ut(new xt(2)),de=d(Dt.setInt8);Te.setInt8(0,2147483648),Te.setInt8(1,2147483649),(Te.getInt8(0)||!Te.getInt8(1))&&A(Dt,{setInt8:function(Ft,Tt){de(this,Ft,Tt<<24>>24)},setUint8:function(Ft,Tt){de(this,Ft,Tt<<24>>24)}},{unsafe:!0})}V(xt,q),V(Ut,nt),x.exports={ArrayBuffer:xt,DataView:Ut}},function(x){x.exports=typeof ArrayBuffer!="undefined"&&typeof DataView!="undefined"},function(x,b,r){var u=r(47);x.exports=function(d,h,p){for(var y in h)u(d,y,h[y],p);return d}},function(x,b,r){var u=r(24),d=TypeError;x.exports=function(h,p){if(u(p,h))return h;throw new d("Incorrect invocation")}},function(x,b,r){var u=r(61),d=r(64),h=RangeError;x.exports=function(p){if(p===void 0)return 0;var y=u(p),T=d(y);if(y!==T)throw new h("Wrong length or index");return T}},function(x,b,r){var u=r(214),d=11920928955078125e-23,h=34028234663852886e22,p=11754943508222875e-54;x.exports=Math.fround||function(T){return u(T,d,h,p)}},function(x,b,r){var u=r(215),d=r(216),h=Math.abs,p=2220446049250313e-31;x.exports=function(y,T,$,A){var E=+y,R=h(E),I=u(E);if(R$||C!==C?I*(1/0):I*C}},function(x){x.exports=Math.sign||function(r){var u=+r;return u===0||u!==u?u:u<0?-1:1}},function(x){var b=2220446049250313e-31,r=1/b;x.exports=function(u){return u+r-r}},function(x){var b=Array,r=Math.abs,u=Math.pow,d=Math.floor,h=Math.log,p=Math.LN2,y=function($,A,E){var R=b(E),I=E*8-A-1,O=(1<>1,D=A===23?u(2,-24)-u(2,-77):0,M=$<0||$===0&&1/$<0?1:0,F=0,z,U,j;for($=r($),$!==$||$===1/0?(U=$!==$?1:0,z=O):(z=d(h($)/p),j=u(2,-z),$*j<1&&(z--,j*=2),z+C>=1?$+=D/j:$+=D*u(2,1-C),$*j>=2&&(z++,j/=2),z+C>=O?(U=0,z=O):z+C>=1?(U=($*j-1)*u(2,A),z+=C):(U=$*u(2,C-1)*u(2,A),z=0));A>=8;)R[F++]=U&255,U/=256,A-=8;for(z=z<0;)R[F++]=z&255,z/=256,I-=8;return R[F-1]|=M*128,R},T=function($,A){var E=$.length,R=E*8-A-1,I=(1<>1,C=R-7,D=E-1,M=$[D--],F=M&127,z;for(M>>=7;C>0;)F=F*256+$[D--],C-=8;for(z=F&(1<<-C)-1,F>>=-C,C+=A;C>0;)z=z*256+$[D--],C-=8;if(F===0)F=1-O;else{if(F===I)return z?NaN:M?-1/0:1/0;z+=u(2,A),F-=O}return(M?-1:1)*z*u(2,F-A)};x.exports={pack:y,unpack:T}},function(x,b,r){var u=r(3),d=r(219),h=d.NATIVE_ARRAY_BUFFER_VIEWS;u({target:"ArrayBuffer",stat:!0,forced:!h},{isView:d.isView})},function(x,b,r){var u=r(209),d=r(6),h=r(4),p=r(21),y=r(20),T=r(38),$=r(69),A=r(31),E=r(43),R=r(47),I=r(77),O=r(24),C=r(128),D=r(113),M=r(33),F=r(40),z=r(51),U=z.enforce,j=z.get,G=h.Int8Array,B=G&&G.prototype,V=h.Uint8ClampedArray,Y=V&&V.prototype,Z=G&&C(G),J=B&&C(B),q=Object.prototype,nt=h.TypeError,rt=M("toStringTag"),_=F("TYPED_ARRAY_TAG"),tt="TypedArrayConstructor",et=u&&!!D&&$(h.opera)!=="Opera",lt=!1,mt,gt,xt,yt={Int8Array:1,Uint8Array:1,Uint8ClampedArray:1,Int16Array:2,Uint16Array:2,Int32Array:4,Uint32Array:4,Float32Array:4,Float64Array:8},Ut={BigInt64Array:8,BigUint64Array:8},Dt=function(Ht){if(!y(Ht))return!1;var re=$(Ht);return re==="DataView"||T(yt,re)||T(Ut,re)},Xt=function(Mt){var Ht=C(Mt);if(y(Ht)){var re=j(Ht);return re&&T(re,tt)?re[tt]:Xt(Ht)}},Qt=function(Mt){if(!y(Mt))return!1;var Ht=$(Mt);return T(yt,Ht)||T(Ut,Ht)},kt=function(Mt){if(Qt(Mt))return Mt;throw new nt("Target is not a typed array")},me=function(Mt){if(p(Mt)&&(!D||O(Z,Mt)))return Mt;throw new nt(A(Mt)+" is not a typed array constructor")},ge=function(Mt,Ht,re,se){if(d){if(re)for(var ee in yt){var fe=h[ee];if(fe&&T(fe.prototype,Mt))try{delete fe.prototype[Mt]}catch(Pe){try{fe.prototype[Mt]=Ht}catch(Me){}}}(!J[Mt]||re)&&R(J,Mt,re?Ht:et&&B[Mt]||Ht,se)}},ae=function(Mt,Ht,re){var se,ee;if(d){if(D){if(re){for(se in yt)if(ee=h[se],ee&&T(ee,Mt))try{delete ee[Mt]}catch(fe){}}if(!Z[Mt]||re)try{return R(Z,Mt,re?Ht:et&&Z[Mt]||Ht)}catch(fe){}else return}for(se in yt)ee=h[se],ee&&(!ee[Mt]||re)&&R(ee,Mt,Ht)}};for(mt in yt)gt=h[mt],xt=gt&>.prototype,xt?U(xt)[tt]=gt:et=!1;for(mt in Ut)gt=h[mt],xt=gt&>.prototype,xt&&(U(xt)[tt]=gt);if((!et||!p(Z)||Z===Function.prototype)&&(Z=function(){throw new nt("Incorrect invocation")},et))for(mt in yt)h[mt]&&D(h[mt],Z);if((!et||!J||J===q)&&(J=Z.prototype,et))for(mt in yt)h[mt]&&D(h[mt].prototype,J);if(et&&C(Y)!==J&&D(Y,J),d&&!T(J,rt)){lt=!0,I(J,rt,{configurable:!0,get:function(){return y(this)?this[_]:void 0}});for(mt in yt)h[mt]&&E(h[mt],_,mt)}x.exports={NATIVE_ARRAY_BUFFER_VIEWS:et,TYPED_ARRAY_TAG:lt&&_,aTypedArray:kt,aTypedArrayConstructor:me,exportTypedArrayMethod:ge,exportTypedArrayStaticMethod:ae,getTypedArrayConstructor:Xt,isView:Dt,isTypedArray:Qt,TypedArray:Z,TypedArrayPrototype:J}},function(x,b,r){var u=r(3),d=r(85),h=r(7),p=r(208),y=r(46),T=r(60),$=r(64),A=p.ArrayBuffer,E=p.DataView,R=E.prototype,I=d(A.prototype.slice),O=d(R.getUint8),C=d(R.setUint8),D=h(function(){return!new A(2).slice(1,void 0).byteLength});u({target:"ArrayBuffer",proto:!0,unsafe:!0,forced:D},{slice:function(F,z){if(I&&z===void 0)return I(y(this),F);for(var U=y(this).byteLength,j=T(F,U),G=T(z===void 0?U:z,U),B=new A($(G-j)),V=new E(this),Y=new E(B),Z=0;j>>15,O=R>>>10&p,C=R&y;return O===p?C===0?I===0?1/0:-1/0:NaN:O===0?C*(I===0?T:-T):h(2,O-15)*(I===0?1+C*$:-1-C*$)},E=d(DataView.prototype.getUint16);u({target:"DataView",proto:!0},{getFloat16:function(I){var O=E(this,I,arguments.length>1?arguments[1]:!1);return A(O)}})},function(x,b,r){var u=r(3),d=r(14),h=r(225),p=r(212),y=r(226),T=r(216),$=Math.pow,A=65520,E=61005353927612305e-21,R=16777216,I=1024,O=function(D){if(D!==D)return 32256;if(D===0)return(1/D===-1/0)<<15;var M=D<0;if(M&&(D=-D),D>=A)return M<<15|31744;if(D2?arguments[2]:!1)}})},function(x,b,r){var u=r(69),d=TypeError;x.exports=function(h){if(u(h)==="DataView")return h;throw new d("Argument is not a DataView")}},function(x){var b=Math.log,r=Math.LN2;x.exports=Math.log2||function(d){return b(d)/r}},function(x,b,r){var u=r(6),d=r(77),h=r(228),p=ArrayBuffer.prototype;u&&!("detached"in p)&&d(p,"detached",{configurable:!0,get:function(){return h(this)}})},function(x,b,r){var u=r(4),d=r(209),h=r(229),p=u.DataView;x.exports=function(y){if(!d||h(y)!==0)return!1;try{return new p(y),!1}catch(T){return!0}}},function(x,b,r){var u=r(4),d=r(114),h=r(15),p=u.ArrayBuffer,y=u.TypeError;x.exports=p&&d(p.prototype,"byteLength","get")||function(T){if(h(T)!=="ArrayBuffer")throw new y("ArrayBuffer expected");return T.byteLength}},function(x,b,r){var u=r(3),d=r(231);d&&u({target:"ArrayBuffer",proto:!0},{transfer:function(){return d(this,arguments.length?arguments[0]:void 0,!0)}})},function(x,b,r){var u=r(4),d=r(14),h=r(114),p=r(212),y=r(232),T=r(229),$=r(233),A=r(235),E=u.structuredClone,R=u.ArrayBuffer,I=u.DataView,O=Math.min,C=R.prototype,D=I.prototype,M=d(C.slice),F=h(C,"resizable","get"),z=h(C,"maxByteLength","get"),U=d(D.getInt8),j=d(D.setInt8);x.exports=(A||$)&&function(G,B,V){var Y=T(G),Z=B===void 0?Y:p(B),J=!F||!F(G),q;if(y(G),A&&(G=E(G,{transfer:[G]}),Y===Z&&(V||J)))return G;if(Y>=Z&&(!V||J))q=M(G,0,Z);else{var nt=V&&!J&&z?{maxByteLength:z(G)}:void 0;q=new R(Z,nt);for(var rt=new I(G),_=new I(q),tt=O(Z,Y),et=0;et92||p==="NODE"&&h>94||p==="BROWSER"&&h>97)return!1;var T=new ArrayBuffer(8),$=y(T,{transfer:[T]});return T.byteLength!==0||$.byteLength!==8})},function(x,b,r){var u=r(3),d=r(231);d&&u({target:"ArrayBuffer",proto:!0},{transferToFixedLength:function(){return d(this,arguments.length?arguments[0]:void 0,!1)}})},function(x,b,r){var u=r(3),d=r(14),h=r(7),p=h(function(){return new Date(16e11).getYear()!==120}),y=d(Date.prototype.getFullYear);u({target:"Date",proto:!0,forced:p},{getYear:function(){return y(this)-1900}})},function(x,b,r){var u=r(3),d=r(14),h=Date,p=d(h.prototype.getTime);u({target:"Date",stat:!0},{now:function(){return p(new h)}})},function(x,b,r){var u=r(3),d=r(14),h=r(61),p=Date.prototype,y=d(p.getTime),T=d(p.setFullYear);u({target:"Date",proto:!0},{setYear:function(A){y(this);var E=h(A),R=E>=0&&E<=99?E+1900:E;return T(this,R)}})},function(x,b,r){var u=r(3);u({target:"Date",proto:!0},{toGMTString:Date.prototype.toUTCString})},function(x,b,r){var u=r(3),d=r(242);u({target:"Date",proto:!0,forced:Date.prototype.toISOString!==d},{toISOString:d})},function(x,b,r){var u=r(14),d=r(7),h=r(243).start,p=RangeError,y=isFinite,T=Math.abs,$=Date.prototype,A=$.toISOString,E=u($.getTime),R=u($.getUTCDate),I=u($.getUTCFullYear),O=u($.getUTCHours),C=u($.getUTCMilliseconds),D=u($.getUTCMinutes),M=u($.getUTCMonth),F=u($.getUTCSeconds);x.exports=d(function(){return A.call(new Date(-50000000000001))!=="0385-07-25T07:06:39.999Z"})||!d(function(){A.call(new Date(NaN))})?function(){if(!y(E(this)))throw new p("Invalid time value");var U=this,j=I(U),G=C(U),B=j<0?"-":j>9999?"+":"";return B+h(T(j),B?6:4,0)+"-"+h(M(U)+1,2,0)+"-"+h(R(U),2,0)+"T"+h(O(U),2,0)+":"+h(D(U),2,0)+":"+h(F(U),2,0)+"."+h(G,3,0)+"Z"}:A},function(x,b,r){var u=r(14),d=r(64),h=r(68),p=r(244),y=r(16),T=u(p),$=u("".slice),A=Math.ceil,E=function(R){return function(I,O,C){var D=h(y(I)),M=d(O),F=D.length,z=C===void 0?" ":h(C),U,j;return M<=F||z===""?D:(U=M-F,j=T(z,A(U/z.length)),j.length>U&&(j=$(j,0,U)),R?D+j:j+D)}};x.exports={start:E(!1),end:E(!0)}},function(x,b,r){var u=r(61),d=r(68),h=r(16),p=RangeError;x.exports=function(T){var $=d(h(this)),A="",E=u(T);if(E<0||E===1/0)throw new p("Wrong number of repetitions");for(;E>0;(E>>>=1)&&($+=$))E&1&&(A+=$);return A}},function(x,b,r){var u=r(3),d=r(7),h=r(39),p=r(19),y=d(function(){return new Date(NaN).toJSON()!==null||Date.prototype.toJSON.call({toISOString:function(){return 1}})!==1});u({target:"Date",proto:!0,arity:1,forced:y},{toJSON:function($){var A=h(this),E=p(A,"number");return typeof E=="number"&&!isFinite(E)?null:A.toISOString()}})},function(x,b,r){var u=r(38),d=r(47),h=r(247),p=r(33),y=p("toPrimitive"),T=Date.prototype;u(T,y)||d(T,y,h)},function(x,b,r){var u=r(46),d=r(32),h=TypeError;x.exports=function(p){if(u(this),p==="string"||p==="default")p="string";else if(p!=="number")throw new h("Incorrect hint");return d(this,p)}},function(x,b,r){var u=r(14),d=r(47),h=Date.prototype,p="Invalid Date",y="toString",T=u(h[y]),$=u(h.getTime);String(new Date(NaN))!==p&&d(h,y,function(){var E=$(this);return E===E?T(this):p})},function(x,b,r){var u=r(3),d=r(14),h=r(68),p=d("".charAt),y=d("".charCodeAt),T=d(/./.exec),$=d(1 .toString),A=d("".toUpperCase),E=/[\w*+\-./@]/,R=function(I,O){for(var C=$(I,16);C.length1?arguments[1]:void 0),_;_=_?_.next:nt.first;)for(rt(_.value,_.key,this);_&&_.removed;)_=_.previous},has:function(q){return!!Z(this,q)}}),h(B,U?{get:function(q){var nt=Z(this,q);return nt&&nt.value},set:function(q,nt){return Y(this,q===0?0:q,nt)}}:{add:function(q){return Y(this,q=q===0?0:q,q)}}),I&&d(B,"size",{configurable:!0,get:function(){return V(this).size}}),G},setStrong:function(F,z,U){var j=z+" Iterator",G=M(z),B=M(j);A(F,z,function(V,Y){D(this,{type:j,target:V,state:G(V),kind:Y,last:null})},function(){for(var V=B(this),Y=V.kind,Z=V.last;Z&&Z.removed;)Z=Z.previous;return!V.target||!(V.last=Z=Z?Z.next:V.state.first)?(V.target=null,E(void 0,!0)):E(Y==="keys"?Z.key:Y==="values"?Z.value:[Z.key,Z.value],!1)},U?"entries":"values",!U,!0),R(z)}}},function(x,b,r){var u=r(3),d=r(14),h=r(30),p=r(16),y=r(130),T=r(284),$=r(36),A=r(7),E=T.Map,R=T.has,I=T.get,O=T.set,C=d([].push),D=$||A(function(){return E.groupBy("ab",function(M){return M}).get("a").length!==1});u({target:"Map",stat:!0,forced:$||D},{groupBy:function(F,z){p(F),h(z);var U=new E,j=0;return y(F,function(G){var B=z(G,j++);R(U,B)?C(I(U,B),G):O(U,B,[G])}),U}})},function(x,b,r){var u=r(14),d=Map.prototype;x.exports={Map,set:u(d.set),get:u(d.get),has:u(d.has),remove:u(d.delete),proto:d}},function(x,b,r){var u=r(3),d=r(286),h=Math.acosh,p=Math.log,y=Math.sqrt,T=Math.LN2,$=!h||Math.floor(h(Number.MAX_VALUE))!==710||h(1/0)!==1/0;u({target:"Math",stat:!0,forced:$},{acosh:function(E){var R=+E;return R<1?NaN:R>9490626562425156e-8?p(R)+T:d(R-1+y(R-1)*y(R+1))}})},function(x){var b=Math.log;x.exports=Math.log1p||function(u){var d=+u;return d>-1e-8&&d<1e-8?d-d*d/2:b(1+d)}},function(x,b,r){var u=r(3),d=Math.asinh,h=Math.log,p=Math.sqrt;function y($){var A=+$;return!isFinite(A)||A===0?A:A<0?-y(-A):h(A+p(A*A+1))}var T=!(d&&1/d(0)>0);u({target:"Math",stat:!0,forced:T},{asinh:y})},function(x,b,r){var u=r(3),d=Math.atanh,h=Math.log,p=!(d&&1/d(-0)<0);u({target:"Math",stat:!0,forced:p},{atanh:function(T){var $=+T;return $===0?$:h((1+$)/(1-$))/2}})},function(x,b,r){var u=r(3),d=r(215),h=Math.abs,p=Math.pow;u({target:"Math",stat:!0},{cbrt:function(T){var $=+T;return d($)*p(h($),.3333333333333333)}})},function(x,b,r){var u=r(3),d=Math.floor,h=Math.log,p=Math.LOG2E;u({target:"Math",stat:!0},{clz32:function(T){var $=T>>>0;return $?31-d(h($+.5)*p):32}})},function(x,b,r){var u=r(3),d=r(292),h=Math.cosh,p=Math.abs,y=Math.E,T=!h||h(710)===1/0;u({target:"Math",stat:!0,forced:T},{cosh:function(A){var E=d(p(A)-1)+1;return(E+1/(E*y*y))*(y/2)}})},function(x){var b=Math.expm1,r=Math.exp;x.exports=!b||b(10)>22025.465794806718||b(10)<22025.465794806718||b(-2e-17)!==-2e-17?function(d){var h=+d;return h===0?h:h>-1e-6&&h<1e-6?h+h*h/2:r(h)-1}:b},function(x,b,r){var u=r(3),d=r(292);u({target:"Math",stat:!0,forced:d!==Math.expm1},{expm1:d})},function(x,b,r){var u=r(3),d=r(213);u({target:"Math",stat:!0},{fround:d})},function(x,b,r){var u=r(3),d=r(214),h=.0009765625,p=65504,y=6103515625e-14;u({target:"Math",stat:!0},{f16round:function($){return d($,h,p,y)}})},function(x,b,r){var u=r(3),d=Math.hypot,h=Math.abs,p=Math.sqrt,y=!!d&&d(1/0,NaN)!==1/0;u({target:"Math",stat:!0,arity:2,forced:y},{hypot:function($,A){for(var E=0,R=0,I=arguments.length,O=0,C,D;R0?(D=C/O,E+=D*D):E+=C;return O===1/0?1/0:O*p(E)}})},function(x,b,r){var u=r(3),d=r(7),h=Math.imul,p=d(function(){return h(4294967295,5)!==-5||h.length!==2});u({target:"Math",stat:!0,forced:p},{imul:function(T,$){var A=65535,E=+T,R=+$,I=A&E,O=A&R;return 0|I*O+((A&E>>>16)*O+I*(A&R>>>16)<<16>>>0)}})},function(x,b,r){var u=r(3),d=r(299);u({target:"Math",stat:!0},{log10:d})},function(x){var b=Math.log,r=Math.LOG10E;x.exports=Math.log10||function(d){return b(d)*r}},function(x,b,r){var u=r(3),d=r(286);u({target:"Math",stat:!0},{log1p:d})},function(x,b,r){var u=r(3),d=r(226);u({target:"Math",stat:!0},{log2:d})},function(x,b,r){var u=r(3),d=r(215);u({target:"Math",stat:!0},{sign:d})},function(x,b,r){var u=r(3),d=r(7),h=r(292),p=Math.abs,y=Math.exp,T=Math.E,$=d(function(){return Math.sinh(-2e-17)!==-2e-17});u({target:"Math",stat:!0,forced:$},{sinh:function(E){var R=+E;return p(R)<1?(h(R)-h(-R))/2:(y(R-1)-y(-R-1))*(T/2)}})},function(x,b,r){var u=r(3),d=r(292),h=Math.exp;u({target:"Math",stat:!0},{tanh:function(y){var T=+y,$=d(T),A=d(-T);return $===1/0?1:A===1/0?-1:($-A)/(h(T)+h(-T))}})},function(x,b,r){var u=r(82);u(Math,"Math",!0)},function(x,b,r){var u=r(3),d=r(62);u({target:"Math",stat:!0},{trunc:d})},function(x,b,r){var u=r(3),d=r(36),h=r(6),p=r(4),y=r(80),T=r(14),$=r(67),A=r(38),E=r(118),R=r(24),I=r(22),O=r(19),C=r(7),D=r(57).f,M=r(5).f,F=r(44).f,z=r(308),U=r(309).trim,j="Number",G=p[j],B=y[j],V=G.prototype,Y=p.TypeError,Z=T("".slice),J=T("".charCodeAt),q=function(lt){var mt=O(lt,"number");return typeof mt=="bigint"?mt:nt(mt)},nt=function(lt){var mt=O(lt,"number"),gt,xt,yt,Ut,Dt,Xt,Qt,kt;if(I(mt))throw new Y("Cannot convert a Symbol value to a number");if(typeof mt=="string"&&mt.length>2){if(mt=U(mt),gt=J(mt,0),gt===43||gt===45){if(xt=J(mt,2),xt===88||xt===120)return NaN}else if(gt===48){switch(J(mt,1)){case 66:case 98:yt=2,Ut=49;break;case 79:case 111:yt=8,Ut=55;break;default:return+mt}for(Dt=Z(mt,2),Xt=Dt.length,Qt=0;QtUt)return NaN;return parseInt(Dt,yt)}}return+mt},rt=$(j,!G(" 0o1")||!G("0b1")||G("+0x1")),_=function(lt){return R(V,lt)&&C(function(){z(lt)})},tt=function(mt){var gt=arguments.length<1?0:G(q(mt));return _(this)?E(Object(gt),this,tt):gt};tt.prototype=V,rt&&!d&&(V.constructor=tt),u({global:!0,constructor:!0,wrap:!0,forced:rt},{Number:tt});var et=function(lt,mt){for(var gt=h?D(mt):"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,isFinite,isInteger,isNaN,isSafeInteger,parseFloat,parseInt,fromString,range".split(","),xt=0,yt;gt.length>xt;xt++)A(mt,yt=gt[xt])&&!A(lt,yt)&&F(lt,yt,M(mt,yt))};d&&B&&et(y[j],B),(rt||d)&&et(y[j],G)},function(x,b,r){var u=r(14);x.exports=u(1 .valueOf)},function(x,b,r){var u=r(14),d=r(16),h=r(68),p=r(310),y=u("".replace),T=RegExp("^["+p+"]+"),$=RegExp("(^|[^"+p+"])["+p+"]+$"),A=function(E){return function(R){var I=h(d(R));return E&1&&(I=y(I,T,"")),E&2&&(I=y(I,$,"$1")),I}};x.exports={start:A(1),end:A(2),trim:A(3)}},function(x){x.exports=` \v\f\r \xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF`},function(x,b,r){var u=r(3);u({target:"Number",stat:!0,nonConfigurable:!0,nonWritable:!0},{EPSILON:Math.pow(2,-52)})},function(x,b,r){var u=r(3),d=r(313);u({target:"Number",stat:!0},{isFinite:d})},function(x,b,r){var u=r(4),d=u.isFinite;x.exports=Number.isFinite||function(p){return typeof p=="number"&&d(p)}},function(x,b,r){var u=r(3),d=r(315);u({target:"Number",stat:!0},{isInteger:d})},function(x,b,r){var u=r(20),d=Math.floor;x.exports=Number.isInteger||function(p){return!u(p)&&isFinite(p)&&d(p)===p}},function(x,b,r){var u=r(3);u({target:"Number",stat:!0},{isNaN:function(h){return h!==h}})},function(x,b,r){var u=r(3),d=r(315),h=Math.abs;u({target:"Number",stat:!0},{isSafeInteger:function(y){return d(y)&&h(y)<=9007199254740991}})},function(x,b,r){var u=r(3);u({target:"Number",stat:!0,nonConfigurable:!0,nonWritable:!0},{MAX_SAFE_INTEGER:9007199254740991})},function(x,b,r){var u=r(3);u({target:"Number",stat:!0,nonConfigurable:!0,nonWritable:!0},{MIN_SAFE_INTEGER:-9007199254740991})},function(x,b,r){var u=r(3),d=r(321);u({target:"Number",stat:!0,forced:Number.parseFloat!==d},{parseFloat:d})},function(x,b,r){var u=r(4),d=r(7),h=r(14),p=r(68),y=r(309).trim,T=r(310),$=h("".charAt),A=u.parseFloat,E=u.Symbol,R=E&&E.iterator,I=1/A(T+"-0")!==-1/0||R&&!d(function(){A(Object(R))});x.exports=I?function(C){var D=y(p(C)),M=A(D);return M===0&&$(D,0)==="-"?-0:M}:A},function(x,b,r){var u=r(3),d=r(323);u({target:"Number",stat:!0,forced:Number.parseInt!==d},{parseInt:d})},function(x,b,r){var u=r(4),d=r(7),h=r(14),p=r(68),y=r(309).trim,T=r(310),$=u.parseInt,A=u.Symbol,E=A&&A.iterator,R=/^[+-]?0x/i,I=h(R.exec),O=$(T+"08")!==8||$(T+"0x16")!==22||E&&!d(function(){$(Object(E))});x.exports=O?function(D,M){var F=y(p(D));return $(F,M>>>0||(I(R,F)?16:10))}:$},function(x,b,r){var u=r(3),d=r(14),h=r(61),p=r(308),y=r(244),T=r(299),$=r(7),A=RangeError,E=String,R=isFinite,I=Math.abs,O=Math.floor,C=Math.pow,D=Math.round,M=d(1 .toExponential),F=d(y),z=d("".slice),U=M(-69e-12,4)==="-6.9000e-11"&&M(1.255,2)==="1.25e+0"&&M(12345,3)==="1.235e+4"&&M(25,0)==="3e+1",j=function(){return $(function(){M(1,1/0)})&&$(function(){M(1,-1/0)})},G=function(){return!$(function(){M(1/0,1/0),M(NaN,1/0)})},B=!U||!j()||!G();u({target:"Number",proto:!0,forced:B},{toExponential:function(Y){var Z=p(this);if(Y===void 0)return M(Z);var J=h(Y);if(!R(Z))return String(Z);if(J<0||J>20)throw new A("Incorrect fraction digits");if(U)return M(Z,J);var q="",nt,rt,_,tt;if(Z<0&&(q="-",Z=-Z),Z===0)rt=0,nt=F("0",J+1);else{var et=T(Z);rt=O(et);var lt=C(10,rt-J),mt=D(Z/lt);2*Z>=(2*mt+1)*lt&&(mt+=1),mt>=C(10,J+1)&&(mt/=10,rt+=1),nt=E(mt)}return J!==0&&(nt=z(nt,0,1)+"."+z(nt,1)),rt===0?(_="+",tt="0"):(_=rt>0?"+":"-",tt=E(I(rt))),nt+="e"+_+tt,q+nt}})},function(x,b,r){var u=r(3),d=r(14),h=r(61),p=r(308),y=r(244),T=r(7),$=RangeError,A=String,E=Math.floor,R=d(y),I=d("".slice),O=d(1 .toFixed),C=function(j,G,B){return G===0?B:G%2===1?C(j,G-1,B*j):C(j*j,G/2,B)},D=function(j){for(var G=0,B=j;B>=4096;)G+=12,B/=4096;for(;B>=2;)G+=1,B/=2;return G},M=function(j,G,B){for(var V=-1,Y=B;++V<6;)Y+=G*j[V],j[V]=Y%1e7,Y=E(Y/1e7)},F=function(j,G){for(var B=6,V=0;--B>=0;)V+=j[B],j[B]=E(V/G),V=V%G*1e7},z=function(j){for(var G=6,B="";--G>=0;)if(B!==""||G===0||j[G]!==0){var V=A(j[G]);B=B===""?V:B+R("0",7-V.length)+V}return B},U=T(function(){return O(8e-5,3)!=="0.000"||O(.9,0)!=="1"||O(1.255,2)!=="1.25"||O(0xde0b6b3a7640080,0)!=="1000000000000000128"})||!T(function(){O({})});u({target:"Number",proto:!0,forced:U},{toFixed:function(G){var B=p(this),V=h(G),Y=[0,0,0,0,0,0],Z="",J="0",q,nt,rt,_;if(V<0||V>20)throw new $("Incorrect fraction digits");if(B!==B)return"NaN";if(B<=-1e21||B>=1e21)return A(B);if(B<0&&(Z="-",B=-B),B>1e-21)if(q=D(B*C(2,69,1))-69,nt=q<0?B*C(2,-q,1):B/C(2,q,1),nt*=4503599627370496,q=52-q,q>0){for(M(Y,0,nt),rt=V;rt>=7;)M(Y,1e7,0),rt-=7;for(M(Y,C(10,rt,1),0),rt=q-1;rt>=23;)F(Y,8388608),rt-=23;F(Y,1<0?(_=J.length,J=Z+(_<=V?"0."+R("0",V-_)+J:I(J,0,_-V)+"."+I(J,_-V))):J=Z+J,J}})},function(x,b,r){var u=r(3),d=r(14),h=r(7),p=r(308),y=d(1 .toPrecision),T=h(function(){return y(1,void 0)!=="1"})||!h(function(){y({})});u({target:"Number",proto:!0,forced:T},{toPrecision:function(A){return A===void 0?y(p(this)):y(p(this),A)}})},function(x,b,r){var u=r(3),d=r(328);u({target:"Object",stat:!0,arity:2,forced:Object.assign!==d},{assign:d})},function(x,b,r){var u=r(6),d=r(14),h=r(8),p=r(7),y=r(73),T=r(66),$=r(10),A=r(39),E=r(13),R=Object.assign,I=Object.defineProperty,O=d([].concat);x.exports=!R||p(function(){if(u&&R({b:1},R(I({},"a",{enumerable:!0,get:function(){I(this,"b",{value:3,enumerable:!1})}}),{b:2})).b!==1)return!0;var C={},D={},M=Symbol("assign detection"),F="abcdefghijklmnopqrst";return C[M]=7,F.split("").forEach(function(z){D[z]=z}),R({},C)[M]!==7||y(R({},D)).join("")!==F})?function(D,M){for(var F=A(D),z=arguments.length,U=1,j=T.f,G=$.f;z>U;)for(var B=E(arguments[U++]),V=j?O(y(B),j(B)):y(B),Y=V.length,Z=0,J;Y>Z;)J=V[Z++],(!u||h(G,B,J))&&(F[J]=B[J]);return F}:R},function(x,b,r){var u=r(3),d=r(6),h=r(71);u({target:"Object",stat:!0,sham:!d},{create:h})},function(x,b,r){var u=r(3),d=r(6),h=r(331),p=r(30),y=r(39),T=r(44);d&&u({target:"Object",proto:!0,forced:h},{__defineGetter__:function(A,E){T.f(y(this),A,{get:p(E),enumerable:!0,configurable:!0})}})},function(x,b,r){var u=r(36),d=r(4),h=r(7),p=r(192);x.exports=u||!h(function(){if(!(p&&p<535)){var y=Math.random();__defineSetter__.call(null,y,function(){}),delete d[y]}})},function(x,b,r){var u=r(3),d=r(6),h=r(72).f;u({target:"Object",stat:!0,forced:Object.defineProperties!==h,sham:!d},{defineProperties:h})},function(x,b,r){var u=r(3),d=r(6),h=r(44).f;u({target:"Object",stat:!0,forced:Object.defineProperty!==h,sham:!d},{defineProperty:h})},function(x,b,r){var u=r(3),d=r(6),h=r(331),p=r(30),y=r(39),T=r(44);d&&u({target:"Object",proto:!0,forced:h},{__defineSetter__:function(A,E){T.f(y(this),A,{set:p(E),enumerable:!0,configurable:!0})}})},function(x,b,r){var u=r(3),d=r(336).entries;u({target:"Object",stat:!0},{entries:function(p){return d(p)}})},function(x,b,r){var u=r(6),d=r(7),h=r(14),p=r(128),y=r(73),T=r(12),$=r(10).f,A=h($),E=h([].push),R=u&&d(function(){var O=Object.create(null);return O[2]=2,!A(O,2)}),I=function(O){return function(C){for(var D=T(C),M=y(D),F=R&&p(D)===null,z=M.length,U=0,j=[],G;z>U;)G=M[U++],(!u||(F?G in D:A(D,G)))&&E(j,O?[G,D[G]]:D[G]);return j}};x.exports={entries:I(!0),values:I(!1)}},function(x,b,r){var u=r(3),d=r(281),h=r(7),p=r(20),y=r(278).onFreeze,T=Object.freeze,$=h(function(){T(1)});u({target:"Object",stat:!0,forced:$,sham:!d},{freeze:function(E){return T&&p(E)?T(y(E)):E}})},function(x,b,r){var u=r(3),d=r(130),h=r(141);u({target:"Object",stat:!0},{fromEntries:function(y){var T={};return d(y,function($,A){h(T,$,A)},{AS_ENTRIES:!0}),T}})},function(x,b,r){var u=r(3),d=r(7),h=r(12),p=r(5).f,y=r(6),T=!y||d(function(){p(1)});u({target:"Object",stat:!0,forced:T,sham:!y},{getOwnPropertyDescriptor:function(A,E){return p(h(A),E)}})},function(x,b,r){var u=r(3),d=r(6),h=r(56),p=r(12),y=r(5),T=r(141);u({target:"Object",stat:!0,sham:!d},{getOwnPropertyDescriptors:function(A){for(var E=p(A),R=y.f,I=h(E),O={},C=0,D,M;I.length>C;)M=R(E,D=I[C++]),M!==void 0&&T(O,D,M);return O}})},function(x,b,r){var u=r(3),d=r(7),h=r(75).f,p=d(function(){return!Object.getOwnPropertyNames(1)});u({target:"Object",stat:!0,forced:p},{getOwnPropertyNames:h})},function(x,b,r){var u=r(3),d=r(7),h=r(39),p=r(128),y=r(129),T=d(function(){p(1)});u({target:"Object",stat:!0,forced:T,sham:!y},{getPrototypeOf:function(A){return p(h(A))}})},function(x,b,r){var u=r(3),d=r(23),h=r(14),p=r(30),y=r(16),T=r(18),$=r(130),A=r(7),E=Object.groupBy,R=d("Object","create"),I=h([].push),O=!E||A(function(){return E("ab",function(C){return C}).a.length!==1});u({target:"Object",stat:!0,forced:O},{groupBy:function(D,M){y(D),p(M);var F=R(null),z=0;return $(D,function(U){var j=T(M(U,z++));j in F?I(F[j],U):F[j]=[U]}),F}})},function(x,b,r){var u=r(3),d=r(38);u({target:"Object",stat:!0},{hasOwn:d})},function(x,b,r){var u=r(3),d=r(346);u({target:"Object",stat:!0},{is:d})},function(x){x.exports=Object.is||function(r,u){return r===u?r!==0||1/r===1/u:r!==r&&u!==u}},function(x,b,r){var u=r(3),d=r(279);u({target:"Object",stat:!0,forced:Object.isExtensible!==d},{isExtensible:d})},function(x,b,r){var u=r(3),d=r(7),h=r(20),p=r(15),y=r(280),T=Object.isFrozen,$=y||d(function(){T(1)});u({target:"Object",stat:!0,forced:$},{isFrozen:function(E){return!h(E)||y&&p(E)==="ArrayBuffer"?!0:T?T(E):!1}})},function(x,b,r){var u=r(3),d=r(7),h=r(20),p=r(15),y=r(280),T=Object.isSealed,$=y||d(function(){T(1)});u({target:"Object",stat:!0,forced:$},{isSealed:function(E){return!h(E)||y&&p(E)==="ArrayBuffer"?!0:T?T(E):!1}})},function(x,b,r){var u=r(3),d=r(39),h=r(73),p=r(7),y=p(function(){h(1)});u({target:"Object",stat:!0,forced:y},{keys:function($){return h(d($))}})},function(x,b,r){var u=r(3),d=r(6),h=r(331),p=r(39),y=r(18),T=r(128),$=r(5).f;d&&u({target:"Object",proto:!0,forced:h},{__lookupGetter__:function(E){var R=p(this),I=y(E),O;do if(O=$(R,I))return O.get;while(R=T(R))}})},function(x,b,r){var u=r(3),d=r(6),h=r(331),p=r(39),y=r(18),T=r(128),$=r(5).f;d&&u({target:"Object",proto:!0,forced:h},{__lookupSetter__:function(E){var R=p(this),I=y(E),O;do if(O=$(R,I))return O.set;while(R=T(R))}})},function(x,b,r){var u=r(3),d=r(20),h=r(278).onFreeze,p=r(281),y=r(7),T=Object.preventExtensions,$=y(function(){T(1)});u({target:"Object",stat:!0,forced:$,sham:!p},{preventExtensions:function(E){return T&&d(E)?T(h(E)):E}})},function(x,b,r){var u=r(6),d=r(77),h=r(20),p=r(116),y=r(39),T=r(16),$=Object.getPrototypeOf,A=Object.setPrototypeOf,E=Object.prototype,R="__proto__";if(u&&$&&A&&!(R in E))try{d(E,R,{configurable:!0,get:function(){return $(y(this))},set:function(O){var C=T(this);p(O)&&h(C)&&A(C,O)}})}catch(I){}},function(x,b,r){var u=r(3),d=r(20),h=r(278).onFreeze,p=r(281),y=r(7),T=Object.seal,$=y(function(){T(1)});u({target:"Object",stat:!0,forced:$,sham:!p},{seal:function(E){return T&&d(E)?T(h(E)):E}})},function(x,b,r){var u=r(3),d=r(113);u({target:"Object",stat:!0},{setPrototypeOf:d})},function(x,b,r){var u=r(70),d=r(47),h=r(358);u||d(Object.prototype,"toString",h,{unsafe:!0})},function(x,b,r){var u=r(70),d=r(69);x.exports=u?{}.toString:function(){return"[object "+d(this)+"]"}},function(x,b,r){var u=r(3),d=r(336).values;u({target:"Object",stat:!0},{values:function(p){return d(p)}})},function(x,b,r){var u=r(3),d=r(321);u({global:!0,forced:parseFloat!==d},{parseFloat:d})},function(x,b,r){var u=r(3),d=r(323);u({global:!0,forced:parseInt!==d},{parseInt:d})},function(x,b,r){r(363),r(379),r(381),r(382),r(383),r(384)},function(x,b,r){var u=r(3),d=r(36),h=r(182),p=r(4),y=r(8),T=r(47),$=r(113),A=r(82),E=r(194),R=r(30),I=r(21),O=r(20),C=r(211),D=r(364),M=r(366).set,F=r(369),z=r(374),U=r(375),j=r(371),G=r(51),B=r(376),V=r(377),Y=r(378),Z="Promise",J=V.CONSTRUCTOR,q=V.REJECTION_EVENT,nt=V.SUBCLASSING,rt=G.getterFor(Z),_=G.set,tt=B&&B.prototype,et=B,lt=tt,mt=p.TypeError,gt=p.document,xt=p.process,yt=Y.f,Ut=yt,Dt=!!(gt&>.createEvent&&p.dispatchEvent),Xt="unhandledrejection",Qt="rejectionhandled",kt=0,me=1,ge=2,ae=1,Mt=2,Ht,re,se,ee,fe=function(Tt){var qt;return O(Tt)&&I(qt=Tt.then)?qt:!1},Pe=function(Tt,qt){var te=qt.value,Zt=qt.state===me,Yt=Zt?Tt.ok:Tt.fail,Ye=Tt.resolve,Ze=Tt.reject,ut=Tt.domain,It,Pt,Ct;try{Yt?(Zt||(qt.rejection===Mt&&Te(qt),qt.rejection=ae),Yt===!0?It=te:(ut&&ut.enter(),It=Yt(te),ut&&(ut.exit(),Ct=!0)),It===Tt.promise?Ze(new mt("Promise-chain cycle")):(Pt=fe(It))?y(Pt,It,Ye,Ze):Ye(It)):Ze(te)}catch(Nt){ut&&!Ct&&ut.exit(),Ze(Nt)}},Me=function(Tt,qt){Tt.notified||(Tt.notified=!0,F(function(){for(var te=Tt.reactions,Zt;Zt=te.get();)Pe(Zt,Tt);Tt.notified=!1,qt&&!Tt.rejection&&ce(Tt)}))},$e=function(Tt,qt,te){var Zt,Yt;Dt?(Zt=gt.createEvent("Event"),Zt.promise=qt,Zt.reason=te,Zt.initEvent(Tt,!1,!0),p.dispatchEvent(Zt)):Zt={promise:qt,reason:te},!q&&(Yt=p["on"+Tt])?Yt(Zt):Tt===Xt&&z("Unhandled promise rejection",te)},ce=function(Tt){y(M,p,function(){var qt=Tt.facade,te=Tt.value,Zt=Ae(Tt),Yt;if(Zt&&(Yt=U(function(){h?xt.emit("unhandledRejection",te,qt):$e(Xt,qt,te)}),Tt.rejection=h||Ae(Tt)?Mt:ae,Yt.error))throw Yt.value})},Ae=function(Tt){return Tt.rejection!==ae&&!Tt.parent},Te=function(Tt){y(M,p,function(){var qt=Tt.facade;h?xt.emit("rejectionHandled",qt):$e(Qt,qt,Tt.value)})},de=function(Tt,qt,te){return function(Zt){Tt(qt,Zt,te)}},bt=function(Tt,qt,te){Tt.done||(Tt.done=!0,te&&(Tt=te),Tt.value=qt,Tt.state=ge,Me(Tt,!0))},Ft=function(Tt,qt,te){if(!Tt.done){Tt.done=!0,te&&(Tt=te);try{if(Tt.facade===qt)throw new mt("Promise can't be resolved itself");var Zt=fe(qt);Zt?F(function(){var Yt={done:!1};try{y(Zt,qt,de(Ft,Yt,Tt),de(bt,Yt,Tt))}catch(Ye){bt(Yt,Ye,Tt)}}):(Tt.value=qt,Tt.state=me,Me(Tt,!1))}catch(Yt){bt({done:!1},Yt,Tt)}}};if(J&&(et=function(qt){C(this,lt),R(qt),y(Ht,this);var te=rt(this);try{qt(de(Ft,te),de(bt,te))}catch(Zt){bt(te,Zt)}},lt=et.prototype,Ht=function(qt){_(this,{type:Z,done:!1,notified:!1,parent:!1,reactions:new j,rejection:!1,state:kt,value:null})},Ht.prototype=T(lt,"then",function(qt,te){var Zt=rt(this),Yt=yt(D(this,et));return Zt.parent=!0,Yt.ok=I(qt)?qt:!0,Yt.fail=I(te)&&te,Yt.domain=h?xt.domain:void 0,Zt.state===kt?Zt.reactions.add(Yt):F(function(){Pe(Yt,Zt)}),Yt.promise}),re=function(){var Tt=new Ht,qt=rt(Tt);this.promise=Tt,this.resolve=de(Ft,qt),this.reject=de(bt,qt)},Y.f=yt=function(Tt){return Tt===et||Tt===se?new re(Tt):Ut(Tt)},!d&&I(B)&&tt!==Object.prototype)){ee=tt.then,nt||T(tt,"then",function(qt,te){var Zt=this;return new et(function(Yt,Ye){y(ee,Zt,Yt,Ye)}).then(qt,te)},{unsafe:!0});try{delete tt.constructor}catch(Tt){}$&&$(tt,lt)}u({global:!0,constructor:!0,wrap:!0,forced:J},{Promise:et}),A(et,Z,!1,!0),E(Z)},function(x,b,r){var u=r(46),d=r(365),h=r(17),p=r(33),y=p("species");x.exports=function(T,$){var A=u(T).constructor,E;return A===void 0||h(E=u(A)[y])?$:d(E)}},function(x,b,r){var u=r(89),d=r(31),h=TypeError;x.exports=function(p){if(u(p))return p;throw new h(d(p)+" is not a constructor")}},function(x,b,r){var u=r(4),d=r(94),h=r(84),p=r(21),y=r(38),T=r(7),$=r(74),A=r(76),E=r(42),R=r(367),I=r(368),O=r(182),C=u.setImmediate,D=u.clearImmediate,M=u.process,F=u.Dispatch,z=u.Function,U=u.MessageChannel,j=u.String,G=0,B={},V="onreadystatechange",Y,Z,J,q;T(function(){Y=u.location});var nt=function(et){if(y(B,et)){var lt=B[et];delete B[et],lt()}},rt=function(et){return function(){nt(et)}},_=function(et){nt(et.data)},tt=function(et){u.postMessage(j(et),Y.protocol+"//"+Y.host)};(!C||!D)&&(C=function(lt){R(arguments.length,1);var mt=p(lt)?lt:z(lt),gt=A(arguments,1);return B[++G]=function(){d(mt,void 0,gt)},Z(G),G},D=function(lt){delete B[lt]},O?Z=function(et){M.nextTick(rt(et))}:F&&F.now?Z=function(et){F.now(rt(et))}:U&&!I?(J=new U,q=J.port2,J.port1.onmessage=_,Z=h(q.postMessage,q)):u.addEventListener&&p(u.postMessage)&&!u.importScripts&&Y&&Y.protocol!=="file:"&&!T(tt)?(Z=tt,u.addEventListener("message",_,!1)):V in E("script")?Z=function(et){$.appendChild(E("script"))[V]=function(){$.removeChild(this),nt(et)}}:Z=function(et){setTimeout(rt(et),0)}),x.exports={set:C,clear:D}},function(x){var b=TypeError;x.exports=function(r,u){if(r1?p(arguments,1):[],C=y.f(this),D=$(function(){return h(T(I),void 0,O)});return(D.error?C.reject:C.resolve)(D.value),C.promise}})},function(x,b,r){var u=r(3),d=r(378);u({target:"Promise",stat:!0},{withResolvers:function(){var p=d.f(this);return{promise:p.promise,resolve:p.resolve,reject:p.reject}}})},function(x,b,r){var u=r(3),d=r(94),h=r(30),p=r(46),y=r(7),T=!y(function(){Reflect.apply(function(){})});u({target:"Reflect",stat:!0,forced:T},{apply:function(A,E,R){return d(h(A),E,p(R))}})},function(x,b,r){var u=r(3),d=r(23),h=r(94),p=r(251),y=r(365),T=r(46),$=r(20),A=r(71),E=r(7),R=d("Reflect","construct"),I=Object.prototype,O=[].push,C=E(function(){function F(){}return!(R(function(){},[],F)instanceof F)}),D=!E(function(){R(function(){})}),M=C||D;u({target:"Reflect",stat:!0,forced:M,sham:M},{construct:function(z,U){y(z),T(U);var j=arguments.length<3?z:y(arguments[2]);if(D&&!C)return R(z,U,j);if(z===j){switch(U.length){case 0:return new z;case 1:return new z(U[0]);case 2:return new z(U[0],U[1]);case 3:return new z(U[0],U[1],U[2]);case 4:return new z(U[0],U[1],U[2],U[3])}var G=[null];return h(O,G,U),new(h(p,z,G))}var B=j.prototype,V=A($(B)?B:I),Y=h(z,V,U);return $(Y)?Y:V}})},function(x,b,r){var u=r(3),d=r(6),h=r(46),p=r(18),y=r(44),T=r(7),$=T(function(){Reflect.defineProperty(y.f({},1,{value:1}),1,{value:2})});u({target:"Reflect",stat:!0,forced:$,sham:!d},{defineProperty:function(E,R,I){h(E);var O=p(R);h(I);try{return y.f(E,O,I),!0}catch(C){return!1}}})},function(x,b,r){var u=r(3),d=r(46),h=r(5).f;u({target:"Reflect",stat:!0},{deleteProperty:function(y,T){var $=h(d(y),T);return $&&!$.configurable?!1:delete y[T]}})},function(x,b,r){var u=r(3),d=r(8),h=r(20),p=r(46),y=r(396),T=r(5),$=r(128);function A(E,R){var I=arguments.length<3?E:arguments[2],O,C;if(p(E)===I)return E[R];if(O=T.f(E,R),O)return y(O)?O.value:O.get===void 0?void 0:d(O.get,I);if(h(C=$(E)))return A(C,R,I)}u({target:"Reflect",stat:!0},{get:A})},function(x,b,r){var u=r(38);x.exports=function(d){return d!==void 0&&(u(d,"value")||u(d,"writable"))}},function(x,b,r){var u=r(3),d=r(6),h=r(46),p=r(5);u({target:"Reflect",stat:!0,sham:!d},{getOwnPropertyDescriptor:function(T,$){return p.f(h(T),$)}})},function(x,b,r){var u=r(3),d=r(46),h=r(128),p=r(129);u({target:"Reflect",stat:!0,sham:!p},{getPrototypeOf:function(T){return h(d(T))}})},function(x,b,r){var u=r(3);u({target:"Reflect",stat:!0},{has:function(h,p){return p in h}})},function(x,b,r){var u=r(3),d=r(46),h=r(279);u({target:"Reflect",stat:!0},{isExtensible:function(y){return d(y),h(y)}})},function(x,b,r){var u=r(3),d=r(56);u({target:"Reflect",stat:!0},{ownKeys:d})},function(x,b,r){var u=r(3),d=r(23),h=r(46),p=r(281);u({target:"Reflect",stat:!0,sham:!p},{preventExtensions:function(T){h(T);try{var $=d("Object","preventExtensions");return $&&$(T),!0}catch(A){return!1}}})},function(x,b,r){var u=r(3),d=r(8),h=r(46),p=r(20),y=r(396),T=r(7),$=r(44),A=r(5),E=r(128),R=r(11);function I(C,D,M){var F=arguments.length<4?C:arguments[3],z=A.f(h(C),D),U,j,G;if(!z){if(p(j=E(C)))return I(j,D,M,F);z=R(0)}if(y(z)){if(z.writable===!1||!p(F))return!1;if(U=A.f(F,D)){if(U.get||U.set||U.writable===!1)return!1;U.value=M,$.f(F,D,U)}else $.f(F,D,R(0,M))}else{if(G=z.set,G===void 0)return!1;d(G,F,M)}return!0}var O=T(function(){var C=function(){},D=$.f(new C,"a",{configurable:!0});return Reflect.set(C.prototype,"a",1,D)!==!1});u({target:"Reflect",stat:!0,forced:O},{set:I})},function(x,b,r){var u=r(3),d=r(46),h=r(115),p=r(113);p&&u({target:"Reflect",stat:!0},{setPrototypeOf:function(T,$){d(T),h($);try{return p(T,$),!0}catch(A){return!1}}})},function(x,b,r){var u=r(3),d=r(4),h=r(82);u({global:!0},{Reflect:{}}),h(d.Reflect,"Reflect",!0)},function(x,b,r){var u=r(6),d=r(4),h=r(14),p=r(67),y=r(118),T=r(43),$=r(71),A=r(57).f,E=r(24),R=r(407),I=r(68),O=r(408),C=r(410),D=r(117),M=r(47),F=r(7),z=r(38),U=r(51).enforce,j=r(194),G=r(33),B=r(411),V=r(412),Y=G("match"),Z=d.RegExp,J=Z.prototype,q=d.SyntaxError,nt=h(J.exec),rt=h("".charAt),_=h("".replace),tt=h("".indexOf),et=h("".slice),lt=/^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/,mt=/a/g,gt=/a/g,xt=new Z(mt)!==mt,yt=C.MISSED_STICKY,Ut=C.UNSUPPORTED_Y,Dt=u&&(!xt||yt||B||V||F(function(){return gt[Y]=!1,Z(mt)!==mt||Z(gt)===gt||String(Z(mt,"i"))!=="/a/i"})),Xt=function(ae){for(var Mt=ae.length,Ht=0,re="",se=!1,ee;Ht<=Mt;Ht++){if(ee=rt(ae,Ht),ee==="\\"){re+=ee+rt(ae,++Ht);continue}!se&&ee==="."?re+="[\\s\\S]":(ee==="["?se=!0:ee==="]"&&(se=!1),re+=ee)}return re},Qt=function(ae){for(var Mt=ae.length,Ht=0,re="",se=[],ee=$(null),fe=!1,Pe=!1,Me=0,$e="",ce;Ht<=Mt;Ht++){if(ce=rt(ae,Ht),ce==="\\")ce+=rt(ae,++Ht);else if(ce==="]")fe=!1;else if(!fe)switch(!0){case ce==="[":fe=!0;break;case ce==="(":if(re+=ce,et(ae,Ht+1,Ht+3)==="?:")continue;nt(lt,et(ae,Ht+1))&&(Ht+=2,Pe=!0),Me++;continue;case(ce===">"&&Pe):if($e===""||z(ee,$e))throw new q("Invalid capture group name");ee[$e]=!0,se[se.length]=[$e,Me],Pe=!1,$e="";continue}Pe?$e+=ce:re+=ce}return[re,se]};if(p("RegExp",Dt)){for(var kt=function(Mt,Ht){var re=E(J,this),se=R(Mt),ee=Ht===void 0,fe=[],Pe=Mt,Me,$e,ce,Ae,Te,de;if(!re&&se&&ee&&Mt.constructor===kt)return Mt;if((se||E(J,Mt))&&(Mt=Mt.source,ee&&(Ht=O(Pe))),Mt=Mt===void 0?"":I(Mt),Ht=Ht===void 0?"":I(Ht),Pe=Mt,B&&"dotAll"in mt&&($e=!!Ht&&tt(Ht,"s")>-1,$e&&(Ht=_(Ht,/s/g,""))),Me=Ht,yt&&"sticky"in mt&&(ce=!!Ht&&tt(Ht,"y")>-1,ce&&Ut&&(Ht=_(Ht,/y/g,""))),V&&(Ae=Qt(Mt),Mt=Ae[0],fe=Ae[1]),Te=y(Z(Mt,Ht),re?this:J,kt),($e||ce||fe.length)&&(de=U(Te),$e&&(de.dotAll=!0,de.raw=kt(Xt(Mt),Me)),ce&&(de.sticky=!0),fe.length&&(de.groups=fe)),Mt!==Pe)try{T(Te,"source",Pe===""?"(?:)":Pe)}catch(bt){}return Te},me=A(Z),ge=0;me.length>ge;)D(kt,Z,me[ge++]);J.constructor=kt,kt.prototype=J,M(d,"RegExp",kt,{constructor:!0})}j("RegExp")},function(x,b,r){var u=r(20),d=r(15),h=r(33),p=h("match");x.exports=function(y){var T;return u(y)&&((T=y[p])!==void 0?!!T:d(y)==="RegExp")}},function(x,b,r){var u=r(8),d=r(38),h=r(24),p=r(409),y=RegExp.prototype;x.exports=function(T){var $=T.flags;return $===void 0&&!("flags"in y)&&!d(T,"flags")&&h(y,T)?u(p,T):$}},function(x,b,r){var u=r(46);x.exports=function(){var d=u(this),h="";return d.hasIndices&&(h+="d"),d.global&&(h+="g"),d.ignoreCase&&(h+="i"),d.multiline&&(h+="m"),d.dotAll&&(h+="s"),d.unicode&&(h+="u"),d.unicodeSets&&(h+="v"),d.sticky&&(h+="y"),h}},function(x,b,r){var u=r(7),d=r(4),h=d.RegExp,p=u(function(){var $=h("a","y");return $.lastIndex=2,$.exec("abcd")!==null}),y=p||u(function(){return!h("a","y").sticky}),T=p||u(function(){var $=h("^r","gy");return $.lastIndex=2,$.exec("str")!==null});x.exports={BROKEN_CARET:T,MISSED_STICKY:y,UNSUPPORTED_Y:p}},function(x,b,r){var u=r(7),d=r(4),h=d.RegExp;x.exports=u(function(){var p=h(".","s");return!(p.dotAll&&p.test(` `)&&p.flags==="s")})},function(x,b,r){var u=r(7),d=r(4),h=d.RegExp;x.exports=u(function(){var p=h("(?b)","g");return p.exec("b").groups.a!=="b"||"b".replace(p,"$c")!=="bc"})},function(x,b,r){var u=r(3),d=r(14),h=r(414),p=r(38),y=r(243).start,T=r(310),$=Array,A=RegExp.escape,E=d("".charAt),R=d("".charCodeAt),I=d(1.1.toString),O=d([].join),C=/^[0-9a-z]/i,D=/^[$()*+./?[\\\]^{|}]/,M=RegExp("^[!\"#%&',\\-:;<=>@`~"+T+"]"),F=d(C.exec),z={" ":"t","\n":"n","\v":"v","\f":"f","\r":"r"},U=function(G){var B=I(R(G,0),16);return B.length<3?"\\x"+y(B,2,"0"):"\\u"+y(B,4,"0")},j=!A||A("ab")!=="\\x61b";u({target:"RegExp",stat:!0,forced:j},{escape:function(B){h(B);for(var V=B.length,Y=$(V),Z=0;Z=56320||Z+1>=V||(R(B,Z+1)&64512)!==56320?Y[Z]=U(J):(Y[Z]=J,Y[++Z]=E(B,Z))}}return O(Y,"")}})},function(x){var b=TypeError;x.exports=function(r){if(typeof r=="string")return r;throw new b("Argument is not a string")}},function(x,b,r){var u=r(6),d=r(411),h=r(15),p=r(77),y=r(51).get,T=RegExp.prototype,$=TypeError;u&&d&&p(T,"dotAll",{configurable:!0,get:function(){if(this!==T){if(h(this)==="RegExp")return!!y(this).dotAll;throw new $("Incompatible receiver, RegExp required")}}})},function(x,b,r){var u=r(3),d=r(417);u({target:"RegExp",proto:!0,forced:/./.exec!==d},{exec:d})},function(x,b,r){var u=r(8),d=r(14),h=r(68),p=r(409),y=r(410),T=r(34),$=r(71),A=r(51).get,E=r(411),R=r(412),I=T("native-string-replace",String.prototype.replace),O=RegExp.prototype.exec,C=O,D=d("".charAt),M=d("".indexOf),F=d("".replace),z=d("".slice),U=function(){var V=/a/,Y=/b*/g;return u(O,V,"a"),u(O,Y,"a"),V.lastIndex!==0||Y.lastIndex!==0}(),j=y.BROKEN_CARET,G=/()??/.exec("")[1]!==void 0,B=U||G||j||E||R;B&&(C=function(Y){var Z=this,J=A(Z),q=h(Y),nt=J.raw,rt,_,tt,et,lt,mt,gt;if(nt)return nt.lastIndex=Z.lastIndex,rt=u(C,nt,q),Z.lastIndex=nt.lastIndex,rt;var xt=J.groups,yt=j&&Z.sticky,Ut=u(p,Z),Dt=Z.source,Xt=0,Qt=q;if(yt&&(Ut=F(Ut,"y",""),M(Ut,"g")===-1&&(Ut+="g"),Qt=z(q,Z.lastIndex),Z.lastIndex>0&&(!Z.multiline||Z.multiline&&D(q,Z.lastIndex-1)!==` `)&&(Dt="(?: "+Dt+")",Qt=" "+Qt,Xt++),_=new RegExp("^(?:"+Dt+")",Ut)),G&&(_=new RegExp("^"+Dt+"$(?!\\s)",Ut)),U&&(tt=Z.lastIndex),et=u(O,yt?_:Z,Qt),yt?et?(et.input=z(et.input,Xt),et[0]=z(et[0],Xt),et.index=Z.lastIndex,Z.lastIndex+=et[0].length):Z.lastIndex=0:U&&et&&(Z.lastIndex=Z.global?et.index+et[0].length:tt),G&&et&&et.length>1&&u(I,et[0],_,function(){for(lt=1;ltC.size?T(C.getIterator(),function(M){E(O,M)&&A(D,M)}):y(O,function(M){C.includes(M)&&A(D,M)}),D}},function(x,b,r){var u=r(3),d=r(437),h=r(433),p=!h("isDisjointFrom",function(y){return!y});u({target:"Set",proto:!0,real:!0,forced:p},{isDisjointFrom:d})},function(x,b,r){var u=r(426),d=r(427).has,h=r(431),p=r(432),y=r(429),T=r(430),$=r(135);x.exports=function(E){var R=u(this),I=p(E);if(h(R)<=I.size)return y(R,function(C){if(I.includes(C))return!1},!0)!==!1;var O=I.getIterator();return T(O,function(C){if(d(R,C))return $(O,"normal",!1)})!==!1}},function(x,b,r){var u=r(3),d=r(439),h=r(433),p=!h("isSubsetOf",function(y){return y});u({target:"Set",proto:!0,real:!0,forced:p},{isSubsetOf:d})},function(x,b,r){var u=r(426),d=r(431),h=r(429),p=r(432);x.exports=function(T){var $=u(this),A=p(T);return d($)>A.size?!1:h($,function(E){if(!A.includes(E))return!1},!0)!==!1}},function(x,b,r){var u=r(3),d=r(441),h=r(433),p=!h("isSupersetOf",function(y){return!y});u({target:"Set",proto:!0,real:!0,forced:p},{isSupersetOf:d})},function(x,b,r){var u=r(426),d=r(427).has,h=r(431),p=r(432),y=r(430),T=r(135);x.exports=function(A){var E=u(this),R=p(A);if(h(E)=0?C:O+C;return D<0||D>=O?void 0:$(I,D)}})},function(x,b,r){var u=r(3),d=r(448).codeAt;u({target:"String",proto:!0},{codePointAt:function(p){return d(this,p)}})},function(x,b,r){var u=r(14),d=r(61),h=r(68),p=r(16),y=u("".charAt),T=u("".charCodeAt),$=u("".slice),A=function(E){return function(R,I){var O=h(p(R)),C=d(I),D=O.length,M,F;return C<0||C>=D?E?"":void 0:(M=T(O,C),M<55296||M>56319||C+1===D||(F=T(O,C+1))<56320||F>57343?E?y(O,C):M:E?$(O,C,C+2):(M-55296<<10)+(F-56320)+65536)}};x.exports={codeAt:A(!1),charAt:A(!0)}},function(x,b,r){var u=r(3),d=r(85),h=r(5).f,p=r(64),y=r(68),T=r(450),$=r(16),A=r(451),E=r(36),R=d("".slice),I=Math.min,O=A("endsWith"),C=!E&&!O&&!!function(){var D=h(String.prototype,"endsWith");return D&&!D.writable}();u({target:"String",proto:!0,forced:!C&&!O},{endsWith:function(M){var F=y($(this));T(M);var z=arguments.length>1?arguments[1]:void 0,U=F.length,j=z===void 0?U:I(p(z),U),G=y(M);return R(F,j-G.length,j)===G}})},function(x,b,r){var u=r(407),d=TypeError;x.exports=function(h){if(u(h))throw new d("The method doesn't accept regular expressions");return h}},function(x,b,r){var u=r(33),d=u("match");x.exports=function(h){var p=/./;try{"/./"[h](p)}catch(y){try{return p[d]=!1,"/./"[h](p)}catch(T){}}return!1}},function(x,b,r){var u=r(3),d=r(14),h=r(60),p=RangeError,y=String.fromCharCode,T=String.fromCodePoint,$=d([].join),A=!!T&&T.length!==1;u({target:"String",stat:!0,arity:1,forced:A},{fromCodePoint:function(R){for(var I=[],O=arguments.length,C=0,D;O>C;){if(D=+arguments[C++],h(D,1114111)!==D)throw new p(D+" is not a valid code point");I[C]=D<65536?y(D):y(((D-=65536)>>10)+55296,D%1024+56320)}return $(I,"")}})},function(x,b,r){var u=r(3),d=r(14),h=r(450),p=r(16),y=r(68),T=r(451),$=d("".indexOf);u({target:"String",proto:!0,forced:!T("includes")},{includes:function(E){return!!~$(y(p(this)),y(h(E)),arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(14),h=r(16),p=r(68),y=d("".charCodeAt);u({target:"String",proto:!0},{isWellFormed:function(){for(var $=p(h(this)),A=$.length,E=0;E=56320||++E>=A||(y($,E)&64512)!==56320))return!1}return!0}})},function(x,b,r){var u=r(448).charAt,d=r(68),h=r(51),p=r(169),y=r(172),T="String Iterator",$=h.set,A=h.getterFor(T);p(String,"String",function(E){$(this,{type:T,string:d(E),index:0})},function(){var R=A(this),I=R.string,O=R.index,C;return O>=I.length?y(void 0,!0):(C=u(I,O),R.index+=C.length,y(C,!1))})},function(x,b,r){var u=r(8),d=r(457),h=r(46),p=r(17),y=r(64),T=r(68),$=r(16),A=r(29),E=r(458),R=r(459);d("match",function(I,O,C){return[function(M){var F=$(this),z=p(M)?void 0:A(M,I);return z?u(z,M,F):new RegExp(M)[I](T(F))},function(D){var M=h(this),F=T(D),z=C(O,M,F);if(z.done)return z.value;if(!M.global)return R(M,F);var U=M.unicode;M.lastIndex=0;for(var j=[],G=0,B;(B=R(M,F))!==null;){var V=T(B[0]);j[G]=V,V===""&&(M.lastIndex=E(F,y(M.lastIndex),U)),G++}return G===0?null:j}]})},function(x,b,r){r(416);var u=r(8),d=r(47),h=r(417),p=r(7),y=r(33),T=r(43),$=y("species"),A=RegExp.prototype;x.exports=function(E,R,I,O){var C=y(E),D=!p(function(){var U={};return U[C]=function(){return 7},""[E](U)!==7}),M=D&&!p(function(){var U=!1,j=/a/;return E==="split"&&(j={},j.constructor={},j.constructor[$]=function(){return j},j.flags="",j[C]=/./[C]),j.exec=function(){return U=!0,null},j[C](""),!U});if(!D||!M||I){var F=/./[C],z=R(C,""[E],function(U,j,G,B,V){var Y=j.exec;return Y===h||Y===A.exec?D&&!V?{done:!0,value:u(F,j,G,B)}:{done:!0,value:u(U,G,j,B)}:{done:!1}});d(String.prototype,E,z[0]),d(A,C,z[1])}O&&T(A[C],"sham",!0)}},function(x,b,r){var u=r(448).charAt;x.exports=function(d,h,p){return h+(p?u(d,h).length:1)}},function(x,b,r){var u=r(8),d=r(46),h=r(21),p=r(15),y=r(417),T=TypeError;x.exports=function($,A){var E=$.exec;if(h(E)){var R=u(E,$,A);return R!==null&&d(R),R}if(p($)==="RegExp")return u(y,$,A);throw new T("RegExp#exec called on incompatible receiver")}},function(x,b,r){var u=r(3),d=r(8),h=r(85),p=r(170),y=r(172),T=r(16),$=r(64),A=r(68),E=r(46),R=r(17),I=r(15),O=r(407),C=r(408),D=r(29),M=r(47),F=r(7),z=r(33),U=r(364),j=r(458),G=r(459),B=r(51),V=r(36),Y=z("matchAll"),Z="RegExp String",J=Z+" Iterator",q=B.set,nt=B.getterFor(J),rt=RegExp.prototype,_=TypeError,tt=h("".indexOf),et=h("".matchAll),lt=!!et&&!F(function(){et("a",/./)}),mt=p(function(yt,Ut,Dt,Xt){q(this,{type:J,regexp:yt,string:Ut,global:Dt,unicode:Xt,done:!1})},Z,function(){var yt=nt(this);if(yt.done)return y(void 0,!0);var Ut=yt.regexp,Dt=yt.string,Xt=G(Ut,Dt);return Xt===null?(yt.done=!0,y(void 0,!0)):yt.global?(A(Xt[0])===""&&(Ut.lastIndex=j(Dt,$(Ut.lastIndex),yt.unicode)),y(Xt,!1)):(yt.done=!0,y(Xt,!1))}),gt=function(xt){var yt=E(this),Ut=A(xt),Dt=U(yt,RegExp),Xt=A(C(yt)),Qt,kt,me;return Qt=new Dt(Dt===RegExp?yt.source:yt,Xt),kt=!!~tt(Xt,"g"),me=!!~tt(Xt,"u"),Qt.lastIndex=$(yt.lastIndex),new mt(Qt,Ut,kt,me)};u({target:"String",proto:!0,forced:lt},{matchAll:function(yt){var Ut=T(this),Dt,Xt,Qt,kt;if(R(yt)){if(lt)return et(Ut,yt)}else{if(O(yt)&&(Dt=A(T(C(yt))),!~tt(Dt,"g")))throw new _("`.matchAll` does not allow non-global regexes");if(lt)return et(Ut,yt);if(Qt=D(yt,Y),Qt===void 0&&V&&I(yt)==="RegExp"&&(Qt=gt),Qt)return d(Qt,yt,Ut)}return Xt=A(Ut),kt=new RegExp(yt,"g"),V?d(gt,kt,Xt):kt[Y](Xt)}}),V||Y in rt||M(rt,Y,gt)},function(x,b,r){var u=r(3),d=r(243).end,h=r(462);u({target:"String",proto:!0,forced:h},{padEnd:function(y){return d(this,y,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(28);x.exports=/Version\/10(?:\.\d+){1,2}(?: [\w./]+)?(?: Mobile\/\w+)? Safari\//.test(u)},function(x,b,r){var u=r(3),d=r(243).start,h=r(462);u({target:"String",proto:!0,forced:h},{padStart:function(y){return d(this,y,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(14),h=r(12),p=r(39),y=r(68),T=r(63),$=d([].push),A=d([].join);u({target:"String",stat:!0},{raw:function(R){var I=h(p(R).raw),O=T(I);if(!O)return"";for(var C=arguments.length,D=[],M=0;;){if($(D,y(I[M++])),M===O)return A(D,"");M")!=="7"});p("replace",function(_,tt,et){var lt=nt?"$":"$0";return[function(gt,xt){var yt=O(this),Ut=A(gt)?void 0:D(gt,U);return Ut?d(Ut,gt,yt,xt):d(tt,I(yt),gt,xt)},function(mt,gt){var xt=T(this),yt=I(mt);if(typeof gt=="string"&&Y(gt,lt)===-1&&Y(gt,"$<")===-1){var Ut=et(tt,xt,yt,gt);if(Ut.done)return Ut.value}var Dt=$(gt);Dt||(gt=I(gt));var Xt=xt.global,Qt;Xt&&(Qt=xt.unicode,xt.lastIndex=0);for(var kt=[],me;me=F(xt,yt),!(me===null||(V(kt,me),!Xt));){var ge=I(me[0]);ge===""&&(xt.lastIndex=C(yt,R(xt.lastIndex),Qt))}for(var ae="",Mt=0,Ht=0;Ht=Mt&&(ae+=Z(yt,Mt,se)+fe,Mt=se+re.length)}return ae+Z(yt,Mt)}]},!rt||!q||nt)},function(x,b,r){var u=r(14),d=r(39),h=Math.floor,p=u("".charAt),y=u("".replace),T=u("".slice),$=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,A=/\$([$&'`]|\d{1,2})/g;x.exports=function(E,R,I,O,C,D){var M=I+E.length,F=O.length,z=A;return C!==void 0&&(C=d(C),z=$),y(D,z,function(U,j){var G;switch(p(j,0)){case"$":return"$";case"&":return E;case"`":return T(R,0,I);case"'":return T(R,M);case"<":G=C[T(j,1,-1)];break;default:var B=+j;if(B===0)return U;if(B>F){var V=h(B/10);return V===0?U:V<=F?O[V-1]===void 0?p(j,1):O[V-1]+p(j,1):U}G=O[B-1]}return G===void 0?"":G})}},function(x,b,r){var u=r(3),d=r(8),h=r(14),p=r(16),y=r(21),T=r(17),$=r(407),A=r(68),E=r(29),R=r(408),I=r(467),O=r(33),C=r(36),D=O("replace"),M=TypeError,F=h("".indexOf),z=h("".replace),U=h("".slice),j=Math.max;u({target:"String",proto:!0},{replaceAll:function(B,V){var Y=p(this),Z,J,q,nt,rt,_,tt,et,lt,mt,gt=0,xt="";if(!T(B)){if(Z=$(B),Z&&(J=A(p(R(B))),!~F(J,"g")))throw new M("`.replaceAll` does not allow non-global regexes");if(q=E(B,D),q)return d(q,B,Y,V);if(C&&Z)return z(A(Y),B,V)}for(nt=A(Y),rt=A(B),_=y(V),_||(V=A(V)),tt=rt.length,et=j(1,tt),lt=F(nt,rt);lt!==-1;)mt=_?A(V(rt,lt,nt)):I(rt,nt,lt,[],void 0,V),xt+=U(nt,gt,lt)+mt,gt=lt+tt,lt=lt+et>nt.length?-1:F(nt,rt,lt+et);return gt1||"".split(/.?/).length;h("split",function(V,Y,Z){var J="0".split(void 0,0).length?function(q,nt){return q===void 0&&nt===0?[]:u(Y,this,q,nt)}:Y;return[function(nt,rt){var _=T(this),tt=y(nt)?void 0:I(nt,V);return tt?u(tt,nt,_,rt):u(J,R(_),nt,rt)},function(q,nt){var rt=p(this),_=R(q);if(!B){var tt=Z(J,rt,_,nt,J!==Y);if(tt.done)return tt.value}var et=$(rt,RegExp),lt=rt.unicode,mt=(rt.ignoreCase?"i":"")+(rt.multiline?"m":"")+(rt.unicode?"u":"")+(M?"g":"y"),gt=new et(M?"^(?:"+rt.source+")":rt,mt),xt=nt===void 0?F:nt>>>0;if(xt===0)return[];if(_.length===0)return O(gt,_)===null?[_]:[];for(var yt=0,Ut=0,Dt=[];Ut<_.length;){gt.lastIndex=M?0:Ut;var Xt=O(gt,M?j(_,Ut):_),Qt;if(Xt===null||(Qt=z(E(gt.lastIndex+(M?Ut:0)),_.length))===yt)Ut=A(_,Ut,lt);else{if(U(Dt,j(_,yt,Ut)),Dt.length===xt)return Dt;for(var kt=1;kt<=Xt.length-1;kt++)if(U(Dt,Xt[kt]),Dt.length===xt)return Dt;Ut=yt=Qt}}return U(Dt,j(_,yt)),Dt}]},B||!G,M)},function(x,b,r){var u=r(3),d=r(85),h=r(5).f,p=r(64),y=r(68),T=r(450),$=r(16),A=r(451),E=r(36),R=d("".slice),I=Math.min,O=A("startsWith"),C=!E&&!O&&!!function(){var D=h(String.prototype,"startsWith");return D&&!D.writable}();u({target:"String",proto:!0,forced:!C&&!O},{startsWith:function(M){var F=y($(this));T(M);var z=p(I(arguments.length>1?arguments[1]:void 0,F.length)),U=y(M);return R(F,z,z+U.length)===U}})},function(x,b,r){var u=r(3),d=r(14),h=r(16),p=r(61),y=r(68),T=d("".slice),$=Math.max,A=Math.min,E=!"".substr||"ab".substr(-1)!=="b";u({target:"String",proto:!0,forced:E},{substr:function(I,O){var C=y(h(this)),D=C.length,M=p(I),F,z;return M===1/0&&(M=0),M<0&&(M=$(D+M,0)),F=O===void 0?D:p(O),F<=0||F===1/0?"":(z=A(M+F,D),M>=z?"":T(C,M,z))}})},function(x,b,r){var u=r(3),d=r(8),h=r(14),p=r(16),y=r(68),T=r(7),$=Array,A=h("".charAt),E=h("".charCodeAt),R=h([].join),I="".toWellFormed,O="\uFFFD",C=I&&T(function(){return d(I,1)!=="1"});u({target:"String",proto:!0,forced:C},{toWellFormed:function(){var M=y(p(this));if(C)return d(I,M);for(var F=M.length,z=$(F),U=0;U=56320||U+1>=F||(E(M,U+1)&64512)!==56320?z[U]=O:(z[U]=A(M,U),z[++U]=A(M,U))}return R(z,"")}})},function(x,b,r){var u=r(3),d=r(309).trim,h=r(475);u({target:"String",proto:!0,forced:h("trim")},{trim:function(){return d(this)}})},function(x,b,r){var u=r(49).PROPER,d=r(7),h=r(310),p="\u200B\x85\u180E";x.exports=function(y){return d(function(){return!!h[y]()||p[y]()!==p||u&&h[y].name!==y})}},function(x,b,r){r(477);var u=r(3),d=r(478);u({target:"String",proto:!0,name:"trimEnd",forced:"".trimEnd!==d},{trimEnd:d})},function(x,b,r){var u=r(3),d=r(478);u({target:"String",proto:!0,name:"trimEnd",forced:"".trimRight!==d},{trimRight:d})},function(x,b,r){var u=r(309).end,d=r(475);x.exports=d("trimEnd")?function(){return u(this)}:"".trimEnd},function(x,b,r){r(480);var u=r(3),d=r(481);u({target:"String",proto:!0,name:"trimStart",forced:"".trimStart!==d},{trimStart:d})},function(x,b,r){var u=r(3),d=r(481);u({target:"String",proto:!0,name:"trimStart",forced:"".trimLeft!==d},{trimLeft:d})},function(x,b,r){var u=r(309).start,d=r(475);x.exports=d("trimStart")?function(){return u(this)}:"".trimStart},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("anchor")},{anchor:function(y){return d(this,"a","name",y)}})},function(x,b,r){var u=r(14),d=r(16),h=r(68),p=/"/g,y=u("".replace);x.exports=function(T,$,A,E){var R=h(d(T)),I="<"+$;return A!==""&&(I+=" "+A+'="'+y(h(E),p,""")+'"'),I+">"+R+""}},function(x,b,r){var u=r(7);x.exports=function(d){return u(function(){var h=""[d]('"');return h!==h.toLowerCase()||h.split('"').length>3})}},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("big")},{big:function(){return d(this,"big","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("blink")},{blink:function(){return d(this,"blink","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("bold")},{bold:function(){return d(this,"b","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("fixed")},{fixed:function(){return d(this,"tt","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("fontcolor")},{fontcolor:function(y){return d(this,"font","color",y)}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("fontsize")},{fontsize:function(y){return d(this,"font","size",y)}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("italics")},{italics:function(){return d(this,"i","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("link")},{link:function(y){return d(this,"a","href",y)}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("small")},{small:function(){return d(this,"small","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("strike")},{strike:function(){return d(this,"strike","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("sub")},{sub:function(){return d(this,"sub","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("sup")},{sup:function(){return d(this,"sup","","")}})},function(x,b,r){var u=r(498);u("Float32",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(3),d=r(4),h=r(8),p=r(6),y=r(499),T=r(219),$=r(208),A=r(211),E=r(11),R=r(43),I=r(315),O=r(64),C=r(212),D=r(500),M=r(501),F=r(18),z=r(38),U=r(69),j=r(20),G=r(22),B=r(71),V=r(24),Y=r(113),Z=r(57).f,J=r(502),q=r(83).forEach,nt=r(194),rt=r(77),_=r(44),tt=r(5),et=r(199),lt=r(51),mt=r(118),gt=lt.get,xt=lt.set,yt=lt.enforce,Ut=_.f,Dt=tt.f,Xt=d.RangeError,Qt=$.ArrayBuffer,kt=Qt.prototype,me=$.DataView,ge=T.NATIVE_ARRAY_BUFFER_VIEWS,ae=T.TYPED_ARRAY_TAG,Mt=T.TypedArray,Ht=T.TypedArrayPrototype,re=T.isTypedArray,se="BYTES_PER_ELEMENT",ee="Wrong length",fe=function(Ae,Te){rt(Ae,Te,{configurable:!0,get:function(){return gt(this)[Te]}})},Pe=function(Ae){var Te;return V(kt,Ae)||(Te=U(Ae))==="ArrayBuffer"||Te==="SharedArrayBuffer"},Me=function(Ae,Te){return re(Ae)&&!G(Te)&&Te in Ae&&I(+Te)&&Te>=0},$e=function(Te,de){return de=F(de),Me(Te,de)?E(2,Te[de]):Dt(Te,de)},ce=function(Te,de,bt){return de=F(de),Me(Te,de)&&j(bt)&&z(bt,"value")&&!z(bt,"get")&&!z(bt,"set")&&!bt.configurable&&(!z(bt,"writable")||bt.writable)&&(!z(bt,"enumerable")||bt.enumerable)?(Te[de]=bt.value,Te):Ut(Te,de,bt)};p?(ge||(tt.f=$e,_.f=ce,fe(Ht,"buffer"),fe(Ht,"byteOffset"),fe(Ht,"byteLength"),fe(Ht,"length")),u({target:"Object",stat:!0,forced:!ge},{getOwnPropertyDescriptor:$e,defineProperty:ce}),x.exports=function(Ae,Te,de){var bt=Ae.match(/\d+/)[0]/8,Ft=Ae+(de?"Clamped":"")+"Array",Tt="get"+Ae,qt="set"+Ae,te=d[Ft],Zt=te,Yt=Zt&&Zt.prototype,Ye={},Ze=function(Ct,Nt){var Et=gt(Ct);return Et.view[Tt](Nt*bt+Et.byteOffset,!0)},ut=function(Ct,Nt,Et){var ie=gt(Ct);ie.view[qt](Nt*bt+ie.byteOffset,de?M(Et):Et,!0)},It=function(Ct,Nt){Ut(Ct,Nt,{get:function(){return Ze(this,Nt)},set:function(Et){return ut(this,Nt,Et)},enumerable:!0})};ge?y&&(Zt=Te(function(Ct,Nt,Et,ie){return A(Ct,Yt),mt(function(){return j(Nt)?Pe(Nt)?ie!==void 0?new te(Nt,D(Et,bt),ie):Et!==void 0?new te(Nt,D(Et,bt)):new te(Nt):re(Nt)?et(Zt,Nt):h(J,Zt,Nt):new te(C(Nt))}(),Ct,Zt)}),Y&&Y(Zt,Mt),q(Z(te),function(Ct){Ct in Zt||R(Zt,Ct,te[Ct])}),Zt.prototype=Yt):(Zt=Te(function(Ct,Nt,Et,ie){A(Ct,Yt);var we=0,Rt=0,zt,jt,Wt;if(!j(Nt))Wt=C(Nt),jt=Wt*bt,zt=new Qt(jt);else if(Pe(Nt)){zt=Nt,Rt=D(Et,bt);var ue=Nt.byteLength;if(ie===void 0){if(ue%bt)throw new Xt(ee);if(jt=ue-Rt,jt<0)throw new Xt(ee)}else if(jt=O(ie)*bt,jt+Rt>ue)throw new Xt(ee);Wt=jt/bt}else return re(Nt)?et(Zt,Nt):h(J,Zt,Nt);for(xt(Ct,{buffer:zt,byteOffset:Rt,byteLength:jt,length:Wt,view:new me(zt)});we255?255:u&255}},function(x,b,r){var u=r(84),d=r(8),h=r(365),p=r(39),y=r(63),T=r(133),$=r(134),A=r(131),E=r(503),R=r(219).aTypedArrayConstructor,I=r(504);x.exports=function(C){var D=h(this),M=p(C),F=arguments.length,z=F>1?arguments[1]:void 0,U=z!==void 0,j=$(M),G,B,V,Y,Z,J,q,nt;if(j&&!A(j))for(q=T(M,j),nt=q.next,M=[];!(J=d(nt,q)).done;)M.push(J.value);for(U&&F>2&&(z=u(z,arguments[2])),B=y(M),V=new(R(D))(B),Y=E(V),G=0;B>G;G++)Z=U?z(M[G],G):M[G],V[G]=Y?I(Z):+Z;return V}},function(x,b,r){var u=r(69);x.exports=function(d){var h=u(d);return h==="BigInt64Array"||h==="BigUint64Array"}},function(x,b,r){var u=r(19),d=TypeError;x.exports=function(h){var p=u(h,"number");if(typeof p=="number")throw new d("Can't convert number to bigint");return BigInt(p)}},function(x,b,r){var u=r(498);u("Float64",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Int8",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Int16",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Int32",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Uint8",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Uint8",function(d){return function(p,y,T){return d(this,p,y,T)}},!0)},function(x,b,r){var u=r(498);u("Uint16",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Uint32",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(219),d=r(63),h=r(61),p=u.aTypedArray,y=u.exportTypedArrayMethod;y("at",function($){var A=p(this),E=d(A),R=h($),I=R>=0?R:E+R;return I<0||I>=E?void 0:A[I]})},function(x,b,r){var u=r(14),d=r(219),h=r(144),p=u(h),y=d.aTypedArray,T=d.exportTypedArrayMethod;T("copyWithin",function(A,E){return p(y(this),A,E,arguments.length>2?arguments[2]:void 0)})},function(x,b,r){var u=r(219),d=r(83).every,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("every",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(149),h=r(504),p=r(69),y=r(8),T=r(14),$=r(7),A=u.aTypedArray,E=u.exportTypedArrayMethod,R=T("".slice),I=$(function(){var O=0;return new Int8Array(2).fill({valueOf:function(){return O++}}),O!==1});E("fill",function(C){var D=arguments.length;A(this);var M=R(p(this),0,3)==="Big"?h(C):+C;return y(d,this,M,D>1?arguments[1]:void 0,D>2?arguments[2]:void 0)},I)},function(x,b,r){var u=r(219),d=r(83).filter,h=r(518),p=u.aTypedArray,y=u.exportTypedArrayMethod;y("filter",function($){var A=d(p(this),$,arguments.length>1?arguments[1]:void 0);return h(this,A)})},function(x,b,r){var u=r(199),d=r(219).getTypedArrayConstructor;x.exports=function(h,p){return u(d(h),p)}},function(x,b,r){var u=r(219),d=r(83).find,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("find",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(83).findIndex,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("findIndex",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(154).findLast,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("findLast",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(154).findLastIndex,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("findLastIndex",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(83).forEach,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("forEach",function(T){d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(499),d=r(219).exportTypedArrayStaticMethod,h=r(502);d("from",h,u)},function(x,b,r){var u=r(219),d=r(59).includes,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("includes",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(59).indexOf,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("indexOf",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(4),d=r(7),h=r(14),p=r(219),y=r(168),T=r(33),$=T("iterator"),A=u.Uint8Array,E=h(y.values),R=h(y.keys),I=h(y.entries),O=p.aTypedArray,C=p.exportTypedArrayMethod,D=A&&A.prototype,M=!d(function(){D[$].call([1])}),F=!!D&&D.values&&D[$]===D.values&&D.values.name==="values",z=function(){return E(O(this))};C("entries",function(){return I(O(this))},M),C("keys",function(){return R(O(this))},M),C("values",z,M||!F,{name:"values"}),C($,z,M||!F,{name:"values"})},function(x,b,r){var u=r(219),d=r(14),h=u.aTypedArray,p=u.exportTypedArrayMethod,y=d([].join);p("join",function($){return y(h(this),$)})},function(x,b,r){var u=r(219),d=r(94),h=r(175),p=u.aTypedArray,y=u.exportTypedArrayMethod;y("lastIndexOf",function($){var A=arguments.length;return d(h,p(this),A>1?[$,arguments[1]]:[$])})},function(x,b,r){var u=r(219),d=r(83).map,h=u.aTypedArray,p=u.getTypedArrayConstructor,y=u.exportTypedArrayMethod;y("map",function($){return d(h(this),$,arguments.length>1?arguments[1]:void 0,function(A,E){return new(p(A))(E)})})},function(x,b,r){var u=r(219),d=r(499),h=u.aTypedArrayConstructor,p=u.exportTypedArrayStaticMethod;p("of",function(){for(var T=0,$=arguments.length,A=new(h(this))($);$>T;)A[T]=arguments[T++];return A},d)},function(x,b,r){var u=r(219),d=r(181).left,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("reduce",function(T){var $=arguments.length;return d(h(this),T,$,$>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(181).right,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("reduceRight",function(T){var $=arguments.length;return d(h(this),T,$,$>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=u.aTypedArray,h=u.exportTypedArrayMethod,p=Math.floor;h("reverse",function(){for(var T=this,$=d(T).length,A=p($/2),E=0,R;E1?arguments[1]:void 0,1),j=T(z);if(D)return d(I,this,j,U);var G=this.length,B=p(j),V=0;if(B+U>G)throw new A("Wrong length");for(;VC;)M[C]=I[C++];return M},$)},function(x,b,r){var u=r(219),d=r(83).some,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("some",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(4),d=r(85),h=r(7),p=r(30),y=r(189),T=r(219),$=r(190),A=r(191),E=r(27),R=r(192),I=T.aTypedArray,O=T.exportTypedArrayMethod,C=u.Uint16Array,D=C&&d(C.prototype.sort),M=!!D&&!(h(function(){D(new C(2),null)})&&h(function(){D(new C(2),{})})),F=!!D&&!h(function(){if(E)return E<74;if($)return $<67;if(A)return!0;if(R)return R<602;var U=new C(516),j=Array(516),G,B;for(G=0;G<516;G++)B=G%4,U[G]=515-G,j[G]=G-2*B+3;for(D(U,function(V,Y){return(V/4|0)-(Y/4|0)}),G=0;G<516;G++)if(U[G]!==j[G])return!0}),z=function(U){return function(j,G){return U!==void 0?+U(j,G)||0:G!==G?-1:j!==j?1:j===0&&G===0?1/j>0&&1/G<0?1:-1:j>G}};O("sort",function(j){return j!==void 0&&p(j),F?D(this,j):y(I(this),z(j))},!F||M)},function(x,b,r){var u=r(219),d=r(64),h=r(60),p=u.aTypedArray,y=u.getTypedArrayConstructor,T=u.exportTypedArrayMethod;T("subarray",function(A,E){var R=p(this),I=R.length,O=h(A,I),C=y(R);return new C(R.buffer,R.byteOffset+O*R.BYTES_PER_ELEMENT,d((E===void 0?I:h(E,I))-O))})},function(x,b,r){var u=r(4),d=r(94),h=r(219),p=r(7),y=r(76),T=u.Int8Array,$=h.aTypedArray,A=h.exportTypedArrayMethod,E=[].toLocaleString,R=!!T&&p(function(){E.call(new T(1))}),I=p(function(){return[1,2].toLocaleString()!==new T([1,2]).toLocaleString()})||!p(function(){T.prototype.toLocaleString.call([1,2])});A("toLocaleString",function(){return d(E,R?y($(this)):$(this),y(arguments))},I)},function(x,b,r){var u=r(197),d=r(219),h=d.aTypedArray,p=d.exportTypedArrayMethod,y=d.getTypedArrayConstructor;p("toReversed",function(){return u(h(this),y(this))})},function(x,b,r){var u=r(219),d=r(14),h=r(30),p=r(199),y=u.aTypedArray,T=u.getTypedArrayConstructor,$=u.exportTypedArrayMethod,A=d(u.TypedArrayPrototype.sort);$("toSorted",function(R){R!==void 0&&h(R);var I=y(this),O=p(T(I),I);return A(O,R)})},function(x,b,r){var u=r(219).exportTypedArrayMethod,d=r(7),h=r(4),p=r(14),y=h.Uint8Array,T=y&&y.prototype||{},$=[].toString,A=p([].join);d(function(){$.call({})})&&($=function(){return A(this)});var E=T.toString!==$;u("toString",$,E)},function(x,b,r){var u=r(206),d=r(219),h=r(503),p=r(61),y=r(504),T=d.aTypedArray,$=d.getTypedArrayConstructor,A=d.exportTypedArrayMethod,E=!!function(){try{new Int8Array(1).with(2,{valueOf:function(){throw 8}})}catch(R){return R===8}}();A("with",function(R,I){var O=T(this),C=p(R),D=h(O)?y(I):+I;return u(O,$(O),C,D)},!E)},function(x,b,r){var u=r(3),d=r(14),h=r(68),p=String.fromCharCode,y=d("".charAt),T=d(/./.exec),$=d("".slice),A=/^[\da-f]{2}$/i,E=/^[\da-f]{4}$/i;u({global:!0},{unescape:function(I){for(var O=h(I),C="",D=O.length,M=0,F,z;M>(-2*_&6)));return nt}})},function(x){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",r=b+"+/",u=b+"-_",d=function(h){for(var p={},y=0;y<64;y++)p[h.charAt(y)]=y;return p};x.exports={i2c:r,c2i:d(r),i2cUrl:u,c2iUrl:d(u)}},function(x,b,r){var u=r(3),d=r(4),h=r(23),p=r(14),y=r(8),T=r(7),$=r(68),A=r(367),E=r(552).i2c,R=h("btoa"),I=p("".charAt),O=p("".charCodeAt),C=!!R&&!T(function(){return R("hi")!=="aGk="}),D=C&&!T(function(){R()}),M=C&&T(function(){return R(null)!=="bnVsbA=="}),F=C&&R.length!==1;u({global:!0,bind:!0,enumerable:!0,forced:!C||D||M||F},{btoa:function(U){if(A(arguments.length,1),C)return y(R,d,$(U));for(var j=$(U),G="",B=0,V=E,Y,Z;I(j,B)||(V="=",B%1);){if(Z=O(j,B+=.75),Z>255)throw new(h("DOMException"))("The string contains characters outside of the Latin1 range","InvalidCharacterError");Y=Y<<8|Z,G+=I(V,63&Y>>8-B%1*8)}return G}})},function(x,b,r){var u=r(4),d=r(555),h=r(556),p=r(160),y=r(43),T=function(A){if(A&&A.forEach!==p)try{y(A,"forEach",p)}catch(E){A.forEach=p}};for(var $ in d)d[$]&&T(u[$]&&u[$].prototype);T(h)},function(x){x.exports={CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0}},function(x,b,r){var u=r(42),d=u("span").classList,h=d&&d.constructor&&d.constructor.prototype;x.exports=h===Object.prototype?void 0:h},function(x,b,r){var u=r(4),d=r(555),h=r(556),p=r(168),y=r(43),T=r(82),$=r(33),A=$("iterator"),E=p.values,R=function(O,C){if(O){if(O[A]!==E)try{y(O,A,E)}catch(M){O[A]=E}if(T(O,C,!0),d[C]){for(var D in p)if(O[D]!==p[D])try{y(O,D,p[D])}catch(M){O[D]=p[D]}}}};for(var I in d)R(u[I]&&u[I].prototype,I);R(h,"DOMTokenList")},function(x,b,r){var u=r(3),d=r(23),h=r(234),p=r(7),y=r(71),T=r(11),$=r(44).f,A=r(47),E=r(77),R=r(38),I=r(211),O=r(46),C=r(125),D=r(119),M=r(559),F=r(122),z=r(51),U=r(6),j=r(36),G="DOMException",B="DATA_CLONE_ERR",V=d("Error"),Y=d(G)||function(){try{var Mt=d("MessageChannel")||h("worker_threads").MessageChannel;new Mt().port1.postMessage(new WeakMap)}catch(Ht){if(Ht.name===B&&Ht.code===25)return Ht.constructor}}(),Z=Y&&Y.prototype,J=V.prototype,q=z.set,nt=z.getterFor(G),rt="stack"in new V(G),_=function(Mt){return R(M,Mt)&&M[Mt].m?M[Mt].c:0},tt=function(){I(this,et);var Ht=arguments.length,re=D(Ht<1?void 0:arguments[0]),se=D(Ht<2?void 0:arguments[1],"Error"),ee=_(se);if(q(this,{type:G,name:se,message:re,code:ee}),U||(this.name=se,this.message=re,this.code=ee),rt){var fe=new V(re);fe.name=G,$(this,"stack",T(1,F(fe.stack,1)))}},et=tt.prototype=y(J),lt=function(Mt){return{enumerable:!0,configurable:!0,get:Mt}},mt=function(Mt){return lt(function(){return nt(this)[Mt]})};U&&(E(et,"code",mt("code")),E(et,"message",mt("message")),E(et,"name",mt("name"))),$(et,"constructor",T(1,tt));var gt=p(function(){return!(new Y instanceof V)}),xt=gt||p(function(){return J.toString!==C||String(new Y(1,2))!=="2: 1"}),yt=gt||p(function(){return new Y(1,"DataCloneError").code!==25}),Ut=gt||Y[B]!==25||Z[B]!==25,Dt=j?xt||yt||Ut:gt;u({global:!0,constructor:!0,forced:Dt},{DOMException:Dt?tt:Y});var Xt=d(G),Qt=Xt.prototype;xt&&(j||Y===Xt)&&A(Qt,"toString",C),yt&&U&&Y===Xt&&E(Qt,"code",lt(function(){return _(O(this).name)}));for(var kt in M)if(R(M,kt)){var me=M[kt],ge=me.s,ae=T(6,me.c);R(Xt,ge)||$(Xt,ge,ae),R(Qt,ge)||$(Qt,ge,ae)}},function(x){x.exports={IndexSizeError:{s:"INDEX_SIZE_ERR",c:1,m:1},DOMStringSizeError:{s:"DOMSTRING_SIZE_ERR",c:2,m:0},HierarchyRequestError:{s:"HIERARCHY_REQUEST_ERR",c:3,m:1},WrongDocumentError:{s:"WRONG_DOCUMENT_ERR",c:4,m:1},InvalidCharacterError:{s:"INVALID_CHARACTER_ERR",c:5,m:1},NoDataAllowedError:{s:"NO_DATA_ALLOWED_ERR",c:6,m:0},NoModificationAllowedError:{s:"NO_MODIFICATION_ALLOWED_ERR",c:7,m:1},NotFoundError:{s:"NOT_FOUND_ERR",c:8,m:1},NotSupportedError:{s:"NOT_SUPPORTED_ERR",c:9,m:1},InUseAttributeError:{s:"INUSE_ATTRIBUTE_ERR",c:10,m:1},InvalidStateError:{s:"INVALID_STATE_ERR",c:11,m:1},SyntaxError:{s:"SYNTAX_ERR",c:12,m:1},InvalidModificationError:{s:"INVALID_MODIFICATION_ERR",c:13,m:1},NamespaceError:{s:"NAMESPACE_ERR",c:14,m:1},InvalidAccessError:{s:"INVALID_ACCESS_ERR",c:15,m:1},ValidationError:{s:"VALIDATION_ERR",c:16,m:0},TypeMismatchError:{s:"TYPE_MISMATCH_ERR",c:17,m:1},SecurityError:{s:"SECURITY_ERR",c:18,m:1},NetworkError:{s:"NETWORK_ERR",c:19,m:1},AbortError:{s:"ABORT_ERR",c:20,m:1},URLMismatchError:{s:"URL_MISMATCH_ERR",c:21,m:1},QuotaExceededError:{s:"QUOTA_EXCEEDED_ERR",c:22,m:1},TimeoutError:{s:"TIMEOUT_ERR",c:23,m:1},InvalidNodeTypeError:{s:"INVALID_NODE_TYPE_ERR",c:24,m:1},DataCloneError:{s:"DATA_CLONE_ERR",c:25,m:1}}},function(x,b,r){var u=r(3),d=r(4),h=r(23),p=r(11),y=r(44).f,T=r(38),$=r(211),A=r(118),E=r(119),R=r(559),I=r(122),O=r(6),C=r(36),D="DOMException",M=h("Error"),F=h(D),z=function(){$(this,U);var tt=arguments.length,et=E(tt<1?void 0:arguments[0]),lt=E(tt<2?void 0:arguments[1],"Error"),mt=new F(et,lt),gt=new M(et);return gt.name=D,y(mt,"stack",p(1,I(gt.stack,1))),A(mt,this,z),mt},U=z.prototype=F.prototype,j="stack"in new M(D),G="stack"in new F(1,2),B=F&&O&&Object.getOwnPropertyDescriptor(d,D),V=!!B&&!(B.writable&&B.configurable),Y=j&&!V&&!G;u({global:!0,constructor:!0,forced:C||Y},{DOMException:Y?z:F});var Z=h(D),J=Z.prototype;if(J.constructor!==Z){C||y(J,"constructor",p(1,Z));for(var q in R)if(T(R,q)){var nt=R[q],rt=nt.s;T(Z,rt)||y(Z,rt,p(6,nt.c))}}},function(x,b,r){var u=r(23),d=r(82),h="DOMException";d(u(h),h)},function(x,b,r){r(563),r(564)},function(x,b,r){var u=r(3),d=r(4),h=r(366).clear;u({global:!0,bind:!0,enumerable:!0,forced:d.clearImmediate!==h},{clearImmediate:h})},function(x,b,r){var u=r(3),d=r(4),h=r(366).set,p=r(565),y=d.setImmediate?p(h,!1):h;u({global:!0,bind:!0,enumerable:!0,forced:d.setImmediate!==y},{setImmediate:y})},function(x,b,r){var u=r(4),d=r(94),h=r(21),p=r(183),y=r(28),T=r(76),$=r(367),A=u.Function,E=/MSIE .\./.test(y)||p==="BUN"&&function(){var R=u.Bun.version.split(".");return R.length<3||R[0]==="0"&&(R[1]<3||R[1]==="3"&&R[2]==="0")}();x.exports=function(R,I){var O=I?2:1;return E?function(C,D){var M=$(arguments.length,1)>O,F=h(C)?C:A(C),z=M?T(arguments,O):[],U=M?function(){d(F,this,z)}:F;return I?R(U,D):R(U)}:R}},function(x,b,r){var u=r(3),d=r(4),h=r(369),p=r(30),y=r(367),T=r(7),$=r(6),A=T(function(){return $&&Object.getOwnPropertyDescriptor(d,"queueMicrotask").value.length!==1});u({global:!0,enumerable:!0,dontCallGetSet:!0,forced:A},{queueMicrotask:function(R){y(arguments.length,1),h(p(R))}})},function(x,b,r){var u=r(3),d=r(4),h=r(77),p=r(6),y=TypeError,T=Object.defineProperty,$=d.self!==d;try{if(p){var A=Object.getOwnPropertyDescriptor(d,"self");($||!A||!A.get||!A.enumerable)&&h(d,"self",{get:function(){return d},set:function(R){if(this!==d)throw new y("Illegal invocation");T(d,"self",{value:R,writable:!0,configurable:!0,enumerable:!0})},configurable:!0,enumerable:!0})}else u({global:!0,simple:!0,forced:$},{self:d})}catch(E){}},function(x,b,r){var u=r(36),d=r(3),h=r(4),p=r(23),y=r(14),T=r(7),$=r(40),A=r(21),E=r(89),R=r(17),I=r(20),O=r(22),C=r(130),D=r(46),M=r(69),F=r(38),z=r(141),U=r(43),j=r(63),G=r(367),B=r(408),V=r(284),Y=r(427),Z=r(429),J=r(233),q=r(123),nt=r(235),rt=h.Object,_=h.Array,tt=h.Date,et=h.Error,lt=h.TypeError,mt=h.PerformanceMark,gt=p("DOMException"),xt=V.Map,yt=V.has,Ut=V.get,Dt=V.set,Xt=Y.Set,Qt=Y.add,kt=Y.has,me=p("Object","keys"),ge=y([].push),ae=y((!0).valueOf),Mt=y(1 .valueOf),Ht=y("".valueOf),re=y(tt.prototype.getTime),se=$("structuredClone"),ee="DataCloneError",fe="Transferring",Pe=function(ut){return!T(function(){var It=new h.Set([7]),Pt=ut(It),Ct=ut(rt(7));return Pt===It||!Pt.has(7)||!I(Ct)||+Ct!=7})&&ut},Me=function(ut,It){return!T(function(){var Pt=new It,Ct=ut({a:Pt,b:Pt});return!(Ct&&Ct.a===Ct.b&&Ct.a instanceof It&&Ct.a.stack===Pt.stack)})},$e=function(ut){return!T(function(){var It=ut(new h.AggregateError([1],se,{cause:3}));return It.name!=="AggregateError"||It.errors[0]!==1||It.message!==se||It.cause!==3})},ce=h.structuredClone,Ae=u||!Me(ce,et)||!Me(ce,gt)||!$e(ce),Te=!ce&&Pe(function(ut){return new mt(se,{detail:ut}).detail}),de=Pe(ce)||Te,bt=function(ut){throw new gt("Uncloneable type: "+ut,ee)},Ft=function(ut,It){throw new gt((It||"Cloning")+" of "+ut+" cannot be properly polyfilled in this engine",ee)},Tt=function(ut,It){return de||Ft(It),de(ut)},qt=function(){var ut;try{ut=new h.DataTransfer}catch(It){try{ut=new h.ClipboardEvent("").clipboardData}catch(Pt){}}return ut&&ut.items&&ut.files?ut:null},te=function(ut,It,Pt){if(yt(It,ut))return Ut(It,ut);var Ct=Pt||M(ut),Nt,Et,ie,we,Rt,zt;if(Ct==="SharedArrayBuffer")de?Nt=de(ut):Nt=ut;else{var jt=h.DataView;!jt&&!A(ut.slice)&&Ft("ArrayBuffer");try{if(A(ut.slice)&&!ut.resizable)Nt=ut.slice(0);else for(Et=ut.byteLength,ie=("maxByteLength"in ut)?{maxByteLength:ut.maxByteLength}:void 0,Nt=new ArrayBuffer(Et,ie),we=new jt(ut),Rt=new jt(Nt),zt=0;zt1&&!R(arguments[1])?D(arguments[1]):void 0,Ct=Pt?Pt.transfer:void 0,Nt,Et;Ct!==void 0&&(Nt=new xt,Et=Ye(Ct,Nt));var ie=Yt(It,Nt);return Et&&Ze(Et),ie}})},function(x,b,r){r(570),r(571)},function(x,b,r){var u=r(3),d=r(4),h=r(565),p=h(d.setInterval,!0);u({global:!0,bind:!0,forced:d.setInterval!==p},{setInterval:p})},function(x,b,r){var u=r(3),d=r(4),h=r(565),p=h(d.setTimeout,!0);u({global:!0,bind:!0,forced:d.setTimeout!==p},{setTimeout:p})},function(x,b,r){r(573)},function(x,b,r){r(455);var u=r(3),d=r(6),h=r(574),p=r(4),y=r(84),T=r(14),$=r(47),A=r(77),E=r(211),R=r(38),I=r(328),O=r(162),C=r(76),D=r(448).codeAt,M=r(575),F=r(68),z=r(82),U=r(367),j=r(576),G=r(51),B=G.set,V=G.getterFor("URL"),Y=j.URLSearchParams,Z=j.getState,J=p.URL,q=p.TypeError,nt=p.parseInt,rt=Math.floor,_=Math.pow,tt=T("".charAt),et=T(/./.exec),lt=T([].join),mt=T(1 .toString),gt=T([].pop),xt=T([].push),yt=T("".replace),Ut=T([].shift),Dt=T("".split),Xt=T("".slice),Qt=T("".toLowerCase),kt=T([].unshift),me="Invalid authority",ge="Invalid scheme",ae="Invalid host",Mt="Invalid port",Ht=/[a-z]/i,re=/[\d+-.a-z]/i,se=/\d/,ee=/^0x/i,fe=/^[0-7]+$/,Pe=/^\d+$/,Me=/^[\da-f]+$/i,$e=/[\0\t\n\r #%/:<>?@[\\\]^|]/,ce=/[\0\t\n\r #/:<>?@[\\\]^|]/,Ae=/^[\u0000-\u0020]+/,Te=/(^|[^\u0000-\u0020])[\u0000-\u0020]+$/,de=/[\t\n\r]/g,bt,Ft=function(ft){var wt=Dt(ft,"."),pt,it,Ot,ye,_t,Ie,rn;if(wt.length&&wt[wt.length-1]===""&&wt.length--,pt=wt.length,pt>4)return ft;for(it=[],Ot=0;Ot1&&tt(ye,0)==="0"&&(_t=et(ee,ye)?16:8,ye=Xt(ye,_t===8?1:2)),ye==="")Ie=0;else{if(!et(_t===10?Pe:_t===8?fe:Me,ye))return ft;Ie=nt(ye,_t)}xt(it,Ie)}for(Ot=0;Ot=_(256,5-pt))return null}else if(Ie>255)return null;for(rn=gt(it),Ot=0;Ot6))return;for(Ie=0;an();){if(rn=null,Ie>0)if(an()==="."&&Ie<4)Ot++;else return;if(!et(se,an()))return;for(;et(se,an());){if(hn=nt(an(),10),rn===null)rn=hn;else{if(rn===0)return;rn=rn*10+hn}if(rn>255)return;Ot++}wt[pt]=wt[pt]*256+rn,Ie++,(Ie===2||Ie===4)&&pt++}if(Ie!==4)return;break}else if(an()===":"){if(Ot++,!an())return}else if(an())return;wt[pt++]=ye}if(it!==null)for(pn=pt-it,pt=7;pt!==0&&pn>0;)ot=wt[pt],wt[pt--]=wt[it+pn-1],wt[it+--pn]=ot;else if(pt!==8)return;return wt},qt=function(ft){for(var wt=null,pt=1,it=null,Ot=0,ye=0;ye<8;ye++)ft[ye]!==0?(Ot>pt&&(wt=it,pt=Ot),it=null,Ot=0):(it===null&&(it=ye),++Ot);return Ot>pt?it:wt},te=function(ft){var wt,pt,it,Ot;if(typeof ft=="number"){for(wt=[],pt=0;pt<4;pt++)kt(wt,ft%256),ft=rt(ft/256);return lt(wt,".")}if(typeof ft=="object"){for(wt="",it=qt(ft),pt=0;pt<8;pt++)Ot&&ft[pt]===0||(Ot&&(Ot=!1),it===pt?(wt+=pt?":":"::",Ot=!0):(wt+=mt(ft[pt],16),pt<7&&(wt+=":")));return"["+wt+"]"}return ft},Zt={},Yt=I({},Zt,{" ":1,'"':1,"<":1,">":1,"`":1}),Ye=I({},Yt,{"#":1,"?":1,"{":1,"}":1}),Ze=I({},Ye,{"/":1,":":1,";":1,"=":1,"@":1,"[":1,"\\":1,"]":1,"^":1,"|":1}),ut=function(ft,wt){var pt=D(ft,0);return pt>32&&pt<127&&!R(wt,ft)?ft:encodeURIComponent(ft)},It={ftp:21,file:null,http:80,https:443,ws:80,wss:443},Pt=function(ft,wt){var pt;return ft.length===2&&et(Ht,tt(ft,0))&&((pt=tt(ft,1))===":"||!wt&&pt==="|")},Ct=function(ft){var wt;return ft.length>1&&Pt(Xt(ft,0,2))&&(ft.length===2||(wt=tt(ft,2))==="/"||wt==="\\"||wt==="?"||wt==="#")},Nt=function(ft){return ft==="."||Qt(ft)==="%2e"},Et=function(ft){return ft=Qt(ft),ft===".."||ft==="%2e."||ft===".%2e"||ft==="%2e%2e"},ie={},we={},Rt={},zt={},jt={},Wt={},ue={},Ee={},Xe={},Je={},nn={},vn={},jn={},Hr={},Ya={},ga={},yr={},Vn={},Wa={},ir={},Wn={},va=function(ft,wt,pt){var it=F(ft),Ot,ye,_t;if(wt){if(ye=this.parse(it),ye)throw new q(ye);this.searchParams=null}else{if(pt!==void 0&&(Ot=new va(pt,!0)),ye=this.parse(it,null,Ot),ye)throw new q(ye);_t=Z(new Y),_t.bindURL(this),this.searchParams=_t}};va.prototype={type:"URL",parse:function(ft,wt,pt){var it=this,Ot=wt||ie,ye=0,_t="",Ie=!1,rn=!1,hn=!1,pn,ot,an,Fn;for(ft=F(ft),wt||(it.scheme="",it.username="",it.password="",it.host=null,it.port=null,it.path=[],it.query=null,it.fragment=null,it.cannotBeABaseURL=!1,ft=yt(ft,Ae,""),ft=yt(ft,Te,"$1")),ft=yt(ft,de,""),pn=O(ft);ye<=pn.length;){switch(ot=pn[ye],Ot){case ie:if(ot&&et(Ht,ot))_t+=Qt(ot),Ot=we;else{if(wt)return ge;Ot=Rt;continue}break;case we:if(ot&&(et(re,ot)||ot==="+"||ot==="-"||ot==="."))_t+=Qt(ot);else if(ot===":"){if(wt&&(it.isSpecial()!==R(It,_t)||_t==="file"&&(it.includesCredentials()||it.port!==null)||it.scheme==="file"&&!it.host))return;if(it.scheme=_t,wt){it.isSpecial()&&It[it.scheme]===it.port&&(it.port=null);return}_t="",it.scheme==="file"?Ot=Hr:it.isSpecial()&&pt&&pt.scheme===it.scheme?Ot=zt:it.isSpecial()?Ot=Ee:pn[ye+1]==="/"?(Ot=jt,ye++):(it.cannotBeABaseURL=!0,xt(it.path,""),Ot=Wa)}else{if(wt)return ge;_t="",Ot=Rt,ye=0;continue}break;case Rt:if(!pt||pt.cannotBeABaseURL&&ot!=="#")return ge;if(pt.cannotBeABaseURL&&ot==="#"){it.scheme=pt.scheme,it.path=C(pt.path),it.query=pt.query,it.fragment="",it.cannotBeABaseURL=!0,Ot=Wn;break}Ot=pt.scheme==="file"?Hr:Wt;continue;case zt:if(ot==="/"&&pn[ye+1]==="/")Ot=Xe,ye++;else{Ot=Wt;continue}break;case jt:if(ot==="/"){Ot=Je;break}else{Ot=Vn;continue}case Wt:if(it.scheme=pt.scheme,ot===bt)it.username=pt.username,it.password=pt.password,it.host=pt.host,it.port=pt.port,it.path=C(pt.path),it.query=pt.query;else if(ot==="/"||ot==="\\"&&it.isSpecial())Ot=ue;else if(ot==="?")it.username=pt.username,it.password=pt.password,it.host=pt.host,it.port=pt.port,it.path=C(pt.path),it.query="",Ot=ir;else if(ot==="#")it.username=pt.username,it.password=pt.password,it.host=pt.host,it.port=pt.port,it.path=C(pt.path),it.query=pt.query,it.fragment="",Ot=Wn;else{it.username=pt.username,it.password=pt.password,it.host=pt.host,it.port=pt.port,it.path=C(pt.path),it.path.length--,Ot=Vn;continue}break;case ue:if(it.isSpecial()&&(ot==="/"||ot==="\\"))Ot=Xe;else if(ot==="/")Ot=Je;else{it.username=pt.username,it.password=pt.password,it.host=pt.host,it.port=pt.port,Ot=Vn;continue}break;case Ee:if(Ot=Xe,ot!=="/"||tt(_t,ye+1)!=="/")continue;ye++;break;case Xe:if(ot!=="/"&&ot!=="\\"){Ot=Je;continue}break;case Je:if(ot==="@"){Ie&&(_t="%40"+_t),Ie=!0,an=O(_t);for(var en=0;en65535)return Mt;it.port=it.isSpecial()&&Bn===It[it.scheme]?null:Bn,_t=""}if(wt)return;Ot=yr;continue}else return Mt;break;case Hr:if(it.scheme="file",ot==="/"||ot==="\\")Ot=Ya;else if(pt&&pt.scheme==="file")switch(ot){case bt:it.host=pt.host,it.path=C(pt.path),it.query=pt.query;break;case"?":it.host=pt.host,it.path=C(pt.path),it.query="",Ot=ir;break;case"#":it.host=pt.host,it.path=C(pt.path),it.query=pt.query,it.fragment="",Ot=Wn;break;default:Ct(lt(C(pn,ye),""))||(it.host=pt.host,it.path=C(pt.path),it.shortenPath()),Ot=Vn;continue}else{Ot=Vn;continue}break;case Ya:if(ot==="/"||ot==="\\"){Ot=ga;break}pt&&pt.scheme==="file"&&!Ct(lt(C(pn,ye),""))&&(Pt(pt.path[0],!0)?xt(it.path,pt.path[0]):it.host=pt.host),Ot=Vn;continue;case ga:if(ot===bt||ot==="/"||ot==="\\"||ot==="?"||ot==="#"){if(!wt&&Pt(_t))Ot=Vn;else if(_t===""){if(it.host="",wt)return;Ot=yr}else{if(Fn=it.parseHost(_t),Fn)return Fn;if(it.host==="localhost"&&(it.host=""),wt)return;_t="",Ot=yr}continue}else _t+=ot;break;case yr:if(it.isSpecial()){if(Ot=Vn,ot!=="/"&&ot!=="\\")continue}else if(!wt&&ot==="?")it.query="",Ot=ir;else if(!wt&&ot==="#")it.fragment="",Ot=Wn;else if(ot!==bt&&(Ot=Vn,ot!=="/"))continue;break;case Vn:if(ot===bt||ot==="/"||ot==="\\"&&it.isSpecial()||!wt&&(ot==="?"||ot==="#")){if(Et(_t)?(it.shortenPath(),ot!=="/"&&!(ot==="\\"&&it.isSpecial())&&xt(it.path,"")):Nt(_t)?ot!=="/"&&!(ot==="\\"&&it.isSpecial())&&xt(it.path,""):(it.scheme==="file"&&!it.path.length&&Pt(_t)&&(it.host&&(it.host=""),_t=tt(_t,0)+":"),xt(it.path,_t)),_t="",it.scheme==="file"&&(ot===bt||ot==="?"||ot==="#"))for(;it.path.length>1&&it.path[0]==="";)Ut(it.path);ot==="?"?(it.query="",Ot=ir):ot==="#"&&(it.fragment="",Ot=Wn)}else _t+=ut(ot,Ye);break;case Wa:ot==="?"?(it.query="",Ot=ir):ot==="#"?(it.fragment="",Ot=Wn):ot!==bt&&(it.path[0]+=ut(ot,Zt));break;case ir:!wt&&ot==="#"?(it.fragment="",Ot=Wn):ot!==bt&&(ot==="'"&&it.isSpecial()?it.query+="%27":ot==="#"?it.query+="%23":it.query+=ut(ot,Zt));break;case Wn:ot!==bt&&(it.fragment+=ut(ot,Yt));break}ye++}},parseHost:function(ft){var wt,pt,it;if(tt(ft,0)==="["){if(tt(ft,ft.length-1)!=="]"||(wt=Tt(Xt(ft,1,-1)),!wt))return ae;this.host=wt}else if(this.isSpecial()){if(ft=M(ft),et($e,ft)||(wt=Ft(ft),wt===null))return ae;this.host=wt}else{if(et(ce,ft))return ae;for(wt="",pt=O(ft),it=0;it1?arguments[1]:void 0,Ot=B(pt,new va(wt,!1,it));d||(pt.href=Ot.serialize(),pt.origin=Ot.getOrigin(),pt.protocol=Ot.getProtocol(),pt.username=Ot.getUsername(),pt.password=Ot.getPassword(),pt.host=Ot.getHost(),pt.hostname=Ot.getHostname(),pt.port=Ot.getPort(),pt.pathname=Ot.getPathname(),pt.search=Ot.getSearch(),pt.searchParams=Ot.getSearchParams(),pt.hash=Ot.getHash())},xn=xr.prototype,Mn=function(ft,wt){return{get:function(){return V(this)[ft]()},set:wt&&function(pt){return V(this)[wt](pt)},configurable:!0,enumerable:!0}};if(d&&(A(xn,"href",Mn("serialize","setHref")),A(xn,"origin",Mn("getOrigin")),A(xn,"protocol",Mn("getProtocol","setProtocol")),A(xn,"username",Mn("getUsername","setUsername")),A(xn,"password",Mn("getPassword","setPassword")),A(xn,"host",Mn("getHost","setHost")),A(xn,"hostname",Mn("getHostname","setHostname")),A(xn,"port",Mn("getPort","setPort")),A(xn,"pathname",Mn("getPathname","setPathname")),A(xn,"search",Mn("getSearch","setSearch")),A(xn,"searchParams",Mn("getSearchParams")),A(xn,"hash",Mn("getHash","setHash"))),$(xn,"toJSON",function(){return V(this).serialize()},{enumerable:!0}),$(xn,"toString",function(){return V(this).serialize()},{enumerable:!0}),J){var Ka=J.createObjectURL,Za=J.revokeObjectURL;Ka&&$(xr,"createObjectURL",y(Ka,J)),Za&&$(xr,"revokeObjectURL",y(Za,J))}z(xr,"URL"),u({global:!0,constructor:!0,forced:!h,sham:!d},{URL:xr})},function(x,b,r){var u=r(7),d=r(33),h=r(6),p=r(36),y=d("iterator");x.exports=!u(function(){var T=new URL("b?a=1&b=2&c=3","https://a"),$=T.searchParams,A=new URLSearchParams("a=1&a=2&b=3"),E="";return T.pathname="c%20d",$.forEach(function(R,I){$.delete("b"),E+=I+R}),A.delete("a",2),A.delete("b",void 0),p&&(!T.toJSON||!A.has("a",1)||A.has("a",2)||!A.has("a",void 0)||A.has("b"))||!$.size&&(p||!h)||!$.sort||T.href!=="https://a/c%20d?a=1&c=3"||$.get("c")!=="3"||String(new URLSearchParams("?a=1"))!=="a=1"||!$[y]||new URL("https://a@b").username!=="a"||new URLSearchParams(new URLSearchParams("a=b")).get("a")!=="b"||new URL("https://\u0442\u0435\u0441\u0442").host!=="xn--e1aybc"||new URL("https://a#\u0431").hash!=="#%D0%B1"||E!=="a1c3"||new URL("https://x",void 0).host!=="x"})},function(x,b,r){var u=r(14),d=2147483647,h=36,p=1,y=26,T=38,$=700,A=72,E=128,R="-",I=/[^\0-\u007E]/,O=/[.\u3002\uFF0E\uFF61]/g,C="Overflow: input needs wider integers to process",D=h-p,M=RangeError,F=u(O.exec),z=Math.floor,U=String.fromCharCode,j=u("".charCodeAt),G=u([].join),B=u([].push),V=u("".replace),Y=u("".split),Z=u("".toLowerCase),J=function(_){for(var tt=[],et=0,lt=_.length;et=55296&&mt<=56319&&et>1,_+=z(_/tt);_>D*y>>1;)_=z(_/D),lt+=h;return z(lt+(D+1)*_/(_+T))},rt=function(_){var tt=[];_=J(_);var et=_.length,lt=E,mt=0,gt=A,xt,yt;for(xt=0;xt<_.length;xt++)yt=_[xt],yt<128&&B(tt,U(yt));var Ut=tt.length,Dt=Ut;for(Ut&&B(tt,R);Dt=lt&&ytz((d-mt)/Qt))throw new M(C);for(mt+=(Xt-lt)*Qt,lt=Xt,xt=0;xt<_.length;xt++){if(yt=_[xt],ytd)throw new M(C);if(yt===lt){for(var kt=mt,me=h;;){var ge=me<=gt?p:me>=gt+y?y:me-gt;if(kt0&&(Rt&jt)!==0;jt>>=1)zt++;return zt},qt=function(Rt){var zt=null;switch(Rt.length){case 1:zt=Rt[0];break;case 2:zt=(Rt[0]&31)<<6|Rt[1]&63;break;case 3:zt=(Rt[0]&15)<<12|(Rt[1]&63)<<6|Rt[2]&63;break;case 4:zt=(Rt[0]&7)<<18|(Rt[1]&63)<<12|(Rt[2]&63)<<6|Rt[3]&63;break}return zt>1114111?null:zt},te=function(Rt){Rt=fe(Rt,Te," ");for(var zt=Rt.length,jt="",Wt=0;Wtzt){jt+="%",Wt++;continue}var Ee=Ft(Rt,Wt+1);if(Ee!==Ee){jt+=ue,Wt++;continue}Wt+=2;var Xe=Tt(Ee);if(Xe===0)ue=ae(Ee);else{if(Xe===1||Xe>4){jt+=de,Wt++;continue}for(var Je=[Ee],nn=1;nnzt||re(Rt,Wt)!=="%"));){var vn=Ft(Rt,Wt+1);if(vn!==vn){Wt+=3;break}if(vn>191||vn<128)break;ee(Je,vn),Wt+=2,nn++}if(Je.length!==Xe){jt+=de;continue}var jn=qt(Je);jn===null?jt+=de:ue=Mt(jn)}}jt+=ue,Wt++}return jt},Zt=/[!'()~]|%20/g,Yt={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"},Ye=function(Rt){return Yt[Rt]},Ze=function(Rt){return fe(ge(Rt),Zt,Ye)},ut=C(function(zt,jt){gt(this,{type:mt,target:xt(zt).entries,index:0,kind:jt})},lt,function(){var zt=yt(this),jt=zt.target,Wt=zt.index++;if(!jt||Wt>=jt.length)return zt.target=null,nt(void 0,!0);var ue=jt[Wt];switch(zt.kind){case"keys":return nt(ue.key,!1);case"values":return nt(ue.value,!1)}return nt([ue.key,ue.value],!1)},!0),It=function(Rt){this.entries=[],this.url=null,Rt!==void 0&&(B(Rt)?this.parseObject(Rt):this.parseQuery(typeof Rt=="string"?re(Rt,0)==="?"?ce(Rt,1):Rt:V(Rt)))};It.prototype={type:lt,bindURL:function(Rt){this.url=Rt,this.update()},parseObject:function(Rt){var zt=this.entries,jt=q(Rt),Wt,ue,Ee,Xe,Je,nn,vn;if(jt)for(Wt=J(Rt,jt),ue=Wt.next;!(Ee=y(ue,Wt)).done;){if(Xe=J(G(Ee.value)),Je=Xe.next,(nn=y(Je,Xe)).done||(vn=y(Je,Xe)).done||!y(Je,Xe).done)throw new me("Expected sequence with length 2");ee(zt,{key:V(nn.value),value:V(vn.value)})}else for(var jn in Rt)z(Rt,jn)&&ee(zt,{key:jn,value:V(Rt[jn])})},parseQuery:function(Rt){if(Rt)for(var zt=this.entries,jt=$e(Rt,"&"),Wt=0,ue,Ee;Wt0?arguments[0]:void 0,jt=gt(this,new It(zt));$||(this.size=jt.entries.length)},Ct=Pt.prototype;if(I(Ct,{append:function(zt,jt){var Wt=xt(this);rt(arguments.length,2),ee(Wt.entries,{key:V(zt),value:V(jt)}),$||this.length++,Wt.updateURL()},delete:function(Rt){for(var zt=xt(this),jt=rt(arguments.length,1),Wt=zt.entries,ue=V(Rt),Ee=jt<2?void 0:arguments[1],Xe=Ee===void 0?Ee:V(Ee),Je=0;JeWt.key?1:-1}),zt.updateURL()},forEach:function(zt){for(var jt=xt(this).entries,Wt=U(zt,arguments.length>1?arguments[1]:void 0),ue=0,Ee;ue1?ie(arguments[1]):{})}}),F(Dt)){var we=function(zt){return M(this,Qt),new Dt(zt,arguments.length>1?ie(arguments[1]):{})};Qt.constructor=we,we.prototype=Qt,u({global:!0,constructor:!0,dontCallGetSet:!0,forced:!0},{Request:we})}}x.exports={URLSearchParams:Pt,getState:xt}},function(x,b,r){var u=r(3),d=r(23),h=r(7),p=r(367),y=r(68),T=r(574),$=d("URL"),A=T&&h(function(){$.canParse()}),E=h(function(){return $.canParse.length!==1});u({target:"URL",stat:!0,forced:!A||E},{canParse:function(I){var O=p(arguments.length,1),C=y(I),D=O<2||arguments[1]===void 0?void 0:y(arguments[1]);try{return!!new $(C,D)}catch(M){return!1}}})},function(x,b,r){var u=r(3),d=r(23),h=r(367),p=r(68),y=r(574),T=d("URL");u({target:"URL",stat:!0,forced:!y},{parse:function(A){var E=h(arguments.length,1),R=p(A),I=E<2||arguments[1]===void 0?void 0:p(arguments[1]);try{return new T(R,I)}catch(O){return null}}})},function(x,b,r){var u=r(3),d=r(8);u({target:"URL",proto:!0,enumerable:!0},{toJSON:function(){return d(URL.prototype.toString,this)}})},function(x,b,r){r(576)},function(x,b,r){var u=r(47),d=r(14),h=r(68),p=r(367),y=URLSearchParams,T=y.prototype,$=d(T.append),A=d(T.delete),E=d(T.forEach),R=d([].push),I=new y("a=1&a=2&b=3");I.delete("a",1),I.delete("b",void 0),I+""!="a=2"&&u(T,"delete",function(O){var C=arguments.length,D=C<2?void 0:arguments[1];if(C&&D===void 0)return A(this,O);var M=[];E(this,function(Y,Z){R(M,{key:Z,value:Y})}),p(C,1);for(var F=h(O),z=h(D),U=0,j=0,G=!1,B=M.length,V;U=W&&(W=X+1);!(k=L[W])&&++W=0;)(s=a[i])&&(o&&s.compareDocumentPosition(o)^4&&o.parentNode.insertBefore(s,o),o=s);return this}function xt(t){t||(t=yt);function e(v,m){return v&&m?t(v.__data__,m.__data__):!v-!m}for(var n=this._groups,a=n.length,i=new Array(a),o=0;oe?1:t>=e?0:NaN}function Ut(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this}function Dt(){return Array.from(this)}function Xt(){for(var t=this._groups,e=0,n=t.length;e=0&&(e=t.slice(0,n))!=="xmlns"&&(t=t.slice(n+1)),ae.hasOwnProperty(e)?{space:ae[e],local:t}:t}function Ht(t){return function(){this.removeAttribute(t)}}function re(t){return function(){this.removeAttributeNS(t.space,t.local)}}function se(t,e){return function(){this.setAttribute(t,e)}}function ee(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function fe(t,e){return function(){var n=e.apply(this,arguments);n==null?this.removeAttribute(t):this.setAttribute(t,n)}}function Pe(t,e){return function(){var n=e.apply(this,arguments);n==null?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function Me(t,e){var n=Mt(t);if(arguments.length<2){var a=this.node();return n.local?a.getAttributeNS(n.space,n.local):a.getAttribute(n)}return this.each((e==null?n.local?re:Ht:typeof e=="function"?n.local?Pe:fe:n.local?ee:se)(n,e))}function $e(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function ce(t){return function(){this.style.removeProperty(t)}}function Ae(t,e,n){return function(){this.style.setProperty(t,e,n)}}function Te(t,e,n){return function(){var a=e.apply(this,arguments);a==null?this.style.removeProperty(t):this.style.setProperty(t,a,n)}}function de(t,e,n){return arguments.length>1?this.each((e==null?ce:typeof e=="function"?Te:Ae)(t,e,n==null?"":n)):bt(this.node(),t)}function bt(t,e){return t.style.getPropertyValue(e)||$e(t).getComputedStyle(t,null).getPropertyValue(e)}function Ft(t){return function(){delete this[t]}}function Tt(t,e){return function(){this[t]=e}}function qt(t,e){return function(){var n=e.apply(this,arguments);n==null?delete this[t]:this[t]=n}}function te(t,e){return arguments.length>1?this.each((e==null?Ft:typeof e=="function"?qt:Tt)(t,e)):this.node()[t]}function Zt(t){return t.trim().split(/^|\s+/)}function Yt(t){return t.classList||new Ye(t)}function Ye(t){this._node=t,this._names=Zt(t.getAttribute("class")||"")}Ye.prototype={add:function(t){var e=this._names.indexOf(t);e<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var e=this._names.indexOf(t);e>=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function Ze(t,e){for(var n=Yt(t),a=-1,i=e.length;++a=0&&(n=e.slice(a+1),e=e.slice(0,a)),{type:e,name:n}})}function Ka(t){return function(){var e=this.__on;if(e){for(var n=0,a=-1,i=e.length,o;n(t(o=new Date(+o)),o),i.ceil=o=>(t(o=new Date(o-1)),e(o,1),t(o),o),i.round=o=>{const s=i(o),l=i.ceil(o);return o-s(e(o=new Date(+o),s==null?1:Math.floor(s)),o),i.range=(o,s,l)=>{const c=[];if(o=i.ceil(o),l=l==null?1:Math.floor(l),!(o0))return c;let f;do c.push(f=new Date(+o)),e(o,l),t(o);while(fen(s=>{if(s>=s)for(;t(s),!o(s);)s.setTime(s-1)},(s,l)=>{if(s>=s)if(l<0)for(;++l<=0;)for(;e(s,-1),!o(s););else for(;--l>=0;)for(;e(s,1),!o(s););}),n&&(i.count=(o,s)=>(an.setTime(+o),Fn.setTime(+s),t(an),t(Fn),Math.floor(n(an,Fn))),i.every=o=>(o=Math.floor(o),!isFinite(o)||!(o>0)?null:o>1?i.filter(a?s=>a(s)%o===0:s=>i.count(0,s)%o===0):i)),i}const Gn=1e3,In=Gn*60,Bn=In*60,or=Bn*24,to=or*7,Ps=or*30,eo=or*365;function Rr(t){return en(e=>{e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)},(e,n)=>{e.setDate(e.getDate()+n*7)},(e,n)=>(n-e-(n.getTimezoneOffset()-e.getTimezoneOffset())*In)/to)}const Ja=Rr(0),Qa=Rr(1),Rf=Rr(2),If=Rr(3),Yr=Rr(4),Of=Rr(5),Cf=Rr(6),I0=Ja.range,O0=Qa.range,C0=Rf.range,P0=If.range,w0=Yr.range,M0=Of.range,D0=Cf.range;function Ir(t){return en(e=>{e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCDate(e.getUTCDate()+n*7)},(e,n)=>(n-e)/to)}const ka=Ir(0),qa=Ir(1),Pf=Ir(2),wf=Ir(3),Wr=Ir(4),Mf=Ir(5),Df=Ir(6),L0=ka.range,N0=qa.range,F0=Pf.range,B0=wf.range,U0=Wr.range,z0=Mf.range,j0=Df.range,pa=en(t=>t.setHours(0,0,0,0),(t,e)=>t.setDate(t.getDate()+e),(t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*In)/or,t=>t.getDate()-1),V0=pa.range,_a=en(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/or,t=>t.getUTCDate()-1),G0=_a.range,ws=en(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/or,t=>Math.floor(t/or)),X0=ws.range,sr=en(t=>{t.setMonth(0,1),t.setHours(0,0,0,0)},(t,e)=>{t.setFullYear(t.getFullYear()+e)},(t,e)=>e.getFullYear()-t.getFullYear(),t=>t.getFullYear());sr.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:en(e=>{e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)},(e,n)=>{e.setFullYear(e.getFullYear()+n*t)});const H0=sr.range,lr=en(t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCFullYear(t.getUTCFullYear()+e)},(t,e)=>e.getUTCFullYear()-t.getUTCFullYear(),t=>t.getUTCFullYear());lr.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:en(e=>{e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCFullYear(e.getUTCFullYear()+n*t)});const Y0=lr.range;function no(t){if(0<=t.y&&t.y<100){var e=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return e.setFullYear(t.y),e}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function ro(t){if(0<=t.y&&t.y<100){var e=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return e.setUTCFullYear(t.y),e}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function ma(t,e,n){return{y:t,m:e,d:n,H:0,M:0,S:0,L:0}}function Lf(t){var e=t.dateTime,n=t.date,a=t.time,i=t.periods,o=t.days,s=t.shortDays,l=t.months,c=t.shortMonths,f=ya(i),g=xa(i),v=ya(o),m=xa(o),S=ya(s),P=xa(s),N=ya(l),L=xa(l),w=ya(c),X=xa(c),W={a:At,A:Gt,b:Bt,B:Kt,c:null,d:Bs,e:Bs,f:rd,g:hd,G:vd,H:td,I:ed,j:nd,L:Us,m:ad,M:id,p:ne,q:le,Q:Hs,s:Ys,S:od,u:sd,U:ld,V:cd,w:ud,W:fd,x:null,X:null,y:dd,Y:gd,Z:pd,"%":Xs},H={a:be,A:Oe,b:Ce,B:He,c:null,d:js,e:js,f:Td,g:Pd,G:Md,H:md,I:yd,j:xd,L:Vs,m:$d,M:Sd,p:Fe,q:dn,Q:Hs,s:Ys,S:Ad,u:Ed,U:bd,V:Rd,w:Id,W:Od,x:null,X:null,y:Cd,Y:wd,Z:Dd,"%":Xs},k={a:dt,A:st,b:Vt,B:vt,c:Q,d:Ns,e:Ns,f:Qf,g:Ls,G:Ds,H:Fs,I:Fs,j:Wf,L:Jf,m:Yf,M:Kf,p:$t,q:Hf,Q:qf,s:_f,S:Zf,u:zf,U:jf,V:Vf,w:Uf,W:Gf,x:St,X:ct,y:Ls,Y:Ds,Z:Xf,"%":kf};W.x=K(n,W),W.X=K(a,W),W.c=K(e,W),H.x=K(n,H),H.X=K(a,H),H.c=K(e,H);function K(Jt,xe){return function(Re){var Lt=[],un=-1,Ge=0,Pn=Jt.length,wn,pe,fn;for(Re instanceof Date||(Re=new Date(+Re));++un53)return null;"w"in Lt||(Lt.w=1),"Z"in Lt?(Ge=ro(ma(Lt.y,0,1)),Pn=Ge.getUTCDay(),Ge=Pn>4||Pn===0?qa.ceil(Ge):qa(Ge),Ge=_a.offset(Ge,(Lt.V-1)*7),Lt.y=Ge.getUTCFullYear(),Lt.m=Ge.getUTCMonth(),Lt.d=Ge.getUTCDate()+(Lt.w+6)%7):(Ge=no(ma(Lt.y,0,1)),Pn=Ge.getDay(),Ge=Pn>4||Pn===0?Qa.ceil(Ge):Qa(Ge),Ge=pa.offset(Ge,(Lt.V-1)*7),Lt.y=Ge.getFullYear(),Lt.m=Ge.getMonth(),Lt.d=Ge.getDate()+(Lt.w+6)%7)}else("W"in Lt||"U"in Lt)&&("w"in Lt||(Lt.w="u"in Lt?Lt.u%7:"W"in Lt?1:0),Pn="Z"in Lt?ro(ma(Lt.y,0,1)).getUTCDay():no(ma(Lt.y,0,1)).getDay(),Lt.m=0,Lt.d="W"in Lt?(Lt.w+6)%7+Lt.W*7-(Pn+5)%7:Lt.w+Lt.U*7-(Pn+6)%7);return"Z"in Lt?(Lt.H+=Lt.Z/100|0,Lt.M+=Lt.Z%100,ro(Lt)):no(Lt)}}function ht(Jt,xe,Re,Lt){for(var un=0,Ge=xe.length,Pn=Re.length,wn,pe;un=Pn)return-1;if(wn=xe.charCodeAt(un++),wn===37){if(wn=xe.charAt(un++),pe=k[wn in Ms?xe.charAt(un++):wn],!pe||(Lt=pe(Jt,Re,Lt))<0)return-1}else if(wn!=Re.charCodeAt(Lt++))return-1}return Lt}function $t(Jt,xe,Re){var Lt=f.exec(xe.slice(Re));return Lt?(Jt.p=g.get(Lt[0].toLowerCase()),Re+Lt[0].length):-1}function dt(Jt,xe,Re){var Lt=S.exec(xe.slice(Re));return Lt?(Jt.w=P.get(Lt[0].toLowerCase()),Re+Lt[0].length):-1}function st(Jt,xe,Re){var Lt=v.exec(xe.slice(Re));return Lt?(Jt.w=m.get(Lt[0].toLowerCase()),Re+Lt[0].length):-1}function Vt(Jt,xe,Re){var Lt=w.exec(xe.slice(Re));return Lt?(Jt.m=X.get(Lt[0].toLowerCase()),Re+Lt[0].length):-1}function vt(Jt,xe,Re){var Lt=N.exec(xe.slice(Re));return Lt?(Jt.m=L.get(Lt[0].toLowerCase()),Re+Lt[0].length):-1}function Q(Jt,xe,Re){return ht(Jt,e,xe,Re)}function St(Jt,xe,Re){return ht(Jt,n,xe,Re)}function ct(Jt,xe,Re){return ht(Jt,a,xe,Re)}function At(Jt){return s[Jt.getDay()]}function Gt(Jt){return o[Jt.getDay()]}function Bt(Jt){return c[Jt.getMonth()]}function Kt(Jt){return l[Jt.getMonth()]}function ne(Jt){return i[+(Jt.getHours()>=12)]}function le(Jt){return 1+~~(Jt.getMonth()/3)}function be(Jt){return s[Jt.getUTCDay()]}function Oe(Jt){return o[Jt.getUTCDay()]}function Ce(Jt){return c[Jt.getUTCMonth()]}function He(Jt){return l[Jt.getUTCMonth()]}function Fe(Jt){return i[+(Jt.getUTCHours()>=12)]}function dn(Jt){return 1+~~(Jt.getUTCMonth()/3)}return{format:function(Jt){var xe=K(Jt+="",W);return xe.toString=function(){return Jt},xe},parse:function(Jt){var xe=at(Jt+="",!1);return xe.toString=function(){return Jt},xe},utcFormat:function(Jt){var xe=K(Jt+="",H);return xe.toString=function(){return Jt},xe},utcParse:function(Jt){var xe=at(Jt+="",!0);return xe.toString=function(){return Jt},xe}}}var Ms={"-":"",_:" ",0:"0"},mn=/^\s*\d+/,Nf=/^%/,Ff=/[\\^$*+?|[\]().{}]/g;function Ne(t,e,n){var a=t<0?"-":"",i=(a?-t:t)+"",o=i.length;return a+(o[e.toLowerCase(),n]))}function Uf(t,e,n){var a=mn.exec(e.slice(n,n+1));return a?(t.w=+a[0],n+a[0].length):-1}function zf(t,e,n){var a=mn.exec(e.slice(n,n+1));return a?(t.u=+a[0],n+a[0].length):-1}function jf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.U=+a[0],n+a[0].length):-1}function Vf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.V=+a[0],n+a[0].length):-1}function Gf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.W=+a[0],n+a[0].length):-1}function Ds(t,e,n){var a=mn.exec(e.slice(n,n+4));return a?(t.y=+a[0],n+a[0].length):-1}function Ls(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.y=+a[0]+(+a[0]>68?1900:2e3),n+a[0].length):-1}function Xf(t,e,n){var a=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return a?(t.Z=a[1]?0:-(a[2]+(a[3]||"00")),n+a[0].length):-1}function Hf(t,e,n){var a=mn.exec(e.slice(n,n+1));return a?(t.q=a[0]*3-3,n+a[0].length):-1}function Yf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.m=a[0]-1,n+a[0].length):-1}function Ns(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.d=+a[0],n+a[0].length):-1}function Wf(t,e,n){var a=mn.exec(e.slice(n,n+3));return a?(t.m=0,t.d=+a[0],n+a[0].length):-1}function Fs(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.H=+a[0],n+a[0].length):-1}function Kf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.M=+a[0],n+a[0].length):-1}function Zf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.S=+a[0],n+a[0].length):-1}function Jf(t,e,n){var a=mn.exec(e.slice(n,n+3));return a?(t.L=+a[0],n+a[0].length):-1}function Qf(t,e,n){var a=mn.exec(e.slice(n,n+6));return a?(t.L=Math.floor(a[0]/1e3),n+a[0].length):-1}function kf(t,e,n){var a=Nf.exec(e.slice(n,n+1));return a?n+a[0].length:-1}function qf(t,e,n){var a=mn.exec(e.slice(n));return a?(t.Q=+a[0],n+a[0].length):-1}function _f(t,e,n){var a=mn.exec(e.slice(n));return a?(t.s=+a[0],n+a[0].length):-1}function Bs(t,e){return Ne(t.getDate(),e,2)}function td(t,e){return Ne(t.getHours(),e,2)}function ed(t,e){return Ne(t.getHours()%12||12,e,2)}function nd(t,e){return Ne(1+pa.count(sr(t),t),e,3)}function Us(t,e){return Ne(t.getMilliseconds(),e,3)}function rd(t,e){return Us(t,e)+"000"}function ad(t,e){return Ne(t.getMonth()+1,e,2)}function id(t,e){return Ne(t.getMinutes(),e,2)}function od(t,e){return Ne(t.getSeconds(),e,2)}function sd(t){var e=t.getDay();return e===0?7:e}function ld(t,e){return Ne(Ja.count(sr(t)-1,t),e,2)}function zs(t){var e=t.getDay();return e>=4||e===0?Yr(t):Yr.ceil(t)}function cd(t,e){return t=zs(t),Ne(Yr.count(sr(t),t)+(sr(t).getDay()===4),e,2)}function ud(t){return t.getDay()}function fd(t,e){return Ne(Qa.count(sr(t)-1,t),e,2)}function dd(t,e){return Ne(t.getFullYear()%100,e,2)}function hd(t,e){return t=zs(t),Ne(t.getFullYear()%100,e,2)}function gd(t,e){return Ne(t.getFullYear()%1e4,e,4)}function vd(t,e){var n=t.getDay();return t=n>=4||n===0?Yr(t):Yr.ceil(t),Ne(t.getFullYear()%1e4,e,4)}function pd(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+Ne(e/60|0,"0",2)+Ne(e%60,"0",2)}function js(t,e){return Ne(t.getUTCDate(),e,2)}function md(t,e){return Ne(t.getUTCHours(),e,2)}function yd(t,e){return Ne(t.getUTCHours()%12||12,e,2)}function xd(t,e){return Ne(1+_a.count(lr(t),t),e,3)}function Vs(t,e){return Ne(t.getUTCMilliseconds(),e,3)}function Td(t,e){return Vs(t,e)+"000"}function $d(t,e){return Ne(t.getUTCMonth()+1,e,2)}function Sd(t,e){return Ne(t.getUTCMinutes(),e,2)}function Ad(t,e){return Ne(t.getUTCSeconds(),e,2)}function Ed(t){var e=t.getUTCDay();return e===0?7:e}function bd(t,e){return Ne(ka.count(lr(t)-1,t),e,2)}function Gs(t){var e=t.getUTCDay();return e>=4||e===0?Wr(t):Wr.ceil(t)}function Rd(t,e){return t=Gs(t),Ne(Wr.count(lr(t),t)+(lr(t).getUTCDay()===4),e,2)}function Id(t){return t.getUTCDay()}function Od(t,e){return Ne(qa.count(lr(t)-1,t),e,2)}function Cd(t,e){return Ne(t.getUTCFullYear()%100,e,2)}function Pd(t,e){return t=Gs(t),Ne(t.getUTCFullYear()%100,e,2)}function wd(t,e){return Ne(t.getUTCFullYear()%1e4,e,4)}function Md(t,e){var n=t.getUTCDay();return t=n>=4||n===0?Wr(t):Wr.ceil(t),Ne(t.getUTCFullYear()%1e4,e,4)}function Dd(){return"+0000"}function Xs(){return"%"}function Hs(t){return+t}function Ys(t){return Math.floor(+t/1e3)}var Kr,ao,Ws,io,Ks;Ld({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});function Ld(t){return Kr=Lf(t),ao=Kr.format,Ws=Kr.parse,io=Kr.utcFormat,Ks=Kr.utcParse,Kr}var Nd=Object.defineProperty,Zs=Object.getOwnPropertySymbols,Fd=Object.prototype.hasOwnProperty,Bd=Object.prototype.propertyIsEnumerable,Js=(t,e,n)=>e in t?Nd(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,ke=(t,e)=>{for(var n in e||(e={}))Fd.call(e,n)&&Js(t,n,e[n]);if(Zs)for(var n of Zs(e))Bd.call(e,n)&&Js(t,n,e[n]);return t};const Se={button:"bb-button",chart:"bb-chart",empty:"bb-empty",main:"bb-main",target:"bb-target",EXPANDED:"_expanded_"},Ve={arc:"bb-arc",arcLabelLine:"bb-arc-label-line",arcRange:"bb-arc-range",arcs:"bb-arcs",chartArc:"bb-chart-arc",chartArcs:"bb-chart-arcs",chartArcsBackground:"bb-chart-arcs-background",chartArcsTitle:"bb-chart-arcs-title",needle:"bb-needle"},ti={area:"bb-area",areas:"bb-areas"},Tn={axis:"bb-axis",axisX:"bb-axis-x",axisXLabel:"bb-axis-x-label",axisY:"bb-axis-y",axisY2:"bb-axis-y2",axisY2Label:"bb-axis-y2-label",axisYLabel:"bb-axis-y-label",axisXTooltip:"bb-axis-x-tooltip",axisYTooltip:"bb-axis-y-tooltip",axisY2Tooltip:"bb-axis-y2-tooltip"},Kn={bar:"bb-bar",bars:"bb-bars",chartBar:"bb-chart-bar",chartBars:"bb-chart-bars"},cr={candlestick:"bb-candlestick",candlesticks:"bb-candlesticks",chartCandlestick:"bb-chart-candlestick",chartCandlesticks:"bb-chart-candlesticks",valueDown:"bb-value-down",valueUp:"bb-value-up"},$n={chartCircles:"bb-chart-circles",circle:"bb-circle",circles:"bb-circles"},oo={colorPattern:"bb-color-pattern",colorScale:"bb-colorscale"},Or={dragarea:"bb-dragarea",INCLUDED:"_included_"},Ta={funnel:"bb-funnel",chartFunnel:"bb-chart-funnel",chartFunnels:"bb-chart-funnels",funnelBackground:"bb-funnel-background"},Un={chartArcsGaugeMax:"bb-chart-arcs-gauge-max",chartArcsGaugeMin:"bb-chart-arcs-gauge-min",chartArcsGaugeUnit:"bb-chart-arcs-gauge-unit",chartArcsGaugeTitle:"bb-chart-arcs-gauge-title",gaugeValue:"bb-gauge-value"},We={legend:"bb-legend",legendBackground:"bb-legend-background",legendItem:"bb-legend-item",legendItemEvent:"bb-legend-item-event",legendItemHidden:"bb-legend-item-hidden",legendItemPoint:"bb-legend-item-point",legendItemTile:"bb-legend-item-tile"},ur={chartLine:"bb-chart-line",chartLines:"bb-chart-lines",line:"bb-line",lines:"bb-lines"},Zn={eventRect:"bb-event-rect",eventRects:"bb-event-rects",eventRectsMultiple:"bb-event-rects-multiple",eventRectsSingle:"bb-event-rects-single"},qe={focused:"bb-focused",defocused:"bb-defocused",legendItemFocused:"bb-legend-item-focused",xgridFocus:"bb-xgrid-focus",ygridFocus:"bb-ygrid-focus"},on={grid:"bb-grid",gridLines:"bb-grid-lines",xgrid:"bb-xgrid",xgridLine:"bb-xgrid-line",xgridLines:"bb-xgrid-lines",xgrids:"bb-xgrids",ygrid:"bb-ygrid",ygridLine:"bb-ygrid-line",ygridLines:"bb-ygrid-lines",ygrids:"bb-ygrids"},Tr={level:"bb-level",levels:"bb-levels"},Qs={chartRadar:"bb-chart-radar",chartRadars:"bb-chart-radars"},$a={region:"bb-region",regions:"bb-regions"},tn={selectedCircle:"bb-selected-circle",selectedCircles:"bb-selected-circles",SELECTED:"_selected_"},sn={shape:"bb-shape",shapes:"bb-shapes"},ks={brush:"bb-brush",subchart:"bb-subchart"},On={chartText:"bb-chart-text",chartTexts:"bb-chart-texts",text:"bb-text",texts:"bb-texts",title:"bb-title",TextOverlapping:"text-overlapping"},ei={tooltip:"bb-tooltip",tooltipContainer:"bb-tooltip-container",tooltipName:"bb-tooltip-name"},qs={treemap:"bb-treemap",chartTreemap:"bb-chart-treemap",chartTreemaps:"bb-chart-treemaps"},so={buttonZoomReset:"bb-zoom-reset",zoomBrush:"bb-zoom-brush"};var Ue=ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke({},Se),Ve),ti),Tn),Kn),cr),$n),oo),Or),Un),We),ur),Zn),qe),Ta),on),Qs),$a),tn),sn),ks),On),ei),qs),so),Ud={boost_useCssRule:!1,boost_useWorker:!1},zd={color_pattern:[],color_tiles:void 0,color_threshold:{},color_onover:void 0},jd={legend_contents_bindto:void 0,legend_contents_template:"{=TITLE}",legend_equally:!1,legend_hide:!1,legend_inset_anchor:"top-left",legend_inset_x:10,legend_inset_y:0,legend_inset_step:void 0,legend_item_interaction:!0,legend_item_dblclick:!1,legend_item_onclick:void 0,legend_item_onover:void 0,legend_item_onout:void 0,legend_item_tile_width:10,legend_item_tile_height:10,legend_item_tile_r:5,legend_item_tile_type:"rectangle",legend_format:void 0,legend_padding:0,legend_position:"bottom",legend_show:!0,legend_tooltip:!1,legend_usePoint:!1},Vd={bindto:"#chart",background:{},clipPath:!0,svg_classname:void 0,size_width:void 0,size_height:void 0,padding:!0,padding_mode:void 0,padding_left:void 0,padding_right:void 0,padding_top:void 0,padding_bottom:void 0,resize_auto:!0,resize_timer:!0,onclick:void 0,onover:void 0,onout:void 0,onresize:void 0,onresized:void 0,onbeforeinit:void 0,oninit:void 0,onafterinit:void 0,onrendered:void 0,transition_duration:250,plugins:[],render:{},regions:[]},Gd={title_text:void 0,title_padding:{top:0,right:0,bottom:0,left:0},title_position:"center"},Xd={tooltip_show:!0,tooltip_doNotHide:!1,tooltip_grouped:!0,tooltip_format_title:void 0,tooltip_format_name:void 0,tooltip_format_value:void 0,tooltip_position:void 0,tooltip_contents:{},tooltip_init_show:!1,tooltip_init_x:0,tooltip_init_position:void 0,tooltip_linked:!1,tooltip_linked_name:"",tooltip_onshow:()=>{},tooltip_onhide:()=>{},tooltip_onshown:()=>{},tooltip_onhidden:()=>{},tooltip_order:null},Hd={data_x:void 0,data_idConverter:t=>t,data_names:{},data_classes:{},data_type:void 0,data_types:{},data_order:"desc",data_groups:[],data_groupsZeroAs:"positive",data_color:void 0,data_colors:{},data_labels:{},data_labels_backgroundColors:void 0,data_labels_colors:void 0,data_labels_position:{},data_hide:!1,data_filter:void 0,data_onclick:()=>{},data_onover:()=>{},data_onout:()=>{},data_onshown:void 0,data_onhidden:void 0,data_onmin:void 0,data_onmax:void 0,data_url:void 0,data_headers:void 0,data_json:void 0,data_rows:void 0,data_columns:void 0,data_mimeType:"csv",data_keys:void 0,data_empty_label_text:""},Yd={interaction_enabled:!0,interaction_brighten:!0,interaction_inputType_mouse:!0,interaction_inputType_touch:{},interaction_onout:!0},Wd={value:()=>{}};function _s(){for(var t=0,e=arguments.length,n={},a;t=0&&(a=n.slice(i+1),n=n.slice(0,i)),n&&!e.hasOwnProperty(n))throw new Error("unknown type: "+n);return{type:n,name:a}})}ni.prototype=_s.prototype={constructor:ni,on:function(t,e){var n=this._,a=Kd(t+"",n),i,o=-1,s=a.length;if(arguments.length<2){for(;++o0)for(var n=new Array(i),a=0,i,o;a>8&15|e>>4&240,e>>4&15|e&240,(e&15)<<4|e&15,1):n===8?ii(e>>24&255,e>>16&255,e>>8&255,(e&255)/255):n===4?ii(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|e&240,((e&15)<<4|e&15)/255):null):(e=kd.exec(t))?new Dn(e[1],e[2],e[3],1):(e=qd.exec(t))?new Dn(e[1]*255/100,e[2]*255/100,e[3]*255/100,1):(e=_d.exec(t))?ii(e[1],e[2],e[3],e[4]):(e=th.exec(t))?ii(e[1]*255/100,e[2]*255/100,e[3]*255/100,e[4]):(e=eh.exec(t))?ll(e[1],e[2]/100,e[3]/100,1):(e=nh.exec(t))?ll(e[1],e[2]/100,e[3]/100,e[4]):nl.hasOwnProperty(t)?il(nl[t]):t==="transparent"?new Dn(NaN,NaN,NaN,0):null}function il(t){return new Dn(t>>16&255,t>>8&255,t&255,1)}function ii(t,e,n,a){return a<=0&&(t=e=n=NaN),new Dn(t,e,n,a)}function ih(t){return t instanceof Aa||(t=Cr(t)),t?(t=t.rgb(),new Dn(t.r,t.g,t.b,t.opacity)):new Dn}function oi(t,e,n,a){return arguments.length===1?ih(t):new Dn(t,e,n,a==null?1:a)}function Dn(t,e,n,a){this.r=+t,this.g=+e,this.b=+n,this.opacity=+a}fo(Dn,oi,el(Aa,{brighter(t){return t=t==null?ai:Math.pow(ai,t),new Dn(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=t==null?Ea:Math.pow(Ea,t),new Dn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new Dn(Pr(this.r),Pr(this.g),Pr(this.b),si(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:ol,formatHex:ol,formatHex8:oh,formatRgb:sl,toString:sl}));function ol(){return`#${wr(this.r)}${wr(this.g)}${wr(this.b)}`}function oh(){return`#${wr(this.r)}${wr(this.g)}${wr(this.b)}${wr((isNaN(this.opacity)?1:this.opacity)*255)}`}function sl(){const t=si(this.opacity);return`${t===1?"rgb(":"rgba("}${Pr(this.r)}, ${Pr(this.g)}, ${Pr(this.b)}${t===1?")":`, ${t})`}`}function si(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function Pr(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function wr(t){return t=Pr(t),(t<16?"0":"")+t.toString(16)}function ll(t,e,n,a){return a<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new Jn(t,e,n,a)}function cl(t){if(t instanceof Jn)return new Jn(t.h,t.s,t.l,t.opacity);if(t instanceof Aa||(t=Cr(t)),!t)return new Jn;if(t instanceof Jn)return t;t=t.rgb();var e=t.r/255,n=t.g/255,a=t.b/255,i=Math.min(e,n,a),o=Math.max(e,n,a),s=NaN,l=o-i,c=(o+i)/2;return l?(e===o?s=(n-a)/l+(n0&&c<1?0:s,new Jn(s,l,c,t.opacity)}function sh(t,e,n,a){return arguments.length===1?cl(t):new Jn(t,e,n,a==null?1:a)}function Jn(t,e,n,a){this.h=+t,this.s=+e,this.l=+n,this.opacity=+a}fo(Jn,sh,el(Aa,{brighter(t){return t=t==null?ai:Math.pow(ai,t),new Jn(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=t==null?Ea:Math.pow(Ea,t),new Jn(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+(this.h<0)*360,e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,a=n+(n<.5?n:1-n)*e,i=2*n-a;return new Dn(ho(t>=240?t-240:t+120,i,a),ho(t,i,a),ho(t<120?t+240:t-120,i,a),this.opacity)},clamp(){return new Jn(ul(this.h),li(this.s),li(this.l),si(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const t=si(this.opacity);return`${t===1?"hsl(":"hsla("}${ul(this.h)}, ${li(this.s)*100}%, ${li(this.l)*100}%${t===1?")":`, ${t})`}`}}));function ul(t){return t=(t||0)%360,t<0?t+360:t}function li(t){return Math.max(0,Math.min(1,t||0))}function ho(t,e,n){return(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)*255}function fl(t,e,n,a,i){var o=t*t,s=o*t;return((1-3*t+3*o-s)*e+(4-6*o+3*s)*n+(1+3*t+3*o-3*s)*a+s*i)/6}function lh(t){var e=t.length-1;return function(n){var a=n<=0?n=0:n>=1?(n=1,e-1):Math.floor(n*e),i=t[a],o=t[a+1],s=a>0?t[a-1]:2*i-o,l=a()=>t;function dl(t,e){return function(n){return t+n*e}}function uh(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(a){return Math.pow(t+a*e,n)}}function W0(t,e){var n=e-t;return n?dl(t,n>180||n<-180?n-360*Math.round(n/360):n):ci(isNaN(t)?e:t)}function fh(t){return(t=+t)==1?hl:function(e,n){return n-e?uh(e,n,t):ci(isNaN(e)?n:e)}}function hl(t,e){var n=e-t;return n?dl(t,n):ci(isNaN(t)?e:t)}var ui=function t(e){var n=fh(e);function a(i,o){var s=n((i=oi(i)).r,(o=oi(o)).r),l=n(i.g,o.g),c=n(i.b,o.b),f=hl(i.opacity,o.opacity);return function(g){return i.r=s(g),i.g=l(g),i.b=c(g),i.opacity=f(g),i+""}}return a.gamma=t,a}(1);function gl(t){return function(e){var n=e.length,a=new Array(n),i=new Array(n),o=new Array(n),s,l;for(s=0;sn&&(o=e.slice(n,o),l[s]?l[s]+=o:l[++s]=o),(a=a[0])===(i=i[0])?l[s]?l[s]+=i:l[++s]=i:(l[++s]=null,c.push({i:s,x:Qn(a,i)})),n=vo.lastIndex;return n=0&&t._call.call(void 0,e),t=t._next;--kr}function Sl(){Mr=(di=Ca.now())+hi,kr=Ra=0;try{yh()}finally{kr=0,Th(),Mr=0}}function xh(){var t=Ca.now(),e=t-di;e>xl&&(hi-=e,di=t)}function Th(){for(var t,e=fi,n,a=1/0;e;)e._call?(a>e._time&&(a=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:fi=n);Oa=t,mo(a)}function mo(t){if(!kr){Ra&&(Ra=clearTimeout(Ra));var e=t-Mr;e>24?(t<1/0&&(Ra=setTimeout(Sl,t-Ca.now()-hi)),Ia&&(Ia=clearInterval(Ia))):(Ia||(di=Ca.now(),Ia=setInterval(xh,xl)),kr=1,Tl(Sl))}}function Al(t,e,n){var a=new gi;return e=e==null?0:+e,a.restart(i=>{a.stop(),t(i+e)},e,n),a}var $h=ri("start","end","cancel","interrupt"),Sh=[],El=0,bl=1,yo=2,vi=3,Rl=4,xo=5,pi=6;function mi(t,e,n,a,i,o){var s=t.__transition;if(!s)t.__transition={};else if(n in s)return;Ah(t,n,{name:e,index:a,group:i,on:$h,tween:Sh,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:El})}function To(t,e){var n=kn(t,e);if(n.state>El)throw new Error("too late; already scheduled");return n}function er(t,e){var n=kn(t,e);if(n.state>vi)throw new Error("too late; already running");return n}function kn(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function Ah(t,e,n){var a=t.__transition,i;a[e]=n,n.timer=$l(o,0,n.time);function o(f){n.state=bl,n.timer.restart(s,n.delay,n.time),n.delay<=f&&s(f-n.delay)}function s(f){var g,v,m,S;if(n.state!==bl)return c();for(g in a)if(S=a[g],S.name===n.name){if(S.state===vi)return Al(s);S.state===Rl?(S.state=pi,S.timer.stop(),S.on.call("interrupt",t,t.__data__,S.index,S.group),delete a[g]):+gyo&&a.state180?g+=360:g-f>180&&(f+=360),m.push({i:v.push(i(v)+"rotate(",null,a)-2,x:Qn(f,g)})):g&&v.push(i(v)+"rotate("+g+a)}function l(f,g,v,m){f!==g?m.push({i:v.push(i(v)+"skewX(",null,a)-2,x:Qn(f,g)}):g&&v.push(i(v)+"skewX("+g+a)}function c(f,g,v,m,S,P){if(f!==v||g!==m){var N=S.push(i(S)+"scale(",null,",",null,")");P.push({i:N-4,x:Qn(f,v)},{i:N-2,x:Qn(g,m)})}else(v!==1||m!==1)&&S.push(i(S)+"scale("+v+","+m+")")}return function(f,g){var v=[],m=[];return f=t(f),g=t(g),o(f.translateX,f.translateY,g.translateX,g.translateY,v,m),s(f.rotate,g.rotate,v,m),l(f.skewX,g.skewX,v,m),c(f.scaleX,f.scaleY,g.scaleX,g.scaleY,v,m),f=g=null,function(S){for(var P=-1,N=m.length,L;++P=0&&(e=e.slice(0,n)),!e||e==="start"})}function rg(t,e,n){var a,i,o=ng(e)?To:er;return function(){var s=o(this,t),l=s.on;l!==a&&(i=(a=l).copy()).on(e,n),s.on=i}}function ag(t,e){var n=this._id;return arguments.length<2?kn(this.node(),n).on.on(t):this.each(rg(n,t,e))}function ig(t){return function(){var e=this.parentNode;for(var n in this.__transition)if(+n!==t)return;e&&e.removeChild(this)}}function og(){return this.on("end.remove",ig(this._id))}function sg(t){var e=this._name,n=this._id;typeof t!="function"&&(t=p(t));for(var a=this._groups,i=a.length,o=new Array(i),s=0;s()=>t;function Mg(t,{sourceEvent:e,target:n,selection:a,mode:i,dispatch:o}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:e,enumerable:!0,configurable:!0},target:{value:n,enumerable:!0,configurable:!0},selection:{value:a,enumerable:!0,configurable:!0},mode:{value:i,enumerable:!0,configurable:!0},_:{value:o}})}function Dg(t){t.stopImmediatePropagation()}function Eo(t){t.preventDefault(),t.stopImmediatePropagation()}var Ll={name:"drag"},bo={name:"space"},_r={name:"handle"},ta={name:"center"};const{abs:Nl,max:Sn,min:An}=Math;function Fl(t){return[+t[0],+t[1]]}function Ro(t){return[Fl(t[0]),Fl(t[1])]}var xi={name:"x",handles:["w","e"].map(Pa),input:function(t,e){return t==null?null:[[+t[0],e[0][1]],[+t[1],e[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Ti={name:"y",handles:["n","s"].map(Pa),input:function(t,e){return t==null?null:[[e[0][0],+t[0]],[e[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Lg={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(Pa),input:function(t){return t==null?null:Ro(t)},output:function(t){return t}},hr={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Bl={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},Ul={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},Ng={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},Fg={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function Pa(t){return{type:t}}function Bg(t){return!t.ctrlKey&&!t.button}function Ug(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?(t=t.viewBox.baseVal,[[t.x,t.y],[t.x+t.width,t.y+t.height]]):[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function zg(){return navigator.maxTouchPoints||"ontouchstart"in this}function Io(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function jg(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function zl(t){var e=t.__brush;return e?e.dim.output(e.selection):null}function Vg(){return Oo(xi)}function Gg(){return Oo(Ti)}function q0(){return Oo(Lg)}function Oo(t){var e=Ug,n=Bg,a=zg,i=!0,o=ri("start","brush","end"),s=6,l;function c(L){var w=L.property("__brush",N).selectAll(".overlay").data([Pa("overlay")]);w.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",hr.overlay).merge(w).each(function(){var W=Io(this).extent;ot(this).attr("x",W[0][0]).attr("y",W[0][1]).attr("width",W[1][0]-W[0][0]).attr("height",W[1][1]-W[0][1])}),L.selectAll(".selection").data([Pa("selection")]).enter().append("rect").attr("class","selection").attr("cursor",hr.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var X=L.selectAll(".handle").data(t.handles,function(W){return W.type});X.exit().remove(),X.enter().append("rect").attr("class",function(W){return"handle handle--"+W.type}).attr("cursor",function(W){return hr[W.type]}),L.each(f).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",m).filter(a).on("touchstart.brush",m).on("touchmove.brush",S).on("touchend.brush touchcancel.brush",P).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}c.move=function(L,w,X){L.tween?L.on("start.brush",function(W){g(this,arguments).beforestart().start(W)}).on("interrupt.brush end.brush",function(W){g(this,arguments).end(W)}).tween("brush",function(){var W=this,H=W.__brush,k=g(W,arguments),K=H.selection,at=t.input(typeof w=="function"?w.apply(this,arguments):w,H.extent),ht=Qr(K,at);function $t(dt){H.selection=dt===1&&at===null?null:ht(dt),f.call(W),k.brush()}return K!==null&&at!==null?$t:$t(1)}):L.each(function(){var W=this,H=arguments,k=W.__brush,K=t.input(typeof w=="function"?w.apply(W,H):w,k.extent),at=g(W,H).beforestart();qr(W),k.selection=K===null?null:K,f.call(W),at.start(X).brush(X).end(X)})},c.clear=function(L,w){c.move(L,null,w)};function f(){var L=ot(this),w=Io(this).selection;w?(L.selectAll(".selection").style("display",null).attr("x",w[0][0]).attr("y",w[0][1]).attr("width",w[1][0]-w[0][0]).attr("height",w[1][1]-w[0][1]),L.selectAll(".handle").style("display",null).attr("x",function(X){return X.type[X.type.length-1]==="e"?w[1][0]-s/2:w[0][0]-s/2}).attr("y",function(X){return X.type[0]==="s"?w[1][1]-s/2:w[0][1]-s/2}).attr("width",function(X){return X.type==="n"||X.type==="s"?w[1][0]-w[0][0]+s:s}).attr("height",function(X){return X.type==="e"||X.type==="w"?w[1][1]-w[0][1]+s:s})):L.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function g(L,w,X){var W=L.__brush.emitter;return W&&(!X||!W.clean)?W:new v(L,w,X)}function v(L,w,X){this.that=L,this.args=w,this.state=L.__brush,this.active=0,this.clean=X}v.prototype={beforestart:function(){return++this.active===1&&(this.state.emitter=this,this.starting=!0),this},start:function(L,w){return this.starting?(this.starting=!1,this.emit("start",L,w)):this.emit("brush",L),this},brush:function(L,w){return this.emit("brush",L,w),this},end:function(L,w){return--this.active===0&&(delete this.state.emitter,this.emit("end",L,w)),this},emit:function(L,w,X){var W=ot(this.that).datum();o.call(L,this.that,new Mg(L,{sourceEvent:w,target:c,selection:t.output(this.state.selection),mode:X,dispatch:o}),W)}};function m(L){if(l&&!L.touches||!n.apply(this,arguments))return;var w=this,X=L.target.__data__.type,W=(i&&L.metaKey?X="overlay":X)==="selection"?Ll:i&&L.altKey?ta:_r,H=t===Ti?null:Ng[X],k=t===xi?null:Fg[X],K=Io(w),at=K.extent,ht=K.selection,$t=at[0][0],dt,st,Vt=at[0][1],vt,Q,St=at[1][0],ct,At,Gt=at[1][1],Bt,Kt,ne=0,le=0,be,Oe=H&&k&&i&&L.shiftKey,Ce,He,Fe=Array.from(L.touches||[L],pe=>{const fn=pe.identifier;return pe=Xn(pe,w),pe.point0=pe.slice(),pe.identifier=fn,pe});qr(w);var dn=g(w,arguments,!0).beforestart();if(X==="overlay"){ht&&(be=!0);const pe=[Fe[0],Fe[1]||Fe[0]];K.selection=ht=[[dt=t===Ti?$t:An(pe[0][0],pe[1][0]),vt=t===xi?Vt:An(pe[0][1],pe[1][1])],[ct=t===Ti?St:Sn(pe[0][0],pe[1][0]),Bt=t===xi?Gt:Sn(pe[0][1],pe[1][1])]],Fe.length>1&&un(L)}else dt=ht[0][0],vt=ht[0][1],ct=ht[1][0],Bt=ht[1][1];st=dt,Q=vt,At=ct,Kt=Bt;var Jt=ot(w).attr("pointer-events","none"),xe=Jt.selectAll(".overlay").attr("cursor",hr[X]);if(L.touches)dn.moved=Lt,dn.ended=Ge;else{var Re=ot(L.view).on("mousemove.brush",Lt,!0).on("mouseup.brush",Ge,!0);i&&Re.on("keydown.brush",Pn,!0).on("keyup.brush",wn,!0),co(L.view)}f.call(w),dn.start(L,W.name);function Lt(pe){for(const fn of pe.changedTouches||[pe])for(const Ga of Fe)Ga.identifier===fn.identifier&&(Ga.cur=Xn(fn,w));if(Oe&&!Ce&&!He&&Fe.length===1){const fn=Fe[0];Nl(fn.cur[0]-fn[0])>Nl(fn.cur[1]-fn[1])?He=!0:Ce=!0}for(const fn of Fe)fn.cur&&(fn[0]=fn.cur[0],fn[1]=fn.cur[1]);be=!0,Eo(pe),un(pe)}function un(pe){const fn=Fe[0],Ga=fn.point0;var br;switch(ne=fn[0]-Ga[0],le=fn[1]-Ga[1],W){case bo:case Ll:{H&&(ne=Sn($t-dt,An(St-ct,ne)),st=dt+ne,At=ct+ne),k&&(le=Sn(Vt-vt,An(Gt-Bt,le)),Q=vt+le,Kt=Bt+le);break}case _r:{Fe[1]?(H&&(st=Sn($t,An(St,Fe[0][0])),At=Sn($t,An(St,Fe[1][0])),H=1),k&&(Q=Sn(Vt,An(Gt,Fe[0][1])),Kt=Sn(Vt,An(Gt,Fe[1][1])),k=1)):(H<0?(ne=Sn($t-dt,An(St-dt,ne)),st=dt+ne,At=ct):H>0&&(ne=Sn($t-ct,An(St-ct,ne)),st=dt,At=ct+ne),k<0?(le=Sn(Vt-vt,An(Gt-vt,le)),Q=vt+le,Kt=Bt):k>0&&(le=Sn(Vt-Bt,An(Gt-Bt,le)),Q=vt,Kt=Bt+le));break}case ta:{H&&(st=Sn($t,An(St,dt-ne*H)),At=Sn($t,An(St,ct+ne*H))),k&&(Q=Sn(Vt,An(Gt,vt-le*k)),Kt=Sn(Vt,An(Gt,Bt+le*k)));break}}At0&&(dt=st-ne),k<0?Bt=Kt-le:k>0&&(vt=Q-le),W=bo,xe.attr("cursor",hr.selection),un(pe));break}default:return}Eo(pe)}function wn(pe){switch(pe.keyCode){case 16:{Oe&&(Ce=He=Oe=!1,un(pe));break}case 18:{W===ta&&(H<0?ct=At:H>0&&(dt=st),k<0?Bt=Kt:k>0&&(vt=Q),W=_r,un(pe));break}case 32:{W===bo&&(pe.altKey?(H&&(ct=At-ne*H,dt=st+ne*H),k&&(Bt=Kt-le*k,vt=Q+le*k),W=ta):(H<0?ct=At:H>0&&(dt=st),k<0?Bt=Kt:k>0&&(vt=Q),W=_r),xe.attr("cursor",hr[X]),un(pe));break}default:return}Eo(pe)}}function S(L){g(this,arguments).moved(L)}function P(L){g(this,arguments).ended(L)}function N(){var L=this.__brush||{selection:null};return L.extent=Ro(e.apply(this,arguments)),L.dim=t,L}return c.extent=function(L){return arguments.length?(e=typeof L=="function"?L:Ao(Ro(L)),c):e},c.filter=function(L){return arguments.length?(n=typeof L=="function"?L:Ao(!!L),c):n},c.touchable=function(L){return arguments.length?(a=typeof L=="function"?L:Ao(!!L),c):a},c.handleSize=function(L){return arguments.length?(s=+L,c):s},c.keyModifiers=function(L){return arguments.length?(i=!!L,c):i},c.on=function(){var L=o.on.apply(o,arguments);return L===o?c:L},c}function Xg(){return typeof globalThis=="object"&&globalThis!==null&&globalThis.Object===Object&&globalThis||typeof global=="object"&&global!==null&&global.Object===Object&&global||typeof self=="object"&&self!==null&&self.Object===Object&&self||Function("return this")()}function Hg(t){const e=typeof(t==null?void 0:t.requestAnimationFrame)=="function"&&typeof(t==null?void 0:t.cancelAnimationFrame)=="function",n=typeof(t==null?void 0:t.requestIdleCallback)=="function"&&typeof(t==null?void 0:t.cancelIdleCallback)=="function",a=o=>setTimeout(o,1),i=o=>clearTimeout(o);return[e?t.requestAnimationFrame:a,e?t.cancelAnimationFrame:i,n?t.requestIdleCallback:a,n?t.cancelIdleCallback:i]}const Ke=Xg(),gn=Ke==null?void 0:Ke.document,[Yg,_0,jl,t1]=Hg(Ke);var Wg=Object.defineProperty,Vl=Object.getOwnPropertySymbols,Kg=Object.prototype.hasOwnProperty,Zg=Object.prototype.propertyIsEnumerable,Gl=(t,e,n)=>e in t?Wg(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,Xl=(t,e)=>{for(var n in e||(e={}))Kg.call(e,n)&&Gl(t,n,e[n]);if(Vl)for(var n of Vl(e))Zg.call(e,n)&&Gl(t,n,e[n]);return t};const De=t=>t||t===0,ve=t=>typeof t=="function",ze=t=>typeof t=="string",he=t=>typeof t=="number",ln=t=>typeof t=="undefined",Qe=t=>typeof t!="undefined",Co=t=>typeof t=="boolean",Jg=t=>Math.ceil(t/10)*10,$i=t=>Math.ceil(t)+.5,Dr=t=>t[1]-t[0],nr=t=>typeof t=="object",qn=t=>ln(t)||t===null||ze(t)&&t.length===0||nr(t)&&!(t instanceof Date)&&Object.keys(t).length===0||he(t)&&isNaN(t),cn=t=>!qn(t),je=t=>Array.isArray(t),Be=t=>t&&!(t!=null&&t.nodeType)&&nr(t)&&!je(t);function $r(t,e,n){return Qe(t[e])?t[e]:n}function Qg(t,e){let n=!1;return Object.keys(t).forEach(a=>t[a]===e&&(n=!0)),n}function _e(t,e,...n){const a=ve(t);return a&&t.call(e,...n),a}function Si(t,e){let n=0;const a=function(...i){!--n&&e.apply(this,...i)};"duration"in t?t.each(()=>++n).on("end",a):(++n,t.call(a))}function Po(t){return ze(t)?t.replace(/<(script|img)?/ig,"<").replace(/(script)?>/ig,">"):t}function wa(t,e,n=[-1,1],a=!1){if(!(!t||!ze(e)))if(e.indexOf(` `)===-1)t.text(e);else{const i=[t.text(),e].map(o=>o.replace(/[\s\n]/g,""));if(i[0]!==i[1]){const o=e.split(` `),s=a?o.length-1:1;t.html(""),o.forEach((l,c)=>{t.append("tspan").attr("x",0).attr("dy",`${c===0?n[0]*s:n[1]}em`).text(l)})}}}function Hl(t){const{x:e,y:n,width:a,height:i}=t.getBBox();return[{x:e,y:n+i},{x:e,y:n},{x:e+a,y:n},{x:e+a,y:n+i}]}function Yl(t){const{width:e,height:n}=t.getBoundingClientRect(),a=Hl(t),i=a[0].x,o=Math.min(a[0].y,a[1].y);return{x:i,y:o,width:e,height:n}}function Hn(t,e){var n;const a=t&&((n=t.touches||t.sourceEvent&&t.sourceEvent.touches)==null?void 0:n[0]);let i=[0,0];try{i=Xn(a||t,e)}catch(o){}return i.map(o=>isNaN(o)?0:o)}function Wl(t){const{event:e,$el:n}=t,a=n.subchart.main||n.main;let i;return e&&e.type==="brush"?i=e.selection:a&&(i=a.select(".bb-brush").node())&&(i=zl(i)),i}function Ma(t){return!("rect"in t)||"rect"in t&&t.hasAttribute("width")&&t.rect.width!==+t.getAttribute("width")?t.rect=t.getBoundingClientRect():t.rect}function gr(t=!0,e=0,n=1e4){const a=Ke.crypto||Ke.msCrypto,i=a?e+a.getRandomValues(new Uint32Array(1))[0]%(n-e+1):Math.floor(Math.random()*(n-e)+e);return t?String(i):i}function wo(t,e,n,a,i){if(n>a)return-1;const o=Math.floor((n+a)/2);let{x:s,w:l=0}=t[o];return i&&(s=t[o].y,l=t[o].h),e>=s&&e<=s+l?o:e{if(Be(n)&&n.constructor){const a=new n.constructor;for(const i in n)a[i]=e(n[i]);return a}return n};return t.map(n=>e(n)).reduce((n,a)=>Xl(Xl({},n),a))}function yn(t={},e){je(e)&&e.forEach(n=>yn(t,n));for(const n in e)/^\d+$/.test(n)||n in t||(t[n]=e[n]);return t}const Cn=t=>t.charAt(0).toUpperCase()+t.slice(1);function qg(t,e="-"){return t.split(e).map((n,a)=>a?n.charAt(0).toUpperCase()+n.slice(1).toLowerCase():n.toLowerCase()).join("")}const Lr=t=>[].slice.call(t);function _g(t,e,n){const{rootSelector:a="",sheet:i}=t,s=`${a} ${(l=>l.replace(/\s?(bb-)/g,".$1").replace(/\.+/g,"."))(e)} {${n.join(";")}}`;return i[i.insertRule?"insertRule":"addRule"](s,i.cssRules.length)}function tv(t){let e=[];return t.forEach(n=>{var a;try{n.cssRules&&n.cssRules.length&&(e=e.concat(Lr(n.cssRules)))}catch(i){(a=Ke.console)==null||a.warn(`Error while reading rules from ${n.href}: ${i.toString()}`)}}),e}function Zl(t){var e,n,a,i,o,s;return{x:((n=(e=Ke.pageXOffset)!=null?e:Ke.scrollX)!=null?n:0)+((a=t.scrollLeft)!=null?a:0),y:((o=(i=Ke.pageYOffset)!=null?i:Ke.scrollY)!=null?o:0)+((s=t.scrollTop)!=null?s:0)}}function Ai(t,e=0,n=0,a=!0){const i=new DOMPoint(e,n),o=t.getScreenCTM(),s=i.matrixTransform(a?o==null?void 0:o.inverse():o);if(a===!1){const l=t.getBoundingClientRect();s.x-=l.x,s.y-=l.y}return s}function Jl(t){const e=t?t.transform:null,n=e&&e.baseVal;return n&&n.numberOfItems?n.getItem(0).matrix:{a:0,b:0,c:0,d:0,e:0,f:0}}function Mo(t){const e=t[0]instanceof Date,n=(e?t.map(Number):t).filter((a,i,o)=>o.indexOf(a)===i);return e?n.map(a=>new Date(a)):n}function Do(t){return t&&t.length?t.reduce((e,n)=>e.concat(n)):[]}function ea(t,...e){if(!e.length||e.length===1&&!e[0])return t;const n=e.shift();return Be(t)&&Be(n)&&Object.keys(n).forEach(a=>{if(!/^(__proto__|constructor|prototype)$/i.test(a)){const i=n[a];Be(i)?(!t[a]&&(t[a]={}),t[a]=ea(t[a],i)):t[a]=je(i)?i.concat():i}}),ea(t,...e)}function na(t,e=!0){let n;return t[0]instanceof Date?n=e?(a,i)=>a-i:(a,i)=>i-a:e&&!t.every(isNaN)?n=(a,i)=>a-i:e||(n=(a,i)=>a>i&&-1||acn(a));return n.length?he(n[0])?n=Math[t](...n):n[0]instanceof Date&&(n=na(n,t==="min")[0]):n=void 0,n}const Ei=(t,e,n=1)=>{const a=[],i=Math.max(0,Math.ceil((e-t)/n))|0;for(let o=t;o{const t=()=>({bubbles:!1,cancelable:!1,screenX:0,screenY:0,clientX:0,clientY:0});try{return new MouseEvent("t"),(e,n,a=t())=>{e.dispatchEvent(new MouseEvent(n,a))}}catch(e){return(n,a,i=t())=>{const o=gn.createEvent("MouseEvent");o.initMouseEvent(a,i.bubbles,i.cancelable,Ke,0,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),n.dispatchEvent(o)}}})(),touch:(t,e,n)=>{const a=new Touch(ea({identifier:Date.now(),target:t,radiusX:2.5,radiusY:2.5,rotationAngle:10,force:.5},n));t.dispatchEvent(new TouchEvent(e,{cancelable:!0,bubbles:!0,shiftKey:!0,touches:[a],targetTouches:[],changedTouches:[a]}))}};function bi(t,e){let n=t;for(const a in e)n=n.replace(new RegExp(`{=${a}}`,"g"),e[a]);return n}function Yn(t){var e;let n;if(t instanceof Date)n=t;else if(ze(t)){const{config:a,format:i}=this;n=(e=i.dataTime(a.data_xFormat)(t))!=null?e:new Date(t)}else he(t)&&!isNaN(t)&&(n=new Date(+t));return(!n||isNaN(+n))&&console&&console.error&&console.error(`Failed to parse x '${t}' to Date object`),n}function Lo(t){const e=t.attr("viewBox");return e?/(\d+(\.\d+)?){3}/.test(e):!1}function nv(t,e,n=!1){const a=!!t.node;let i=!1;for(const[o,s]of Object.entries(e))if(i=a?t.style(o)===s:t.style[o]===s,n===!1&&i)break;return i}function Da(){var t,e;return((t=gn)==null?void 0:t.hidden)===!1||((e=gn)==null?void 0:e.visibilityState)==="visible"}function rv(t,e){const{DocumentTouch:n,matchMedia:a,navigator:i}=Ke,o=a==null?void 0:a("(pointer:coarse)").matches;let s=!1;if(e)if(i&&"maxTouchPoints"in i)s=i.maxTouchPoints>0;else if("ontouchmove"in Ke||n&&gn instanceof n)s=!0;else if(o)s=!0;else{const c=i.userAgent;s=/\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(c)||/\b(Android|Windows Phone|iPad|iPod)\b/i.test(c)}return t&&!o&&(a==null?void 0:a("(pointer:fine)").matches)&&"mouse"||s&&"touch"||"mouse"}function Ql(t,e){e()===!1?Yg(()=>Ql(t,e)):t()}var av=Object.defineProperty,kl=Object.getOwnPropertySymbols,iv=Object.prototype.hasOwnProperty,ov=Object.prototype.propertyIsEnumerable,No=(t,e,n)=>e in t?av(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,ql=(t,e)=>{for(var n in e||(e={}))iv.call(e,n)&&No(t,n,e[n]);if(kl)for(var n of kl(e))ov.call(e,n)&&No(t,n,e[n]);return t},sv=(t,e,n)=>No(t,typeof e!="symbol"?e+"":e,n);const _l=class bf{static setOptions(e){this.data=e.reduce((n,a)=>ql(ql({},n),a),this.data)}constructor(){return kg(Vd,Ud,Hd,zd,Yd,jd,Gd,Xd,bf.data)}};sv(_l,"data",{});let Nr=_l;class lv{constructor(){return{chart:null,main:null,svg:null,axis:{x:null,y:null,y2:null,subX:null},axisTooltip:{x:null,y:null,y2:null},defs:null,tooltip:null,legend:null,title:null,subchart:{main:null,bar:null,line:null,area:null},arcs:null,bar:null,candlestick:null,line:null,area:null,circle:null,radar:null,text:null,grid:{main:null,x:null,y:null},gridLines:{main:null,x:null,y:null},region:{main:null,list:null},eventRect:null,zoomResetBtn:null}}}class cv{constructor(){return{width:0,width2:0,height:0,height2:0,margin:{top:0,bottom:0,left:0,right:0},margin2:{top:0,bottom:0,left:0,right:0},margin3:{top:0,bottom:0,left:0,right:0},arcWidth:0,arcHeight:0,xAxisHeight:0,hasAxis:!1,hasFunnel:!1,hasRadar:!1,hasTreemap:!1,cssRule:{},current:{domain:void 0,width:0,height:0,dataMax:0,maxTickSize:{x:{width:0,height:0,ticks:[],clipPath:0,domain:""},y:{width:0,height:0,domain:""},y2:{width:0,height:0,domain:""}},types:[],needle:void 0},isLegendRight:!1,isLegendInset:!1,isLegendTop:!1,isLegendLeft:!1,legendStep:0,legendItemWidth:0,legendItemHeight:0,legendHasRendered:!1,eventReceiver:{currentIdx:-1,rect:{},data:[],coords:[]},axis:{x:{padding:{left:0,right:0},tickCount:0}},rotatedPadding:{left:30,right:0,top:5},withoutFadeIn:{},inputType:"",datetimeId:"",clip:{id:"",idXAxis:"",idYAxis:"",idXAxisTickTexts:"",idGrid:"",idSubchart:"",path:"",pathXAxis:"",pathYAxis:"",pathXAxisTickTexts:"",pathGrid:""},event:null,dragStart:null,dragging:!1,flowing:!1,cancelClick:!1,mouseover:!1,rendered:!1,transiting:!1,redrawing:!1,resizing:!1,toggling:!1,zooming:!1,hasNegativeValue:!1,hasPositiveValue:!0,orgAreaOpacity:"0.2",orgConfig:{},hiddenTargetIds:[],hiddenLegendIds:[],focusedTargetIds:[],defocusedTargetIds:[],radius:0,innerRadius:0,outerRadius:void 0,innerRadiusRatio:0,gaugeArcWidth:0,radiusExpanded:0,xgridAttr:{x1:null,x2:null,y1:null,y2:null}}}}const tc={element:lv,state:cv};class uv{constructor(){Object.keys(tc).forEach(e=>{this[e]=new tc[e]})}getStore(e){return this[e]}}var fv=Object.defineProperty,dv=(t,e,n)=>e in t?fv(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,hv=(t,e,n)=>dv(t,typeof e!="symbol"?e+"":e,n);const Ln={bubbleBaseLength:"$baseLength",colorPattern:"__colorPattern__",dataMinMax:"$dataMinMax",dataTotalSum:"$dataTotalSum",dataTotalPerIndex:"$totalPerIndex",legendItemTextBox:"legendItemTextBox",radarPoints:"$radarPoints",radarTextWidth:"$radarTextWidth",setOverOut:"setOverOut",callOverOutForTouch:"callOverOutForTouch",textRect:"textRect"};class gv{constructor(){hv(this,"cache",{})}add(e,n,a=!1){return this.cache[e]=a?this.cloneTarget(n):n,this.cache[e]}remove(e){(ze(e)?[e]:e).forEach(n=>delete this.cache[n])}get(e,n=!1){if(n&&Array.isArray(e)){const a=[];for(let i=0,o;o=e[i];i++)o in this.cache&&a.push(this.cloneTarget(this.cache[o]));return a}else{const a=this.cache[e];return De(a)?a:null}}reset(e){const n=this;for(const a in n.cache)(e||/^\$/.test(a))&&(n.cache[a]=null)}cloneTarget(e){return{id:e.id,id_org:e.id_org,values:e.values.map(n=>({x:n.x,value:n.value,id:n.id}))}}}const oe={AREA:"area",AREA_LINE_RANGE:"area-line-range",AREA_SPLINE:"area-spline",AREA_SPLINE_RANGE:"area-spline-range",AREA_STEP:"area-step",AREA_STEP_RANGE:"area-step-range",BAR:"bar",BUBBLE:"bubble",CANDLESTICK:"candlestick",DONUT:"donut",FUNNEL:"funnel",GAUGE:"gauge",LINE:"line",PIE:"pie",POLAR:"polar",RADAR:"radar",SCATTER:"scatter",SPLINE:"spline",STEP:"step",TREEMAP:"treemap"},Fo={AREA:"initArea",AREA_LINE_RANGE:"initArea",AREA_SPLINE:"initArea",AREA_SPLINE_RANGE:"initArea",AREA_STEP:"initArea",AREA_STEP_RANGE:"initArea",BAR:"initBar",BUBBLE:"initCircle",CANDLESTICK:"initCandlestick",DONUT:"initArc",FUNNEL:"initFunnel",GAUGE:"initArc",LINE:"initLine",PIE:"initArc",POLAR:"initPolar",RADAR:"initCircle",SCATTER:"initCircle",SPLINE:"initLine",STEP:"initLine",TREEMAP:"initTreemap"},Sr={Area:[oe.AREA,oe.AREA_SPLINE,oe.AREA_SPLINE_RANGE,oe.AREA_LINE_RANGE,oe.AREA_STEP,oe.AREA_STEP_RANGE],AreaRange:[oe.AREA_SPLINE_RANGE,oe.AREA_LINE_RANGE,oe.AREA_STEP_RANGE],Arc:[oe.PIE,oe.DONUT,oe.GAUGE,oe.POLAR,oe.RADAR],Line:[oe.LINE,oe.SPLINE,oe.AREA,oe.AREA_SPLINE,oe.AREA_SPLINE_RANGE,oe.AREA_LINE_RANGE,oe.STEP,oe.AREA_STEP,oe.AREA_STEP_RANGE],Step:[oe.STEP,oe.AREA_STEP,oe.AREA_STEP_RANGE],Spline:[oe.SPLINE,oe.AREA_SPLINE,oe.AREA_SPLINE_RANGE]};function vv(t){const e=t,{config:n}=e;let a="";if(qn(n.data_type||n.data_types)&&!e[Fo.LINE])a="line";else for(const i in Fo){const o=oe[i];if(e.hasType(o)&&!e[Fo[i]]){a=o;break}}a&&pv(`Please, make sure if %c${qg(a)}`,"module has been imported and specified correctly.","https://github.com/naver/billboard.js/wiki/CHANGELOG-v2#modularization-by-its-functionality")}function pv(t,e,n){var a;const i="[billboard.js]";if((a=Ke.console)==null?void 0:a.error){const s=e?["background:red;color:white;display:block;font-size:15px",e]:[];console.error(`\u274C ${i} ${t}`,"background:red;color:white;display:block;font-size:15px",...s),n&&console.info("%c\u2139\uFE0F","font-size:15px",n)}throw Error(`${i} ${t.replace(/\%c([a-z-]+)/i,"'$1' ")} ${e!=null?e:""}`)}const{setTimeout:mv,clearTimeout:yv}=Ke;function xv(t){const e=[];let n;const a=function(){a.clear(),t===!1?jl(()=>{e.forEach(i=>i())},{timeout:200}):n=mv(()=>{e.forEach(i=>i())},he(t)?t:200)};return a.clear=()=>{n&&(yv(n),n=null)},a.add=i=>e.push(i),a.remove=i=>e.splice(e.indexOf(i),1),a}function ec(){let t=[];const e=function(n,a){function i(){var o;let s=0;for(let l=0,c;c=t[l];l++){if(c===!0||(o=c.empty)!=null&&o.call(c)){s++;continue}if(Da()===!1){s=t.length;break}try{c.transition()}catch(f){s++}}return s===t.length}Ql(()=>{a==null||a()},i)};return e.add=function(n){je(n)?t=t.concat(n):t.push(n)},e}const Bo={};function Tv(t,e){var n;const a=t.toString(),i=a.replace(/(function|[\s\W\n])/g,"").substring(0,15);return i in Bo||(Bo[i]=new Ke.Blob([`${(n=e==null?void 0:e.map(String).join(";"))!=null?n:""} self.onmessage=function({data}) { const result = (${a}).apply(null, data); self.postMessage(result); };`],{type:"text/javascript"})),Ke.URL.createObjectURL(Bo[i])}function $v(t){const e=new Ke.Worker(t);return e.onerror=function(n){console.error?console.error(n):console.log(n)},e}function Uo(t=!0,e,n,a){let i=function(...o){const s=e(...o);n(s)};if(Ke.Worker&&t){const o=Tv(e,a),s=$v(o);i=function(...l){s.postMessage(l),s.onmessage=function(c){return Ke.URL.revokeObjectURL(o),n(c.data)}}}return i}var nc={},zo={},jo=34,La=10,Vo=13;function rc(t){return new Function("d","return {"+t.map(function(e,n){return JSON.stringify(e)+": d["+n+'] || ""'}).join(",")+"}")}function Sv(t,e){var n=rc(t);return function(a,i){return e(n(a),i,t)}}function ac(t){var e=Object.create(null),n=[];return t.forEach(function(a){for(var i in a)i in e||n.push(e[i]=i)}),n}function Nn(t,e){var n=t+"",a=n.length;return a9999?"+"+Nn(t,6):Nn(t,4)}function Ev(t){var e=t.getUTCHours(),n=t.getUTCMinutes(),a=t.getUTCSeconds(),i=t.getUTCMilliseconds();return isNaN(t)?"Invalid Date":Av(t.getUTCFullYear(),4)+"-"+Nn(t.getUTCMonth()+1,2)+"-"+Nn(t.getUTCDate(),2)+(i?"T"+Nn(e,2)+":"+Nn(n,2)+":"+Nn(a,2)+"."+Nn(i,3)+"Z":a?"T"+Nn(e,2)+":"+Nn(n,2)+":"+Nn(a,2)+"Z":n||e?"T"+Nn(e,2)+":"+Nn(n,2)+"Z":"")}function ic(t){var e=new RegExp('["'+t+` \r]`),n=t.charCodeAt(0);function a(v,m){var S,P,N=i(v,function(L,w){if(S)return S(L,w-1);P=L,S=m?Sv(L,m):rc(L)});return N.columns=P||[],N}function i(v,m){var S=[],P=v.length,N=0,L=0,w,X=P<=0,W=!1;v.charCodeAt(P-1)===La&&--P,v.charCodeAt(P-1)===Vo&&--P;function H(){if(X)return zo;if(W)return W=!1,nc;var K,at=N,ht;if(v.charCodeAt(at)===jo){for(;N++=P?X=!0:(ht=v.charCodeAt(N++))===La?W=!0:ht===Vo&&(W=!0,v.charCodeAt(N)===La&&++N),v.slice(at+1,K-1).replace(/""/g,'"')}for(;N0){if(typeof e[s-1]=="undefined"&&(e[s-1]={}),typeof o=="undefined")throw new Error(`Source data is missing a component at (${a}, ${s})!`);e[s-1][i]=o}})}),e}function Xo(t){const e=t[0],n=[];return t.forEach(function(a,i){if(i>0){const o={};a.forEach(function(s,l){if(typeof s=="undefined")throw new Error(`Source data is missing a component at (${i}, ${l})!`);o[e[l]]=s}),n.push(o)}}),n}function oc(t,e){const n=[];let a,i;if(Array.isArray(t)){const o=function(s,l){if(s[l]!==void 0)return s[l];const f=l.replace(/\[(\w+)\]/g,".$1").replace(/^\./,"").split(".");let g=s;return f.some(function(v){return!(g=g&&v in g?g[v]:void 0)}),g};e.x?a=e.value.concat(e.x):a=e.value,n.push(a),t.forEach(function(s){const l=a.map(function(c){let f=o(s,c);return typeof f=="undefined"&&(f=null),f});n.push(l)}),i=Xo(n)}else Object.keys(t).forEach(function(o){var s;const l=t[o].concat();(s=l.unshift)==null||s.call(l,o),n.push(l)}),i=Go(n);return i}function Cv(t,e="csv",n,a,i){const o=new XMLHttpRequest,s={csv:Pv,tsv:wv,json:oc};o.open("GET",t),n&&Object.keys(n).forEach(function(l){o.setRequestHeader(l,n[l])}),o.onreadystatechange=function(){if(o.readyState===4)if(o.status===200){const l=o.responseText;l&&i.call(this,s[e](e==="json"?JSON.parse(l):l,a))}else throw new Error(`${t}: Something went wrong loading!`)},o.send()}function sc(t,e){const n=t.rows(e);let a;return n.length===1?(a=[{}],n[0].forEach(i=>{a[0][i]=null})):a=t.parse(e),a}function Pv(t){return sc({rows:Rv,parse:bv},t)}function wv(t){return sc({rows:Ov,parse:Iv},t)}function lc(t,e){const n=t||(e==null?void 0:e.data_keys);return n!=null&&n.x&&(e.data_x=n.x),n}var Mv={convertData(t,e){const{config:n}=this,a=n.boost_useWorker;let i=t;if(t.bindto&&(i={},["url","mimeType","headers","keys","json","keys","rows","columns"].forEach(o=>{const s=`data_${o}`;s in t&&(i[o]=t[s])})),i.url&&e)Cv(i.url,i.mimeType,i.headers,lc(i.keys,n),e);else if(i.json)Uo(a,oc,e,[Go,Xo])(i.json,lc(i.keys,n));else if(i.rows)Uo(a,Xo,e)(i.rows);else if(i.columns)Uo(a,Go,e)(i.columns);else if(t.bindto)throw Error("url or json or rows or columns is required.")},convertDataToTargets(t,e){const n=this,{axis:a,config:i,state:o}=n,s=i.data_type;let l=!1,c=!1,f=!1;a&&(l=a.isCategorized(),c=a.isTimeSeries(),f=a.isCustomX());const g=Object.keys(t[0]||{}),v=g.length?g.filter(n.isNotX,n):[],m=g.length?g.filter(n.isX,n):[];let S;v.forEach(N=>{const L=this.getXKey(N);f||c?m.indexOf(L)>=0?S=(e&&n.data.xs[N]||[]).concat(t.map(w=>w[L]).filter(De).map((w,X)=>n.generateTargetX(w,N,X))):i.data_x?S=this.getOtherTargetXs():cn(i.data_xs)&&(S=n.getXValuesOfXKey(L,n.data.targets)):S=t.map((w,X)=>X),S&&(this.data.xs[N]=S)}),v.forEach(N=>{if(!this.data.xs[N])throw new Error(`x is not defined for id = "${N}".`)});const P=v.map((N,L)=>{const w=i.data_idConverter.bind(n.api)(N),X=n.getXKey(N),W=f&&l,H=W&&t.map(at=>at.x).every(at=>i.axis_x_categories.indexOf(at)>-1),k=t.__append__,K=X===null&&k?n.api.data.values(N).length:0;return{id:w,id_org:N,values:t.map((at,ht)=>{const $t=at[X];let dt=at[N],st;return dt=dt!==null&&!isNaN(dt)&&!Be(dt)?+dt:je(dt)||Be(dt)?dt:null,(W||o.hasRadar)&&L===0&&!ln($t)?(!H&&L===0&&ht===0&&!k&&(i.axis_x_categories=[]),st=i.axis_x_categories.indexOf($t),st===-1&&(st=i.axis_x_categories.length,i.axis_x_categories.push($t))):st=n.generateTargetX($t,N,K+ht),(ln(dt)||n.data.xs[N].length<=ht)&&(st=void 0),{x:st,value:dt,id:w,index:-1}}).filter(at=>Qe(at.x))}});if(P.forEach(N=>{var L;i.data_xSort&&(N.values=N.values.sort((w,X)=>{const W=w.x||w.x===0?w.x:1/0,H=X.x||X.x===0?X.x:1/0;return W-H})),N.values.forEach((w,X)=>w.index=X),(L=n.data.xs[N.id])==null||L.sort((w,X)=>w-X)}),o.hasNegativeValue=n.hasNegativeValueInTargets(P),o.hasPositiveValue=n.hasPositiveValueInTargets(P),s&&n.isValidChartType(s)){const N=n.mapToIds(P).filter(L=>!(L in i.data_types)||!n.isValidChartType(i.data_types[L]));n.setTargetType(N,s)}return P.forEach(N=>n.cache.add(N.id_org,N,!0)),P}},Dv={isX(t){const e=this,{config:n}=e,a=n.data_x&&t===n.data_x,i=cn(n.data_xs)&&Qg(n.data_xs,t);return a||i},isNotX(t){return!this.isX(t)},isStackNormalized(){const{config:t}=this;return!!(t.data_stack_normalize&&t.data_groups.length)},isGrouped(t){const e=this.config.data_groups;return t?e.some(n=>n.indexOf(t)>=0&&n.length>1):e.length>0},getXKey(t){const e=this,{config:n}=e;return n.data_x?n.data_x:cn(n.data_xs)?n.data_xs[t]:null},getXValuesOfXKey(t,e){const n=this,a=e&&cn(e)?n.mapToIds(e):[];let i;return a.forEach(o=>{n.getXKey(o)===t&&(i=n.data.xs[o])}),i},getIndexByX(t,e){const n=this;return e?e.indexOf(ze(t)?t:+t):(n.filterByX(n.data.targets,t)[0]||{index:null}).index},getXValue(t,e){const n=this;return t in n.data.xs&&n.data.xs[t]&&De(n.data.xs[t][e])?n.data.xs[t][e]:e},getOtherTargetXs(){const t=this,e=Object.keys(t.data.xs);return e.length?t.data.xs[e[0]]:null},getOtherTargetX(t){const e=this.getOtherTargetXs();return e&&t{n.data_xs[a]=t[a]})},isMultipleX(){return!this.config.axis_x_forceAsSingle&&(cn(this.config.data_xs)||this.hasType("bubble")||this.hasType("scatter"))},addName(t){const e=this,{config:n}=e;let a;return t&&(a=n.data_names[t.id],t.name=a!==void 0?a:t.id),t},getAllValuesOnIndex(t,e=!1){const n=this;let a=n.filterTargetsToShow(n.data.targets).map(i=>n.addName(n.getValueOnIndex(i.values,t)));return e&&(a=a.filter(i=>i&&"value"in i&&De(i.value))),a},getValueOnIndex(t,e){const n=t.filter(a=>a.index===e);return n.length?n[0]:null},updateTargetX(t,e){const n=this;t.forEach(a=>{a.values.forEach((i,o)=>{i.x=n.generateTargetX(e[o],a.id,o)}),n.data.xs[a.id]=e})},updateTargetXs(t,e){const n=this;t.forEach(a=>{e[a.id]&&n.updateTargetX([a],e[a.id])})},generateTargetX(t,e,n){const a=this,{axis:i}=a;let o=i!=null&&i.isCategorized()?n:t||n;if(i!=null&&i.isTimeSeries()){const s=Yn.bind(a);o=s(t||a.getXValue(e,n))}else i!=null&&i.isCustomX()&&!(i!=null&&i.isCategorized())&&(o=De(t)?+t:a.getXValue(e,n));return o},updateXs(t){t.length&&(this.axis.xs=t.map(e=>e.x))},getPrevX(t){const e=this.axis.xs[t-1];return Qe(e)?e:null},getNextX(t){const e=this.axis.xs[t+1];return Qe(e)?e:null},getBaseValue(t){const e=this,{hasAxis:n}=e.state;let{value:a}=t;return a&&n&&(e.isAreaRangeType(t)?a=e.getRangedData(t,"mid"):e.isBubbleZType(t)&&(a=e.getBubbleZData(a,"y"))),a},getMinMaxValue(t){const e=this.getBaseValue.bind(this);let n,a;return(t||this.data.targets.map(i=>i.values)).forEach((i,o)=>{const s=i.map(e).filter(he);n=Math.min(o?n:1/0,...s),a=Math.max(o?a:-1/0,...s)}),{min:n,max:a}},getMinMaxData(){const t=this,e=Ln.dataMinMax;let n=t.cache.get(e);if(!n){const a=t.data.targets.map(l=>l.values),i=t.getMinMaxValue(a);let o=[],s=[];a.forEach(l=>{const c=t.getFilteredDataByValue(l,i.min),f=t.getFilteredDataByValue(l,i.max);c.length&&(o=o.concat(c)),f.length&&(s=s.concat(f))}),t.cache.add(e,n={min:o,max:s})}return n},getTotalPerIndex(){const t=this,e=Ln.dataTotalPerIndex;let n=t.cache.get(e);return(t.config.data_groups.length||t.isStackNormalized())&&!n&&(n=[],t.data.targets.forEach(a=>{a.values.forEach((i,o)=>{n[o]||(n[o]=0),n[o]+=he(i.value)?i.value:0})})),n},getTotalDataSum(t){const e=this,n=Ln.dataTotalSum;let a=e.cache.get(n);if(!he(a)){const i=Do(e.data.targets.map(o=>o.values)).map(o=>o.value);a=i.length?i.reduce((o,s)=>o+s):0,e.cache.add(n,a)}return t&&(a-=e.getHiddenTotalDataSum()),a},getHiddenTotalDataSum(){const t=this,{api:e,state:{hiddenTargetIds:n}}=t;let a=0;return n.length&&(a=e.data.values.bind(e)(n).reduce((i,o)=>i+o)),a},getFilteredDataByValue(t,e){return t.filter(n=>this.getBaseValue(n)===e)},getMaxDataCount(){return Math.max(...this.data.targets.map(t=>t.values.length),0)},getMaxDataCountTarget(){let t=this.filterTargetsToShow()||[];const e=t.length,n=this.config.axis_x_inverted;return e>1?(t=t.map(a=>a.values).reduce((a,i)=>a.concat(i)).map(a=>a.x),t=na(Mo(t)).map((a,i,o)=>({x:a,index:n?o.length-i-1:i}))):e&&(t=t[0].values.concat()),t},mapToIds(t){return t.map(e=>e.id)},mapToTargetIds(t){const e=this;return t?je(t)?t.concat():[t]:e.mapToIds(e.data.targets)},hasTarget(t,e){const n=this.mapToIds(t);for(let a=0,i;i=n[a];a++)if(i===e)return!0;return!1},isTargetToShow(t){return this.state.hiddenTargetIds.indexOf(t)<0},isLegendToShow(t){return this.state.hiddenLegendIds.indexOf(t)<0},filterTargetsToShow(t){const e=this;return(t||e.data.targets).filter(n=>e.isTargetToShow(n.id))},mapTargetsToUniqueXs(t){const e=this,{axis:n}=e;let a=[];return t!=null&&t.length&&(a=Mo(Do(t.map(i=>i.values.map(o=>+o.x)))),a=n!=null&&n.isTimeSeries()?a.map(i=>new Date(+i)):a.map(Number)),na(a)},addTargetIds(t,e){const{state:n}=this;(je(e)?e:[e]).forEach(i=>{n[t].indexOf(i)<0&&n[t].push(i)})},removeTargetIds(t,e){const{state:n}=this;(je(e)?e:[e]).forEach(i=>{const o=n[t].indexOf(i);o>=0&&n[t].splice(o,1)})},addHiddenTargetIds(t){this.addTargetIds("hiddenTargetIds",t)},removeHiddenTargetIds(t){this.removeTargetIds("hiddenTargetIds",t)},addHiddenLegendIds(t){this.addTargetIds("hiddenLegendIds",t)},removeHiddenLegendIds(t){this.removeTargetIds("hiddenLegendIds",t)},getValuesAsIdKeyed(t){const e=this,{hasAxis:n}=e.state,a={},i=e.isMultipleX(),o=i?e.mapTargetsToUniqueXs(t).map(s=>ze(s)?s:+s):null;return t.forEach(s=>{const l=[];s.values.filter(({value:c})=>De(c)||c===null).forEach(c=>{let{value:f}=c;f!==null&&e.isCandlestickType(c)&&(f=je(f)?f.slice(0,4):[f.open,f.high,f.low,f.close]),je(f)?l.push(...f):Be(f)&&"high"in f?l.push(...Object.values(f)):e.isBubbleZType(c)?l.push(n&&e.getBubbleZData(f,"y")):i?l[e.getIndexByX(c.x,o)]=f:l.push(f)}),a[s.id]=l}),a},checkValueInTargets(t,e){const n=Object.keys(t);let a;for(let i=0;i1},hasNegativeValueInTargets(t){return this.checkValueInTargets(t,e=>e<0)},hasPositiveValueInTargets(t){return this.checkValueInTargets(t,e=>e>0)},orderTargets(t){const e=this,n=[...t],a=e.getSortCompareFn();return a&&n.sort(a),n},getSortCompareFn(t=!1){const e=this,{config:n}=e,a=n.data_order,i=/asc/i.test(a),o=/desc/i.test(a);let s;if(i||o){const l=(f,g)=>f+Math.abs(g.value),c=f=>he(f)?f:"values"in f?f.values.reduce(l,0):f.value;s=(f,g)=>{const v=c(f),m=c(g);return t?i?v-m:m-v:i?m-v:v-m}}else ve(a)&&(s=a.bind(e.api));return s||null},filterByX(t,e){return Do(t.map(n=>n.values)).filter(n=>n.x-e===0)},filterRemoveNull(t){return t.filter(e=>De(this.getBaseValue(e)))},filterByXDomain(t,e){return t.map(n=>({id:n.id,id_org:n.id_org,values:n.values.filter(a=>e[0]<=a.x&&a.x<=e[1])}))},hasDataLabel(){const t=this.config.data_labels;return Co(t)&&t||nr(t)&&cn(t)},hasNullDataValue(t){return t.some(({value:e})=>e===null)},getDataIndexFromEvent(t){const e=this,{$el:n,config:a,state:{hasRadar:i,inputType:o,eventReceiver:{coords:s,rect:l}}}=e;let c;if(i){let f=t.target;/tspan/i.test(f.tagName)&&(f=f.parentNode);const g=ot(f).datum();c=g&&Object.keys(g).length===1?g.index:void 0}else{const f=a.axis_rotated,g=Zl(n.chart.node()),v=o==="touch"&&t.changedTouches?t.changedTouches[0]:t;let m=f?v.clientY+g.y:v.clientX+g.x;if(Lo(n.svg)){const S=[m,0];f&&S.reverse(),m=Ai(n.eventRect.node(),...S)[f?"y":"x"]}else m-=f?l.top:l.left;c=wo(s,m,0,s.length-1,f)}return c},getDataLabelLength(t,e,n){const a=this,i=[0,0],o=1.3;return a.$el.chart.select("svg").selectAll(".dummy").data([t,e]).enter().append("text").text(s=>a.dataLabelFormat(s.id)(s)).each(function(s,l){i[l]=this.getBoundingClientRect()[n]*o}).remove(),i},isNoneArc(t){return this.hasTarget(this.data.targets,t.id)},isArc(t){return"data"in t&&this.hasTarget(this.data.targets,t.data.id)},findSameXOfValues(t,e){const n=t[e].x,a=[];let i;for(i=e-1;i>=0&&n===t[i].x;i--)a.push(t[i]);for(i=e;in.findClosest(i.values,e));return n.findClosest(a,e)},findClosest(t,e){const n=this,{$el:{main:a}}=n,i=t.filter(l=>l&&De(l.value));let o,s;return i.filter(l=>n.isBarType(l.id)||n.isCandlestickType(l.id)).forEach(l=>{const c=n.isBarType(l.id)?`.${Kn.chartBar}.${Se.target}${n.getTargetSelectorSuffix(l.id)} .${Kn.bar}-${l.index}`:`.${cr.chartCandlestick}.${Se.target}${n.getTargetSelectorSuffix(l.id)} .${cr.candlestick}-${l.index} path`;!s&&n.isWithinBar(a.select(c).node())&&(s=l)}),i.filter(l=>!n.isBarType(l.id)&&!n.isCandlestickType(l.id)).forEach(l=>{const c=n.dist(l,e);o=n.getPointSensitivity(l),c{const{x:i,id:o}=a;n.push({x:i,id:o,value:a.value[0]}),n.push({x:i,id:o,value:a.value[2]})}),n},updateDataAttributes(t,e){const n=this,{config:a}=n,i=a[`data_${t}`];return ln(e)||(Object.keys(e).forEach(o=>{i[o]=e[o]}),n.redraw({withLegend:!0})),i},getRangedData(t,e="",n="areaRange"){const a=t==null?void 0:t.value;if(je(a)){if(n==="bar")return a.reduce((i,o)=>o-i);{const i={areaRange:["high","mid","low"],candlestick:["open","high","low","close","volume"]}[n].indexOf(e);return i>=0&&a?a[i]:void 0}}else if(a&&e)return a[e];return a},setRatioForGroupedData(t){const e=this,{config:n}=e;if(n.data_groups.length&&t.some(a=>e.isGrouped(a.id))){const a=i=>e.getRatio("index",i,!0);t.forEach(i=>{"values"in i?i.values.forEach(a):a(i)})}},getRatio(t,e,n=!1){const a=this,{config:i,state:o}=a,s=a.api;let l=0;if(e&&s.data.shown().length)if(l=e.ratio||e.value,t==="arc")if(a.pie.padAngle()())l=e.value/a.getTotalDataSum(!0);else{const c=i.gauge_fullCircle?a.getArcLength():a.getStartingAngle()*-2,f=a.hasType("gauge")?c:Math.PI*2;l=(e.endAngle-e.startAngle)/f}else if(t==="index"){const c=s.data.values.bind(s);let f=this.getTotalPerIndex();if(o.hiddenTargetIds.length){let v=c(o.hiddenTargetIds,!1);v.length&&(v=v.reduce((m,S)=>m.map((P,N)=>(he(P)?P:0)+S[N])),f=f.map((m,S)=>m-v[S]))}const g=f[e.index];e.ratio=he(e.value)&&f&&g?e.value/g:0,l=e.ratio}else if(t==="radar")l=parseFloat(String(Math.max(e.value,0)))/o.current.dataMax*i.radar_size_ratio;else if(t==="bar"){const f=a.getYScaleById.bind(a)(e.id).domain().reduce((g,v)=>v-g);l=f===0?0:Math.abs(a.getRangedData(e,null,t)/f)}else t==="treemap"&&(l/=a.getTotalDataSum(!0));return n&&l?l*100:l},updateDataIndexByX(t){const e=this,n=t.reduce((a,i,o)=>(a[Number(i.x)]=o,a),{});e.data.targets.forEach(a=>{a.values.forEach((i,o)=>{let s=n[Number(i.x)];s===void 0&&(s=o),i.index=s})})},isBubbleZType(t){return this.isBubbleType(t)&&(Be(t.value)&&("z"in t.value||"y"in t.value)||je(t.value)&&t.value.length>=2)},isBarRangeType(t){const e=this,{value:n}=t;return e.isBarType(t)&&je(n)&&n.length>=2&&n.every(a=>he(a))},getDataById(t){var e;const n=this.cache.get(t)||this.api.data(t);return(e=n==null?void 0:n[0])!=null?e:n}};function cc(t,e=!1){const n=this,{api:a}=n;e&&n.api.flush(!0),t==null||t.call(a)}var Lv={load(t,e){const n=this,{axis:a,data:i,org:o,scale:s}=n,{append:l}=e,c={domain:null,currentDomain:null,x:null};let f=t;f&&(e.filter&&(f=f.filter(e.filter)),(e.type||e.types)&&f.forEach(g=>{var v;const m=((v=e.types)==null?void 0:v[g.id])||e.type;n.setTargetType(g.id,m)}),i.targets.forEach(g=>{for(let v=0;v{const a=t.data||n;t.append&&(a.__append__=!0),a&&e.load(e.convertDataToTargets(a),t)}))},unload(t,e){var n;const a=this,{state:i,$el:o,$T:s}=a,l=!!((n=a.hasLegendDefsPoint)!=null&&n.call(a));let c=e,f=t;if(a.cache.reset(),c||(c=()=>{}),f=f.filter(v=>a.hasTarget(a.data.targets,v)),!f||f.length===0){c();return}const g=o.svg.selectAll(f.map(v=>a.selectorTarget(v)));s(g).style("opacity","0").remove().call(Si,c),f.forEach(v=>{var m;const S=a.getTargetSelectorSuffix(v);i.withoutFadeIn[v]=!1,o.legend&&o.legend.selectAll(`.${We.legendItem}${S}`).remove(),a.data.targets=a.data.targets.filter(P=>P.id!==v),l&&((m=o.defs)==null||m.select(`#${a.getDefsPointId(S)}`).remove())}),i.hasFunnel&&a.updateFunnel(a.data.targets),i.hasTreemap&&a.updateTargetsForTreemap(a.data.targets),a.updateTypesElements()}},Ri=t=>()=>t;function Ho(t,{sourceEvent:e,subject:n,target:a,identifier:i,active:o,x:s,y:l,dx:c,dy:f,dispatch:g}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:e,enumerable:!0,configurable:!0},subject:{value:n,enumerable:!0,configurable:!0},target:{value:a,enumerable:!0,configurable:!0},identifier:{value:i,enumerable:!0,configurable:!0},active:{value:o,enumerable:!0,configurable:!0},x:{value:s,enumerable:!0,configurable:!0},y:{value:l,enumerable:!0,configurable:!0},dx:{value:c,enumerable:!0,configurable:!0},dy:{value:f,enumerable:!0,configurable:!0},_:{value:g}})}Ho.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};function Nv(t){return!t.ctrlKey&&!t.button}function Fv(){return this.parentNode}function Bv(t,e){return e==null?{x:t.x,y:t.y}:e}function Uv(){return navigator.maxTouchPoints||"ontouchstart"in this}function uc(){var t=Nv,e=Fv,n=Bv,a=Uv,i={},o=ri("start","drag","end"),s=0,l,c,f,g,v=0;function m(H){H.on("mousedown.drag",S).filter(a).on("touchstart.drag",L).on("touchmove.drag",w,Jd).on("touchend.drag touchcancel.drag",X).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function S(H,k){if(!(g||!t.call(this,H,k))){var K=W(this,e.call(this,H,k),H,k,"mouse");K&&(ot(H.view).on("mousemove.drag",P,Sa).on("mouseup.drag",N,Sa),co(H.view),lo(H),f=!1,l=H.clientX,c=H.clientY,K("start",H))}}function P(H){if(Zr(H),!f){var k=H.clientX-l,K=H.clientY-c;f=k*k+K*K>v}i.mouse("drag",H)}function N(H){ot(H.view).on("mousemove.drag mouseup.drag",null),uo(H.view,f),Zr(H),i.mouse("end",H)}function L(H,k){if(t.call(this,H,k)){var K=H.changedTouches,at=e.call(this,H,k),ht=K.length,$t,dt;for($t=0;$ti.$el[o]).forEach(o=>{a&&i.$el[o].classed(Se.EXPANDED,!1),i.getShapeByIndex(o,e,n).classed(Se.EXPANDED,t)})},setOverOut(t,e){const n=this,{config:a,state:{hasFunnel:i,hasRadar:o,hasTreemap:s},$el:{main:l}}=n,c=Be(e);if(c||e!==-1){const f=a[t?"data_onover":"data_onout"].bind(n.api);if(a.color_onover&&n.setOverColor(t,e,c),c){const g=n.getTargetSelectorSuffix(e.id),v=i||s?`${Se.target+g} .${sn.shape}`:Ve.arc+g;f(e,l.select(`.${v}`).node())}else if(a.tooltip_grouped)t&&(o&&n.isPointFocusOnly()?n.showCircleFocus(n.getAllValuesOnIndex(e,!0)):n.setExpand(e,null,!0)),!n.isMultipleX()&&l.selectAll(`.${sn.shape}-${e}`).each(function(g){f(g,this)});else{const g=n.cache.get(Ln.setOverOut)||[],v=l.selectAll(`.${sn.shape}-${e}`).filter(function(S){return n.isWithinShape(this,S)}),m=v.filter(function(){return g.every(S=>S!==this)});if(!t||v.empty()||g.length===m.size()&&m.nodes().every((S,P)=>S!==g[P]))for(;g.length;){const S=g.pop();a.data_onout.bind(n.api)(ot(S).datum(),S)}m.each(function(){t&&(f(ot(this).datum(),this),g.push(this))}),n.cache.add(Ln.setOverOut,g)}}},callOverOutForTouch(t){const e=this,n=e.cache.get(Ln.callOverOutForTouch);(Be(t)&&n?t.id!==n.id:t!==n)&&((n||he(n))&&e.setOverOut(!1,n),(t||he(t))&&e.setOverOut(!0,t),e.cache.add(Ln.callOverOutForTouch,t))},getDraggableSelection(){const t=this,{config:e,state:n}=t;return e.interaction_enabled&&e.data_selection_draggable&&t.drag?uc().on("drag",function(a){n.event=a,t.drag(Hn(a,this))}).on("start",function(a){n.event=a,t.dragstart(Hn(a,this))}).on("end",a=>{n.event=a,t.dragend()}):()=>{}},dispatchEvent(t,e,n){var a,i,o;const s=this,{config:l,state:{eventReceiver:c,hasAxis:f,hasFunnel:g,hasRadar:v,hasTreemap:m},$el:{eventRect:S,funnel:P,radar:N,svg:L,treemap:w}}=s;let X=(o=(i=(g||m)&&c.rect||v&&N.axes.select(`.${Tn.axis}-${e} text`)||S||((a=s.getArcElementByIdOrIndex)==null?void 0:a.call(s,e)))==null?void 0:i.node)==null?void 0:o.call(i);if(X){const W=s.isMultipleX(),H=l.axis_rotated;let{width:k,left:K,top:at}=X.getBoundingClientRect();if(f&&!v&&!W){const st=c.coords[e];st?(k=st.w,K+=st.x,at+=st.y):(k=0,K=0,at=0)}let ht=K+(n?n[0]:0)+(W||H?0:k/2),$t=at+(n?n[1]:0)+(H?4:0);if(Lo(L)){const st=Ai(s.$el.eventRect.node(),ht,$t,!1);ht=st.x,$t=st.y}const dt={screenX:ht,screenY:$t,clientX:ht,clientY:$t,bubbles:v};(g||m)&&(X=(P!=null?P:w).node()),ev[/^(mouse|click)/.test(t)?"mouse":"touch"](X,t,dt)}},setDragStatus(t){this.state.dragging=t},unbindZoomEvent(){const t=this,{$el:{eventRect:e,zoomResetBtn:n}}=t;e==null||e.on(".zoom wheel.zoom .drag",null),n==null||n.on("click",null).style("display","none")},unbindAllEvents(){var t;const e=this,{$el:{arcs:n,eventRect:a,legend:i,region:o,svg:s,treemap:l},brush:c}=e,f=["wheel","click","mouseover","mousemove","mouseout","touchstart","touchmove","touchend","touchstart.eventRect","touchmove.eventRect","touchend.eventRect",".brush",".drag",".zoom","wheel.zoom","dblclick.zoom"].join(" ");[s,a,o==null?void 0:o.list,c==null?void 0:c.getSelection(),n==null?void 0:n.selectAll("path"),i==null?void 0:i.selectAll("g"),l].forEach(g=>g==null?void 0:g.on(f,null)),(t=e.unbindZoomEvent)==null||t.call(e)}},jv={categoryName(t){var e;const{axis_x_categories:n}=this.config;return(e=n==null?void 0:n[t])!=null?e:t}},Vv={generateClass(t,e){return` ${t} ${t+this.getTargetSelectorSuffix(e)}`},getClass(t,e){const n=/s$/.test(t),a=/^(area|arc|line|funnel|treemap)s?$/.test(t),i=n?"id":"index";return o=>{const s=o.data||o;return((e?this.generateClass(Ue[n?"shapes":"shape"],s[i]):"")+this.generateClass(Ue[t],s[a?"id":i])).trim()}},getChartClass(t){return e=>Ue[`chart${t}`]+this.classTarget((e.data?e.data:e).id)},generateExtraLineClass(){const e=this.config.line_classes||[],n=[];return function(a){var i;const o=a.id||((i=a.data)==null?void 0:i.id)||a;return n.indexOf(o)<0&&n.push(o),e[n.indexOf(o)%e.length]}},classRegion(t,e){return`${this.generateClass(Ue.region,e)} ${"class"in t?t.class:""}`},classTarget(t){const e=this.config.data_classes[t];let n="";return e&&(n=` ${Ue.target}-${e}`),this.generateClass(Ue.target,t)+n},classFocus(t){return this.classFocused(t)+this.classDefocused(t)},classFocused(t){return` ${this.state.focusedTargetIds.indexOf(t.id)>=0?Ue.focused:""}`},classDefocused(t){return` ${this.state.defocusedTargetIds.indexOf(t.id)>=0?Ue.defocused:""}`},getTargetSelectorSuffix(t){return(t||t===0?`-${t}`:"").replace(/[\x00-\x20\x7F-\xA0\s?!@#$%^&*()_=+,.<>'":;\[\]\/|~`{}\\]/g,"-")},selectorTarget(t,e="",n=""){const a=this.getTargetSelectorSuffix(t);return`${e}.${Ue.target+a} ${n}, ${e}.${Ue.circles+a} ${n}`},selectorTargets(t,e){const n=t||[];return n.length?n.map(a=>this.selectorTarget(a,e)):null},selectorLegend(t){return`.${Ue.legendItem+this.getTargetSelectorSuffix(t)}`},selectorLegends(t){return t!=null&&t.length?t.map(e=>this.selectorLegend(e)):null}};class fc extends Map{constructor(e,n=gc){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),e!=null)for(const[a,i]of e)this.set(a,i)}get(e){return super.get(Yo(this,e))}has(e){return super.has(Yo(this,e))}set(e,n){return super.set(dc(this,e),n)}delete(e){return super.delete(hc(this,e))}}class f1 extends Set{constructor(e,n=gc){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),e!=null)for(const a of e)this.add(a)}has(e){return super.has(Yo(this,e))}add(e){return super.add(dc(this,e))}delete(e){return super.delete(hc(this,e))}}function Yo({_intern:t,_key:e},n){const a=e(n);return t.has(a)?t.get(a):n}function dc({_intern:t,_key:e},n){const a=e(n);return t.has(a)?t.get(a):(t.set(a,n),n)}function hc({_intern:t,_key:e},n){const a=e(n);return t.has(a)&&(n=t.get(a),t.delete(a)),n}function gc(t){return t!==null&&typeof t=="object"?t.valueOf():t}function ra(t,e){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(e).domain(t);break}return this}function d1(t,e){switch(arguments.length){case 0:break;case 1:{typeof t=="function"?this.interpolator(t):this.range(t);break}default:{this.domain(t),typeof e=="function"?this.interpolator(e):this.range(e);break}}return this}const vc=Symbol("implicit");function pc(){var t=new fc,e=[],n=[],a=vc;function i(o){let s=t.get(o);if(s===void 0){if(a!==vc)return a;t.set(o,s=e.push(o)-1)}return n[s%n.length]}return i.domain=function(o){if(!arguments.length)return e.slice();e=[],t=new fc;for(const s of o)t.has(s)||t.set(s,e.push(s)-1);return i},i.range=function(o){return arguments.length?(n=Array.from(o),i):n.slice()},i.unknown=function(o){return arguments.length?(a=o,i):a},i.copy=function(){return pc(e,n).unknown(a)},ra.apply(i,arguments),i}const Gv=(t,e,n)=>{const a=ot(t.cloneNode(!0));return a.attr("id",n).insert("rect",":first-child").attr("width",a.attr("width")).attr("height",a.attr("height")).style("fill",e),{id:n,node:a.node()}};function Xv(t){const e=Ln.colorPattern,{body:n}=gn;let a=n[e];if(!a){const i=";",o=t.classed(oo.colorPattern,!0).style("background-image");t.classed(oo.colorPattern,!1),o.indexOf(i)>-1&&(a=o.replace(/url[^#]*|["'()]|(\s|%20)/g,"").split(i).map(s=>s.trim().replace(/[\"'\s]/g,"")).filter(Boolean),n[e]=a)}return a}const Hv=["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"];var Yv={generateColor(){const t=this,{$el:e,config:n}=t,a=n.data_colors,i=n.data_color,o=[];let s=cn(n.color_pattern)?n.color_pattern:pc(Xv(e.chart)||Hv).range();const l=s;if(ve(n.color_tiles)){const c=n.color_tiles.bind(t.api)(),f=s.map((g,v)=>{const m=g.replace(/[#\(\)\s,]/g,""),S=`${t.state.datetimeId}-pattern-${m}-${v}`;return Gv(c[v%c.length],g,S)});s=f.map(g=>`url(#${g.id})`),t.patterns=f}return function(c){var f;const g=c.id||((f=c.data)==null?void 0:f.id)||c,v=t.isTypeOf(g,["line","spline","step"])||!n.data_types[g];let m;return ve(a[g])?m=a[g].bind(t.api)(c):a[g]?m=a[g]:(o.indexOf(g)<0&&o.push(g),m=v?l[o.indexOf(g)%l.length]:s[o.indexOf(g)%s.length],a[g]=m),ve(i)?i.bind(t.api)(m,c):m}},generateLevelColor(){const t=this,{config:e}=t,n=e.color_pattern,a=e.color_threshold,i=a.unit==="value",o=a.max||100,s=a.values&&a.values.length?a.values:[];return cn(a)?function(l){const c=i?l:l*100/o;let f=n[n.length-1];for(let g=0,v=s.length;g{const l=`${i.datetimeId}-labels-bg${n.getTargetSelectorSuffix(s)}${ze(t)?n.getTargetSelectorSuffix(t):""}`;a.defs.append("filter").attr("x",e.x).attr("y",e.y).attr("width",e.width).attr("height",e.height).attr("id",l).html(` `)})}},getGradienColortUrl(t){return`url(#${this.state.datetimeId}-gradient${this.getTargetSelectorSuffix(t)})`},updateLinearGradient(){const t=this,{config:e,data:{targets:n},state:{datetimeId:a},$el:{defs:i}}=t;n.forEach(o=>{const s=`${a}-gradient${t.getTargetSelectorSuffix(o.id)}`,l=t.hasPointType()&&e.point_radialGradient,c=t.isAreaType(o)&&"area"||t.isBarType(o)&&"bar";if((l||c)&&i.select(`#${s}`).empty()){const f=t.color(o),g={defs:null,stops:[]};if(l){const{cx:v=.3,cy:m=.3,r:S=.7,stops:P=[[.1,f,0],[.9,f,1]]}=l;g.stops=P,g.defs=i.append("radialGradient").attr("id",`${s}`).attr("cx",v).attr("cy",m).attr("r",S)}else{const v=e.axis_rotated,{x:m=v?[1,0]:[0,0],y:S=v?[0,0]:[0,1],stops:P=[[0,f,1],[1,f,0]]}=e[`${c}_linearGradient`];g.stops=P,g.defs=i.append("linearGradient").attr("id",`${s}`).attr("x1",m[0]).attr("x2",m[1]).attr("y1",S[0]).attr("y2",S[1])}g.stops.forEach(v=>{const[m,S,P]=v,N=ve(S)?S.bind(t.api)(o.id):S;g.defs&&g.defs.append("stop").attr("offset",m).attr("stop-color",N||f).attr("stop-opacity",P)})}})},setOverColor(t,e){const n=this,{config:a,$el:{main:i}}=n,o=a.color_onover;let s=t?o:n.color;Be(s)?s=({id:l})=>l in o?o[l]:n.color(l):ze(s)?s=()=>o:ve(o)&&(s=s.bind(n.api)),i.selectAll(Be(e)?`.${Ve.arc}${n.getTargetSelectorSuffix(e.id)}`:`.${sn.shape}-${e}`).style("fill",s)}},Wv={getYDomainMinMax(t,e){const n=this,{axis:a,config:i}=n,o=e==="min",s=i.data_groups,l=n.mapToIds(t),c=n.getValuesAsIdKeyed(t);if(s.length>0){const f=n[`has${o?"Negative":"Positive"}ValueInTargets`](t);s.forEach(g=>{const v=g.filter(m=>l.indexOf(m)>=0);if(v.length){const m=v[0],S=a.getId(m);f&&c[m]&&(c[m]=c[m].map(P=>(o?P<0:P>0)?P:0)),v.filter((P,N)=>N>0).forEach(P=>{if(c[P]){const N=a.getId(P);c[P].forEach((L,w)=>{const X=+L,W=o?X>0:X<0;N===S&&!(f&&W)&&(c[m][w]+=X)})}})}})}return _n(e,Object.keys(c).map(f=>_n(e,c[f])))},isHiddenTargetWithYDomain(t){const e=this;return e.state.hiddenTargetIds.some(n=>e.axis.getId(n)===t)},getYDomain(t,e,n){const a=this,{axis:i,config:o,scale:s}=a,l=`axis_${e}`;if(a.isStackNormalized())return[0,100];const c=(s==null?void 0:s[e])&&s[e].type==="log",f=t.filter(dt=>i.getId(dt.id)===e),g=n?a.filterByXDomain(f,n):f;if(g.length===0)return a.isHiddenTargetWithYDomain(e)?s[e].domain():e==="y2"?s.y.domain():a.getYDomain(t,"y2",n);const v=o[`${l}_min`],m=o[`${l}_max`],S=o[`${l}_center`],P=o[`${l}_inverted`],N=a.hasDataLabel()&&o.axis_rotated,L=a.hasDataLabel()&&!o.axis_rotated;let w=a.getYDomainMinMax(g,"min"),X=a.getYDomainMinMax(g,"max"),W=[oe.BAR,oe.BUBBLE,oe.SCATTER,...Sr.Line].some(dt=>{const st=dt.indexOf("area")>-1?"area":dt;return a.hasType(dt,g,!0)&&o[`${st}_zerobased`]});w=De(v)?v:De(m)?w<=m?w:m-10:w,X=De(m)?m:De(v)?v<=X?X:v+10:X,isNaN(w)&&(w=0),isNaN(X)&&(X=w),w===X&&(w<0?X=0:w=0);const H=w>=0&&X>=0,k=w<=0&&X<=0;(De(v)&&H||De(m)&&k)&&(W=!1),W&&(H&&(w=0),k&&(X=0));const K=Math.abs(X-w);let at={top:K*.1,bottom:K*.1};if(Qe(S)){const dt=Math.max(Math.abs(w),Math.abs(X));X=S+dt,w=S-dt}if(N){const dt=Dr(s.y.range()),st=a.getDataLabelLength(w,X,"width").map(Vt=>Vt/dt);["bottom","top"].forEach((Vt,vt)=>{at[Vt]+=K*(st[vt]/(1-st[0]-st[1]))})}else if(L){const dt=a.getDataLabelLength(w,X,"height");["bottom","top"].forEach((st,Vt)=>{at[st]+=a.convertPixelToScale("y",dt[Vt],K)})}at=a.getResettedPadding(at);const ht=o[`${l}_padding`];cn(ht)&&["bottom","top"].forEach(dt=>{at[dt]=i.getPadding(ht,dt,at[dt],K)}),W&&(H&&(at.bottom=w),k&&(at.top=-X));const $t=c?[w,X].map(dt=>dt<0?0:dt):[w-at.bottom,X+at.top];return P?$t.reverse():$t},getXDomainMinMax(t,e){var n;const a=this,i=a.config[`axis_x_${e}`],o=_n(e,t.map(l=>_n(e,l.values.map(c=>c.x))));let s=Be(i)?i.value:i;return s=Qe(s)&&((n=a.axis)!=null&&n.isTimeSeries())?Yn.bind(this)(s):s,Be(i)&&i.fit&&(e==="min"&&so)&&(s=void 0),Qe(s)?s:o},getXDomainPadding(t,e){const n=this,{axis:a,config:i}=n,o=i.axis_x_padding,s=a.isTimeSeries()&&e,l=Dr(t);let c;if(a.isCategorized()||s)c=0;else if(n.hasType("bar")){const v=n.getMaxDataCount();c=v>1?l/(v-1)/2:.5}else c=n.getResettedPadding(l*.01);let{left:f=c,right:g=c}=he(o)?{left:o,right:o}:o;if(o.unit==="px"){const v=Math.abs(l+l*.2);f=a.getPadding(o,"left",c,v),g=a.getPadding(o,"right",c,v)}else{const v=l+f+g;if(s&&v){const m=l/e/v;f=f/v/m,g=g/v/m}}return{left:f,right:g}},getXDomain(t){const e=this,{axis:n,config:a,scale:{x:i}}=e,o=a.axis_x_inverted,s=[e.getXDomainMinMax(t,"min"),e.getXDomainMinMax(t,"max")];let[l=0,c=0]=s;if(i.type!=="log"){const f=n.isCategorized(),g=n.isTimeSeries(),v=e.getXDomainPadding(s);let[m,S]=s;m-S===0&&!f&&(g?(m=new Date(m.getTime()*.5),S=new Date(S.getTime()*1.5)):(m=m===0?1:m*.5,S=S===0?-1:S*1.5)),(m||m===0)&&(l=g?new Date(m.getTime()-v.left):m-v.left),(S||S===0)&&(c=g?new Date(S.getTime()+v.right):S+v.right)}return o?[c,l]:[l,c]},updateXDomain(t,e,n,a,i){var o;const s=this,{config:l,org:c,scale:{x:f,subX:g}}=s,v=l.zoom_enabled;if(n&&(f.domain(i||na(s.getXDomain(t),!l.axis_x_inverted)),c.xDomain=f.domain(),g.domain(f.domain()),(o=s.brush)==null||o.scale(g)),e){const m=i||!s.brush||Kl(s)?c.xDomain:Wl(s).map(g.invert);f.domain(m)}return(n||e)&&v&&s.zoom.updateScaleExtent(),a&&f.domain(s.trimXDomain(f.orgDomain())),f.domain()},trimXDomain(t){const e=this,n=e.config.axis_x_inverted,a=e.getZoomDomain(),[i,o]=a;return(n?t[0]>=i:t[0]<=i)&&(t[1]=+t[1]+(i-t[0]),t[0]=i),(n?t[1]<=o:t[1]>=o)&&(t[0]=+t[0]-(t[1]-o),t[1]=o),t},getZoomDomain(t="zoom",e=!1){const n=this,{config:a,scale:i,org:o}=n;let[s,l]=e&&i[t]?i[t].domain():o.xDomain;return t==="zoom"&&(Qe(a.zoom_x_min)&&(s=_n("min",[s,a.zoom_x_min])),Qe(a.zoom_x_max)&&(l=_n("max",[l,a.zoom_x_max]))),[s,l]},getZoomDomainValue(t){const e=this,{config:n,axis:a}=e;if(a.isCategorized()&&Array.isArray(t)){const i=n.axis_x_inverted;return t.map((s,l)=>Number(s)+(l===0?+i:+!i))}return t},convertPixelToScale(t,e,n){const a=this,{config:i,state:o}=a,s=i.axis_rotated;let l;return t==="x"?l=s?"height":"width":l=s?"width":"height",n*(e/o[l])},withinRange(t,e=[0,0],n){const i=this.config.axis_x_inverted,[o,s]=n;if(Array.isArray(t)){const l=[...t];if(i&&l.reverse(),l[0](f===0?i?+c<=o:+c>=o:i?+c>=s:+c<=s)&&!t.every((g,v)=>g===e[v]))}return!1}};function mc(t,e,n){const{config:a}=t,i=`axis_${e}_tick_format`;return(a[i]?a[i]:t.defaultValueFormat).call(t.api,n)}var Kv={yFormat(t){return mc(this,"y",t)},y2Format(t){return mc(this,"y2",t)},getDefaultValueFormat(){const t=this,{defaultArcValueFormat:e,yFormat:n,y2Format:a}=t,i=t.hasArcType(null,["gauge","polar","radar"]);return function(o,s,l){return(i?e:t.axis&&t.axis.getId(l)==="y2"?a:n).call(t,o,s)}},defaultValueFormat(t){return je(t)?t.join("~"):De(t)?+t:""},defaultArcValueFormat(t,e){return`${(e*100).toFixed(1)}%`},defaultPolarValueFormat(t){return`${t}`},dataLabelFormat(t){const e=this,n=e.config.data_labels,a=o=>{const s="~";let l=o;return je(o)?l=o.join(s):Be(o)&&(l=Object.values(o).join(s)),l};let i=a;return ve(n.format)?i=n.format:nr(n.format)&&(n.format[t]?i=n.format[t]===!0?a:n.format[t]:i=()=>""),i.bind(e.api)}};function Ii(t){const e=this,n=e.getDataById(t);return e.levelColor?e.levelColor(n.values[0].value):e.color(n)}function Wo(t,e=!0){var n;const{config:a}=this;let i=(n=a.data_names[t])!=null?n:t;return e&&ve(a.legend_format)&&(i=a.legend_format(i,t!==i?t:void 0)),i}var Zv={initLegend(){const t=this,{config:e,$el:n}=t;t.legendItemTextBox={},t.state.legendHasRendered=!1,e.legend_show?(e.legend_contents_bindto||(n.legend=t.$el.svg.append("g").classed(We.legend,!0).attr("transform",t.getTranslate("legend"))),t.updateLegend()):t.state.hiddenLegendIds=t.mapToIds(t.data.targets)},updateLegend(t,e,n){var a;const i=this,{config:o,state:s,scale:l,$el:c}=i,f=e||{withTransform:!1,withTransitionForTransform:!1,withTransition:!1};f.withTransition=$r(f,"withTransition",!0),f.withTransitionForTransform=$r(f,"withTransitionForTransform",!0),o.legend_contents_bindto&&o.legend_contents_template?i.updateLegendTemplate():s.hasTreemap||i.updateLegendElement(t||i.mapToIds(i.data.targets),f,n),(a=c.legend)==null||a.selectAll(`.${We.legendItem}`).classed(We.legendItemHidden,function(g){const v=!i.isTargetToShow(g);return v&&(this.style.opacity=null),v}),i.updateScales(!1,!l.zoom),i.updateSvgSize(),i.transformAll(f.withTransitionForTransform,n),s.legendHasRendered=!0},updateLegendTemplate(){const t=this,{config:e,$el:n}=t,a=ot(e.legend_contents_bindto),i=e.legend_contents_template;if(!a.empty()){const o=t.mapToIds(t.data.targets),s=[];let l="";o.forEach(f=>{const g=ve(i)?i.bind(t.api)(f,t.color(f),t.api.data(f)[0].values):bi(i,{COLOR:t.color(f),TITLE:f});g&&(s.push(f),l+=g)});const c=a.html(l).selectAll(function(){return this.childNodes}).data(s);t.setLegendItem(c),n.legend=a}},updateSizeForLegend(t){const e=this,{config:n,state:{isLegendTop:a,isLegendLeft:i,isLegendRight:o,isLegendInset:s,current:l}}=e,{width:c,height:f}=t,g={top:a?e.getCurrentPaddingByDirection("top")+n.legend_inset_y+5.5:l.height-f-e.getCurrentPaddingByDirection("bottom")-n.legend_inset_y,left:i?e.getCurrentPaddingByDirection("left")+n.legend_inset_x+.5:l.width-c-e.getCurrentPaddingByDirection("right")-n.legend_inset_x+.5};e.state.margin3={top:o?0:s?g.top:l.height-f,right:NaN,bottom:0,left:o?l.width-c:s?g.left:0}},transformLegend(t){const e=this,{$el:{legend:n},$T:a}=e;a(n,t).attr("transform",e.getTranslate("legend"))},updateLegendStep(t){this.state.legendStep=t},updateLegendItemWidth(t){this.state.legendItemWidth=t},updateLegendItemHeight(t){this.state.legendItemHeight=t},updateLegendItemColor(t,e){const{legend:n}=this.$el;n&&n.select(`.${We.legendItem}-${t} line`).style("stroke",e)},getLegendWidth(){const t=this,{current:{width:e},isLegendRight:n,isLegendInset:a,legendItemWidth:i,legendStep:o}=t.state;return t.config.legend_show?n||a?i*(o+1):e:0},getLegendHeight(){var t;const e=this,{current:n,isLegendRight:a,legendItemHeight:i,legendStep:o}=e.state,s=((t=e.config.padding)==null?void 0:t.mode)==="fit";return e.config.legend_show?a?n.height:Math.max(s?10:20,i)*(o+1):0},opacityForUnfocusedLegend(t){return t.classed(We.legendItemHidden)?null:"0.3"},toggleFocusLegend(t,e){const n=this,{$el:{legend:a},$T:i}=n,o=n.mapToTargetIds(t);a&&i(a.selectAll(`.${We.legendItem}`).filter(s=>o.indexOf(s)>=0).classed(qe.legendItemFocused,e)).style("opacity",function(){return e?null:n.opacityForUnfocusedLegend.call(n,ot(this))})},revertLegend(){const t=this,{$el:{legend:e},$T:n}=t;e&&n(e.selectAll(`.${We.legendItem}`).classed(qe.legendItemFocused,!1)).style("opacity",null)},showLegend(t){const e=this,{config:n,$el:a,$T:i}=e;n.legend_show||(n.legend_show=!0,a.legend?a.legend.style("visibility",null):e.initLegend(),!e.state.legendHasRendered&&e.updateLegend()),e.removeHiddenLegendIds(t),i(a.legend.selectAll(e.selectorLegends(t)).style("visibility",null)).style("opacity",null)},hideLegend(t){const e=this,{config:n,$el:{legend:a}}=e;n.legend_show&&qn(t)&&(n.legend_show=!1,a.style("visibility","hidden")),e.addHiddenLegendIds(t),a.selectAll(e.selectorLegends(t)).style("opacity","0").style("visibility","hidden")},getLegendItemTextBox(t,e){const n=this,{cache:a,state:i}=n;let o;const s=Ln.legendItemTextBox;return t&&(o=!i.redrawing&&a.get(s)||{},o[t]||(o[t]=n.getTextRect(e,We.legendItem),a.add(s,o)),o=o[t]),o},setLegendItem(t){const e=this,{$el:n,api:a,config:i,state:o}=e,s=o.inputType==="touch",l=e.hasType("gauge"),c=i.boost_useCssRule,f=i.legend_item_interaction;t.attr("class",function(g){const v=ot(this);return(!v.empty()&&v.attr("class")||"")+e.generateClass(We.legendItem,g)}).style("visibility",g=>e.isLegendToShow(g)?null:"hidden"),i.interaction_enabled&&(c&&[[`.${We.legendItem}`,"cursor:pointer"],[`.${We.legendItem} text`,"pointer-events:none"],[`.${We.legendItemPoint} text`,"pointer-events:none"],[`.${We.legendItemTile}`,"pointer-events:none"],[`.${We.legendItemEvent}`,"fill-opacity:0"]].forEach(g=>{const[v,m]=g;e.setCssRule(!1,v,[m])(n.legend)}),t.on(f.dblclick?"dblclick":"click",f||ve(i.legend_item_onclick)?function(g,v){if(!_e(i.legend_item_onclick,a,v,!o.hiddenTargetIds.includes(v))){const{altKey:m,target:S,type:P}=g;P==="dblclick"||m?o.hiddenTargetIds.length&&S.parentNode.getAttribute("class").indexOf(We.legendItemHidden)===-1?a.show():(a.hide(),a.show(v)):(a.toggle(v),ot(this).classed(qe.legendItemFocused,!1))}s&&e.hideTooltip()}:null),!s&&t.on("mouseout",f||ve(i.legend_item_onout)?function(g,v){_e(i.legend_item_onout,a,v,!o.hiddenTargetIds.includes(v))||(ot(this).classed(qe.legendItemFocused,!1),l&&e.undoMarkOverlapped(e,`.${Un.gaugeValue}`),e.api.revert())}:null).on("mouseover",f||ve(i.legend_item_onover)?function(g,v){_e(i.legend_item_onover,a,v,!o.hiddenTargetIds.includes(v))||(ot(this).classed(qe.legendItemFocused,!0),l&&e.markOverlapped(v,e,`.${Un.gaugeValue}`),!o.transiting&&e.isTargetToShow(v)&&a.focus(v))}:null),!t.empty()&&t.on("click mouseout mouseover")&&t.style("cursor",e.getStylePropValue("pointer")))},updateLegendElement(t,e){const n=this,{config:a,state:i,$el:{legend:o},$T:s}=n,c=a.legend_item_tile_type!=="circle",f=a.legend_item_tile_r,g={width:c?a.legend_item_tile_width:f*2,height:c?a.legend_item_tile_height:f*2},v={padding:{top:4,right:10},max:{width:0,height:0},posMin:10,step:0,tileWidth:g.width+5,totalLength:0},m={offsets:{},widths:{},heights:{},margins:[0],steps:{}};let S,P,N;const L=t.filter(K=>!Qe(a.data_names[K])||a.data_names[K]!==null),w=e.withTransition,X=n.getUpdateLegendPositions(L,v,m);i.isLegendInset&&(v.step=a.legend_inset_step?a.legend_inset_step:L.length,n.updateLegendStep(v.step)),i.isLegendRight?(S=K=>v.max.width*m.steps[K],P=K=>m.margins[m.steps[K]]+m.offsets[K]):i.isLegendInset?(S=K=>v.max.width*m.steps[K]+10,P=K=>m.margins[m.steps[K]]+m.offsets[K]):(S=K=>m.margins[m.steps[K]]+m.offsets[K],P=K=>v.max.height*m.steps[K]);const W={xText:(K,at)=>S(K,at)+4+g.width,xRect:(K,at)=>S(K,at),x1Tile:(K,at)=>S(K,at)-2,x2Tile:(K,at)=>S(K,at)-2+g.width,yText:(K,at)=>P(K,at)+9,yRect:(K,at)=>P(K,at)-5,yTile:(K,at)=>P(K,at)+4};n.generateLegendItem(L,g,X,W),N=o.select(`.${We.legendBackground} rect`),i.isLegendInset&&v.max.width>0&&N.size()===0&&(N=o.insert("g",`.${We.legendItem}`).attr("class",We.legendBackground).append("rect")),a.legend_tooltip&&o.selectAll("title").data(L).text(K=>Wo.bind(n)(K,!1));const H=o.selectAll("text").data(L).text(K=>Wo.bind(n)(K)).each(function(K,at){X(this,K,at)});s(H,w).attr("x",W.xText).attr("y",W.yText);const k=o.selectAll(`rect.${We.legendItemEvent}`).data(L);s(k,w).attr("width",K=>m.widths[K]).attr("height",K=>m.heights[K]).attr("x",W.xRect).attr("y",W.yRect),n.updateLegendItemPos(L,w,W),N&&s(N,w).attr("height",n.getLegendHeight()-12).attr("width",v.max.width*(v.step+1)+10),n.updateLegendItemWidth(v.max.width),n.updateLegendItemHeight(v.max.height),n.updateLegendStep(v.step)},getUpdateLegendPositions(t,e,n){const a=this,{config:i,state:o}=a,s=o.isLegendRight||o.isLegendInset;return function(l,c,f){const g=f===0,v=f===t.length-1,m=a.getLegendItemTextBox(c,l),S=m.width+e.tileWidth+(v&&!s?0:e.padding.right)+i.legend_padding,P=m.height+e.padding.top,N=s?P:S,L=s?a.getLegendHeight():a.getLegendWidth();let w;const X=function(H,k){k||(w=(L-e.totalLength-N)/2,w=e.max.width)&&(e.max.width=S),(!e.max.height||P>=e.max.height)&&(e.max.height=P);const W=s?e.max.height:e.max.width;i.legend_equally?(Object.keys(n.widths).forEach(H=>n.widths[H]=e.max.width),Object.keys(n.heights).forEach(H=>n.heights[H]=e.max.height),w=(L-W*t.length)/2,wX(H))):X(c,!0)):X(c)}},generateLegendItem(t,e,n,a){const i=this,{config:o,state:s,$el:{legend:l}}=i,c=o.legend_usePoint,f=o.legend_item_tile_r,g=o.legend_item_tile_type,v=g!=="circle",m=s.isLegendRight||s.isLegendInset,S=-200,P=l.selectAll(`.${We.legendItem}`).data(t).enter().append("g");if(i.setLegendItem(P),o.legend_tooltip&&P.append("title").text(N=>N),P.append("text").text(N=>Wo.bind(i)(N)).each(function(N,L){n(this,N,L)}).style("pointer-events",i.getStylePropValue("none")).attr("x",m?a.xText:S).attr("y",m?S:a.yText),P.append("rect").attr("class",We.legendItemEvent).style("fill-opacity",i.getStylePropValue("0")).attr("x",m?a.xRect:S).attr("y",m?S:a.yRect),c){const N=[];P.append(L=>{const w=cn(o.point_pattern)?o.point_pattern:[o.point_type];N.indexOf(L)===-1&&N.push(L);let X=w[N.indexOf(L)%w.length];return X==="rectangle"&&(X="rect"),gn.createElementNS(ae.svg,"hasValidPointType"in i&&i.hasValidPointType(X)?X:"use")}).attr("class",We.legendItemPoint).style("fill",Ii.bind(i)).style("pointer-events",i.getStylePropValue("none")).attr("href",(L,w,X)=>{const H=X[w].nodeName.toLowerCase(),k=i.getTargetSelectorSuffix(L);return H==="use"?`#${s.datetimeId}-point${k}`:void 0})}else P.append(v?"line":g).attr("class",We.legendItemTile).style("stroke",Ii.bind(i)).style("pointer-events",i.getStylePropValue("none")).call(N=>{g==="circle"?N.attr("r",f).style("fill",Ii.bind(i)).attr("cx",m?a.x2Tile:S).attr("cy",m?S:a.yTile):v&&N.attr("stroke-width",e.height).attr("x1",m?a.x1Tile:S).attr("y1",m?S:a.yTile).attr("x2",m?a.x2Tile:S).attr("y2",m?S:a.yTile)})},updateLegendItemPos(t,e,n){const a=this,{config:i,$el:{legend:o},$T:s}=a,l=i.legend_usePoint,c=i.legend_item_tile_type,f=c!=="circle";if(l){const g=o.selectAll(`.${We.legendItemPoint}`).data(t);s(g,e).each(function(){const v=this.nodeName.toLowerCase(),m=i.point_r;let S="x",P="y",N=2,L=2.5,w=null,X=null,W=null;if(v==="circle"){const H=m*.2;S="cx",P="cy",w=m+H,N=m*2,L=-H}else if(v==="rect"){const H=m*2.5;X=H,W=H,L=3}ot(this).attr(S,H=>n.x1Tile(H)+N).attr(P,H=>n.yTile(H)-L).attr("r",w).attr("width",X).attr("height",W)})}else{const g=o.selectAll(`.${We.legendItemTile}`).data(t);s(g,e).style("stroke",Ii.bind(a)).call(v=>{c==="circle"?v.attr("cx",m=>{const S=n.x2Tile(m);return S-(S-n.x1Tile(m))/2}).attr("cy",n.yTile):f&&v.attr("x1",n.x1Tile).attr("y1",n.yTile).attr("x2",n.x2Tile).attr("y2",n.yTile)})}}},Jv={redraw(t={}){var e,n,a,i;const o=this,{config:s,state:l,$el:c}=o,{main:f,treemap:g}=c;l.redrawing=!0;const v=o.filterTargetsToShow(o.data.targets),{flow:m,initializing:S}=t,P=o.getWithOption(t),N=P.Transition?s.transition_duration:0,L=P.TransitionForExit?N:0,w=P.TransitionForAxis?N:0,X=(e=o.axis)==null?void 0:e.generateTransitions(w);o.updateSizes(S),P.Legend&&s.legend_show?(t.withTransition=!!N,!g&&o.updateLegend(o.mapToIds(o.data.targets),t,X)):P.Dimension&&o.updateDimension(!0),s.data_empty_label_text&&f.select(`text.${On.text}.${Se.empty}`).attr("x",l.width/2).attr("y",l.height/2).text(s.data_empty_label_text).style("display",v.length?"none":null),l.hasAxis?(o.axis.redrawAxis(v,P,X,m,S),o.hasGrid()&&o.updateGrid(),s.regions.length&&o.updateRegion(),["bar","candlestick","line","area"].forEach(W=>{const H=Cn(W);(/^(line|area)$/.test(W)&&o.hasTypeOf(H)||o.hasType(W))&&o[`update${H}`](P.TransitionForExit)}),c.text&&f.selectAll(`.${tn.selectedCircles}`).filter(o.isBarType.bind(o)).selectAll("circle").remove(),s.interaction_enabled&&!m&&P.EventRect&&(o.redrawEventRect(),(n=o.bindZoomEvent)==null||n.call(o))):(c.arcs&&o.redrawArc(N,L,P.Transform),c.radar&&o.redrawRadar(),c.polar&&o.redrawPolar(),c.funnel&&o.redrawFunnel(),g&&o.updateTreemap(L)),!l.resizing&&!g&&(o.hasPointType()||l.hasRadar)?o.updateCircle():(a=o.hasLegendDefsPoint)!=null&&a.call(o)&&o.data.targets.forEach(o.point("create",this)),o.hasDataLabel()&&!o.hasArcType(null,["radar"])&&o.updateText(),(i=o.redrawTitle)==null||i.call(o),S&&o.updateTypesElements(),o.generateRedrawList(v,m,N,P.Subchart),o.updateTooltipOnRedraw(),o.callPluginHook("$redraw",t,N)},generateRedrawList(t,e,n,a){const i=this,{config:o,state:s}=i,l=i.getDrawShape();s.hasAxis&&o.subchart_show&&i.redrawSubchart(a,n,l);const c=e&&i.generateFlow({targets:t,flow:e,duration:e.duration,shape:l,xv:i.xv.bind(i)}),f=(n||c)&&Da(),g=i.getRedrawList(l,e,c,f),v=()=>{c&&c(),s.redrawing=!1,_e(o.onrendered,i.api)};if(v)if(f&&g.length){const m=ec();Ml().duration(n).each(()=>{g.reduce((S,P)=>S.concat(P),[]).forEach(S=>m.add(S))}).call(m,v)}else s.transiting||v();i.mapToIds(i.data.targets).forEach(m=>{s.withoutFadeIn[m]=!0})},getRedrawList(t,e,n,a){const i=this,{config:o,state:{hasAxis:s,hasRadar:l,hasTreemap:c},$el:{grid:f}}=i,{cx:g,cy:v,xForText:m,yForText:S}=t.pos,P=[];return s&&((o.grid_x_lines.length||o.grid_y_lines.length)&&P.push(i.redrawGrid(a)),o.regions.length&&P.push(i.redrawRegion(a)),Object.keys(t.type).forEach(N=>{const L=Cn(N),w=t.type[N];(/^(area|line)$/.test(N)&&i.hasTypeOf(L)||i.hasType(N))&&P.push(i[`redraw${L}`](w,a))}),!e&&f.main&&P.push(i.updateGridFocus())),(!i.hasArcType()||l)&&cn(o.data_labels)&&o.data_labels!==!1&&P.push(i.redrawText(m,S,e,a)),(i.hasPointType()||l)&&!i.isPointFocusOnly()&&i.redrawCircle&&P.push(i.redrawCircle(g,v,a,n)),c&&P.push(i.redrawTreemap(a)),P},updateAndRedraw(t={}){const e=this,{config:n,state:a}=e;let i;t.withTransition=$r(t,"withTransition",!0),t.withTransform=$r(t,"withTransform",!1),t.withLegend=$r(t,"withLegend",!1),t.withUpdateXDomain=!0,t.withUpdateOrgXDomain=!0,t.withTransitionForExit=!1,t.withTransitionForTransform=$r(t,"withTransitionForTransform",t.withTransition),t.withLegend&&n.legend_show||(a.hasAxis&&(i=e.axis.generateTransitions(t.withTransitionForAxis?n.transition_duration:0)),e.updateScales(),e.updateSvgSize(),e.transformAll(t.withTransitionForTransform,i)),e.redraw(t,i)}};const Qv=Math.sqrt(50),kv=Math.sqrt(10),qv=Math.sqrt(2);function Oi(t,e,n){const a=(e-t)/Math.max(0,n),i=Math.floor(Math.log10(a)),o=a/Math.pow(10,i),s=o>=Qv?10:o>=kv?5:o>=qv?2:1;let l,c,f;return i<0?(f=Math.pow(10,-i)/s,l=Math.round(t*f),c=Math.round(e*f),l/fe&&--c,f=-f):(f=Math.pow(10,i)*s,l=Math.round(t/f),c=Math.round(e/f),l*fe&&--c),c0))return[];if(t===e)return[t];const a=e=i))return[];const l=o-i+1,c=new Array(l);if(a)if(s<0)for(let f=0;fe?1:t>=e?0:NaN}function _v(t,e){return t==null||e==null?NaN:et?1:e>=t?0:NaN}function Qo(t){let e,n,a;t.length!==2?(e=Ci,n=(l,c)=>Ci(t(l),c),a=(l,c)=>t(l)-c):(e=t===Ci||t===_v?t:tp,n=t,a=t);function i(l,c,f=0,g=l.length){if(f>>1;n(l[v],c)<0?f=v+1:g=v}while(f>>1;n(l[v],c)<=0?f=v+1:g=v}while(ff&&a(l[v-1],c)>-a(l[v],c)?v-1:v}return{left:i,center:s,right:o}}function tp(){return 0}function ep(t){return t===null?NaN:+t}function*h1(t,e){if(e===void 0)for(let n of t)n!=null&&(n=+n)>=n&&(yield n);else{let n=-1;for(let a of t)(a=e(a,++n,t))!=null&&(a=+a)>=a&&(yield a)}}const yc=Qo(Ci),np=yc.right,g1=yc.left,v1=Qo(ep).center;var rp=np;function ap(t,e){return t=+t,e=+e,function(n){return Math.round(t*(1-n)+e*n)}}function ip(t){return function(){return t}}function op(t){return+t}var xc=[0,1];function aa(t){return t}function ko(t,e){return(e-=t=+t)?function(n){return(n-t)/e}:ip(isNaN(e)?NaN:.5)}function sp(t,e){var n;return t>e&&(n=t,t=e,e=n),function(a){return Math.max(t,Math.min(e,a))}}function lp(t,e,n){var a=t[0],i=t[1],o=e[0],s=e[1];return i2?cp:lp,c=f=null,v}function v(m){return m==null||isNaN(m=+m)?o:(c||(c=l(t.map(a),e,n)))(a(s(m)))}return v.invert=function(m){return s(i((f||(f=l(e,t.map(a),Qn)))(m)))},v.domain=function(m){return arguments.length?(t=Array.from(m,op),g()):t.slice()},v.range=function(m){return arguments.length?(e=Array.from(m),g()):e.slice()},v.rangeRound=function(m){return e=Array.from(m),n=ap,g()},v.clamp=function(m){return arguments.length?(s=m?!0:aa,g()):s!==aa},v.interpolate=function(m){return arguments.length?(n=m,g()):n},v.unknown=function(m){return arguments.length?(o=m,v):o},function(m,S){return a=m,i=S,g()}}function Tc(){return qo()(aa,aa)}var up=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Na(t){if(!(e=up.exec(t)))throw new Error("invalid format: "+t);var e;return new _o({fill:e[1],align:e[2],sign:e[3],symbol:e[4],zero:e[5],width:e[6],comma:e[7],precision:e[8]&&e[8].slice(1),trim:e[9],type:e[10]})}Na.prototype=_o.prototype;function _o(t){this.fill=t.fill===void 0?" ":t.fill+"",this.align=t.align===void 0?">":t.align+"",this.sign=t.sign===void 0?"-":t.sign+"",this.symbol=t.symbol===void 0?"":t.symbol+"",this.zero=!!t.zero,this.width=t.width===void 0?void 0:+t.width,this.comma=!!t.comma,this.precision=t.precision===void 0?void 0:+t.precision,this.trim=!!t.trim,this.type=t.type===void 0?"":t.type+""}_o.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(this.width===void 0?"":Math.max(1,this.width|0))+(this.comma?",":"")+(this.precision===void 0?"":"."+Math.max(0,this.precision|0))+(this.trim?"~":"")+this.type};function fp(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)}function wi(t,e){if((n=(t=e?t.toExponential(e-1):t.toExponential()).indexOf("e"))<0)return null;var n,a=t.slice(0,n);return[a.length>1?a[0]+a.slice(2):a,+t.slice(n+1)]}function ia(t){return t=wi(Math.abs(t)),t?t[1]:NaN}function dp(t,e){return Math.max(0,Math.max(-8,Math.min(8,Math.floor(ia(e)/3)))*3-ia(Math.abs(t)))}function hp(t,e){return function(n,a){for(var i=n.length,o=[],s=0,l=t[0],c=0;i>0&&l>0&&(c+l+1>a&&(l=Math.max(1,a-c)),o.push(n.substring(i-=l,i+l)),!((c+=l+1)>a));)l=t[s=(s+1)%t.length];return o.reverse().join(e)}}function gp(t){return function(e){return e.replace(/[0-9]/g,function(n){return t[+n]})}}function vp(t){t:for(var e=t.length,n=1,a=-1,i;n0&&(a=0);break}return a>0?t.slice(0,a)+t.slice(i+1):t}var $c;function pp(t,e){var n=wi(t,e);if(!n)return t+"";var a=n[0],i=n[1],o=i-($c=Math.max(-8,Math.min(8,Math.floor(i/3)))*3)+1,s=a.length;return o===s?a:o>s?a+new Array(o-s+1).join("0"):o>0?a.slice(0,o)+"."+a.slice(o):"0."+new Array(1-o).join("0")+wi(t,Math.max(0,e+o-1))[0]}function Sc(t,e){var n=wi(t,e);if(!n)return t+"";var a=n[0],i=n[1];return i<0?"0."+new Array(-i).join("0")+a:a.length>i+1?a.slice(0,i+1)+"."+a.slice(i+1):a+new Array(i-a.length+2).join("0")}var Ac={"%":(t,e)=>(t*100).toFixed(e),b:t=>Math.round(t).toString(2),c:t=>t+"",d:fp,e:(t,e)=>t.toExponential(e),f:(t,e)=>t.toFixed(e),g:(t,e)=>t.toPrecision(e),o:t=>Math.round(t).toString(8),p:(t,e)=>Sc(t*100,e),r:Sc,s:pp,X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function Ec(t){return t}var bc=Array.prototype.map,Rc=["y","z","a","f","p","n","\xB5","m","","k","M","G","T","P","E","Z","Y"];function mp(t){var e=t.grouping===void 0||t.thousands===void 0?Ec:hp(bc.call(t.grouping,Number),t.thousands+""),n=t.currency===void 0?"":t.currency[0]+"",a=t.currency===void 0?"":t.currency[1]+"",i=t.decimal===void 0?".":t.decimal+"",o=t.numerals===void 0?Ec:gp(bc.call(t.numerals,String)),s=t.percent===void 0?"%":t.percent+"",l=t.minus===void 0?"\u2212":t.minus+"",c=t.nan===void 0?"NaN":t.nan+"";function f(v){v=Na(v);var m=v.fill,S=v.align,P=v.sign,N=v.symbol,L=v.zero,w=v.width,X=v.comma,W=v.precision,H=v.trim,k=v.type;k==="n"?(X=!0,k="g"):Ac[k]||(W===void 0&&(W=12),H=!0,k="g"),(L||m==="0"&&S==="=")&&(L=!0,m="0",S="=");var K=N==="$"?n:N==="#"&&/[boxX]/.test(k)?"0"+k.toLowerCase():"",at=N==="$"?a:/[%p]/.test(k)?s:"",ht=Ac[k],$t=/[defgprs%]/.test(k);W=W===void 0?6:/[gprs]/.test(k)?Math.max(1,Math.min(21,W)):Math.max(0,Math.min(20,W));function dt(st){var Vt=K,vt=at,Q,St,ct;if(k==="c")vt=ht(st)+vt,st="";else{st=+st;var At=st<0||1/st<0;if(st=isNaN(st)?c:ht(Math.abs(st),W),H&&(st=vp(st)),At&&+st==0&&P!=="+"&&(At=!1),Vt=(At?P==="("?P:l:P==="-"||P==="("?"":P)+Vt,vt=(k==="s"?Rc[8+$c/3]:"")+vt+(At&&P==="("?")":""),$t){for(Q=-1,St=st.length;++Qct||ct>57){vt=(ct===46?i+st.slice(Q+1):st.slice(Q))+vt,st=st.slice(0,Q);break}}}X&&!L&&(st=e(st,1/0));var Gt=Vt.length+st.length+vt.length,Bt=Gt>1)+Vt+st+vt+Bt.slice(Gt);break;default:st=Bt+Vt+st+vt;break}return o(st)}return dt.toString=function(){return v+""},dt}function g(v,m){var S=f((v=Na(v),v.type="f",v)),P=Math.max(-8,Math.min(8,Math.floor(ia(m)/3)))*3,N=Math.pow(10,-P),L=Rc[8+P/3];return function(w){return S(N*w)+L}}return{format:f,formatPrefix:g}}var Mi,ts,Ic;yp({thousands:",",grouping:[3],currency:["$",""]});function yp(t){return Mi=mp(t),ts=Mi.format,Ic=Mi.formatPrefix,Mi}function xp(t,e){return t=Math.abs(t),e=Math.abs(e)-t,Math.max(0,ia(e)-ia(t))+1}function Tp(t){return Math.max(0,-ia(Math.abs(t)))}function $p(t,e,n,a){var i=Jo(t,e,n),o;switch(a=Na(a==null?",f":a),a.type){case"s":{var s=Math.max(Math.abs(t),Math.abs(e));return a.precision==null&&!isNaN(o=dp(i,s))&&(a.precision=o),Ic(a,s)}case"":case"e":case"g":case"p":case"r":{a.precision==null&&!isNaN(o=xp(i,Math.max(Math.abs(t),Math.abs(e))))&&(a.precision=o-(a.type==="e"));break}case"f":case"%":{a.precision==null&&!isNaN(o=Tp(i))&&(a.precision=o-(a.type==="%")*2);break}}return ts(a)}function Oc(t){var e=t.domain;return t.ticks=function(n){var a=e();return Ko(a[0],a[a.length-1],n==null?10:n)},t.tickFormat=function(n,a){var i=e();return $p(i[0],i[i.length-1],n==null?10:n,a)},t.nice=function(n){n==null&&(n=10);var a=e(),i=0,o=a.length-1,s=a[i],l=a[o],c,f,g=10;for(l0;){if(f=Zo(s,l,n),f===c)return a[i]=s,a[o]=l,e(a);if(f>0)s=Math.floor(s/f)*f,l=Math.ceil(l/f)*f;else if(f<0)s=Math.ceil(s*f)/f,l=Math.floor(l*f)/f;else break;c=f}return t},t}function Di(){var t=Tc();return t.copy=function(){return Pi(t,Di())},ra.apply(t,arguments),Oc(t)}function Cc(t){return function(e){return Math.sign(e)*Math.log1p(Math.abs(e/t))}}function Pc(t){return function(e){return Math.sign(e)*Math.expm1(Math.abs(e))*t}}function Sp(t){var e=1,n=t(Cc(e),Pc(e));return n.constant=function(a){return arguments.length?t(Cc(e=+a),Pc(e)):e},Oc(n)}function wc(){var t=Sp(qo());return t.copy=function(){return Pi(t,wc()).constant(t.constant())},ra.apply(t,arguments)}function Mc(t,e){t=t.slice();var n=0,a=t.length-1,i=t[n],o=t[a],s;return oMath.pow(t,e)}function Ip(t){return t===Math.E?Math.log:t===10&&Math.log10||t===2&&Math.log2||(t=Math.log(t),e=>Math.log(e)/t)}function Nc(t){return(e,n)=>-t(-e,n)}function Op(t){const e=t(Dc,Lc),n=e.domain;let a=10,i,o;function s(){return i=Ip(a),o=Rp(a),n()[0]<0?(i=Nc(i),o=Nc(o),t(Ap,Ep)):t(Dc,Lc),e}return e.base=function(l){return arguments.length?(a=+l,s()):a},e.domain=function(l){return arguments.length?(n(l),s()):n()},e.ticks=l=>{const c=n();let f=c[0],g=c[c.length-1];const v=g0){for(;m<=S;++m)for(P=1;Pg)break;w.push(N)}}else for(;m<=S;++m)for(P=a-1;P>=1;--P)if(N=m>0?P/o(-m):P*o(m),!(Ng)break;w.push(N)}w.length*2{if(l==null&&(l=10),c==null&&(c=a===10?"s":","),typeof c!="function"&&(!(a%1)&&(c=Na(c)).precision==null&&(c.trim=!0),c=ts(c)),l===1/0)return c;const f=Math.max(1,a*l/e.ticks().length);return g=>{let v=g/o(Math.round(i(g)));return v*an(Mc(n(),{floor:l=>o(Math.floor(i(l))),ceil:l=>o(Math.ceil(i(l)))})),e}function Fc(){const t=Op(qo()).domain([1,10]);return t.copy=()=>Pi(t,Fc()).base(t.base()),ra.apply(t,arguments),t}const Li=en(()=>{},(t,e)=>{t.setTime(+t+e)},(t,e)=>e-t);Li.every=t=>(t=Math.floor(t),!isFinite(t)||!(t>0)?null:t>1?en(e=>{e.setTime(Math.floor(e/t)*t)},(e,n)=>{e.setTime(+e+n*t)},(e,n)=>(n-e)/t):Li);const p1=Li.range,Ur=en(t=>{t.setTime(t-t.getMilliseconds())},(t,e)=>{t.setTime(+t+e*Gn)},(t,e)=>(e-t)/Gn,t=>t.getUTCSeconds()),m1=Ur.range,es=en(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Gn)},(t,e)=>{t.setTime(+t+e*In)},(t,e)=>(e-t)/In,t=>t.getMinutes()),y1=es.range,ns=en(t=>{t.setUTCSeconds(0,0)},(t,e)=>{t.setTime(+t+e*In)},(t,e)=>(e-t)/In,t=>t.getUTCMinutes()),x1=ns.range,rs=en(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Gn-t.getMinutes()*In)},(t,e)=>{t.setTime(+t+e*Bn)},(t,e)=>(e-t)/Bn,t=>t.getHours()),T1=rs.range,as=en(t=>{t.setUTCMinutes(0,0,0)},(t,e)=>{t.setTime(+t+e*Bn)},(t,e)=>(e-t)/Bn,t=>t.getUTCHours()),$1=as.range,is=en(t=>{t.setDate(1),t.setHours(0,0,0,0)},(t,e)=>{t.setMonth(t.getMonth()+e)},(t,e)=>e.getMonth()-t.getMonth()+(e.getFullYear()-t.getFullYear())*12,t=>t.getMonth()),S1=is.range,os=en(t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCMonth(t.getUTCMonth()+e)},(t,e)=>e.getUTCMonth()-t.getUTCMonth()+(e.getUTCFullYear()-t.getUTCFullYear())*12,t=>t.getUTCMonth()),A1=os.range;function Bc(t,e,n,a,i,o){const s=[[Ur,1,Gn],[Ur,5,5*Gn],[Ur,15,15*Gn],[Ur,30,30*Gn],[o,1,In],[o,5,5*In],[o,15,15*In],[o,30,30*In],[i,1,Bn],[i,3,3*Bn],[i,6,6*Bn],[i,12,12*Bn],[a,1,or],[a,2,2*or],[n,1,to],[e,1,Ps],[e,3,3*Ps],[t,1,eo]];function l(f,g,v){const m=gL).right(s,m);if(S===s.length)return t.every(Jo(f/eo,g/eo,v));if(S===0)return Li.every(Math.max(Jo(f,g,v),1));const[P,N]=s[m/s[S-1][2]n.axis.x.tickOffset()),i=n.config.axis_x_inverted,o=function(s){return t(s)+a()};for(const s in t)o[s]=t[s];return o.orgDomain=()=>t.domain(),o.orgScale=()=>t,n.axis.isCategorized()&&(o.domain=function(s){let l=s;return arguments.length?(t.domain(l),o):(l=this.orgDomain(),i?[l[0]+1,l[1]]:[l[0],l[1]+1])}),o},updateScales(t,e=!0){var n,a;const i=this,{axis:o,config:s,format:l,org:c,scale:f,state:{current:g,width:v,height:m,width2:S,height2:P,hasAxis:N,hasTreemap:L}}=i;if(N){const w=s.axis_rotated,X=i.getResettedPadding(1),W={x:w?X:0,y:w?0:m,subX:w?1:0,subY:w?0:P},H={x:w?m:v,y:w?v:X,subX:w?m:v,subY:w?S:1},k=e&&((n=f.x)==null?void 0:n.orgDomain()),K=e&&c.xDomain;f.x=i.getXScale(W.x,H.x,k,()=>o.x.tickOffset()),f.subX=i.getXScale(W.x,H.x,K,at=>{var ht;return at%1?0:((ht=o.subX)!=null?ht:o.x).tickOffset()}),l.xAxisTick=o.getXAxisTickFormat(),l.subXAxisTick=o.getXAxisTickFormat(!0),o.setAxis("x",f.x,s.axis_x_tick_outer,t),s.subchart_show&&o.setAxis("subX",f.subX,s.axis_x_tick_outer,t),f.y=i.getYScale("y",W.y,H.y,f.y?f.y.domain():s.axis_y_default),f.subY=i.getYScale("y",W.subY,H.subY,f.subY?f.subY.domain():s.axis_y_default),o.setAxis("y",f.y,s.axis_y_tick_outer,t),s.axis_y2_show&&(f.y2=i.getYScale("y2",W.y,H.y,f.y2?f.y2.domain():s.axis_y2_default),f.subY2=i.getYScale("y2",W.subY,H.subY,f.subY2?f.subY2.domain():s.axis_y2_default),o.setAxis("y2",f.y2,s.axis_y2_tick_outer,t))}else if(L){const w=i.getCurrentPadding();f.x=Di().rangeRound([w.left,g.width-w.right]),f.y=Di().rangeRound([w.top,g.height-w.bottom])}else(a=i.updateArc)==null||a.call(i)},xx(t){const e=this,{config:n,scale:{x:a,zoom:i}}=e,o=n.zoom_enabled&&i?i:a;return t?o(De(t.x)?t.x:t):null},xv(t){const e=this,{axis:n,config:a,scale:{x:i,zoom:o}}=e,s=a.zoom_enabled&&o?o:i;let l=e.getBaseValue(t);return n.isTimeSeries()?l=Yn.call(e,l):n.isCategorized()&&ze(l)&&(l=a.axis_x_categories.indexOf(l)),s(l)},yv(t){const e=this,{scale:{y:n,y2:a}}=e;return(t.axis&&t.axis==="y2"?a:n)(e.getBaseValue(t))},subxx(t){return t?this.scale.subX(t.x):null}},Up={setContainerSize(){const t=this,{state:e}=t;e.current.width=t.getCurrentWidth(),e.current.height=t.getCurrentHeight()},getCurrentWidth(){const t=this;return t.config.size_width||t.getParentWidth()},getCurrentHeight(){const t=this,{config:e}=t,n=e.size_height||t.getParentHeight();return n>0?n:320/(t.hasType("gauge")&&!e.gauge_fullCircle?2:1)},getParentRectValue(t){const e=`offset${Cn(t)}`;let n=this.$el.chart.node(),a=0;for(;a<30&&n&&n.tagName!=="BODY";){try{a=n.getBoundingClientRect()[t]}catch(o){e in n&&(a=n[e])}n=n.parentNode}const i=gn.body[e];return a>i&&(a=i),a},getParentWidth(){return this.getParentRectValue("width")},getParentHeight(){const t=this.$el.chart.style("height");let e=0;return t&&(e=/px$/.test(t)?parseInt(t,10):this.getParentRectValue("height")),e},getSvgLeft(t){const e=this,{config:n,state:{hasAxis:a},$el:i}=e,o=n.axis_rotated,s=o||!o&&!n.axis_y_inner,l=o?Tn.axisX:Tn.axisY,c=i.main.select(`.${l}`).node(),f=a&&n[`axis_${o?"x":"y"}_label`];let g=0;if(a&&(ze(f)||ze(f.text)||/^inner-/.test(f==null?void 0:f.position))){const N=i.main.select(`.${l}-label`);N.empty()||(g=N.node().getBoundingClientRect().left)}const v=c&&s?c.getBoundingClientRect():{right:0},m=i.chart.node().getBoundingClientRect().left+g,S=e.hasArcType(),P=v.right-m-(S?0:e.getCurrentPaddingByDirection("left",t));return P>0?P:0},updateDimension(t){var e;const n=this,{config:a,state:{hasAxis:i},$el:o}=n;i&&!t&&n.axis.x&&a.axis_rotated&&((e=n.axis.subX)==null||e.create(o.axis.subX)),n.updateScales(t),n.updateSvgSize(),n.transformAll(!1)},updateSvgSize(){const t=this,{config:e,state:{clip:n,current:a,hasAxis:i,width:o,height:s},$el:{svg:l}}=t;if(e.resize_auto==="viewBox"?l.attr("viewBox",`0 0 ${a.width} ${a.height}`):l.attr("width",a.width).attr("height",a.height),i){const c=l.select(`.${ks.brush} .overlay`),f={width:0,height:0};c.size()&&(f.width=+c.attr("width"),f.height=+c.attr("height")),l.selectAll([`#${n.id}`,`#${n.idGrid}`]).select("rect").attr("width",o).attr("height",s),l.select(`#${n.idXAxis}`).select("rect").call(t.setXAxisClipPath.bind(t)),l.select(`#${n.idYAxis}`).select("rect").call(t.setYAxisClipPath.bind(t)),n.idSubchart&&l.select(`#${n.idSubchart}`).select("rect").attr("width",o).attr("height",f.height)}},getCurrentPaddingByDirection(t,e=!1,n=!1){var a;const i=this,{config:o,$el:s,state:{hasAxis:l}}=i,c=o.axis_rotated,f=((a=o.padding)==null?void 0:a.mode)==="fit",g=he(o[`padding_${t}`])?o[`padding_${t}`]:void 0,v=l?{top:c?"y2":null,bottom:c?"y":"x",left:c?"x":"y",right:c?null:"y2"}[t]:null,m=/^(left|right)$/.test(t),S=v&&o[`axis_${v}_inner`],P=v&&o[`axis_${v}_show`],N=v?o[`axis_${v}_axes`].length:0;let L=v?m?i.getAxisWidthByAxisId(v,e):i.getHorizontalAxisHeight(v):0;const w=20;let X=0;!f&&m&&(L=Jg(L));let W=l&&m&&(S||ln(g)&&!P)?0:f?(P?L:0)+(g!=null?g:0):ln(g)?L:g;return m&&l?(v&&(f||S)&&o[`axis_${v}_label`].text&&(W+=i.axis.getAxisLabelPosition(v).isOuter?w:0),t==="right"?(W+=c?!f&&ln(g)?10:2:!P||S?f?2:1:0,W+=n?i.axis.getXAxisTickTextY2Overflow(w):0):t==="left"&&c&&ln(g)&&(W=o.axis_x_show?f?L:Math.max(L,40):1)):t==="top"?(s.title&&s.title.node()&&(W+=i.getTitlePadding()),X=c&&!S?N:0):t==="bottom"&&l&&c&&!P&&(W+=1),W+L*N-X},getCurrentPadding(t=!1){const e=this,[n,a,i,o]=["top","bottom","left","right"].map(s=>e.getCurrentPaddingByDirection(s,null,t));return{top:n,bottom:a,left:i,right:o}},getResettedPadding(t){const e=this,{config:n}=e,a=he(t);let i=a?0:{};return n.padding===!1?!a&&Object.keys(t).forEach(o=>{i[o]=!qn(n.data_labels)&&n.data_labels!==!1&&o==="top"?t[o]:0}):i=t,i},updateSizes(t){var e,n,a,i,o;const s=this,{config:l,state:c,$el:{legend:f}}=s,g=l.axis_rotated,v=s.hasArcType()||c.hasFunnel||c.hasTreemap,m=((e=l.padding)==null?void 0:e.mode)==="fit";!t&&s.setContainerSize();const S={width:f?s.getLegendWidth():0,height:f?s.getLegendHeight():0};!v&&l.axis_x_show&&l.axis_x_tick_autorotate&&s.updateXAxisTickClip();const P={right:l.legend_show&&c.isLegendRight?s.getLegendWidth()+(m?0:20):0,bottom:!l.legend_show||c.isLegendRight||c.isLegendInset?0:S.height},N=g||v?0:s.getHorizontalAxisHeight("x"),L=l.subchart_axis_x_show&&l.subchart_axis_x_tick_text_show?N:30,w=l.subchart_show&&!v?l.subchart_size_height+L:0,X=s.hasType("gauge")&&l.arc_needle_show&&!l.gauge_fullCircle&&!l.gauge_label_show?10:0,W=s.getCurrentPadding(!0);if(c.margin=!v&&g?{top:W.top,right:v?0:W.right+P.right,bottom:P.bottom+W.bottom,left:w+(v?0:W.left)}:{top:(m?0:4)+W.top,right:v?0:W.right+P.right,bottom:X+w+P.bottom+W.bottom,left:v?0:W.left},c.margin=s.getResettedPadding(c.margin),c.margin2=g?{top:c.margin.top,right:NaN,bottom:20+P.bottom,left:s.state.rotatedPadding.left}:{top:c.current.height-w-P.bottom,right:NaN,bottom:L+P.bottom,left:c.margin.left},c.margin3={top:0,right:NaN,bottom:0,left:0},(n=s.updateSizeForLegend)==null||n.call(s,S),c.width=c.current.width-c.margin.left-c.margin.right,c.height=c.current.height-c.margin.top-c.margin.bottom,c.width<0&&(c.width=0),c.height<0&&(c.height=0),c.width2=g?c.margin.left-c.rotatedPadding.left-c.rotatedPadding.right:c.width,c.height2=g?c.height:c.current.height-c.margin2.top-c.margin2.bottom,c.width2<0&&(c.width2=0),c.height2<0&&(c.height2=0),s.hasArcType()){const H=s.hasType("gauge"),k=l.legend_show&&c.isLegendRight,K=(a=c.hasRadar&&s.cache.get(Ln.radarTextWidth))!=null?a:0;c.arcWidth=c.width-(k?S.width+10:0)-K,c.arcHeight=c.height-(k&&!H?0:10),(i=l.arc_rangeText_values)!=null&&i.length&&(H?(c.arcWidth-=25,c.arcHeight-=10,c.margin.left+=10):(c.arcHeight-=20,c.margin.top+=10)),H&&!l.gauge_fullCircle&&(c.arcHeight+=c.height-s.getPaddingBottomForGauge()),(o=s.updateRadius)==null||o.call(s)}c.isLegendRight&&v&&(c.margin3.left=c.arcWidth/2+c.radiusExpanded*1.1)}},zp={setCssRule(t,e,n,a){const i=this,{config:o,state:{cssRule:s,style:l}}=i;return o.boost_useCssRule?c=>{c.each(f=>{const g=a&&(a==null?void 0:a.call(i,f)),v=`${t?`.${sn.shapes+i.getTargetSelectorSuffix(f.id)}`:""}${e}`;e in s&&l.sheet.deleteRule(s[v]),i.state.cssRule[v]=_g(l,v,n.filter(Boolean).map(m=>ze(g)&&m.indexOf(":")===-1?`${m}: ${g}`:m||""))})}:()=>{}},getStylePropValue(t){const{config:{boost_useCssRule:e}}=this;return e?null:ve(t)?t.bind(this):t}};function Uc(t){return typeof t=="string"?new Ie([document.querySelectorAll(t)],[document.documentElement]):new Ie([T(t)],_t)}function jp(t){let e="middle";return t>0&&t<=170?e="end":t>190&&t<=360&&(e="start"),e}function Vp(t,e,n,a,i){var o;const s=this,{value:l}=t,c=s.isCandlestickType(t),f=he(l)&&l<0||c&&!((o=s.getCandlestickData(t))!=null&&o._isUp);let{x:g,y:v}=e;const m=4,S=m*2;return a?n==="start"?(g+=f?0:S,v+=m):n==="middle"?(g+=S,v-=S):n==="end"&&(f&&(g-=S),v+=m):(n==="start"?(g+=m,f&&(v+=S*2)):n==="middle"?v-=S:n==="end"&&(g-=m,f&&(v+=S*2)),i&&(v+=f?-17:c?13:7)),{x:g,y:v}}function zc(t,e){var n;const a=this.config.data_labels_position,{id:i,index:o,value:s}=t;return(n=ve(a)?a.bind(this.api)(e,s,i,o,this.$el.text):(i in a?a[i]:a)[e])!=null?n:0}var Gp={opacityForText(t){const e=this;return e.isBarType(t)&&!e.meetsLabelThreshold(Math.abs(e.getRatio("bar",t)),"bar")?"0":e.hasDataLabel?null:"0"},initText(){const{$el:t}=this;t.main.select(`.${Se.chart}`).append("g").attr("class",On.chartTexts).style("pointer-events",t.funnel||t.treemap?"none":null)},updateTargetsForText(t){const e=this,n=e.getChartClass("Text"),a=e.getClass("texts","id"),i=e.classFocus.bind(e);e.$el.main.select(`.${On.chartTexts}`).selectAll(`.${On.chartText}`).data(t).attr("class",l=>`${n(l)}${i(l)}`.trim()).enter().append("g").style("opacity","0").attr("class",n).call(e.setCssRule(!0,` .${On.text}`,["fill","pointer-events:none"],e.updateTextColor)).append("g").attr("class",a)},updateText(){const t=this,{$el:e,$T:n,config:a,axis:i}=t,o=t.getClass("text","index"),s=a.data_labels.centered,l=e.main.selectAll(`.${On.texts}`).selectAll(`.${On.text}`).data(t.labelishData.bind(t));n(l.exit()).style("fill-opacity","0").remove(),e.text=l.enter().append("text").merge(l).attr("class",o).attr("text-anchor",c=>{let g=a[`axis_${i==null?void 0:i.getId(c.id)}_inverted`]?c.value>0:c.value<0;if(t.isCandlestickType(c)){const v=t.getCandlestickData(c);g=!(v!=null&&v._isUp)}else if(t.isTreemapType(c))return s?"middle":"start";return a.axis_rotated?g?"end":"start":"middle"}).style("fill",t.getStylePropValue(t.updateTextColor)).style("fill-opacity","0").each(function(c,f,g){const v=ot(this);let{value:m}=c;if(t.isBubbleZType(c))m=t.getBubbleZData(m,"z");else if(t.isCandlestickType(c)){const S=t.getCandlestickData(c);S&&(m=S.close)}m=t.isTreemapType(c)?t.treemapDataLabelFormat(c)(v):t.dataLabelFormat(c.id)(m,c.id,c.index,g),he(m)?this.textContent=m:wa(v,m)})},updateTextColor(t){const e=this,{config:n}=e,a=n.data_labels_colors,i=e.isArcType(t)&&!e.isRadarType(t)||e.isFunnelType(t)||e.isTreemapType(t)?null:e.color(t);let o;if(ze(a))o=a;else if(Be(a)){const{id:s}=t.data||t;o=a[s]}else ve(a)&&(o=a.bind(e.api)(i,t));if(e.isCandlestickType(t)&&!ve(a)){const s=e.getCandlestickData(t);if(!(s!=null&&s._isUp)){const l=n.candlestick_color_down;o=Be(l)?l[t.id]:l}}return o||i},updateTextBGColor(t,e){const n=this,{$el:a}=n;let i="";if(ze(e)||Be(e)){const o=ze(e)?"":n.getTargetSelectorSuffix("id"in t?t.id:t.data.id),s=a.defs.select(["filter[id*='labels-bg","']"].join(o));s.size()&&(i=`url(#${s.attr("id")})`)}return i||null},redrawText(t,e,n,a){const i=this,{$T:o,axis:s,config:l,state:{hasTreemap:c}}=i,f=gr(!0),g=l.axis_rotated,v=l.data_labels.rotate,m=jp(v),S=v?`rotate(${v})`:"";return i.$el.text.style("fill",i.getStylePropValue(i.updateTextColor)).attr("filter",P=>i.updateTextBGColor.bind(i)(P,l.data_labels_backgroundColors)).style("fill-opacity",n?0:i.opacityForText.bind(i)).each(function(P,N){const L=o(c&&this.childElementCount?this.parentNode:this,!!(a&&this.getAttribute("x")),f),w=l[`axis_${s==null?void 0:s.getId(P.id)}_inverted`];let X={x:t.bind(this)(P,N),y:e.bind(this)(P,N)};v&&(X=Vp.bind(i)(P,X,m,g,w),L.attr("text-anchor",m)),this.childElementCount||v?L.attr("transform",`translate(${X.x} ${X.y}) ${S}`):L.attr("x",X.x).attr("y",X.y)}),!0},getTextRect(t,e){const n=this;let a=t.node?t.node():t;/text/i.test(a.tagName)||(a=a.querySelector("text"));const i=a.textContent,o=`${Ln.textRect}-${i.replace(/\W/g,"_")}`;let s=n.cache.get(o);return s||(n.$el.svg.append("text").style("visibility","hidden").style("font",ot(a).style("font")).classed(e,!0).text(i).call(l=>{s=Ma(l.node())}).remove(),n.cache.add(o,s)),s},generateXYForText(t,e){const n=this,{state:{hasRadar:a,hasFunnel:i,hasTreemap:o}}=n,s=Object.keys(t),l={},c=e?n.getXForText:n.getYForText;return i&&s.push("funnel"),a&&s.push("radar"),o&&s.push("treemap"),s.forEach(f=>{l[f]=n[`generateGet${Cn(f)}Points`](t[f],!1)}),function(f,g){const v=n.isAreaType(f)&&"area"||n.isBarType(f)&&"bar"||n.isCandlestickType(f)&&"candlestick"||n.isFunnelType(f)&&"funnel"||n.isRadarType(f)&&"radar"||n.isTreemapType(f)&&"treemap"||"line";return c.call(n,l[v](f,g),f,this)}},getCenteredTextPos(t,e,n,a){const i=this,{config:o}=i,s=o.axis_rotated,l=i.isBarType(t),c=i.isTreemapType(t);if(o.data_labels.centered&&(l||c)){const f=Ma(n);if(l){const g=i.getRangedData(t,null,"bar")>=0;if(s){const v=(g?e[1][1]-e[0][1]:e[0][1]-e[1][1])/2+f.width/2;return g?-v-3:v+2}else{const v=(g?e[0][1]-e[1][1]:e[1][1]-e[0][1])/2+f.height/2;return g?v:-v-2}}else if(c)return a==="x"?(e[1][0]-e[0][0])/2:(e[1][1]-e[0][1])/2+f.height/2}return 0},getXForText(t,e,n){var a;const i=this,{config:o}=i,s=o.axis_rotated,l=i.isFunnelType(e),c=i.isTreemapType(e);let f=t?t[0][0]:0;if(i.isCandlestickType(e))s?f=(a=i.getCandlestickData(e))!=null&&a._isUp?t[2][2]+4:t[2][1]-4:f+=(t[1][0]-f)/2;else if(l)f+=i.state.current.width/2;else if(c)f+=o.data_labels.centered?0:5;else if(s){const g=o[`axis_${i.axis.getId(e.id)}_inverted`],v=i.isBarType(e)?4:6,m=e.value;f=t[2][1],g?f-=v*(m>0?1:-1):f+=v*(m<0?-1:1)}else f=i.hasType("bar")?(t[2][0]+t[0][0])/2:f;return(s||c)&&(f+=i.getCenteredTextPos(e,t,n,"x")),f+zc.call(this,e,"x")},getYForText(t,e,n){const a=this,{axis:i,config:o,state:s}=a,l=o.axis_rotated,c=o[`axis_${i==null?void 0:i.getId(e.id)}_inverted`],f=a.isBarType(e),g=a.isFunnelType(e),v=a.isTreemapType(e),m=o.point_r,S=Ma(n);let{value:P}=e,N=3,L;if(a.isCandlestickType(e))P=a.getCandlestickData(e),l?(L=t[0][0],L+=(t[1][0]-L)/2+N):(L=P&&P._isUp?t[2][2]-N:t[2][1]+N*4,c&&(L+=15*(P._isUp?1:-1)));else if(g)L=t?t[0][1]+(t[1][1]-t[0][1])/2+S.height/2-3:0;else if(v)L=t[0][1]+(o.data_labels.centered?0:S.height+5);else if(l)L=(t[0][0]+t[2][0]+S.height*.6)/2;else if(L=t[2][1],he(m)&&m>5&&(a.isLineType(e)||a.isScatterType(e))&&(N+=o.point_r/2.3),P<0||P===0&&!s.hasPositiveValue&&s.hasNegativeValue)L+=c?f?-3:-5:S.height+(f?-N:N);else{let w=-N*2;f?w=-N:a.isBubbleType(e)&&(w=N),c&&(w=f?10:15),L+=w}return(!l||v)&&(L+=a.getCenteredTextPos(e,t,n,"y")),L+zc.call(this,e,"y")},markOverlapped(t,e,n){const a=e.$el.arcs.selectAll(n),i=a.filter(c=>c.data.id!==t),o=a.filter(c=>c.data.id===t),s=Jl(o.node()),l=(c,f)=>Math.sqrt(Math.pow(c,2)+Math.pow(f,2));o.node()&&i.each(function(){const c=Jl(this),f=ot(this),g=l(s.e,s.f)>l(c.e,c.f)?o:f,v=Math.ceil(Math.abs(s.e-c.e))=i}};function jc(t="left",e){const n=he(e);let a;return t.indexOf("center")>-1?a=n?e/2:"middle":t.indexOf("right")>-1?a=n?e:"end":a=n?0:"start",a}var Xp={initTitle(){const t=this,{config:e,$el:n}=t;if(e.title_text){n.title=n.svg.append("g");const a=n.title.append("text").style("text-anchor",jc(e.title_position)).attr("class",On.title);wa(a,e.title_text,[.3,1.5])}},redrawTitle(){const t=this,{config:e,state:{current:n},$el:{title:a}}=t;if(a){const i=jc(e.title_position,n.width),o=(e.title_padding.top||0)+t.getTextRect(t.$el.title,On.title).height;a.attr("transform",`translate(${i}, ${o})`)}},getTitlePadding(){const t=this,{$el:{title:e},config:n}=t;return(n.title_padding.top||0)+(e?t.getTextRect(e,On.title).height:0)+(n.title_padding.bottom||0)}},Hp={initTooltip(){const t=this,{config:e,$el:n}=t;n.tooltip=ot(e.tooltip_contents.bindto),n.tooltip.empty()&&(n.tooltip=n.chart.append("div").attr("class",ei.tooltipContainer).style("position","absolute").style("pointer-events","none").style("display","none")),t.bindTooltipResizePos()},initShowTooltip(){var t;const e=this,{config:n,$el:a,state:{hasAxis:i,hasRadar:o}}=e;if(n.tooltip_init_show){const s=!(i||o);(t=e.axis)!=null&&t.isTimeSeries()&&ze(n.tooltip_init_x)&&(n.tooltip_init_x=Yn.call(e,n.tooltip_init_x)),e.api.tooltip.show({data:{[s?"index":"x"]:n.tooltip_init_x}});const l=n.tooltip_init_position;if(!n.tooltip_contents.bindto&&!qn(l)){const{top:c=0,left:f=50}=l;a.tooltip.style("top",ze(c)?c:`${c}px`).style("left",ze(f)?f:`${f}px`).style("display",null)}}},getTooltipHTML(...t){const e=this,{api:n,config:a}=e;return ve(a.tooltip_contents)?a.tooltip_contents.bind(n)(...t):e.getTooltipContent(...t)},getTooltipContent(t,e,n,a){var i;const o=this,{api:s,config:l,state:c,$el:f}=o,[g,v,m]=["title","name","value"].map(vt=>{const Q=l[`tooltip_format_${vt}`];return ve(Q)?Q.bind(s):Q}),S=(...vt)=>Po((g||e)(...vt)),P=(...vt)=>Po((v||(Q=>Q))(...vt)),N=(...vt)=>{const Q=m||(c.hasTreemap||o.isStackNormalized()?(St,ct)=>`${(ct*100).toFixed(2)}%`:n);return Po(Q(...vt))},L=l.tooltip_order,w=vt=>o.axis&&o.isBubbleZType(vt)?o.getBubbleZData(vt.value,"z"):o.getBaseValue(vt),X=o.levelColor?vt=>o.levelColor(vt.value):vt=>a(vt),W=l.tooltip_contents,H=W.template,k=o.mapToTargetIds();if(L===null&&l.data_groups.length){const vt=o.orderTargets(o.data.targets).map(Q=>Q.id).reverse();t.sort((Q,St)=>{let ct=Q?Q.value:null,At=St?St.value:null;return ct>0&&At>0&&(ct=Q.id?vt.indexOf(Q.id):null,At=St.id?vt.indexOf(St.id):null),ct-At})}else if(/^(asc|desc)$/.test(L)){const vt=L==="asc";t.sort((Q,St)=>{const ct=Q?w(Q):null,At=St?w(St):null;return vt?ct-At:At-ct})}else ve(L)&&t.sort(L.bind(s));const K=o.getTooltipContentTemplate(H),at=t.length;let ht,$t,dt,st,Vt;for(Vt=0;Vt${vt}`:""})}if(!$t.ratio&&f.arcs&&(dt=["arc",o.$el.arcs.select(`path.${Ve.arc}-${$t.id}`).data()[0]],$t.ratio=o.getRatio(...dt)),dt=[$t.ratio,$t.id,$t.index],o.isAreaRangeType($t)){const[vt,Q]=["high","low"].map(ct=>N(o.getRangedData($t,ct),...dt));st=`Mid: ${N(w($t),...dt)} High: ${vt} Low: ${Q}`}else if(o.isCandlestickType($t)){const[vt,Q,St,ct,At]=["open","high","low","close","volume"].map(Gt=>o.getRangedData($t,Gt,"candlestick")?N(o.getRangedData($t,Gt,"candlestick"),...dt):void 0);st=`Open: ${vt} High: ${Q} Low: ${St} Close: ${ct}${At?` Volume: ${At}`:""}`}else if(o.isBarRangeType($t)){const{value:vt,id:Q,index:St}=$t;st=`${N(vt,void 0,Q,St)}`}else st=N(w($t),...dt);if(st!==void 0){if($t.name===null)continue;const vt=P((i=$t.name)!=null?i:$t.id,...dt),Q=X($t),St={CLASS_TOOLTIP_NAME:ei.tooltipName+o.getTargetSelectorSuffix($t.id),COLOR:H||!o.patterns?Q:``,NAME:vt,VALUE:st};if(H&&Be(W.text)){const ct=k.indexOf($t.id);Object.keys(W.text).forEach(At=>{St[At]=W.text[At][ct]})}ht+=bi(K[1],St)}}return`${ht}`},getTooltipContentTemplate(t){return(t||` {=TITLE} {{}}
      ${this.patterns?"{=COLOR}":''}{=NAME} {=VALUE}
      `).replace(/(\r?\n|\t)/g,"").split(/{{(.*)}}/)},setTooltipPosition(t,e){var n,a;const i=this,{config:o,scale:s,state:l,$el:{eventRect:c,tooltip:f,svg:g}}=i,{bindto:v}=o.tooltip_contents,m=o.axis_rotated,S=f==null?void 0:f.datum();if(!v&&S){const P=t!=null?t:JSON.parse(S.current),[N,L]=Hn(l.event,e!=null?e:c==null?void 0:c.node()),w={x:N,y:L};if(l.hasAxis&&s.x&&S&&"x"in S){const k=(K=0,at,ht="y")=>{var $t;const dt=s[at?($t=i.axis)==null?void 0:$t.getId(at):ht];return dt?dt(K)+(m?l.margin.left:l.margin.top):0};w.xAxis=s.x(S.x)+(o.tooltip_position?m?l.margin.top:l.margin.left:0),P.length===1?w.yAxis=k(P[0].value,P[0].id):w.yAxis=k}const{width:X=0,height:W=0}=S,H=(a=(n=o.tooltip_position)==null?void 0:n.bind(i.api)(P,X,W,c==null?void 0:c.node(),w))!=null?a:Lo(g)?i.getTooltipPositionViewBox.bind(i)(X,W,w):i.getTooltipPosition.bind(i)(X,W,w);["top","left"].forEach(k=>{const K=H[k];f.style(k,`${K}px`),k==="left"&&!S.xPosInPercent&&(S.xPosInPercent=K/l.current.width*100)})}},getTooltipPositionViewBox(t,e,n){var a,i;const o=this,{$el:{eventRect:s,svg:l},config:c,state:f}=o,g=c.axis_rotated,v=o.hasArcType()||f.hasFunnel||f.hasTreemap,m=(i=(a=v?l:s)==null?void 0:a.node())!=null?i:f.event.target;let{x:S,y:P}=n;f.hasAxis&&(S=g?S:n.xAxis,P=g?n.xAxis:P);const N=Ai(m,S,P,!1),L=m.getBoundingClientRect(),w=Ai(m,20,0,!1).x;let X=N.y,W=N.x+t/2+w;return v&&(f.hasFunnel||f.hasTreemap||f.hasRadar?(W-=t/2+w,X+=e):(X+=L.height/2,W+=L.width/2-(t-w))),W+t>L.width&&(W=L.width-t-w),X+e>L.height&&(X-=e*2),{top:X,left:W}},getTooltipPosition(t,e,n){var a,i,o;const s=this,{config:l,scale:c,state:f}=s,{width:g,height:v,current:m,hasFunnel:S,hasRadar:P,hasTreemap:N,isLegendRight:L,inputType:w}=f,X=s.hasType("gauge")&&!l.gauge_fullCircle,W=l.axis_rotated,H=s.hasArcType(),k=s.getSvgLeft(!0);let K=k+m.width-s.getCurrentPaddingByDirection("right");const at=20;let{x:ht,y:$t}=n;if(P)ht+=ht>=g/2?15:-(t+15),$t+=15;else if(H){if(w!=="touch"){let Vt=(i=(a=s.getTitlePadding)==null?void 0:a.call(s))!=null?i:0;Vt&&X&&((o=l.arc_rangeText_values)!=null&&o.length)&&(Vt+=10),ht+=(g-(L?s.getLegendWidth():0))/2,$t+=(X?v:v/2+e)+Vt}}else if(S||N)$t+=e;else{const st={top:s.getCurrentPaddingByDirection("top",!0),left:s.getCurrentPaddingByDirection("left",!0)};W?(ht+=k+st.left+at,$t=st.top+n.xAxis+at,K-=k):(ht=k+st.left+at+(c.zoom?ht:n.xAxis),$t+=st.top-5)}if(ht+t+15>K&&(ht-=t+(S||N||H?0:W?at*2:38)),$t+e>m.height){const st=N?e+10:30;$t-=X?e*1.5:e+st}const dt={top:$t,left:ht};return Object.keys(dt).forEach(st=>{dt[st]<0&&(dt[st]=0)}),dt},showTooltip(t,e){const n=this,{config:a,$el:{tooltip:i}}=n,o=t.filter(c=>c&&De(n.getBaseValue(c)));if(!i||o.length===0||!a.tooltip_show)return;let s=i.datum();const l=JSON.stringify(t);if(!s||s.current!==l){const{index:c,x:f}=t.concat().sort()[0];_e(a.tooltip_onshow,n.api,t),i.html(n.getTooltipHTML(t,n.axis?n.axis.getXAxisTickFormat():n.categoryName.bind(n),n.getDefaultValueFormat(),n.color)).style("display",null).style("visibility",null).datum(s={index:c,x:f,current:l,width:i.property("offsetWidth"),height:i.property("offsetHeight")}),_e(a.tooltip_onshown,n.api,t),n._handleLinkedCharts(!0,c)}n.setTooltipPosition(o,e)},bindTooltipResizePos(){const t=this,{resizeFunction:e,state:n,$el:{tooltip:a}}=t;e.add(()=>{if(a.style("display")==="block"){const{current:i}=n,{width:o,xPosInPercent:s}=a.datum();let l=i.width/100*s;const c=i.width-(l+o);c<0&&(l+=c),a.style("left",`${l}px`)}})},hideTooltip(t){var e;const n=this,{api:a,config:i,$el:{tooltip:o}}=n;if(o&&o.style("display")!=="none"&&(!i.tooltip_doNotHide||t)){const s=JSON.parse((e=o.datum().current)!=null?e:{});_e(i.tooltip_onhide,a,s),o.style("display","none").style("visibility","hidden").datum(null),_e(i.tooltip_onhidden,a,s)}},_handleLinkedCharts(t,e){const n=this,{charts:a,config:i,state:{event:o}}=n;if(o!=null&&o.isTrusted&&i.tooltip_linked&&a.length>1){const s=i.tooltip_linked_name;a.filter(l=>l!==n.api).forEach(l=>{const{config:c,$el:f}=l.internal,g=c.tooltip_linked,v=c.tooltip_linked_name,m=gn.body.contains(f.chart.node());if(g&&s===v&&m){const S=f.tooltip.data()[0],P=e!==(S==null?void 0:S.index);try{l.tooltip[t&&P?"show":"hide"]({index:e})}catch(N){}}})}},updateTooltipOnRedraw(t,e){var n;const a=this,{config:i,$el:{eventRect:o,svg:s,tooltip:l},state:{event:c,hasAxis:f,hasRadar:g,hasTreemap:v}}=a;if((l==null?void 0:l.style("display"))==="block"&&c){const m=t!=null?t:(n=g?s:o)==null?void 0:n.node();if(f||g)if(a.isMultipleX())a.selectRectForMultipleXs(m,!1);else{const S=e!=null?e:a.getDataIndexFromEvent(c);e===-1?a.api.tooltip.hide():(a.selectRectForSingle(m,S),a.setExpand(S,null,!0))}else{const{clientX:S,clientY:P}=c;setTimeout(()=>{let N=[S,P].every(Number.isFinite)&&gn.elementFromPoint(S,P);const L=N&&ot(N).datum();if(L){const w=a.hasArcType()?a.convertToArcData(a.updateAngle(L)):L==null?void 0:L.data;v&&(N=s.node()),w&&a.showTooltip([w],N)}else a.api.tooltip.hide()},i.transition_duration)}}}},Yp={getTranslate(t,e=0){var n;const a=this,{config:i,state:o}=a,s=i.axis_rotated;let l=0,c,f;if(e&&/^(x|y2?)$/.test(t)&&(l=a.getAxisSize(t)*e),t==="main")c=$i(o.margin.left),f=$i(o.margin.top);else if(t==="context")c=$i(o.margin2.left),f=$i(o.margin2.top);else if(t==="legend")c=o.margin3.left,f=o.margin3.top;else if(t==="x")c=s?-l:0,f=s?0:o.height+l;else if(t==="y")c=s?0:-l,f=s?o.height+l:0;else if(t==="y2")c=s?0:o.width+l,f=s?-l-1:0;else if(t==="subX")c=0,f=s?0:o.height2;else if(t==="arc")c=o.arcWidth/2,f=o.arcHeight/2,(n=i.arc_rangeText_values)!=null&&n.length&&(f+=5+(a.hasType("gauge")&&i.title_text?10:0));else if(t==="polar")c=o.arcWidth/2,f=o.arcHeight/2;else if(t==="radar"){const[g,v]=a.getRadarSize();c=o.width/2-g,f=o.height/2-v}return`translate(${c}, ${f})`},transformMain(t,e){const n=this,{$el:{main:a},$T:i}=n,o=e!=null&&e.axisX?e.axisX:i(a.select(`.${Tn.axisX}`),t),s=e!=null&&e.axisY?e.axisY:i(a.select(`.${Tn.axisY}`),t),l=e!=null&&e.axisY2?e.axisY2:i(a.select(`.${Tn.axisY2}`),t);i(a,t).attr("transform",n.getTranslate("main")),o.attr("transform",n.getTranslate("x")),s.attr("transform",n.getTranslate("y")),l.attr("transform",n.getTranslate("y2")),a.select(`.${Ve.chartArcs}`).attr("transform",n.getTranslate("arc"))},transformAll(t,e){const n=this,{config:a,state:{hasAxis:i,hasFunnel:o,hasTreemap:s},$el:l}=n;!o&&!s&&n.transformMain(t,e),i&&a.subchart_show&&n.transformContext(t,e),l.legend&&n.transformLegend(t)}},Wp={isValidChartType(t){return!!(t&&Object.values(oe).indexOf(t)>-1)},setTargetType(t,e){const n=this,{config:a,state:{withoutFadeIn:i}}=n;n.mapToTargetIds(t).forEach(o=>{i[o]=e===a.data_types[o],a.data_types[o]=e}),t||(a.data_type=e)},updateTypesElements(){const t=this,{state:{current:e}}=t;Object.keys(oe).forEach(n=>{const a=oe[n],i=t.hasType(a,null,!0),o=e.types.indexOf(a);o===-1&&i?e.types.push(a):o>-1&&!i&&e.types.splice(o,1)}),t.setChartElements()},hasType(t,e,n=!1){var a;const i=this,{config:o,state:{current:s}}=i,l=o.data_types,c=e||i.data.targets;let f=!1;return!n&&((a=s.types)==null?void 0:a.indexOf(t))>-1?f=!0:c!=null&&c.length?c.forEach(g=>{const v=l[g.id];(v===t||!v&&t==="line")&&(f=!0)}):Object.keys(l).length?Object.keys(l).forEach(g=>{l[g]===t&&(f=!0)}):f=o.data_type===t,f},hasTypeOf(t,e,n=[]){return t in Sr?!Sr[t].filter(a=>n.indexOf(a)===-1).every(a=>!this.hasType(a,e)):!1},isTypeOf(t,e){var n;const a=ze(t)?t:t.id,i=this.config&&(((n=this.config.data_types)==null?void 0:n[a])||this.config.data_type);return je(e)?e.indexOf(i)>=0:i===e},hasPointType(){const t=this;return t.hasTypeOf("Line")||t.hasType("bubble")||t.hasType("scatter")},hasArcType(t,e){return this.hasTypeOf("Arc",t,e)},hasMultiArcGauge(){return this.hasType("gauge")&&this.config.gauge_type==="multi"},isLineType(t){const e=ze(t)?t:t.id;return!this.config.data_types[e]||this.isTypeOf(e,Sr.Line)},isStepType(t){return this.isTypeOf(t,Sr.Step)},isSplineType(t){return this.isTypeOf(t,Sr.Spline)},isAreaType(t){return this.isTypeOf(t,Sr.Area)},isAreaRangeType(t){return this.isTypeOf(t,Sr.AreaRange)},isBarType(t){return this.isTypeOf(t,"bar")},isBubbleType(t){return this.isTypeOf(t,"bubble")},isCandlestickType(t){return this.isTypeOf(t,"candlestick")},isScatterType(t){return this.isTypeOf(t,"scatter")},isTreemapType(t){return this.isTypeOf(t,"treemap")},isPieType(t){return this.isTypeOf(t,"pie")},isFunnelType(t){return this.isTypeOf(t,"funnel")},isGaugeType(t){return this.isTypeOf(t,"gauge")},isDonutType(t){return this.isTypeOf(t,"donut")},isPolarType(t){return this.isTypeOf(t,"polar")},isRadarType(t){return this.isTypeOf(t,"radar")},isArcType(t){return this.isPieType(t)||this.isDonutType(t)||this.isGaugeType(t)||this.isPolarType(t)||this.isRadarType(t)},isCirclePoint(t){const{config:e}=this,n=e.point_pattern;let a=!1;return(t==null?void 0:t.tagName)==="circle"?a=!0:a=e.point_type==="circle"&&(!n||je(n)&&n.length===0),a},lineData(t){return this.isLineType(t)?[t]:[]},arcData(t){return this.isArcType(t.data)?[t]:[]},labelishData(t){return this.isBarType(t)||this.isLineType(t)||this.isScatterType(t)||this.isBubbleType(t)||this.isCandlestickType(t)||this.isFunnelType(t)||this.isRadarType(t)||this.isTreemapType(t)?t.values.filter(e=>he(e.value)||!!e.value):[]},barLineBubbleData(t){return this.isBarType(t)||this.isLineType(t)||this.isBubbleType(t)?t.values:[]},isInterpolationType(t){return["basis","basis-closed","basis-open","bundle","cardinal","cardinal-closed","cardinal-open","catmull-rom","catmull-rom-closed","catmull-rom-open","linear","linear-closed","monotone-x","monotone-y","natural"].indexOf(t)>=0}};function Ni(t,e,n){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+e)/6,(t._y0+4*t._y1+n)/6)}function Fi(t){this._context=t}Fi.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Ni(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1);break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Ni(this,t,e);break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}};function Kp(t){return new Fi(t)}function Ar(){}function Vc(t){this._context=t}Vc.prototype={areaStart:Ar,areaEnd:Ar,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:{this._context.moveTo(this._x2,this._y2),this._context.closePath();break}case 2:{this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break}case 3:{this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4);break}}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x2=t,this._y2=e;break;case 1:this._point=2,this._x3=t,this._y3=e;break;case 2:this._point=3,this._x4=t,this._y4=e,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+e)/6);break;default:Ni(this,t,e);break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}};function Zp(t){return new Vc(t)}function Gc(t){this._context=t}Gc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var n=(this._x0+4*this._x1+t)/6,a=(this._y0+4*this._y1+e)/6;this._line?this._context.lineTo(n,a):this._context.moveTo(n,a);break;case 3:this._point=4;default:Ni(this,t,e);break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}};function Jp(t){return new Gc(t)}function Xc(t,e){this._basis=new Fi(t),this._beta=e}Xc.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,e=this._y,n=t.length-1;if(n>0)for(var a=t[0],i=e[0],o=t[n]-a,s=e[n]-i,l=-1,c;++l<=n;)c=l/n,this._basis.point(this._beta*t[l]+(1-this._beta)*(a+c*o),this._beta*e[l]+(1-this._beta)*(i+c*s));this._x=this._y=null,this._basis.lineEnd()},point:function(t,e){this._x.push(+t),this._y.push(+e)}};var Qp=function t(e){function n(a){return e===1?new Fi(a):new Xc(a,e)}return n.beta=function(a){return t(+a)},n}(.85);function Bi(t,e,n){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-e),t._y2+t._k*(t._y1-n),t._x2,t._y2)}function ls(t,e){this._context=t,this._k=(1-e)/6}ls.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Bi(this,this._x1,this._y1);break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2,this._x1=t,this._y1=e;break;case 2:this._point=3;default:Bi(this,t,e);break}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var kp=function t(e){function n(a){return new ls(a,e)}return n.tension=function(a){return t(+a)},n}(0);function cs(t,e){this._context=t,this._k=(1-e)/6}cs.prototype={areaStart:Ar,areaEnd:Ar,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:{this._context.moveTo(this._x3,this._y3),this._context.closePath();break}case 2:{this._context.lineTo(this._x3,this._y3),this._context.closePath();break}case 3:{this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5);break}}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:Bi(this,t,e);break}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var qp=function t(e){function n(a){return new cs(a,e)}return n.tension=function(a){return t(+a)},n}(0);function us(t,e){this._context=t,this._k=(1-e)/6}us.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Bi(this,t,e);break}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var _p=function t(e){function n(a){return new us(a,e)}return n.tension=function(a){return t(+a)},n}(0);const Hc=Math.abs,En=Math.atan2,jr=Math.cos,tm=Math.max,fs=Math.min,rr=Math.sin,oa=Math.sqrt,bn=1e-12,Fa=Math.PI,Ui=Fa/2,zi=2*Fa;function em(t){return t>1?0:t<-1?Fa:Math.acos(t)}function Yc(t){return t>=1?Ui:t<=-1?-Ui:Math.asin(t)}function ds(t,e,n){var a=t._x1,i=t._y1,o=t._x2,s=t._y2;if(t._l01_a>bn){var l=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);a=(a*l-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*l-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>bn){var f=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,g=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*f+t._x1*t._l23_2a-e*t._l12_2a)/g,s=(s*f+t._y1*t._l23_2a-n*t._l12_2a)/g}t._context.bezierCurveTo(a,i,o,s,t._x2,t._y2)}function Wc(t,e){this._context=t,this._alpha=e}Wc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2);break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,a=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+a*a,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3;default:ds(this,t,e);break}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var nm=function t(e){function n(a){return e?new Wc(a,e):new ls(a,0)}return n.alpha=function(a){return t(+a)},n}(.5);function Kc(t,e){this._context=t,this._alpha=e}Kc.prototype={areaStart:Ar,areaEnd:Ar,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:{this._context.moveTo(this._x3,this._y3),this._context.closePath();break}case 2:{this._context.lineTo(this._x3,this._y3),this._context.closePath();break}case 3:{this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5);break}}},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,a=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+a*a,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:ds(this,t,e);break}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var rm=function t(e){function n(a){return e?new Kc(a,e):new cs(a,0)}return n.alpha=function(a){return t(+a)},n}(.5);function Zc(t,e){this._context=t,this._alpha=e}Zc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,a=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+a*a,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:ds(this,t,e);break}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var am=function t(e){function n(a){return e?new Zc(a,e):new us(a,0)}return n.alpha=function(a){return t(+a)},n}(.5);function Jc(t){return t<0?-1:1}function Qc(t,e,n){var a=t._x1-t._x0,i=e-t._x1,o=(t._y1-t._y0)/(a||i<0&&-0),s=(n-t._y1)/(i||a<0&&-0),l=(o*i+s*a)/(a+i);return(Jc(o)+Jc(s))*Math.min(Math.abs(o),Math.abs(s),.5*Math.abs(l))||0}function kc(t,e){var n=t._x1-t._x0;return n?(3*(t._y1-t._y0)/n-e)/2:e}function hs(t,e,n){var a=t._x0,i=t._y0,o=t._x1,s=t._y1,l=(o-a)/3;t._context.bezierCurveTo(a+l,i+l*e,o-l,s-l*n,o,s)}function ji(t){this._context=t}ji.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:hs(this,this._t0,kc(this,this._t0));break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){var n=NaN;if(t=+t,e=+e,!(t===this._x1&&e===this._y1)){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,hs(this,kc(this,n=Qc(this,t,e)),n);break;default:hs(this,this._t0,n=Qc(this,t,e));break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e,this._t0=n}}};function qc(t){this._context=new _c(t)}(qc.prototype=Object.create(ji.prototype)).point=function(t,e){ji.prototype.point.call(this,e,t)};function _c(t){this._context=t}_c.prototype={moveTo:function(t,e){this._context.moveTo(e,t)},closePath:function(){this._context.closePath()},lineTo:function(t,e){this._context.lineTo(e,t)},bezierCurveTo:function(t,e,n,a,i,o){this._context.bezierCurveTo(e,t,a,n,o,i)}};function im(t){return new ji(t)}function om(t){return new qc(t)}function tu(t){this._context=t}tu.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,e=this._y,n=t.length;if(n)if(this._line?this._context.lineTo(t[0],e[0]):this._context.moveTo(t[0],e[0]),n===2)this._context.lineTo(t[1],e[1]);else for(var a=eu(t),i=eu(e),o=0,s=1;s=0;--e)i[e]=(s[e]-i[e+1])/o[e];for(o[n-1]=(t[n]+i[n-1])/2,e=0;e=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:{if(this._t<=0)this._context.lineTo(this._x,e),this._context.lineTo(t,e);else{var n=this._x*(1-this._t)+t*this._t;this._context.lineTo(n,this._y),this._context.lineTo(n,e)}break}}this._x=t,this._y=e}};function cm(t){return new Vi(t,.5)}function um(t){return new Vi(t,0)}function fm(t){return new Vi(t,1)}function dm(t){const e=this;let n;return e.isLineType(t)?n=e.generateGetLinePoints(e.getShapeIndices(e.isLineType)):e.isBarType(t)&&(n=e.generateGetBarPoints(e.getShapeIndices(e.isBarType))),n}var hm={getDrawShape(){const t=this,e=t.config.axis_rotated,{hasRadar:n,hasTreemap:a}=t.state,i={type:{},indices:{},pos:{}};if(!a&&["bar","candlestick","line","area"].forEach(o=>{const s=Cn(/^(bubble|scatter)$/.test(o)?"line":o);if(t.hasType(o)||t.hasTypeOf(s)||o==="line"&&(t.hasType("bubble")||t.hasType("scatter"))){const l=t.getShapeIndices(t[`is${s}Type`]),c=t[`generateDraw${s}`];i.indices[o]=l,i.type[o]=c?c.bind(t)(l,!1):void 0}}),!t.hasArcType()||n||a){let o,s;a||(o=n?t.radarCircleX:e?t.circleY:t.circleX,s=n?t.radarCircleY:e?t.circleX:t.circleY),i.pos={xForText:t.generateXYForText(i.indices,!0),yForText:t.generateXYForText(i.indices,!1),cx:(o||function(){}).bind(t),cy:(s||function(){}).bind(t)}}return i},getShapeIndices(t){const e=this,{config:n}=e,a=n.data_xs,i=cn(a),o={};let s=i?{}:0;return i&&Mo(Object.keys(a).map(l=>a[l])).forEach(l=>{s[l]=0,o[l]={}}),e.filterTargetsToShow(e.data.targets.filter(t,e)).forEach(l=>{var c;const f=l.id in a?a[l.id]:"",g=f?o[f]:o;for(let v=0,m;m=n.data_groups[v];v++)if(!(m.indexOf(l.id)<0))for(let S=0,P;P=m[S];S++){if(P in g){g[l.id]=g[P];break}l.id!==P&&f&&(g[P]=(c=g[l.id])!=null?c:s[f])}ln(g[l.id])&&(g[l.id]=f?s[f]++:s++,g.__max__=(f?s[f]:s)-1)}),o},getIndices(t,e,n){const a=this,{data_xs:i,bar_indices_removeNull:o}=a.config,{id:s,index:l}=e;if(a.isBarType(s)&&o){const c={};return a.getAllValuesOnIndex(l,!0).forEach((f,g)=>{c[f.id]=g,c.__max__=g}),c}return cn(i)?t[i[s]]:t},getIndicesMax(t){return cn(this.config.data_xs)?Object.keys(t).map(e=>t[e].__max__||0).reduce((e,n)=>e+n):t.__max__},getShapeX(t,e,n){const a=this,{config:i,scale:o}=a,s=n?o.subX:o.zoom||o.x,l=i.bar_overlap,c=i.bar_padding,f=(v,m)=>v+m,g=nr(t)&&(t._$total.length?t._$total.reduce(f)/2:0);return v=>{const m=a.getIndices(e,v,"getShapeX"),S=v.id in m?m[v.id]:0,P=(m.__max__||0)+1;let N=0;if(cn(v.x)){const L=s(v.x,!0);if(g){const w=t[v.id]||t._$width;N=l?L-w/2:L-w+t._$total.slice(0,S+1).reduce(f)-g}else N=L-(he(t)?t:t._$width)*(P/2-(l?1:S))}return t&&N&&P>1&&c&&(S&&(N+=c*S),P>2?N-=(P-1)*c/2:P===2&&(N-=c/2)),N}},getShapeY(t){const e=this,n=e.isStackNormalized();return a=>{let{value:i}=a;return he(a)?i=a:e.isAreaRangeType(a)?i=e.getBaseValue(a,"mid"):n?i=e.getRatio("index",a,!0):e.isBubbleZType(a)?i=e.getBubbleZData(a.value,"y"):e.isBarRangeType(a)&&(i=i[1]),e.getYScaleById(a.id,t)(i)}},getShapeYMin(t){const e=this,n=e.axis.getId(t),a=e.scale[n],[i]=a.domain(),o=e.config[`axis_${n}_inverted`];return!e.isGrouped(t)&&!o&&i>0?i:0},getShapeOffsetData(t){const e=this,n=e.orderTargets(e.filterTargetsToShow(e.data.targets.filter(t,e))),a=e.isStackNormalized(),i=n.map(s=>{let l=s.values;const c={};e.isStepType(s)&&(l=e.convertValuesToStep(l));const f=l.reduce((g,v)=>{const m=Number(v.x);return g[m]=v,c[m]=a?e.getRatio("index",v,!0):v.value,g},{});return{id:s.id,rowValues:l,rowValueMapByXValue:f,values:c}});return{indexMapByTargetId:n.reduce((s,{id:l},c)=>(s[l]=c,s),{}),shapeOffsetTargets:i}},getShapeOffset(t,e,n){const a=this,{shapeOffsetTargets:i,indexMapByTargetId:o}=a.getShapeOffsetData(t),s=a.config.data_groupsZeroAs;return(l,c)=>{const{id:f,value:g,x:v}=l,m=a.getIndices(e,l),S=a.getYScaleById(f,n);if(a.isBarRangeType(l))return S(g[0]);const P=Number(v),N=S(s==="zero"?0:a.getShapeYMin(f));let L=N;return i.filter(w=>w.id!==f&&m[w.id]===m[f]).forEach(w=>{const{id:X,rowValueMapByXValue:W,rowValues:H,values:k}=w;if(o[X]=0&&he(K)&&(g!==0||s==="positive"&&K>0||s==="negative"&&K<0)&&(L+=S(K)-N)}}),L}},circleY(t,e){const n=this,a=t.id;let i;return n.isGrouped(a)&&(i=dm.bind(n)(t)),i?i(t,e)[0][1]:n.getYScaleById(a)(n.getBaseValue(t))},getBarW(t,e,n){var a,i,o,s,l;const c=this,{config:f,org:g,scale:v,state:m}=c,S=c.getMaxDataCount(),P=t==="bar"&&((a=f.data_groups)==null?void 0:a.length),N=`${t}_width`,{k:L}=(o=(i=c.getZoomTransform)==null?void 0:i.call(c))!=null?o:{k:1},w=[(s=f.axis_x_min)!=null?s:g.xDomain[0],(l=f.axis_x_max)!=null?l:g.xDomain[1]].map(c.axis.isTimeSeries()?Yn.bind(c):Number);let X=e.tickInterval(S);if(v.zoom&&!c.axis.isCategorized()&&L>1){const k=w.every((K,at)=>K===g.xDomain[at]);X=g.xDomain.map((K,at)=>{const ht=k?K:K-Math.abs(w[at]);return v.zoom(ht)}).reduce((K,at)=>Math.abs(K)+at)/S}const W=k=>{const K=k?f[N][k]:f[N],at=k?K.ratio:f[`${N}_ratio`],ht=k?K.max:f[`${N}_max`],$t=he(K)?K:ve(K)?K.call(c,m.width,n,S):n?X*at/n:0;return ht&&$t>ht?ht:$t};let H=W();return!P&&nr(f[N])&&(H={_$width:H,_$total:[]},c.filterTargetsToShow(c.data.targets).forEach(k=>{f[N][k.id]&&(H[k.id]=W(k.id),H._$total.push(H[k.id]||H._$width))})),H},getShapeByIndex(t,e,n){const a=this,{$el:i}=a,o=De(e)?`-${e}`:"";let s=i[t];return s&&!s.empty()?s=s.filter(l=>n?l.id===n:!0).filter(l=>De(e)?l.index===e:!0):s=(n?i.main.selectAll(`.${Ue[`${t}s`]}${a.getTargetSelectorSuffix(n)}`):i.main).selectAll(`.${Ue[t]}${o}`),s},isWithinShape(t,e){var n;const a=this,i=ot(t);let o;return a.isTargetToShow(e.id)?(n=a.hasValidPointType)!=null&&n.call(a,t.nodeName)?o=a.isStepType(e)?a.isWithinStep(t,a.getYScaleById(e.id)(a.getBaseValue(e))):a.isWithinCircle(t,a.isBubbleType(e)?a.pointSelectR(e)*1.5:0):t.nodeName==="path"&&(o=i.classed(Ue.bar)?a.isWithinBar(t):!0):o=!1,o},getInterpolate(t){const n=this.getInterpolateType(t);return{basis:Kp,"basis-closed":Zp,"basis-open":Jp,bundle:Qp,cardinal:kp,"cardinal-closed":qp,"cardinal-open":_p,"catmull-rom":nm,"catmull-rom-closed":rm,"catmull-rom-open":am,"monotone-x":im,"monotone-y":om,natural:sm,"linear-closed":lm,linear:gs,step:cm,"step-after":fm,"step-before":um}[n]},getInterpolateType(t){const e=this,{config:n}=e,a=n.spline_interpolation_type,i=e.isInterpolationType(a)?a:"cardinal";return e.isSplineType(t)?i:e.isStepType(t)?n.line_step_type:"linear"},isWithinBar(t){const e=Hn(this.state.event,t),n=Hl(t),[a,i]=n,o=Math.min(a.x,i.x),s=Math.min(a.y,i.y),l=this.config.bar_sensitivity,{width:c,height:f}=t.getBBox(),g=o-l,v=o+c+l,m=s+f+l,S=s-l;return ge in t?gm(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,Rn=(t,e,n)=>vm(t,typeof e!="symbol"?e+"":e,n);class Vr{constructor(e){Rn(this,"api"),Rn(this,"config"),Rn(this,"cache"),Rn(this,"$el"),Rn(this,"state"),Rn(this,"charts"),Rn(this,"data",{xs:{},targets:[]}),Rn(this,"axis"),Rn(this,"scale",{x:null,y:null,y2:null,subX:null,subY:null,subY2:null,zoom:null}),Rn(this,"org",{xScale:null,xDomain:null}),Rn(this,"color"),Rn(this,"patterns"),Rn(this,"levelColor"),Rn(this,"point"),Rn(this,"brush"),Rn(this,"format",{extraLineClasses:null,xAxisTick:null,dataTime:null,defaultAxisTime:null,axisTime:null});const n=this;n.api=e,n.config=new Nr,n.cache=new gv;const a=new uv;n.$el=a.getStore("element"),n.state=a.getStore("state"),n.$T=n.$T.bind(n)}$T(e,n,a){const{config:i,state:o}=this,s=i.transition_duration,l=i.subchart_show;let c=e;return c&&("tagName"in c&&(c=ot(c)),c=(n!==!1&&s||n)&&(!o.zooming||o.dragging)&&!o.resizing&&o.rendered&&!l?c.transition(a).duration(s):c),c}beforeInit(){const e=this;e.callPluginHook("$beforeInit"),_e(e.config.onbeforeinit,e.api)}afterInit(){const e=this;e.callPluginHook("$afterInit"),_e(e.config.onafterinit,e.api)}init(){const e=this,{config:n,state:a,$el:i}=e,o=n.boost_useCssRule;if(vv(e),a.hasRadar=!a.hasAxis&&e.hasType("radar"),a.hasFunnel=!a.hasAxis&&e.hasType("funnel"),a.hasTreemap=!a.hasAxis&&e.hasType("treemap"),a.hasAxis=!e.hasArcType()&&!a.hasFunnel&&!a.hasTreemap,a.datetimeId=`bb-${+new Date*gr()}`,o){const l=gn.createElement("style");l.type="text/css",gn.head.appendChild(l),a.style={rootSelctor:`.${a.datetimeId}`,sheet:l.sheet},i.style=l}const s={element:n.bindto,classname:"bb"};Be(n.bindto)&&(s.element=n.bindto.element||"#chart",s.classname=n.bindto.classname||s.classname),i.chart=ve(s.element.node)?n.bindto.element:ot(s.element||[]),i.chart.empty()&&(i.chart=ot(gn.body.appendChild(gn.createElement("div")))),i.chart.html("").classed(s.classname,!0).classed(a.datetimeId,o).style("position","relative"),e.initParams(),e.initToRender()}initToRender(e){const n=this,{config:a,state:i,$el:{chart:o}}=n,s=()=>nv(o,{display:"none",visibility:"hidden"}),l=a.render.lazy===!1?!1:a.render.lazy||s(),c=Ke.MutationObserver;l&&c&&a.render.observe!==!1&&!e&&new c((f,g)=>{s()||(g.disconnect(),!i.rendered&&n.initToRender(!0))}).observe(o.node(),{attributes:!0,attributeFilter:["class","style"]}),(!l||e)&&n.convertData(a,f=>{n.initWithData(f),n.afterInit()})}initParams(){var e;const n=this,{config:a,format:i,state:o}=n,s=a.axis_rotated;if(n.color=n.generateColor(),n.levelColor=n.generateLevelColor(),a.padding===!1&&(a.axis_x_show=!1,a.axis_y_show=!1,a.axis_y2_show=!1,a.subchart_show=!1),(n.hasPointType()||(e=n.hasLegendDefsPoint)!=null&&e.call(n))&&(n.point=n.generatePoint()),o.hasAxis){n.initClip(),i.extraLineClasses=n.generateExtraLineClass(),i.dataTime=a.data_xLocaltime?Ws:Ks,i.axisTime=a.axis_x_localtime?ao:io;const l=n.config.zoom_enabled&&n.config.zoom_type==="drag";i.defaultAxisTime=c=>{const{x:f,zoom:g}=n.scale,v=l?g:g&&f.orgDomain().toString()!==g.domain().toString(),m=c.getMilliseconds()&&".%L"||c.getSeconds()&&".:%S"||c.getMinutes()&&"%I:%M"||c.getHours()&&"%I %p"||c.getDate()!==1&&"%b %d"||v&&c.getDate()===1&&"%b'%y"||c.getMonth()&&"%-m/%-d"||"%Y";return i.axisTime(m)(c)}}o.isLegendRight=a.legend_position==="right",o.isLegendInset=a.legend_position==="inset",o.isLegendTop=a.legend_inset_anchor==="top-left"||a.legend_inset_anchor==="top-right",o.isLegendLeft=a.legend_inset_anchor==="top-left"||a.legend_inset_anchor==="bottom-left",o.rotatedPadding.top=n.getResettedPadding(o.rotatedPadding.top),o.rotatedPadding.right=s&&!a.axis_x_show?0:30,o.inputType=rv(a.interaction_inputType_mouse,a.interaction_inputType_touch)}initWithData(e){var n,a,i;const o=this,{config:s,scale:l,state:c,$el:f,org:g}=o,{hasAxis:v,hasFunnel:m,hasTreemap:S}=c,P=s.interaction_enabled,N=o.hasType("polar"),L=s.data_labels_backgroundColors;if(v&&(o.axis=o.getAxisInstance(),s.zoom_enabled&&o.initZoom()),o.data.xs={},o.data.targets=o.convertDataToTargets(e),s.data_filter&&(o.data.targets=o.data.targets.filter(s.data_filter.bind(o.api))),s.data_hide&&o.addHiddenTargetIds(s.data_hide===!0?o.mapToIds(o.data.targets):s.data_hide),s.legend_hide&&o.addHiddenLegendIds(s.legend_hide===!0?o.mapToIds(o.data.targets):s.legend_hide),o.updateSizes(),o.updateScales(!0),v){const{x:W,y:H,y2:k,subX:K,subY:at,subY2:ht}=l;W&&(W.domain(na(o.getXDomain(o.data.targets),!s.axis_x_inverted)),K.domain(W.domain()),g.xDomain=W.domain()),H&&(H.domain(o.getYDomain(o.data.targets,"y")),at.domain(H.domain())),k&&(k.domain(o.getYDomain(o.data.targets,"y2")),ht&&ht.domain(k.domain()))}if(f.svg=f.chart.append("svg").style("overflow","hidden").style("display","block"),P&&c.inputType){const W=c.inputType==="touch",{onclick:H,onover:k,onout:K}=s;f.svg.on("click",(H==null?void 0:H.bind(o.api))||null).on(W?"touchstart":"mouseenter",(k==null?void 0:k.bind(o.api))||null).on(W?"touchend":"mouseleave",(K==null?void 0:K.bind(o.api))||null)}s.svg_classname&&f.svg.attr("class",s.svg_classname);const w=ve(s.color_tiles)&&o.patterns;(v||w||N||S||L||(n=o.hasLegendDefsPoint)!=null&&n.call(o))&&(f.defs=f.svg.append("defs"),v&&["id","idXAxis","idYAxis","idGrid"].forEach(W=>{o.appendClip(f.defs,c.clip[W])}),o.generateTextBGColorFilter(L),w&&o.patterns.forEach(W=>f.defs.append(()=>W.node))),o.updateSvgSize(),o.bindResize();const X=f.svg.append("g").classed(Se.main,!0).attr("transform",m||S?null:o.getTranslate("main"));if(f.main=X,s.subchart_show&&o.initSubchart(),s.tooltip_show&&o.initTooltip(),s.title_text&&o.initTitle(),!S&&s.legend_show&&o.initLegend(),s.data_empty_label_text&&X.append("text").attr("class",`${On.text} ${Se.empty}`).attr("text-anchor","middle").attr("dominant-baseline","middle"),v&&(s.regions.length&&o.initRegion(),!s.clipPath&&o.axis.init()),X.append("g").classed(Se.chart,!0).attr("clip-path",v?c.clip.path:null),o.callPluginHook("$init"),o.initChartElements(),v&&(P&&((a=o.initEventRect)==null||a.call(o)),o.initGrid(),s.clipPath&&((i=o.axis)==null||i.init())),o.updateTargets(o.data.targets),o.updateDimension(),_e(s.oninit,o.api),o.setBackground(),o.redraw({withTransition:!1,withTransform:!0,withUpdateXDomain:!0,withUpdateOrgXDomain:!0,withTransitionForAxis:!1,initializing:!0}),s.data_onmin||s.data_onmax){const W=o.getMinMaxData();_e(s.data_onmin,o.api,W.min),_e(s.data_onmax,o.api,W.max)}s.tooltip_show&&o.initShowTooltip(),c.rendered=!0}initChartElements(){const e=this,{hasAxis:n,hasRadar:a,hasTreemap:i}=e.state,o=[];if(n){const s=["bar","bubble","candlestick","line"];e.config.bar_front&&s.push(s.shift()),s.forEach(l=>{const c=Cn(l);(l==="line"&&e.hasTypeOf(c)||e.hasType(l))&&o.push(c)})}else if(i)o.push("Treemap");else if(e.hasType("funnel"))o.push("Funnel");else{const s=e.hasType("polar");a||o.push("Arc","Pie"),e.hasType("gauge")?o.push("Gauge"):a?o.push("Radar"):s&&o.push("Polar")}o.forEach(s=>{e[`init${s}`]()}),cn(e.config.data_labels)&&!e.hasArcType(null,["radar"])&&e.initText()}setChartElements(){const e=this,{$el:{chart:n,svg:a,defs:i,main:o,tooltip:s,legend:l,title:c,grid:f,needle:g,arcs:v,circle:m,bar:S,candlestick:P,line:N,area:L,text:w}}=e;e.api.$={chart:n,svg:a,defs:i,main:o,tooltip:s,legend:l,title:c,grid:f,arc:v,circles:m,bar:{bars:S},candlestick:P,line:{lines:N,areas:L},needle:g,text:{texts:w}}}setBackground(){const e=this,{config:{background:n},state:a,$el:{svg:i}}=e;if(cn(n)){const o=i.select("g").insert(n.imgUrl?"image":"rect",":first-child");n.imgUrl?o.attr("href",n.imgUrl):n.color&&o.style("fill",n.color).attr("clip-path",a.clip.path),o.attr("class",n.class||null).attr("width","100%").attr("height","100%")}}updateTargets(e){var n;const a=this,{hasAxis:i,hasFunnel:o,hasRadar:s,hasTreemap:l}=a.state,c=g=>a[`updateTargetsFor${g}`](e.filter(a[`is${g}Type`].bind(a)));if(a.updateTargetsForText(e),i)["bar","candlestick","line"].forEach(g=>{const v=Cn(g);(g==="line"&&a.hasTypeOf(v)||a.hasType(g))&&c(v)}),a.updateTargetsForSubchart&&a.updateTargetsForSubchart(e);else if(a.hasArcType(e)){let g="Arc";s?g="Radar":a.hasType("polar")&&(g="Polar"),c(g)}else o?c("Funnel"):l&&c("Treemap");const f=a.hasType("bubble")||a.hasType("scatter");f&&((n=a.updateTargetForCircle)==null||n.call(a)),a.filterTargetsToShowAtInit(f)}filterTargetsToShowAtInit(e=!1){const n=this,{$el:{svg:a},$T:i}=n;let o=`.${Se.target}`;e&&(o+=`, .${$n.chartCircles} > .${$n.circles}`),i(a.selectAll(o).filter(s=>n.isTargetToShow(s.id))).style("opacity",null)}getWithOption(e){const n={Dimension:!0,EventRect:!0,Legend:!1,Subchart:!0,Transform:!1,Transition:!0,TrimXDomain:!0,UpdateXAxis:"UpdateXDomain",UpdateXDomain:!1,UpdateOrgXDomain:!1,TransitionForExit:"Transition",TransitionForAxis:"Transition",Y:!0};return Object.keys(n).forEach(a=>{let i=n[a];ze(i)&&(i=n[i]),n[a]=$r(e,`with${a}`,i)}),n}initialOpacity(e){const n=this,{withoutFadeIn:a}=n.state;return n.getBaseValue(e)!==null&&a[e.id]?null:"0"}bindResize(){const e=this,{$el:n,config:a,state:i}=e,o=xv(a.resize_timer),s=[];s.push(()=>_e(a.onresize,e.api)),/^(true|parent)$/.test(a.resize_auto)&&s.push(()=>{i.resizing=!0,a.legend_show&&(e.updateSizes(),e.updateLegend()),e.api.flush(!1)}),s.push(()=>{_e(a.onresized,e.api),i.resizing=!1}),s.forEach(l=>o.add(l)),e.resizeFunction=o,a.resize_auto==="parent"?(e.resizeFunction.resizeObserver=new ResizeObserver(e.resizeFunction.bind(e))).observe(n.chart.node().parentNode):Ke.addEventListener("resize",e.resizeFunction)}callPluginHook(e,...n){this.config.plugins.forEach(a=>{e==="$beforeInit"&&(a.$$=this,this.api.plugins.push(a)),a[e](...n)})}}yn(Vr.prototype,[Mv,Dv,Lv,jv,Vv,Yv,Wv,zv,Kv,Zv,Jv,Bp,hm,Up,zp,Gp,Xp,Hp,Yp,Wp]);function pm(t){const e=this.config;let n,a,i;const o=()=>{const s=a.shift();if(s&&n&&nr(n)&&s in n)return n=n[s],o();if(!s)return n};Object.keys(e).forEach(s=>{n=t,a=s.split("_"),i=o(),Qe(i)&&(e[s]=i)}),this.api&&(this.state.orgConfig=t)}var mm={resize(t){const e=this.internal,{config:n,state:a}=e;a.rendered&&(n.size_width=t?t.width:null,n.size_height=t?t.height:null,a.resizing=!0,this.flush(!1),e.resizeFunction())},flush(t){var e,n;const a=this.internal,{state:i,$el:{zoomResetBtn:o}}=a;i.rendered?(i.resizing?(e=a.brush)==null||e.updateResize():(n=a.axis)==null||n.setOrient(),o==null||o.style("display","none"),a.scale.zoom=null,t?a.redraw({withTransform:!0,withUpdateXDomain:!0,withUpdateOrgXDomain:!0,withLegend:!0}):a.updateAndRedraw({withLegend:!0,withTransition:!1,withTransitionForTransform:!1}),!i.resizing&&a.brush&&(a.brush.getSelection().call(a.brush.move),a.unselectRect())):a.initToRender(!0)},destroy(){var t;const e=this.internal,{$el:{chart:n,style:a,svg:i}}=e;if(cn(e)){e.callPluginHook("$willDestroy"),e.charts.splice(e.charts.indexOf(this),1),e.unbindAllEvents(),i.select("*").interrupt(),e.resizeFunction.clear(),(t=e.resizeFunction.resizeObserver)==null||t.disconnect(),Ke.removeEventListener("resize",e.resizeFunction),n.classed("bb",!1).style("position",null).selectChildren().remove(),a&&a.parentNode.removeChild(a),Object.keys(this).forEach(o=>{o==="internal"&&Object.keys(e).forEach(s=>{e[s]=null}),this[o]=null,delete this[o]});for(const o in this)this[o]=()=>{}}return null},config(t,e,n){const a=this.internal,{config:i,state:o}=a,s=t==null?void 0:t.replace(/\./g,"_");let l;return t&&s in i?Qe(e)?(i[s]=e,l=e,n&&this.flush()):l=i[s]:(arguments.length===0||qn(t))&&(l=o.orgConfig),l}},ym={color(t){return this.internal.color(t)}};const au=function(t){const{targets:e}=this.internal.data;if(!ln(t)){const n=je(t)?t:[t];return e.filter(a=>n.some(i=>i===a.id))}return e};yn(au,{shown:function(t){return this.internal.filterTargetsToShow(this.data(t))},values:function(t,e=!0){let n=null;if(t){const a=this.data(t);je(a)&&(n=[],a.forEach(i=>{const o=i.values.map(s=>s.value);e?n=n.concat(o):n.push(o)}))}return n},names:function(t){return this.internal.updateDataAttributes("names",t)},colors:function(t){return this.internal.updateDataAttributes("colors",t)},axes:function(t){return this.internal.updateDataAttributes("axes",t)},min:function(){return this.internal.getMinMaxData().min},max:function(){return this.internal.getMinMaxData().max}});var xm={data:au};const Tm=t=>{var e,n;return(n=(e=Ke).btoa)==null?void 0:n.call(e,encodeURIComponent(t).replace(/%([0-9A-F]{2})/g,(a,i)=>String.fromCharCode(+`0x${i}`)))};function $m(t,e,n){const{width:a,height:i}=e||n,o=new XMLSerializer,s=t.cloneNode(!0),l=tv(Lr(gn.styleSheets)).filter(m=>m.cssText).map(m=>m.cssText);s.setAttribute("xmlns",ae.xhtml),s.style.margin="0",s.style.padding="0",e.preserveFontStyle&&s.querySelectorAll("text").forEach(m=>{m.innerHTML=""});const c=o.serializeToString(s),f=gn.createElement("style");f.appendChild(gn.createTextNode(l.join(` `)));const g=o.serializeToString(f),v=` ${g} ${c.replace(/(url\()[^#]+/g,"$1")} `;return`data:image/svg+xml;base64,${Tm(v)}`}function Sm(t,e){const{top:n,left:a}=e,{x:i,y:o}=t.getBBox(),{a:s,b:l,c,d:f,e:g,f:v}=t.getScreenCTM(),{width:m,height:S}=t.getBoundingClientRect();return{x:s*i+c*o+g-a,y:l*i+f*o+v-n+(S-Math.round(S/4)),width:m,height:S}}function Am(t){const{left:e,top:n}=t.getBoundingClientRect(),a=o=>o.textContent||o.childElementCount,i=[];return Lr(t.querySelectorAll("text")).filter(a).forEach(o=>{const s=l=>{const{fill:c,fontFamily:f,fontSize:g,textAnchor:v,transform:m}=Ke.getComputedStyle(l),{x:S,y:P,width:N,height:L}=Sm(l,{left:e,top:n});return{[l.textContent]:{x:S,y:P,width:N,height:L,fill:c,fontFamily:f,fontSize:g,textAnchor:v,transform:m}}};if(o.childElementCount>1){const l=[];return Lr(o.querySelectorAll("tspan")).filter(a).forEach(c=>{i.push(s(c))}),l}else i.push(s(o))}),i}function Em(t,e){e.forEach(n=>{Object.keys(n).forEach(a=>{const{x:i,y:o,width:s,height:l,fill:c,fontFamily:f,fontSize:g,transform:v}=n[a];if(t.save(),t.font=`${g} ${f}`,t.fillStyle=c,v==="none")t.fillText(a,i,o);else{const m=v.replace(/(matrix|\(|\))/g,"").split(",");m.splice(4).every(S=>+S==0)?(m.push(i+s-s/4),m.push(o-l+l/3)):(m.push(i),m.push(o)),t.transform(...m),t.fillText(a,0,0)}t.restore()})})}var bm={export(t,e){const n=this.internal,{state:a,$el:{chart:i,svg:o}}=n,{width:s,height:l}=a.current,c=ea(Object.create(null),{width:s,height:l,preserveAspectRatio:!0,preserveFontStyle:!1,mimeType:"image/png"},t),f=$m(i.node(),c,{width:s,height:l}),g=c.preserveFontStyle?Am(o.node()):[];if(e&&ve(e)){const v=new Image;v.crossOrigin="Anonymous",v.onload=()=>{const m=gn.createElement("canvas"),S=m.getContext("2d");m.width=c.width||s,m.height=c.height||l,S.drawImage(v,0,0),g.length&&(Em(S,g),g.length=0),e.bind(this)(m.toDataURL(c.mimeType))},v.src=f}return f}},Rm={focus(t){const e=this.internal,{state:n}=e,a=e.mapToTargetIds(t),i=e.$el.svg.selectAll(e.selectorTargets(a.filter(e.isTargetToShow,e)));this.revert(),this.defocus(),i.classed(qe.focused,!0).classed(qe.defocused,!1),e.hasArcType()&&!n.hasRadar&&(e.expandArc(a),e.hasType("gauge")&&e.markOverlapped(t,e,`.${Un.gaugeValue}`)),e.toggleFocusLegend(a,!0),n.focusedTargetIds=a,n.defocusedTargetIds=n.defocusedTargetIds.filter(o=>a.indexOf(o)<0)},defocus(t){const e=this.internal,{state:n}=e,a=e.mapToTargetIds(t);e.$el.svg.selectAll(e.selectorTargets(a.filter(e.isTargetToShow,e))).classed(qe.focused,!1).classed(qe.defocused,!0),e.hasArcType(null,["polar"])&&(e.unexpandArc(a),e.hasType("gauge")&&e.undoMarkOverlapped(e,`.${Un.gaugeValue}`)),e.toggleFocusLegend(a,!1),n.focusedTargetIds=n.focusedTargetIds.filter(o=>a.indexOf(o)<0),n.defocusedTargetIds=a},revert(t){const e=this.internal,{config:n,state:a,$el:i}=e,o=e.mapToTargetIds(t);i.svg.selectAll(e.selectorTargets(o)).classed(qe.focused,!1).classed(qe.defocused,!1),e.hasArcType(null,["polar"])&&e.unexpandArc(o),n.legend_show&&(e.showLegend(o.filter(e.isLegendToShow.bind(e))),i.legend.selectAll(e.selectorLegends(o)).filter(function(){return ot(this).classed(qe.legendItemFocused)}).classed(qe.legendItemFocused,!1)),a.focusedTargetIds=[],a.defocusedTargetIds=[]}},Im={legend:{show:function(t){const e=this.internal;e.showLegend(e.mapToTargetIds(t)),e.updateAndRedraw({withLegend:!0})},hide:function(t){const e=this.internal;e.hideLegend(e.mapToTargetIds(t)),e.updateAndRedraw({withLegend:!0})}}},Om={load(t){const e=this.internal,{config:n}=e;t.xs&&e.addXs(t.xs),"names"in t&&this.data.names(t.names),"classes"in t&&Object.keys(t.classes).forEach(a=>{n.data_classes[a]=t.classes[a]}),"categories"in t&&e.axis.isCategorized()&&(n.axis_x_categories=t.categories),"axes"in t&&Object.keys(t.axes).forEach(a=>{n.data_axes[a]=t.axes[a]}),"colors"in t&&Object.keys(t.colors).forEach(a=>{n.data_colors[a]=t.colors[a]}),"unload"in t&&t.unload!==!1?e.unload(e.mapToTargetIds(t.unload===!0?null:t.unload),()=>{jl(()=>e.loadFromArgs(t))}):e.loadFromArgs(t)},unload(t){const e=this.internal;let n=t||{};qn(n)&&this.tooltip.hide(),je(n)?n={ids:n}:ze(n)&&(n={ids:[n]});const a=e.mapToTargetIds(n.ids);e.unload(a,()=>{e.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0}),e.cache.remove(a),cc.call(e,n.done,n.resizeAfter)})}};function iu(t,e,n){const a=this.internal,i=a.mapToTargetIds(e),o=a.state.hiddenTargetIds.map(c=>i.indexOf(c)>-1&&c).filter(Boolean);a.state.toggling=!0,a[`${t?"remove":"add"}HiddenTargetIds`](i);const s=a.$el.svg.selectAll(a.selectorTargets(i)),l=t?null:"0";t&&o.length&&(s.style("display",null),_e(a.config.data_onshown,this,o)),a.$T(s).style("opacity",l,"important").call(Si,()=>{var c;!t&&o.length===0&&(s.style("display","none"),_e((c=a.config)==null?void 0:c.data_onhidden,this,i)),s.style("opacity",l)}),n.withLegend&&a[`${t?"show":"hide"}Legend`](i),a.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0}),a.state.toggling=!1}var Cm={show(t,e={}){iu.call(this,!0,t,e)},hide(t,e={}){iu.call(this,!1,t,e)},toggle(t,e={}){const n=this.internal,a={show:[],hide:[]};n.mapToTargetIds(t).forEach(i=>a[n.isTargetToShow(i)?"hide":"show"].push(i)),a.show.length&&this.show(a.show,e),a.hide.length&&setTimeout(()=>this.hide(a.hide,e),0)}},Pm={tooltip:{show:function(t){var e,n,a;const i=this.internal,{$el:o,config:s,state:{eventReceiver:l,hasFunnel:c,hasTreemap:f,inputType:g}}=i;let v,m;if(t.mouse&&(m=t.mouse),t.data){const{data:S}=t,P=(e=i.getYScaleById(S.id))==null?void 0:e(S.value);if((c||f)&&S.id){const N=i.selectorTarget(S.id,void 0,`.${sn.shape}`);l.rect=o.main.select(N)}else i.isMultipleX()?m=[i.xx(S),P]:(s.tooltip_grouped||(m=[0,P]),v=(a=S.index)!=null?a:i.hasArcType()&&S.id?(n=i.getArcElementByIdOrIndex(S.id))==null?void 0:n.datum().index:i.getIndexByX(S.x))}else Qe(t.x)?v=i.getIndexByX(t.x):Qe(t.index)&&(v=t.index);(g==="mouse"?["mouseover","mousemove"]:["touchstart"]).forEach(S=>{i.dispatchEvent(S,v,m)})},hide:function(){var t,e,n;const a=this.internal,{state:{inputType:i},$el:{tooltip:o}}=a,s=o==null?void 0:o.datum();if(s){const{index:l}=JSON.parse(s.current)[0];(i==="mouse"?["mouseout"]:["touchend"]).forEach(c=>{a.dispatchEvent(c,l)})}i==="touch"&&a.callOverOutForTouch(),a.hideTooltip(!0),(t=a.hideGridFocus)==null||t.call(a),(e=a.unexpandCircles)==null||e.call(a),(n=a.expandBarTypeShapes)==null||n.call(a,!1)}}},wm=Object.defineProperty,Mm=(t,e,n)=>e in t?wm(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,ou=(t,e,n)=>Mm(t,typeof e!="symbol"?e+"":e,n);class Er{constructor(e){ou(this,"plugins",[]),ou(this,"internal");const n=new Vr(this);this.internal=n,function a(i,o,s){Object.keys(i).forEach(l=>{const c=ve(i[l]),f=o!==s,g=cn(i[l]),v=g&&Object.keys(i[l]).length>0;c&&(!f&&v||f)?o[l]=i[l].bind(s):g&&!c?o[l]={}:o[l]=i[l],v&&a(i[l],o[l],s)})}(Er.prototype,this,this),pm.call(n,e),n.beforeInit(),n.init()}}yn(Er.prototype,[mm,ym,xm,bm,Rm,Im,Om,Cm,Pm]);function su(t=!1,e,n,a){const i=this,{config:o,$el:{main:s}}=i,l=o.data_selection_grouped,c=o.data_selection_isselectable.bind(i.api);o.data_selection_enabled&&s.selectAll(`.${sn.shapes}`).selectAll(`.${sn.shape}`).each(function(f){const g=ot(this),{id:v,index:m}=f.data?f.data:f,S=i.getToggle(this,f).bind(i),P=l||!e||e.indexOf(v)>=0,N=!n||n.indexOf(m)>=0,L=g.classed(tn.SELECTED);g.classed(ur.line)||g.classed(ti.area)||(t?P&&N&&c(f)&&!L?S(!0,g.classed(tn.SELECTED,!0),f,m):Qe(a)&&a&&L&&S(!1,g.classed(tn.SELECTED,!1),f,m):P&&N&&c(f)&&L&&S(!1,g.classed(tn.SELECTED,!1),f,m))})}var Dm={selected(t){const e=this.internal,n=[];return e.$el.main.selectAll(`.${sn.shapes+e.getTargetSelectorSuffix(t)}`).selectAll(`.${sn.shape}`).filter(function(){return ot(this).classed(tn.SELECTED)}).each(a=>n.push(a)),n},select(t,e,n){const a=this.internal;su.bind(a)(!0,t,e,n)},unselect(t,e){const n=this.internal;su.bind(n)(!1,t,e)}};const lu=function(t){var e;const n=this.internal,{axis:a,brush:i,config:o,scale:{x:s,subX:l},state:c}=n;let f;return o.subchart_show&&(f=t,Array.isArray(f)?(a.isTimeSeries()&&(f=f.map(v=>Yn.bind(n)(v))),n.withinRange(f,n.getZoomDomain("subX",!0),n.getZoomDomain("subX"))&&(c.domain=f,i.move(i.getSelection(),f.map(l)))):f=(e=c.domain)!=null?e:s.orgDomain()),f};yn(lu,{show(){var t,e;const n=this.internal,{$el:{subchart:a},config:i}=n,o=i.subchart_show;if(!o){n.unbindZoomEvent(),i.subchart_show=!o,!a.main&&n.initSubchart();let s=a.main.selectAll(`.${Se.target}`);n.data.targets.length!==s.size()&&(n.updateSizes(),n.updateTargetsForSubchart(n.data.targets),s=(t=a.main)==null?void 0:t.selectAll(`.${Se.target}`)),s==null||s.style("opacity",null),(e=a.main)==null||e.style("display",null),this.resize()}},hide(){const t=this.internal,{$el:{subchart:{main:e}},config:n}=t;n.subchart_show&&(e==null?void 0:e.style("display"))!=="none"&&(n.subchart_show=!1,e.style("display","none"),this.resize())},toggle(){const t=this.internal,{config:e}=t;this.subchart[e.subchart_show?"hide":"show"]()},reset(){const t=this.internal,{brush:e}=t;e.clear(e.getSelection())}});var Lm={subchart:lu},Nm=1e-12;function cu(t){return((t=Math.exp(t))+1/t)/2}function Fm(t){return((t=Math.exp(t))-1/t)/2}function Bm(t){return((t=Math.exp(2*t))-1)/(t+1)}var Um=function t(e,n,a){function i(o,s){var l=o[0],c=o[1],f=o[2],g=s[0],v=s[1],m=s[2],S=g-l,P=v-c,N=S*S+P*P,L,w;if(N()=>t;function zm(t,{sourceEvent:e,target:n,transform:a,dispatch:i}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:e,enumerable:!0,configurable:!0},target:{value:n,enumerable:!0,configurable:!0},transform:{value:a,enumerable:!0,configurable:!0},_:{value:i}})}function vr(t,e,n){this.k=t,this.x=e,this.y=n}vr.prototype={constructor:vr,scale:function(t){return t===1?this:new vr(this.k*t,this.x,this.y)},translate:function(t,e){return t===0&e===0?this:new vr(this.k,this.x+this.k*t,this.y+this.k*e)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var ar=new vr(1,0,0);vs.prototype=vr.prototype;function vs(t){for(;!t.__zoom;)if(!(t=t.parentNode))return ar;return t.__zoom}function ps(t){t.stopImmediatePropagation()}function Ba(t){t.preventDefault(),t.stopImmediatePropagation()}function jm(t){return(!t.ctrlKey||t.type==="wheel")&&!t.button}function Vm(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t,t.hasAttribute("viewBox")?(t=t.viewBox.baseVal,[[t.x,t.y],[t.x+t.width,t.y+t.height]]):[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]):[[0,0],[t.clientWidth,t.clientHeight]]}function uu(){return this.__zoom||ar}function Gm(t){return-t.deltaY*(t.deltaMode===1?.05:t.deltaMode?1:.002)*(t.ctrlKey?10:1)}function Xm(){return navigator.maxTouchPoints||"ontouchstart"in this}function Hm(t,e,n){var a=t.invertX(e[0][0])-n[0][0],i=t.invertX(e[1][0])-n[1][0],o=t.invertY(e[0][1])-n[0][1],s=t.invertY(e[1][1])-n[1][1];return t.translate(i>a?(a+i)/2:Math.min(0,a)||Math.max(0,i),s>o?(o+s)/2:Math.min(0,o)||Math.max(0,s))}function Ym(){var t=jm,e=Vm,n=Hm,a=Gm,i=Xm,o=[0,1/0],s=[[-1/0,-1/0],[1/0,1/0]],l=250,c=Um,f=ri("start","zoom","end"),g,v,m,S=500,P=150,N=0,L=10;function w(Q){Q.property("__zoom",uu).on("wheel.zoom",ht,{passive:!1}).on("mousedown.zoom",$t).on("dblclick.zoom",dt).filter(i).on("touchstart.zoom",st).on("touchmove.zoom",Vt).on("touchend.zoom touchcancel.zoom",vt).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}w.transform=function(Q,St,ct,At){var Gt=Q.selection?Q.selection():Q;Gt.property("__zoom",uu),Q!==Gt?k(Q,St,ct,At):Gt.interrupt().each(function(){K(this,arguments).event(At).start().zoom(null,typeof St=="function"?St.apply(this,arguments):St).end()})},w.scaleBy=function(Q,St,ct,At){w.scaleTo(Q,function(){var Gt=this.__zoom.k,Bt=typeof St=="function"?St.apply(this,arguments):St;return Gt*Bt},ct,At)},w.scaleTo=function(Q,St,ct,At){w.transform(Q,function(){var Gt=e.apply(this,arguments),Bt=this.__zoom,Kt=ct==null?H(Gt):typeof ct=="function"?ct.apply(this,arguments):ct,ne=Bt.invert(Kt),le=typeof St=="function"?St.apply(this,arguments):St;return n(W(X(Bt,le),Kt,ne),Gt,s)},ct,At)},w.translateBy=function(Q,St,ct,At){w.transform(Q,function(){return n(this.__zoom.translate(typeof St=="function"?St.apply(this,arguments):St,typeof ct=="function"?ct.apply(this,arguments):ct),e.apply(this,arguments),s)},null,At)},w.translateTo=function(Q,St,ct,At,Gt){w.transform(Q,function(){var Bt=e.apply(this,arguments),Kt=this.__zoom,ne=At==null?H(Bt):typeof At=="function"?At.apply(this,arguments):At;return n(ar.translate(ne[0],ne[1]).scale(Kt.k).translate(typeof St=="function"?-St.apply(this,arguments):-St,typeof ct=="function"?-ct.apply(this,arguments):-ct),Bt,s)},At,Gt)};function X(Q,St){return St=Math.max(o[0],Math.min(o[1],St)),St===Q.k?Q:new vr(St,Q.x,Q.y)}function W(Q,St,ct){var At=St[0]-ct[0]*Q.k,Gt=St[1]-ct[1]*Q.k;return At===Q.x&&Gt===Q.y?Q:new vr(Q.k,At,Gt)}function H(Q){return[(+Q[0][0]+ +Q[1][0])/2,(+Q[0][1]+ +Q[1][1])/2]}function k(Q,St,ct,At){Q.on("start.zoom",function(){K(this,arguments).event(At).start()}).on("interrupt.zoom end.zoom",function(){K(this,arguments).event(At).end()}).tween("zoom",function(){var Gt=this,Bt=arguments,Kt=K(Gt,Bt).event(At),ne=e.apply(Gt,Bt),le=ct==null?H(ne):typeof ct=="function"?ct.apply(Gt,Bt):ct,be=Math.max(ne[1][0]-ne[0][0],ne[1][1]-ne[0][1]),Oe=Gt.__zoom,Ce=typeof St=="function"?St.apply(Gt,Bt):St,He=c(Oe.invert(le).concat(be/Oe.k),Ce.invert(le).concat(be/Ce.k));return function(Fe){if(Fe===1)Fe=Ce;else{var dn=He(Fe),Jt=be/dn[2];Fe=new vr(Jt,le[0]-dn[0]*Jt,le[1]-dn[1]*Jt)}Kt.zoom(null,Fe)}})}function K(Q,St,ct){return!ct&&Q.__zooming||new at(Q,St)}function at(Q,St){this.that=Q,this.args=St,this.active=0,this.sourceEvent=null,this.extent=e.apply(Q,St),this.taps=0}at.prototype={event:function(Q){return Q&&(this.sourceEvent=Q),this},start:function(){return++this.active===1&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(Q,St){return this.mouse&&Q!=="mouse"&&(this.mouse[1]=St.invert(this.mouse[0])),this.touch0&&Q!=="touch"&&(this.touch0[1]=St.invert(this.touch0[0])),this.touch1&&Q!=="touch"&&(this.touch1[1]=St.invert(this.touch1[0])),this.that.__zoom=St,this.emit("zoom"),this},end:function(){return--this.active===0&&(delete this.that.__zooming,this.emit("end")),this},emit:function(Q){var St=ot(this.that).datum();f.call(Q,this.that,new zm(Q,{sourceEvent:this.sourceEvent,target:w,type:Q,transform:this.that.__zoom,dispatch:f}),St)}};function ht(Q,...St){if(!t.apply(this,arguments))return;var ct=K(this,St).event(Q),At=this.__zoom,Gt=Math.max(o[0],Math.min(o[1],At.k*Math.pow(2,a.apply(this,arguments)))),Bt=Xn(Q);if(ct.wheel)(ct.mouse[0][0]!==Bt[0]||ct.mouse[0][1]!==Bt[1])&&(ct.mouse[1]=At.invert(ct.mouse[0]=Bt)),clearTimeout(ct.wheel);else{if(At.k===Gt)return;ct.mouse=[Bt,At.invert(Bt)],qr(this),ct.start()}Ba(Q),ct.wheel=setTimeout(Kt,P),ct.zoom("mouse",n(W(X(At,Gt),ct.mouse[0],ct.mouse[1]),ct.extent,s));function Kt(){ct.wheel=null,ct.end()}}function $t(Q,...St){if(m||!t.apply(this,arguments))return;var ct=Q.currentTarget,At=K(this,St,!0).event(Q),Gt=ot(Q.view).on("mousemove.zoom",le,!0).on("mouseup.zoom",be,!0),Bt=Xn(Q,ct),Kt=Q.clientX,ne=Q.clientY;co(Q.view),ps(Q),At.mouse=[Bt,this.__zoom.invert(Bt)],qr(this),At.start();function le(Oe){if(Ba(Oe),!At.moved){var Ce=Oe.clientX-Kt,He=Oe.clientY-ne;At.moved=Ce*Ce+He*He>N}At.event(Oe).zoom("mouse",n(W(At.that.__zoom,At.mouse[0]=Xn(Oe,ct),At.mouse[1]),At.extent,s))}function be(Oe){Gt.on("mousemove.zoom mouseup.zoom",null),uo(Oe.view,At.moved),Ba(Oe),At.event(Oe).end()}}function dt(Q,...St){if(t.apply(this,arguments)){var ct=this.__zoom,At=Xn(Q.changedTouches?Q.changedTouches[0]:Q,this),Gt=ct.invert(At),Bt=ct.k*(Q.shiftKey?.5:2),Kt=n(W(X(ct,Bt),At,Gt),e.apply(this,St),s);Ba(Q),l>0?ot(this).transition().duration(l).call(k,Kt,At,Q):ot(this).call(w.transform,Kt,At,Q)}}function st(Q,...St){if(t.apply(this,arguments)){var ct=Q.touches,At=ct.length,Gt=K(this,St,Q.changedTouches.length===At).event(Q),Bt,Kt,ne,le;for(ps(Q),Kt=0;KtYn.bind(n)(v))),n.withinRange(f,n.getZoomDomain("zoom",!0),n.getZoomDomain("zoom"))){if(l.domain=f,f=n.getZoomDomainValue(f),n.api.tooltip.hide(),i.subchart_show){const v=s.zoom||s.x;n.brush.getSelection().call(n.brush.move,f.map(v))}else{const v=c?s.x.orgScale():o.xScale||s.x;n.updateCurrentZoomTransform(v,f)}n.setZoomResetButton()}}else f=n.zoom.getDomain();return(e=l.domain)!=null?e:f};yn(fu,{enable(t){const e=this.internal,{config:n}=e;/^(drag|wheel)$/.test(t)&&(n.zoom_type=t),n.zoom_enabled=!!t,e.zoom?t===!1&&e.bindZoomEvent(!1):(e.initZoom(),e.bindZoomEvent()),e.updateAndRedraw()},max(t){const e=this.internal,{config:n,org:{xDomain:a}}=e;return(t===0||t)&&(n.zoom_x_max=_n("max",[a[1],t])),n.zoom_x_max},min(t){const e=this.internal,{config:n,org:{xDomain:a}}=e;return(t===0||t)&&(n.zoom_x_min=_n("min",[a[0],t])),n.zoom_x_min},range(t){const e=this.zoom;if(Be(t)){const{min:n,max:a}=t;Qe(n)&&e.min(n),Qe(a)&&e.max(a)}return{min:e.min(),max:e.max()}}});var Wm={zoom:fu,unzoom(){const t=this.internal,{config:e,$el:{eventRect:n,zoomResetBtn:a},scale:{zoom:i},state:o}=t;i&&(e.subchart_show?t.brush.getSelection().call(t.brush.move,null):t.zoom.updateTransformScale(ar),t.updateZoom(!0),a==null||a.style("display","none"),vs(n.node())!==ar&&t.zoom.transform(n,ar),o.domain=void 0)}},Km={initBrush(){const t=this,{config:e,scale:n,$el:{subchart:a},state:i}=t,o=e.axis_rotated,s=e.subchart_size_height;let l,c,f;t.brush=(o?Gg():Vg()).handleSize(5),t.brush.on("start brush end",g=>{const{selection:v,sourceEvent:m,target:S,type:P}=g;P==="start"&&(t.state.inputType==="touch"&&t.hideTooltip(),c=m?v:null),/(start|brush)/.test(P)&&(P==="brush"&&m&&i.domain&&(c==null||c.forEach((N,L)=>{N!==v[L]&&(i.domain[L]=n.x.orgDomain()[L])})),t.redrawForBrush(P!=="start")),P==="end"&&(l=n.x.orgDomain()),S!=null&&S.handle&&(v===null?t.brush.handle.attr("display","none"):t.brush.handle.attr("display",null).attr("transform",(N,L)=>{const w=[v[L],s/2];return`translate(${o?w.reverse():w})`}))}),t.brush.updateResize=function(){f&&clearTimeout(f),f=setTimeout(()=>{const g=this.getSelection();l&&zl(g.node())&&this.move(g,l.map(n.subX.orgScale()))},0)},t.brush.update=function(){var g;return this.extent()()[1].filter(m=>isNaN(m)).length===0&&((g=a.main)==null||g.select(`.${Ue.brush}`).call(this)),this},t.brush.scale=function(g){const v=e.subchart_size_height;let m=t.axis.getExtent();!m&&g.range?m=[[0,0],[g.range()[1],v]]:je(m)&&(m=m.map((S,P)=>[S,P>0?v:P])),o&&m[1].reverse(),this.extent(m),this.update()},t.brush.getSelection=()=>a.main?a.main.select(`.${Ue.brush}`):ot([])},initSubchart(){const t=this,{config:e,state:{clip:n,hasAxis:a},$el:{defs:i,svg:o,subchart:s,axis:l}}=t;if(!a)return;const c=e.subchart_show?null:"hidden",f=`${n.id}-subchart`,g=t.getClipPath(f);n.idSubchart=f,t.appendClip(i,f),t.initBrush(),s.main=o.append("g").classed(Ue.subchart,!0).attr("transform",t.getTranslate("context"));const{main:v}=s;v.style("visibility",c),v.append("g").attr("clip-path",g).attr("class",Ue.chart),["bar","line","bubble","candlestick","scatter"].forEach(S=>{const P=Cn(/^(bubble|scatter)$/.test(S)?"circle":S);if(t.hasType(S)||t.hasTypeOf(P)){const N=v.select(`.${Ue.chart}`),L=Ue[`chart${P}s`];N.select(`.${L}`).empty()&&N.append("g").attr("class",L)}});const m=v.append("g").attr("clip-path",g).attr("class",Ue.brush).call(t.brush);e.subchart_showHandle&&t.addBrushHandle(m),l.subX=v.append("g").attr("class",Ue.axisX).attr("transform",t.getTranslate("subX")).attr("clip-path",e.axis_rotated?"":n.pathXAxis).style("visibility",e.subchart_axis_x_show?c:"hidden")},addBrushHandle(t){const e=this,{config:n}=e,a=n.axis_rotated,i=n.subchart_init_range,o="handle--custom",s=a?["M8.5 0 a6 6 0 0 0 -6 -6.5 H-2.5 a 6 6 0 0 0 -6 6.5 z m-5 -2 H-3.5 m7 -2 H-3.5z","M8.5 0 a6 -6 0 0 1 -6 6.5 H-2.5 a 6 -6 0 0 1 -6 -6.5z m-5 2 H-3.5 m7 2 H-3.5z"]:["M0 -8.5 A6 6 0 0 0 -6.5 -3.5 V2.5 A6 6 0 0 0 0 8.5 Z M-2 -3.5 V3.5 M-4 -3.5 V3.5z","M0 -8.5 A6 6 0 0 1 6.5 -3.5 V2.5 A6 6 0 0 1 0 8.5 Z M2 -3.5 V3.5 M4 -3.5 V3.5z"];e.brush.handle=t.selectAll(`.${o}`).data(a?[{type:"n"},{type:"s"}]:[{type:"w"},{type:"e"}]).enter().append("path").attr("class",o).attr("cursor",`${a?"ns":"ew"}-resize`).attr("d",l=>s[+/[se]/.test(l.type)]).attr("display",i?null:"none")},updateTargetsForSubchart(t){const e=this,{config:n,state:a,$el:{subchart:{main:i}}}=e;n.subchart_show&&(["bar","line","bubble","candlestick","scatter"].filter(o=>e.hasType(o)||e.hasTypeOf(Cn(o))).forEach(o=>{const s=/^(bubble|scatter)$/.test(o),l=Cn(s?"circle":o),c=e.getChartClass(l,!0),f=e.getClass(s?"circles":`${o}s`,!0),g=i.select(`.${Ue[`chart${`${l}s`}`]}`);if(s){const v=g.selectAll(`.${Ue.circles}`).data(t.filter(e[`is${Cn(o)}Type`].bind(e))).attr("class",f);v.exit().remove(),v.enter().append("g").attr("class",f)}else{const v=g.selectAll(`.${Ue[`chart${l}`]}`).attr("class",c).data(t.filter(e[`is${l}Type`].bind(e))),m=v.enter().append("g").style("opacity","0").attr("class",c).append("g").attr("class",f);v.exit().remove(),o==="line"&&e.hasTypeOf("Area")&&m.append("g").attr("class",e.getClass("areas",!0))}}),i.selectAll(`.${Ue.brush} rect`).attr(n.axis_rotated?"width":"height",n.axis_rotated?a.width2:a.height2))},redrawSubchart(t,e,n){var a;const i=this,{config:o,$el:{subchart:{main:s}},state:l}=i,c=!!e;if(s.style("visibility",o.subchart_show?null:"hidden"),o.subchart_show&&(((a=l.event)==null?void 0:a.type)==="zoom"&&i.brush.update(),t)){const f=o.subchart_init_range;if(!Kl(i)&&i.brush.update(),Object.keys(n.type).forEach(g=>{const v=Cn(g),m=i[`generateDraw${v}`](n.indices[g],!0);i[`update${v}`](c,!0),i[`redraw${v}`](m,c,!0)}),i.hasType("bubble")||i.hasType("scatter")){const{cx:g}=n.pos,v=i.updateCircleY(!0);i.updateCircle(!0),i.redrawCircle(g,v,c,void 0,!0)}!l.rendered&&f&&(l.domain=f,i.brush.move(i.brush.getSelection(),f.map(i.scale.x)))}},redrawForBrush(t=!0){var e;const n=this,{config:{subchart_onbrush:a,zoom_rescale:i},scale:o,state:s}=n;n.redraw({withTransition:!1,withY:i,withSubchart:!1,withUpdateXDomain:!0,withDimension:!1}),t&&s.rendered&&a.bind(n.api)((e=s.domain)!=null?e:o.x.orgDomain())},transformContext(t,e){const n=this,{$el:{subchart:a},$T:i}=n,o=e!=null&&e.axisSubX?e.axisSubX:i(a.main.select(`.${Ue.axisX}`),t);a.main.attr("transform",n.getTranslate("context")),o.attr("transform",n.getTranslate("subX"))}},Zm={initZoom(){const t=this;t.scale.zoom=null,t.generateZoom(),t.config.zoom_type==="drag"&&t.initZoomBehaviour()},bindZoomEvent(t=!0){const e=this,{config:n}=e;n.zoom_enabled&&t?!n.subchart_show&&e.bindZoomOnEventRect():t===!1&&(e.api.unzoom(),e.unbindZoomEvent())},generateZoom(){const t=this,{config:e,org:n,scale:a}=t,i=Ym().duration(0).on("start",t.onZoomStart.bind(t)).on("zoom",t.onZoom.bind(t)).on("end",t.onZoomEnd.bind(t));i.orgScaleExtent=()=>{const o=e.zoom_extent||[1,10];return[o[0],Math.max(t.getMaxDataCount()/o[1],o[1])]},i.updateScaleExtent=function(){const o=Dr(t.scale.x.orgDomain())/Dr(t.getZoomDomain()),s=this.orgScaleExtent();return this.scaleExtent([s[0]*o,s[1]*o]),this},i.updateTransformScale=(o,s)=>{var l;const c=e.axis_rotated;(l=n.xScale)==null||l.range(a.x.range());const f=o[c?"rescaleY":"rescaleX"](n.xScale||a.x);if(f.domain().some(m=>/(Invalid Date|NaN)/.test(m.toString())))return;const g=t.trimXDomain(f.domain()),v=e.zoom_rescale;if(f.domain(g,n.xDomain),s){const m=f(a.x.domain()[0]),S=c?o.x:m,P=c?m:o.y;t.$el.eventRect.property("__zoom",ar.translate(S,P).scale(o.k))}t.state.xTickOffset||(t.state.xTickOffset=t.axis.x.tickOffset()),a.zoom=t.getCustomizedXScale(f),t.axis.x.scale(a.zoom),v?(!n.xScale&&(n.xScale=a.x.copy()),a.x.domain(g)):n.xScale&&(a.x.domain(n.xScale.domain()),n.xScale=null)},i.getDomain=()=>{const o=a[a.zoom?"zoom":"subX"].domain();return t.axis.isCategorized()&&(o[1]-=2),o},t.zoom=i},onZoomStart(t){const e=this,{sourceEvent:n}=t;n&&(e.zoom.startEvent=n,e.state.zooming=!0,_e(e.config.zoom_onzoomstart,e.api,t))},onZoom(t){var e;const n=this,{config:a,scale:i,state:o,org:s}=n,{sourceEvent:l}=t,c=(t==null?void 0:t.transform)===ar;if(!a.zoom_enabled||n.filterTargetsToShow(n.data.targets).length===0||!i.zoom&&(l==null?void 0:l.type.indexOf("touch"))>-1&&(l==null?void 0:l.touches.length)===1)return;t.sourceEvent&&(o.zooming=!0,o.domain=void 0);const f=(l==null?void 0:l.type)==="mousemove",g=(l==null?void 0:l.wheelDelta)<0,{transform:v}=t;!f&&g&&i.x.domain().every((S,P)=>S!==s.xDomain[P])&&i.x.domain(s.xDomain),n.zoom.updateTransformScale(v,a.zoom_type==="wheel"&&l);const m=a.transition_duration>0&&!a.subchart_show&&(o.dragging||c||!t.sourceEvent);n.redraw({withTransition:m,withY:a.zoom_rescale,withSubchart:!1,withEventRect:!1,withDimension:!1}),n.state.cancelClick=f,!c&&_e(a.zoom_onzoom,n.api,(e=n.state.domain)!=null?e:n.zoom.getDomain())},onZoomEnd(t){var e,n;const a=this,{config:i,state:o}=a;let{startEvent:s}=a.zoom,l=t==null?void 0:t.sourceEvent;const c=(t==null?void 0:t.transform)===ar;(s==null?void 0:s.type.indexOf("touch"))>-1&&(s=s.changedTouches[0],l=(e=l==null?void 0:l.changedTouches)==null?void 0:e[0]),!(i.zoom_type==="drag"&&l&&s.clientX===l.clientX&&s.clientY===l.clientY)&&(o.zooming=!1,a.redrawEventRect(),a.updateZoom(),!c&&(l||o.dragging)&&_e(i.zoom_onzoomend,a.api,(n=a.state.domain)!=null?n:a.zoom.getDomain()))},updateZoom(t){const e=this,{subX:n,x:a,zoom:i}=e.scale;if(i){const o=i.domain(),s=n.domain(),l=.015,c=e.config.axis_x_inverted?(o[0]>=s[0]||o[0]+l>=s[0])&&(s[1]>=o[1]||s[1]>=o[1]+l):(o[0]<=s[0]||o[0]-l<=s[0])&&(s[1]<=o[1]||s[1]<=o[1]-l);(t||c)&&(e.axis.x.scale(n),a.domain(n.orgDomain()),e.scale.zoom=null)}},updateCurrentZoomTransform(t,e){const n=this,{$el:{eventRect:a},config:i}=n,o=i.axis_rotated,s=[-t(e[0]),0],l=ar.scale(t.range()[1]/(t(e[1])-t(e[0]))).translate(...o?s.reverse():s);a.call(n.zoom.transform,l)},bindZoomOnEventRect(){var t;const e=this,{config:n,$el:{eventRect:a,svg:i}}=e,o=n.zoom_type==="drag"?e.zoomBehaviour:e.zoom;Ke.GestureEvent&&/^((?!chrome|android|mobile).)*safari/i.test((t=Ke.navigator)==null?void 0:t.userAgent)&&i.on("wheel",()=>{}),a==null||a.call(o).on("dblclick.zoom",null)},initZoomBehaviour(){const t=this,{config:e,state:n}=t,a=e.axis_rotated;let i=0,o=0,s,l;const c={axis:a?"y":"x",attr:a?"height":"width",index:a?1:0};t.zoomBehaviour=uc().clickDistance(4).on("start",function(f){l=t.scale.zoom?null:t.axis.getExtent(),n.event=f,t.setDragStatus(!0),t.unselectRect(),s||(s=t.$el.main.append("rect").attr("clip-path",n.clip.path).attr("class",so.zoomBrush).attr("width",a?n.width:0).attr("height",a?0:n.height)),i=Hn(f,this)[c.index],l&&(il[1]&&(i=l[1])),o=i,s.attr(c.axis,i).attr(c.attr,0),t.onZoomStart(f)}).on("drag",function(f){o=Hn(f,this)[c.index],l&&(o>l[1]?o=l[1]:o{const g=t.scale.zoom||t.scale.x;n.event=f,s.attr(c.axis,0).attr(c.attr,0),i>o&&([i,o]=[o,i]),i<0&&(o+=Math.abs(i),i=0),i!==o&&t.api.zoom([i,o].map(v=>g.invert(v))),t.setDragStatus(!1)})},setZoomResetButton(){const t=this,{config:e,$el:n}=t,a=e.zoom_resetButton;a&&e.zoom_type==="drag"&&(n.zoomResetBtn?n.zoomResetBtn.style("display",null):n.zoomResetBtn=t.$el.chart.append("div").classed(Se.button,!0).append("span").on("click",function(){ve(a.onclick)&&a.onclick.bind(t.api)(this),t.api.unzoom()}).classed(so.buttonZoomReset,!0).text(a.text||"Reset Zoom"))},getZoomTransform(){const t=this,{$el:{eventRect:e}}=t;return e!=null&&e.node()?vs(e.node()):{k:1}}},Jm={drag(t){const e=this,{config:n,state:a,$el:{main:i}}=e,o=n.data_selection_grouped,s=n.interaction_enabled&&n.data_selection_isselectable;if(e.hasArcType()||!n.data_selection_enabled||n.zoom_enabled&&!e.zoom.altDomain||!n.data_selection_multiple)return;const[l,c]=a.dragStart||[0,0],[f,g]=t,v=Math.min(l,f),m=Math.max(l,f),S=o?a.margin.top:Math.min(c,g),P=o?a.height:Math.max(c,g);i.select(`.${Or.dragarea}`).attr("x",v).attr("y",S).attr("width",m-v).attr("height",P-S),i.selectAll(`.${sn.shapes}`).selectAll(`.${sn.shape}`).filter(N=>s==null?void 0:s.bind(e.api)(N)).each(function(N,L){const w=ot(this),X=w.classed(tn.SELECTED),W=w.classed(Or.INCLUDED);let H=!1,k;if(w.classed($n.circle)){const K=+w.attr("cx")*1,at=+w.attr("cy")*1;k=e.togglePoint,H=ve in t?Qm(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,ey=(t,e)=>{for(var n in e||(e={}))_m.call(e,n)&&hu(t,n,e[n]);if(du)for(var n of du(e))ty.call(e,n)&&hu(t,n,e[n]);return t},ny=(t,e)=>km(t,qm(e)),ry=ny(ey({},Jm),{selectPoint(t,e,n){const a=this,{config:i,$el:{main:o},$T:s}=a,l=i.axis_rotated,c=(l?a.circleY:a.circleX).bind(a),f=(l?a.circleX:a.circleY).bind(a),g=a.pointSelectR.bind(a);_e(i.data_onselected,a.api,e,t.node()),s(o.select(`.${tn.selectedCircles}${a.getTargetSelectorSuffix(e.id)}`).selectAll(`.${tn.selectedCircle}-${n}`).data([e]).enter().append("circle").attr("class",()=>a.generateClass(tn.selectedCircle,n)).attr("cx",c).attr("cy",f).attr("stroke",a.color).attr("r",v=>a.pointSelectR(v)*1.4)).attr("r",g)},unselectPoint(t,e,n){const a=this,{config:i,$el:{main:o},$T:s}=a;_e(i.data_onunselected,a.api,e,t==null?void 0:t.node()),s(o.select(`.${tn.selectedCircles}${a.getTargetSelectorSuffix(e.id)}`).selectAll(`.${tn.selectedCircle}-${n}`)).attr("r",0).remove()},togglePoint(t,e,n,a){this[`${t?"":"un"}selectPoint`](e,n,a)},selectPath(t,e){const n=this,{config:a}=n;_e(a.data_onselected,n.api,e,t.node()),a.interaction_brighten&&t.style("filter","brightness(1.25)")},unselectPath(t,e){const n=this,{config:a}=n;_e(a.data_onunselected,n.api,e,t.node()),a.interaction_brighten&&t.style("filter",null)},togglePath(t,e,n,a){this[`${t?"":"un"}selectPath`](e,n,a)},getToggle(t,e){const n=this;return t.nodeName==="path"?n.togglePath:n.isStepType(e)?()=>{}:n.togglePoint},toggleShape(t,e,n){var a;const i=this,{config:o,$el:{main:s}}=i;if(o.data_selection_enabled&&o.data_selection_isselectable.bind(i.api)(e)){const l=ot(t),c=l.classed(tn.SELECTED),f=i.getToggle(t,e).bind(i);let g;if(!o.data_selection_multiple){const v=(a=i.isPointFocusOnly)==null?void 0:a.call(i);let m=`.${v?tn.selectedCircles:sn.shapes}`;o.data_selection_grouped&&(m+=i.getTargetSelectorSuffix(e.id)),s.selectAll(m).selectAll(v?`.${tn.selectedCircle}`:`.${sn.shape}.${tn.SELECTED}`).classed(tn.SELECTED,!1).each(function(S){const P=ot(this);g=P,f(!1,P,S,S.index)})}(!g||g.node()!==l.node())&&(l.classed(tn.SELECTED,!c),f(!c,l,e,n))}}}),ay={data_selection_enabled:!1,data_selection_grouped:!1,data_selection_isselectable:()=>!0,data_selection_multiple:!0,data_selection_draggable:!1,data_onselected:()=>{},data_onunselected:()=>{}},iy={subchart_show:!1,subchart_showHandle:!1,subchart_size_height:60,subchart_axis_x_show:!0,subchart_axis_x_tick_show:!0,subchart_axis_x_tick_format:void 0,subchart_axis_x_tick_text_show:!0,subchart_init_range:void 0,subchart_onbrush:()=>{}},oy={zoom_enabled:!1,zoom_type:"wheel",zoom_extent:void 0,zoom_privileged:!1,zoom_rescale:!1,zoom_onzoom:void 0,zoom_onzoomstart:void 0,zoom_onzoomend:void 0,zoom_resetButton:!0,zoom_x_min:void 0,zoom_x_max:void 0};let gu=()=>(yn(Vr.prototype,ry),yn(Er.prototype,Dm),Nr.setOptions([ay]),(gu=()=>!0)()),vu=()=>(yn(Vr.prototype,Km),yn(Er.prototype,Lm),Nr.setOptions([iy]),(vu=()=>!0)()),pu=()=>(yn(Vr.prototype,Zm),yn(Er.prototype,Wm),Nr.setOptions([oy]),(pu=()=>!0)());function mu(t,e,n){const{config:a}=t,i=(o,s)=>{const l=he(s)?s:s===!1?void 0:null;l!==null&&(a[`axis_${o}_${e}`]=l)};Qe(n)&&(nr(n)?Object.keys(n).forEach(o=>{i(o,n[o])}):(he(n)||n===!1)&&["y","y2"].forEach(o=>{i(o,n)}),t.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0}))}function yu(t,e){const{config:n}=t;return{x:n[`axis_x_${e}`],y:n[`axis_y_${e}`],y2:n[`axis_y2_${e}`]}}var sy={axis:{labels:function(t){const e=this.internal;let n;return t&&(Object.keys(t).forEach(a=>{e.axis.setLabelText(a,t[a])}),e.axis.updateLabels()),["x","y","y2"].forEach(a=>{const i=e.axis.getLabelText(a);i&&(!n&&(n={}),n[a]=i)}),n},min:function(t){const e=this.internal;return De(t)||t===!1?mu(e,"min",t):yu(e,"min")},max:function(t){const e=this.internal;return De(t)||t===!1?mu(e,"max",t):yu(e,"max")},range:function(t){const{axis:e}=this;if(arguments.length){const{min:n,max:a}=t;Qe(a)&&e.max(a),Qe(n)&&e.min(n)}else return{max:e.max(),min:e.min()}}}},ly={category(t,e){const n=this.internal,{config:a}=n;return arguments.length>1&&(a.axis_x_categories[t]=e,n.redraw()),a.axis_x_categories[t]},categories(t){const e=this.internal,{config:n}=e;if(!t||!Array.isArray(t)){const a=n.axis_x_categories;return qn(a)?Object.values(e.data.xs)[0]:a}return n.axis_x_categories=t,e.redraw(),n.axis_x_categories}},cy={flow(t){const e=this.internal;let n;(t.json||t.rows||t.columns)&&e.convertData(t,i=>{n=i,a()});function a(){let i,o=0,s=0,l,c;if(e.state.redrawing||!n||!Da())return;const f=[],g=e.getMaxDataCount(),v=e.convertDataToTargets(n,!0),m=e.axis.isTimeSeries();e.data.targets.forEach(N=>{let L=!1;for(let w=0;w{for(let L=0;L{const L=[];for(let w=e.data.targets[0].values[0].index;w{w.index+=s,m||(w.x+=s)}),N.values=L.concat(N.values)}),e.data.targets=e.data.targets.concat(v);const S=e.data.targets[0],P=S.values[0];Qe(t.to)?(o=0,c=m?Yn.call(e,t.to):t.to,S.values.forEach(N=>{N.x1?S.values[S.values.length-1].x-P.x:P.x-e.getXDomain(e.data.targets)[0]:l=1,i=[P.x-l,P.x]),i&&e.updateXDomain(null,!0,!0,!1,i),e.updateTargets(e.data.targets),e.redraw({flow:{index:P.index,length:o,duration:De(t.duration)?t.duration:e.config.transition_duration,done:t.done,orgDataCount:g},withLegend:!0,withTransition:g>1,withTrimXDomain:!1,withUpdateXAxis:!0})}}};function ms(t,e){const n=this.internal,{config:a}=n,i=a.transition_duration&&Da(),o=`grid_${e}_lines`;return t&&(a[o]=t,n.updateGrid(),n.redrawGrid(i)),a[o]}function xu(t,e){const n=`grid_${e}_lines`;return ms.bind(this)(this.internal.config[n].concat(t||[]),e)}function Tu(t,e){this.internal.removeGridLines(t,e)}const $u=function(t){return ms.bind(this)(t,"x")};yn($u,{add(t){return xu.bind(this)(t,"x")},remove(t){return Tu.bind(this)(t,!0)}});const Su=function(t){return ms.bind(this)(t,"y")};yn(Su,{add(t){return xu.bind(this)(t,"y")},remove(t){return Tu.bind(this)(t,!1)}});var uy={xgrids:$u,ygrids:Su},fy={groups(t){const e=this.internal,{config:n}=e;return ln(t)||(n.data_groups=t,e.redraw()),n.data_groups}};function Au(t,e=!1){const n=this.internal,{config:a}=n,i=a.transition_duration&&Da();return t?(a.regions=e?a.regions.concat(t):t,n.updateRegion(),n.redrawRegion(i),e?a.regions:t):a.regions}const Eu=function(t){return Au.bind(this)(t)};yn(Eu,{add:function(t){return Au.bind(this)(t,!0)},remove:function(t){const e=this.internal,{config:n,$T:a}=e,i=t||{},o=$r(i,"classes",[$a.region]);let s=e.$el.main.select(`.${$a.regions}`).selectAll(o.map(l=>`.${l}`));return a(s).style("opacity","0").remove(),s=n.regions,Object.keys(i).length?(s=s.filter(l=>{let c=!1;return l.class?(l.class.split(" ").forEach(f=>{o.indexOf(f)>=0&&(c=!0)}),!c):!0}),n.regions=s):n.regions=[],s}});var dy={regions:Eu},hy={x(t){const e=this.internal,{axis:n,data:a}=e,i=n.isCustomX()&&n.isCategorized();return je(t)&&(i?this.categories(t):(e.updateTargetX(a.targets,t),e.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0}))),i?this.categories():a.xs},xs(t){const e=this.internal;return Be(t)&&(e.updateTargetXs(e.data.targets,t),e.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})),e.data.xs}};function gy(t){return t}var Xi=1,Hi=2,ys=3,Ua=4,bu=1e-6;function vy(t){return"translate("+t+",0)"}function py(t){return"translate(0,"+t+")"}function my(t){return e=>+t(e)}function yy(t,e){return e=Math.max(0,t.bandwidth()-e*2)/2,t.round()&&(e=Math.round(e)),n=>+t(n)+e}function xy(){return!this.__axis}function Yi(t,e){var n=[],a=null,i=null,o=6,s=6,l=3,c=typeof window!="undefined"&&window.devicePixelRatio>1?0:.5,f=t===Xi||t===Ua?-1:1,g=t===Ua||t===Hi?"x":"y",v=t===Xi||t===ys?vy:py;function m(S){var P=a==null?e.ticks?e.ticks.apply(e,n):e.domain():a,N=i==null?e.tickFormat?e.tickFormat.apply(e,n):gy:i,L=Math.max(o,0)+l,w=e.range(),X=+w[0]+c,W=+w[w.length-1]+c,H=(e.bandwidth?yy:my)(e.copy(),c),k=S.selection?S.selection():S,K=k.selectAll(".domain").data([null]),at=k.selectAll(".tick").data(P,e).order(),ht=at.exit(),$t=at.enter().append("g").attr("class","tick"),dt=at.select("line"),st=at.select("text");K=K.merge(K.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),at=at.merge($t),dt=dt.merge($t.append("line").attr("stroke","currentColor").attr(g+"2",f*o)),st=st.merge($t.append("text").attr("fill","currentColor").attr(g,f*L).attr("dy",t===Xi?"0em":t===ys?"0.71em":"0.32em")),S!==k&&(K=K.transition(S),at=at.transition(S),dt=dt.transition(S),st=st.transition(S),ht=ht.transition(S).attr("opacity",bu).attr("transform",function(Vt){return isFinite(Vt=H(Vt))?v(Vt+c):this.getAttribute("transform")}),$t.attr("opacity",bu).attr("transform",function(Vt){var vt=this.parentNode.__axis;return v((vt&&isFinite(vt=vt(Vt))?vt:H(Vt))+c)})),ht.remove(),K.attr("d",t===Ua||t===Hi?s?"M"+f*s+","+X+"H"+c+"V"+W+"H"+f*s:"M"+c+","+X+"V"+W:s?"M"+X+","+f*s+"V"+c+"H"+W+"V"+f*s:"M"+X+","+c+"H"+W),at.attr("opacity",1).attr("transform",function(Vt){return v(H(Vt)+c)}),dt.attr(g+"2",f*o),st.attr(g,f*L).text(N),k.filter(xy).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===Hi?"start":t===Ua?"end":"middle"),k.each(function(){this.__axis=H})}return m.scale=function(S){return arguments.length?(e=S,m):e},m.ticks=function(){return n=Array.from(arguments),m},m.tickArguments=function(S){return arguments.length?(n=S==null?[]:Array.from(S),m):n.slice()},m.tickValues=function(S){return arguments.length?(a=S==null?null:Array.from(S),m):a&&a.slice()},m.tickFormat=function(S){return arguments.length?(i=S,m):i},m.tickSize=function(S){return arguments.length?(o=s=+S,m):o},m.tickSizeInner=function(S){return arguments.length?(o=+S,m):o},m.tickSizeOuter=function(S){return arguments.length?(s=+S,m):s},m.tickPadding=function(S){return arguments.length?(l=+S,m):l},m.offset=function(S){return arguments.length?(c=+S,m):c},m}function Ty(t){return Yi(Xi,t)}function $y(t){return Yi(Hi,t)}function Ru(t){return Yi(ys,t)}function Iu(t){return Yi(Ua,t)}var Sy=Object.defineProperty,Ay=(t,e,n)=>e in t?Sy(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,xs=(t,e,n)=>Ay(t,typeof e!="symbol"?e+"":e,n);class Ou{constructor(e){xs(this,"owner"),xs(this,"config"),xs(this,"scale");const n=zr(),{config:a,params:i}=e;this.owner=e,this.config=a,this.scale=n,(a.noTransition||!i.config.transition_duration)&&(a.withoutTransition=!0),a.range=this.scaleExtent((i.orgXScale||n).range())}static getSizeFor1Char(e,n=!0){const a={w:5.5,h:11.5};return!e.empty()&&e.text("0").call(i=>{try{const{width:o,height:s}=i.node().getBBox();o&&s&&(a.w=o,a.h=s)}finally{i.text("")}}),n&&(this.getSizeFor1Char=()=>a),a}getTickTransformSetter(e){const{config:n}=this,a=e==="x"?i=>`translate(${i+n.tickOffset},0)`:i=>`translate(0,${i})`;return(i,o)=>{i.attr("transform",s=>{const l=o(s);return De(s)?a(l):null})}}scaleExtent(e){const n=e[0],a=e[e.length-1];return n0?i:1,o]).range(e.range());s=c.ticks();for(let f=o.toFixed().length;s.length>15;f--)s=c.ticks(f);s.splice(0,1,i),s.splice(s.length-1,1,o)}else s=e.ticks(...this.config.tickArguments||[]);s=s.map(c=>ze(c)&&he(c)&&!isNaN(c)&&Math.round(c*10)/10||c)}return s}copyScale(){const e=this.scale.copy();return e.domain().length||e.domain(this.scale.domain()),e.type=this.scale.type,e}textFormatted(e){const n=this.config.tickFormat,a=/\d+\.\d+0{5,}\d$/.test(e)?+String(e).replace(/0+\d$/,""):e,i=n?n(a):a;return Qe(i)?i:""}transitionise(e){const{config:n}=this;let a=e;if(n.withoutTransition)a=e.interrupt();else if(n.transition||!this.owner.params.noTransition)try{a=e.transition(n.transition)}catch(i){}return a}}var Ey=Object.defineProperty,by=(t,e,n)=>e in t?Ey(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,za=(t,e,n)=>by(t,typeof e!="symbol"?e+"":e,n);class Ry{constructor(e={}){za(this,"helper"),za(this,"config"),za(this,"params"),za(this,"g"),za(this,"generatedTicks");const n={innerTickSize:6,outerTickSize:e.outerTick?6:0,orient:"bottom",range:[],tickArguments:null,tickCentered:null,tickCulling:!0,tickFormat:null,tickLength:9,tickOffset:0,tickPadding:3,tickValues:null,transition:null,noTransition:e.noTransition};n.tickLength=Math.max(n.innerTickSize,0)+n.tickPadding,this.config=n,this.params=e,this.helper=new Ou(this)}create(e){const n=this,{config:a,helper:i,params:o}=n,{scale:s}=i,{orient:l}=a,c=this.splitTickText.bind(n),f=/^(left|right)$/.test(l),g=/^(top|bottom)$/.test(l),v=i.getTickTransformSetter(g?"x":"y"),m=v===i.axisX?"y":"x",S=/^(top|left)$/.test(l)?-1:1,P=o.tickTextRotate;this.config.range=s.rangeExtent?s.rangeExtent():i.scaleExtent((o.orgXScale||s).range());const{innerTickSize:N,tickLength:L,range:w}=a,X=o.id,W=X&&/^(x|y|y2)$/.test(X)?o.config[`axis_${X}_tick_text_position`]:{x:0,y:0},H=X==="subX"?"subchart_axis_x":`axis_${X}`,k=o.config[`${H}_show`],K={tick:k?o.config[`${H}_tick_show`]:!1,text:k?o.config[`${H}_tick_text_show`]:!1},at=o.config.axis_evalTextSize;let ht;e.each(function(){const $t=ot(this);let dt=this.__chart__||s,st=i.copyScale();ht=$t,this.__chart__=st,a.tickOffset=o.isCategory?(st(1)-st(0))/2:0;const Vt=$t.selectAll(".domain").data([0]);if(Vt.enter().append("path").attr("class","domain").merge(Vt).attr("d",()=>{const vt=a.outerTickSize*S;return g?`M${w[0]},${vt}V0H${w[1]}V${vt}`:`M${vt},${w[0]}H0V${w[1]}H${vt}`}),K.tick||K.text){const vt=a.tickValues||i.generateTicks(st,f);n.generatedTicks=vt;let Q=$t.selectAll(".tick").data(vt,st);const St=Q.enter().insert("g",".domain").attr("class","tick"),ct=Q.exit().remove();Q=St.merge(Q),K.tick&&St.append("line"),K.text&&St.append("text");const At=Q.select("text"),Gt=ve(at)?at.bind(n.params.owner.api)(At.node()):Ou.getSizeFor1Char(At,at),Bt=[];let Kt=At.selectAll("tspan").data((be,Oe)=>{const Ce=o.tickMultiline?c(be,st,vt,f,Gt.w):je(i.textFormatted(be))?i.textFormatted(be).concat():[i.textFormatted(be)];return Bt[Oe]=Ce.length,Ce.map(He=>({index:Oe,splitted:He}))});Kt.exit().remove(),Kt=Kt.enter().append("tspan").merge(Kt).text(be=>be.splitted),Kt.attr("x",g?0:L*S).attr("dx",(()=>{let be=0;return/(top|bottom)/.test(l)&&P&&(be=8*Math.sin(Math.PI*(P/180))*(l==="top"?-1:1)),be+(W.x||0)})()).attr("dy",(be,Oe)=>{const Ce=".71em";let He=0;return l!=="top"&&(He=Gt.h,Oe===0&&(He=f?-((Bt[be.index]-1)*(Gt.h/2)-3):W.y===0?Ce:0)),he(He)&&W.y?He+W.y:He||Ce});const ne=Q.select("line"),le=Q.select("text");if(St.select("line").attr(`${m}2`,N*S),St.select("text").attr(m,L*S),n.setTickLineTextPosition(ne,le),o.tickTitle){const be=le.select("title");(be.empty()?le.append("title"):be).text(Oe=>o.tickTitle[Oe])}if(st.bandwidth){const be=st,Oe=be.bandwidth()/2;dt=Ce=>be(Ce)+Oe,st=dt}else dt.bandwidth?dt=st:v(ct,st);Q=o.owner.state.flowing?i.transitionise(Q):o.owner.$T(Q),v(St,dt),v(Q.style("opacity",null),st)}}),this.g=ht}getGeneratedTicks(e){var n;const a=((n=this.generatedTicks)==null?void 0:n.length)-1;let i=this.generatedTicks;if(a>e){const o=Math.round(a/e+.1);i=this.generatedTicks.map((s,l)=>l%o===0?s:null).filter(s=>s!==null).splice(0,e)}return i}getTickXY(){const{config:e}=this,n={x:0,y:0};return this.params.isCategory&&(n.x=e.tickCentered?0:e.tickOffset,n.y=e.tickCentered?e.tickOffset:0),n}getTickSize(e){const{scale:n}=this.helper,{config:a}=this,{innerTickSize:i,range:o}=a,s=n(e)+(a.tickCentered?0:a.tickOffset);return o[0]{const N=["start","end"];return o==="top"&&N.reverse(),P?N[P>0?0:1]:"middle"},g=P=>P?`rotate(${P})`:null,v=P=>{const N=P/(o==="bottom"?15:23);return P?11.5-2.5*N*(P>0?1:-1):s},{config:{axis_rotated:m,axis_x_tick_text_inner:S}}=this.params.owner;switch(o){case"bottom":e.attr("x1",a.x).attr("x2",a.x).attr("y2",this.getTickSize.bind(this)),n.attr("x",0).attr("y",v(c)).style("text-anchor",f(c)).style("text-anchor",(P,N,{length:L})=>!m&&N===0&&(S===!0||S.first)?"start":!m&&N===L-1&&(S===!0||S.last)?"end":f(c)).attr("transform",g(c));break;case"top":e.attr("x2",0).attr("y2",-i),n.attr("x",0).attr("y",-v(c)*2).style("text-anchor",f(c)).attr("transform",g(c));break;case"left":e.attr("x2",-i).attr("y1",a.y).attr("y2",a.y),n.attr("x",-s).attr("y",l).style("text-anchor","end");break;case"right":e.attr("x2",i).attr("y2",0),n.attr("x",s).attr("y",0).style("text-anchor","start")}}splitTickText(e,n,a,i,o){const{params:s}=this,l=this.helper.textFormatted(e),c=ze(l)&&l.indexOf(` `)>-1?l.split(` `):[];if(c.length)return c;if(je(l))return l;let f=s.tickWidth;(!f||f<=0)&&(f=i?95:s.isCategory?(s.isInverted?n(a[0])-n(a[1]):n(a[1])-n(a[0]))-12:110);function g(v,m){let S,P,N;for(let L=1;L{const S=v+1;return Se(this.helper.scale.domain());else{if(!arguments.length)return n.tickValues;n.tickValues=e}return this}setTransition(e){return this.config.transition=e,this}}var Iy=Object.defineProperty,Oy=(t,e,n)=>e in t?Iy(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,pr=(t,e,n)=>Oy(t,typeof e!="symbol"?e+"":e,n),Cy={getAxisInstance:function(){return this.axis||new Py(this)}};class Py{constructor(e){pr(this,"owner"),pr(this,"x"),pr(this,"subX"),pr(this,"y"),pr(this,"y2"),pr(this,"axesList",{}),pr(this,"tick",{x:null,y:null,y2:null}),pr(this,"xs",[]),pr(this,"orient",{x:"bottom",y:"left",y2:"right",subX:"bottom"}),this.owner=e,this.setOrient()}getAxisClassName(e){return`${Tn.axis} ${Tn[`axis${Cn(e)}`]}`}isHorizontal(e,n){const a=e.config.axis_rotated;return n?a:!a}isCategorized(){const{config:e,state:n}=this.owner;return e.axis_x_type.indexOf("category")>=0||n.hasRadar}isCustomX(){const{config:e}=this.owner;return!this.isTimeSeries()&&(e.data_x||cn(e.data_xs))}isTimeSeries(e="x"){return this.owner.config[`axis_${e}_type`]==="timeseries"}isLog(e="x"){return this.owner.config[`axis_${e}_type`]==="log"}isTimeSeriesY(){return this.isTimeSeries("y")}getAxisType(e="x"){let n="linear";return this.isTimeSeries(e)?n=this.owner.config.axis_x_localtime?"time":"utc":this.isLog(e)&&(n="log"),n}getExtent(){const e=this.owner,{config:n,scale:a}=e;let i=n.axis_x_extent;if(i){if(ve(i))i=i.bind(e.api)(e.getXDomain(e.data.targets),a.subX);else if(this.isTimeSeries()&&i.every(isNaN)){const o=Yn.bind(e);i=i.map(s=>a.subX(o(s)))}}return i}init(){const e=this.owner,{config:n,$el:{main:a,axis:i},state:{clip:o}}=e,s=["x","y"];n.axis_y2_show&&s.push("y2"),s.forEach(l=>{const c=this.getAxisClassName(l);i[l]=a.append("g").attr("class",c).attr("clip-path",()=>{let f=null;return l==="x"?f=o.pathXAxis:l==="y"&&(f=o.pathYAxis),f}).attr("transform",e.getTranslate(l)).style("visibility",n[`axis_${l}_show`]?null:"hidden"),this.generateAxes(l)})}setOrient(){const e=this.owner,{axis_rotated:n,axis_y_inner:a,axis_y2_inner:i}=e.config;this.orient={x:n?"left":"bottom",y:n?a?"top":"bottom":a?"right":"left",y2:n?i?"bottom":"top":i?"left":"right",subX:n?"left":"bottom"}}generateAxes(e){const n=this.owner,{config:a}=n,i=[],o=a[`axis_${e}_axes`],s=a.axis_rotated;let l;e==="x"?l=s?Iu:Ru:e==="y"?l=s?Ru:Iu:e==="y2"&&(l=s?Ty:$y),o.length&&o.forEach(c=>{const f=c.tick||{},g=n.scale[e].copy();c.domain&&g.domain(c.domain),i.push(l(g).ticks(f.count).tickFormat(ve(f.format)?f.format.bind(n.api):v=>v).tickValues(f.values).tickSizeOuter(f.outer===!1?0:6))}),this.axesList[e]=i}updateAxes(){const e=this.owner,{config:n,$el:{main:a},$T:i}=e;Object.keys(this.axesList).forEach(o=>{const s=n[`axis_${o}_axes`],l=e.scale[o].copy(),c=l.range();this.axesList[o].forEach((f,g)=>{const v=f.scale().range();c.every((P,N)=>P===v[N])||f.scale().range(c);const m=`${this.getAxisClassName(o)}-${g+1}`;let S=a.select(`.${m.replace(/\s/,".")}`);S.empty()?S=a.append("g").attr("class",m).style("visibility",n[`axis_${o}_show`]?null:"hidden").call(f):(s[g].domain&&l.domain(s[g].domain),i(S).call(f.scale(l))),S.attr("transform",e.getTranslate(o,g+1))})})}setAxis(e,n,a,i){const o=this.owner;e!=="subX"&&(this.tick[e]=this.getTickValues(e)),this[e]=this.getAxis(e,n,a,e==="x"&&(o.scale.zoom||o.config.subchart_show||o.state.resizing)?!0:i)}getAxis(e,n,a,i,o){const s=this.owner,{config:l}=s,c=/^(x|subX)$/.test(e),f=c?"x":e,g=c&&this.isCategorized(),v=this.orient[e],m=o?0:s.getAxisTickRotate(f);let S;if(c)S=e==="subX"?s.format.subXAxisTick:s.format.xAxisTick;else{const X=l[`axis_${e}_tick_format`];ve(X)&&(S=X.bind(s.api))}let P=this.tick[f];const N=ea({outerTick:a,noTransition:i,config:l,id:e,tickTextRotate:m,owner:s},c&&{isCategory:g,isInverted:l.axis_x_inverted,tickMultiline:l.axis_x_tick_multiline,tickWidth:l.axis_x_tick_width,tickTitle:g&&l.axis_x_tick_tooltip&&s.api.categories(),orgXScale:s.scale.x});c||(N.tickStepSize=l[`axis_${f}_tick_stepSize`]);const L=new Ry(N).scale(c&&s.scale.zoom||n).orient(v);if(c&&this.isTimeSeries()&&P&&!ve(P)){const X=Yn.bind(s);P=P.map(W=>X(W))}else!c&&this.isTimeSeriesY()&&(L.ticks(l.axis_y_tick_time_value),P=null);P&&L.tickValues(P),L.tickFormat(S||!c&&s.isStackNormalized()&&(X=>`${X}%`)),g&&(L.tickCentered(l.axis_x_tick_centered),qn(l.axis_x_tick_culling)&&(l.axis_x_tick_culling=!1));const w=l[`axis_${f}_tick_count`];return w&&L.ticks(w),L}updateXAxisTickValues(e,n){var a;const i=this.owner,{config:o}=i,s=o.axis_x_tick_fit;let l=o.axis_x_tick_count,c;return(s||l&&s)&&(c=i.mapTargetsToUniqueXs(e),this.isCategorized()&&l>c.length&&(l=c.length),c=this.generateTickValues(c,l,this.isTimeSeries())),n?n.tickValues(c):this.x&&(this.x.tickValues(c),(a=this.subX)==null||a.tickValues(c)),c}getId(e){const{config:n,scale:a}=this.owner;let i=n.data_axes[e];return(!i||!a[i])&&(i="y"),i}getXAxisTickFormat(e){const n=this.owner,{config:a,format:i}=n,o=e&&a.subchart_axis_x_tick_format||a.axis_x_tick_format,s=this.isTimeSeries(),l=this.isCategorized();let c;return o?ve(o)?c=o.bind(n.api):s&&(c=f=>f?i.axisTime(o)(f):""):c=s?i.defaultAxisTime:l?n.categoryName:f=>f<0?f.toFixed(0):f,ve(c)?f=>c.apply(n,l?[f,n.categoryName(f)]:[f]):c}getTickValues(e){const n=this.owner,a=n.config[`axis_${e}_tick_values`],i=n[`${e}Axis`];return(ve(a)?a.call(n.api):a)||(i?i.tickValues():void 0)}getLabelOptionByAxisId(e){return this.owner.config[`axis_${e}_label`]}getLabelText(e){const n=this.getLabelOptionByAxisId(e);return ze(n)?n:n?n.text:null}setLabelText(e,n){const a=this.owner,{config:i}=a,o=this.getLabelOptionByAxisId(e);ze(o)?i[`axis_${e}_label`]=n:o&&(o.text=n)}getLabelPosition(e,n){const a=this.owner.config.axis_rotated,i=this.getLabelOptionByAxisId(e),o=nr(i)&&i.position?i.position:n[+!a],s=l=>!!~o.indexOf(l);return{isInner:s("inner"),isOuter:s("outer"),isLeft:s("left"),isCenter:s("center"),isRight:s("right"),isTop:s("top"),isMiddle:s("middle"),isBottom:s("bottom")}}getAxisLabelPosition(e){return this.getLabelPosition(e,e==="x"?["inner-top","inner-right"]:["inner-right","inner-top"])}getLabelPositionById(e){return this.getAxisLabelPosition(e)}xForAxisLabel(e){const n=this.owner,{state:{width:a,height:i}}=n,o=this.getAxisLabelPosition(e);let s=o.isMiddle?-i/2:0;return this.isHorizontal(n,e!=="x")?s=o.isLeft?0:o.isCenter?a/2:a:o.isBottom&&(s=-i),s}textAnchorForAxisLabel(e){const n=this.owner,a=this.getAxisLabelPosition(e);let i=a.isMiddle?"middle":"end";return this.isHorizontal(n,e!=="x")?i=a.isLeft?"start":a.isCenter?"middle":"end":a.isBottom&&(i="start"),i}dxForAxisLabel(e){const n=this.owner,a=this.getAxisLabelPosition(e);let i=a.isBottom?"0.5em":"0";return this.isHorizontal(n,e!=="x")?i=a.isLeft?"0.5em":a.isRight?"-0.5em":"0":a.isTop&&(i="-0.5em"),i}dyForAxisLabel(e){const n=this.owner,{config:a}=n,i=a.axis_rotated,o=this.getAxisLabelPosition(e).isInner,s=a[`axis_${e}_tick_rotate`]?n.getHorizontalAxisHeight(e):0,{width:l}=this.getMaxTickSize(e);let c;if(e==="x"){const f=a.axis_x_height;i?c=o?"1.2em":-25-l:o?c="-0.5em":f?c=f-10:s?c=s-10:c="3em"}else c={y:["-0.5em",10,"3em","1.2em",10],y2:["1.2em",-20,"-2.2em","-0.5em",15]}[e],i?o?c=c[0]:s?c=s*(e==="y2"?-1:1)-c[1]:c=c[2]:c=o?c[3]:(c[4]+(a[`axis_${e}_inner`]?0:l+c[4]))*(e==="y"?-1:1);return c}getMaxTickSize(e,n){const a=this.owner,{config:i,state:{current:o},$el:{svg:s,chart:l}}=a,c=o.maxTickSize[e],f=`axis_${e}`,g={width:0,height:0};if(n||!i[`${f}_show`]||c.width>0&&a.filterTargetsToShow().length===0)return c;if(s){const v=/^y2?$/.test(e),m=a.filterTargetsToShow(a.data.targets),S=a.scale[e].copy().domain(a[`get${v?"Y":"X"}Domain`](m,e)),P=S.domain(),N=P[0]===P[1]&&P.every(K=>K>0),L=je(c.domain)&&c.domain[0]===c.domain[1]&&c.domain.every(K=>K>0);if(N||L)return c.size;c.domain=P,v||c.ticks.splice(0);const w=this.getAxis(e,S,!1,!1,!0),X=i[`${f}_tick_rotate`],W=i[`${f}_tick_count`];!i[`${f}_tick_values`]&&W&&w.tickValues(this.generateTickValues(P,W,v?this.isTimeSeriesY():this.isTimeSeries())),!v&&this.updateXAxisTickValues(m,w);const k=l.append("svg").style("visibility","hidden").style("position","fixed").style("top","0").style("left","0");w.create(k),k.selectAll("text").attr("transform",he(X)?`rotate(${X})`:null).each(function(K,at){const{width:ht,height:$t}=this.getBoundingClientRect();g.width=Math.max(g.width,ht),g.height=Math.max(g.height,$t),v||(c.ticks[at]=ht)}),k.remove()}return Object.keys(g).forEach(v=>{g[v]>0&&(c[v]=g[v])}),c}getXAxisTickTextY2Overflow(e){const n=this.owner,{axis:a,config:i,state:{current:o,isLegendRight:s,legendItemWidth:l}}=n,c=n.getAxisTickRotate("x"),f=c>0&&c<90;if((a.isCategorized()||a.isTimeSeries())&&i.axis_x_tick_fit&&(!i.axis_x_tick_culling||qn(i.axis_x_tick_culling))&&!i.axis_x_tick_multiline&&f){const g=i.axis_y2_show&&o.maxTickSize.y2.width||0,v=s&&l||0,m=o.width-n.getCurrentPaddingByDirection("left"),S=this.getXAxisTickMaxOverflow(c,m-e)-g-v,P=Math.max(0,S)+e;return Math.min(P,m/2)}return 0}getXAxisTickMaxOverflow(e,n){const a=this.owner,{axis:i,config:o,state:s}=a,l=i.isTimeSeries(),c=s.current.maxTickSize.x.ticks,f=c.length,{left:g,right:v}=s.axis.x.padding;let m=0;const S=f-(l&&o.axis_x_tick_fit?.5:0);for(let L=0;L{const c=this.getLabelText(l),f=`axis${Cn(l)}`,g=Tn[`${f}Label`];if(c){let v=i.select(`text.${g}`);v.empty()&&(v=i.select(`g.${Tn[f]}`).insert("text",":first-child").attr("class",g).attr("transform",["rotate(-90)",null][l==="x"?+!s:+s]).style("text-anchor",()=>this.textAnchorForAxisLabel(l))),o(v,e).attr("x",()=>this.xForAxisLabel(l)).attr("dx",()=>this.dxForAxisLabel(l)).attr("dy",()=>this.dyForAxisLabel(l)).text(c)}})}getPadding(e,n,a,i){const o=he(e)?e:e[n];return De(o)?this.owner.convertPixelToScale(/(bottom|top)/.test(n)?"y":"x",o,i):a}generateTickValues(e,n,a){let i=e;if(n){const o=ve(n)?n():n;if(o===1)i=[e[0]];else if(o===2)i=[e[0],e[e.length-1]];else if(o>2){const s=this.isCategorized(),l=o-2,c=e[0],f=e[e.length-1],g=(f-c)/(l+1);let v;i=[c];for(let m=0;mo-s)),i}generateTransitions(e){const n=this.owner,{$el:{axis:a},$T:i}=n,[o,s,l,c]=["x","y","y2","subX"].map(f=>i(a[f],e));return{axisX:o,axisY:s,axisY2:l,axisSubX:c}}redraw(e,n,a){const i=this.owner,{config:o,state:s,$el:l}=i,c=n?"0":null;["x","y","y2","subX"].forEach(f=>{const g=this[f],v=l.axis[f];g&&v&&(!a&&!o.transition_duration&&(g.config.withoutTransition=!0),v.style("opacity",c),g.create(e[`axis${Cn(f)}`]))}),this.updateAxes(),!s.rendered&&o.axis_tooltip&&this.setAxisTooltip()}redrawAxis(e,n,a,i,o){var s,l,c;const f=this.owner,{config:g,scale:v,$el:m}=f,S=!!v.zoom;let P;!S&&this.isCategorized()&&e.length===0&&v.x.domain([0,m.axis.x.selectAll(".tick").size()]),v.x&&e.length?(!S&&f.updateXDomain(e,n.UpdateXDomain,n.UpdateOrgXDomain,n.TrimXDomain),g.axis_x_tick_values||this.updateXAxisTickValues(e)):this.x&&(this.x.tickValues([]),(s=this.subX)==null||s.tickValues([])),g.zoom_rescale&&!i&&(P=v.x.orgDomain()),["y","y2"].forEach(N=>{const L=`axis_${N}_`,w=v[N];if(w){const X=g[`${L}tick_values`],W=g[`${L}tick_count`];if(w.domain(f.getYDomain(e,N,P)),!X&&W){const H=f.axis[N],k=w.domain();H.tickValues(this.generateTickValues(k,k.every(K=>K===0)?1:W,this.isTimeSeriesY()))}}}),this.redraw(a,f.hasArcType(),o),this.updateLabels(n.Transition),(n.UpdateXDomain||n.UpdateXAxis||n.Y)&&e.length&&this.setCulling(),n.Y&&((l=v.subY)==null||l.domain(f.getYDomain(e,"y")),(c=v.subY2)==null||c.domain(f.getYDomain(e,"y2")))}setCulling(){const e=this.owner,{config:n,state:{clip:a,current:i},$el:o}=e;["subX","x","y","y2"].forEach(s=>{const l=o.axis[s],f=`axis_${s==="subX"?"x":s}_tick_culling`,g=n[f];if(l&&g){const v=l.selectAll(".tick"),m=na(v.data()),S=m.length,P=n[`${f}_max`],N=n[`${f}_lines`];let L;if(S){for(let w=1;w{var f,g,v;if(ze(l)||l[c])if(s[c]=(f=o[c])==null?void 0:f.append("text").classed(Tn[`axis${c.toUpperCase()}Tooltip`],!0).attr("filter",n.updateTextBGColor({id:c},l)),a){const m=c==="x"?"x":"y",S=c==="y"?"1.15em":c==="x"?"-0.3em":"-0.4em";(g=s[c])==null||g.attr(m,S).attr(`d${c==="x"?"y":"x"}`,c==="x"?"0.4em":"-1.3em").style("text-anchor",c==="x"?"end":null)}else{const m=c==="x"?"y":"x",S=c==="x"?"1.15em":`${c==="y"?"-":""}0.4em`;(v=s[c])==null||v.attr(m,S).attr(`d${c==="x"?"x":"y"}`,c==="x"?"-1em":"0.3em").style("text-anchor",c==="y"?"end":null)}})}}var wy={initEventRect(){this.$el.main.select(`.${Se.chart}`).append("g").attr("class",Zn.eventRects).style("fill-opacity","0")},redrawEventRect(){var t;const e=this,{config:n,state:a,$el:i}=e,o=e.isMultipleX(),s=n.axis_x_inverted;if(i.eventRect)e.updateEventRect(i.eventRect,!0);else if(e.data.targets.length){const c=e.$el.main.select(`.${Zn.eventRects}`).style("cursor",n.zoom_enabled&&n.zoom_type!=="drag"?n.axis_rotated?"ns-resize":"ew-resize":null).classed(Zn.eventRectsMultiple,o).classed(Zn.eventRectsSingle,!o).selectAll(`.${Zn.eventRect}`).data([0]).enter().append("rect");e.updateEventRect(c),e.updateEventType(c),c.call(e.getDraggableSelection()),i.eventRect=c,e.state.inputType==="touch"&&!i.svg.on("touchstart.eventRect")&&!e.hasArcType()&&e.bindTouchOnEventRect(),a.rendered&&e.updateEventRect(i.eventRect,!0)}if(!o){const l=e.getMaxDataCountTarget();(!n.data_xSort||s)&&l.sort((c,f)=>s?f.x-c.x:c.x-f.x),e.updateDataIndexByX(l),e.updateXs(l),(t=e.updatePointClass)==null||t.call(e,!0),a.eventReceiver.data=l}e.updateEventRectData()},bindTouchOnEventRect(){const t=this,{config:e,state:n,$el:{eventRect:a,svg:i}}=t,o=m=>{if(t.isMultipleX())t.selectRectForMultipleXs(m);else{const S=t.getDataIndexFromEvent(n.event);t.callOverOutForTouch(S),S===-1?t.unselectRect():t.selectRectForSingle(m,S)}},s=()=>{t.unselectRect(),t.callOverOutForTouch()},l=e.interaction_inputType_touch.preventDefault,c=Co(l)&&l||!1,f=!isNaN(l)&&l||null;let g;const v=m=>{const S=m.type,N=m.changedTouches[0][`client${e.axis_rotated?"Y":"X"}`];S==="touchstart"?c?m.preventDefault():f!==null&&(g=N):S==="touchmove"&&(c||g===!0||f!==null&&Math.abs(g-N)>=f)&&(g=!0,m.preventDefault())};a.on("touchstart",m=>{n.event=m,t.updateEventRect()}).on("touchstart.eventRect touchmove.eventRect",m=>{if(n.event=m,!a.empty()&&a.classed(Zn.eventRect)){if(n.dragging||n.flowing||t.hasArcType()||m.touches.length>1)return;v(m),o(a.node())}else s()},!0).on("touchend.eventRect",m=>{n.event=m,!a.empty()&&a.classed(Zn.eventRect)&&(t.hasArcType()||!t.toggleShape||n.cancelClick)&&n.cancelClick&&(n.cancelClick=!1)},!0),i.on("touchstart",m=>{n.event=m;const{target:S}=m;S&&S!==a.node()&&s()})},updateEventRect(t,e=!1){const n=this,{state:a,$el:i}=n,{eventReceiver:o,width:s,height:l,rendered:c,resizing:f}=a,g=t||i.eventRect,v=()=>{if(o){const m=Zl(i.chart.node());o.rect=g.node().getBoundingClientRect().toJSON(),o.rect.top+=m.y,o.rect.left+=m.x}};(!c||f||e)&&(g.attr("x",0).attr("y",0).attr("width",s).attr("height",l),(!c||e)&&g.classed(Zn.eventRect,!0)),v()},updateEventType(t){const e=this,n=Co(t),a=n?e.$el.eventRect:t,i=n?t!==(a==null?void 0:a.datum().multipleX):!1;a&&(i&&(a==null||a.on("mouseover mousemove mouseout click",null)),e.isMultipleX()?e.generateEventRectsForMultipleXs(a):e.generateEventRectsForSingleX(a))},updateEventRectData(){const t=this,{config:e,scale:n,state:a}=t,i=n.zoom||n.x,o=e.axis_rotated,s=t.isMultipleX();let l,c,f,g;if(t.updateEventType(s),s)l=0,c=0,f=a.width,g=a.height;else{let S,P;if(t.axis.isCategorized())S=t.getEventRectWidth(),P=N=>i(N.x)-S/2;else{const N=({index:L})=>({prev:t.getPrevX(L),next:t.getNextX(L)});S=L=>{const w=N(L),X=i.domain();let W;return w.prev===null&&w.next===null?W=o?a.height:a.width:w.prev===null?W=(i(w.next)+i(L.x))/2:w.next===null?W=i(X[1])-(i(w.prev)+i(L.x))/2:(Object.keys(w).forEach((H,k)=>{var K;w[H]=(K=w[H])!=null?K:X[k]}),W=Math.max(0,(i(w.next)-i(w.prev))/2)),W},P=L=>{const w=N(L);let X;return w.prev===null&&w.next===null?X=0:w.prev===null?X=i(i.domain()[0]):X=(i(L.x)+i(w.prev))/2,X}}l=o?0:P,c=o?P:0,f=o?a.width:S,g=o?S:a.height}const{eventReceiver:v}=a,m=(S,P)=>ve(S)?S(P):S;v.coords.splice(v.data.length),v.data.forEach((S,P)=>{v.coords[P]={x:m(l,S),y:m(c,S),w:m(f,S),h:m(g,S)}})},selectRectForSingle(t,e){var n,a;const i=this,{config:o,$el:{main:s,circle:l}}=i,c=o.data_selection_enabled,f=o.data_selection_grouped,g=o.data_selection_isselectable,v=o.tooltip_grouped,m=i.getAllValuesOnIndex(e);if(v&&(i.showTooltip(m,t),(n=i.showGridFocus)==null||n.call(i,m),!c||f))return;!l&&s.selectAll(`.${Se.EXPANDED}:not(.${sn.shape}-${e})`).classed(Se.EXPANDED,!1);const S=s.selectAll(`.${sn.shape}-${e}`).classed(Se.EXPANDED,!0).style("cursor",g?"pointer":null).filter(function(P){return i.isWithinShape(this,P)});S.empty()&&!v&&o.interaction_onout&&((a=i.hideGridFocus)==null||a.call(i),i.hideTooltip(),!f&&i.setExpand(e)),S.call(P=>{var N,L;const w=P.data();c&&(f||g!=null&&g.bind(i.api)(w))&&(t.style.cursor="pointer"),v||(i.showTooltip(w,t),(N=i.showGridFocus)==null||N.call(i,w),(L=i.unexpandCircles)==null||L.call(i),P.each(X=>i.setExpand(e,X.id)))})},selectRectForMultipleXs(t,e=!0){const n=this,{config:a,state:i}=n,o=n.filterTargetsToShow(n.data.targets);if(i.dragging||n.hasArcType(o))return;const s=Hn(i.event,t),l=n.findClosestFromTargets(o,s);if(e&&i.mouseover&&(!l||l.id!==i.mouseover.id)&&(a.data_onout.call(n.api,i.mouseover),i.mouseover=void 0),!l){n.unselectRect();return}const f=(n.isBubbleType(l)||n.isScatterType(l)||!a.tooltip_grouped?[l]:n.filterByX(o,l.x)).map(v=>n.addName(v));n.showTooltip(f,t),n.setExpand(l.index,l.id,!0),n.showGridFocus(f);const g=n.dist(l,s);(n.isBarType(l.id)||g{const c=l?e.getDataIndexFromEvent(l):i.currentIdx;return c>-1?i.data[c]:null};o.on("mouseover",l=>{a.event=l,e.updateEventRect(),Object.values(e.$el.axisTooltip).forEach(c=>c==null?void 0:c.style("display",null))}).on("mousemove",function(l){const c=s(l);if(a.event=l,!c)return;let{index:f}=c;const g=n.line_step_type;if(n.line_step_tooltipMatch&&e.hasType("step")&&/^step\-(before|after)$/.test(g)){const m=e.scale.zoom||e.scale.x,S=e.axis.xs[f],P=m.invert(Hn(l,this)[0]);g==="step-after"&&PS&&(f+=1)}e.showAxisGridFocus();const v=n.tooltip_grouped&&f===i.currentIdx;if(a.dragging||a.flowing||e.hasArcType()||v){n.tooltip_show&&v&&e.setTooltipPosition();return}f!==i.currentIdx&&(e.setOverOut(!1,i.currentIdx),i.currentIdx=f),f===-1?e.unselectRect():e.selectRectForSingle(this,f),e.setOverOut(f!==-1,f)}).on("mouseout",l=>{a.event=l,!(!n||e.hasArcType()||i.currentIdx===-1||!n.interaction_onout)&&(e.hideAxisGridFocus(),e.unselectRect(),e.setOverOut(!1,i.currentIdx),i.currentIdx=-1)})}return o},clickHandlerForSingleX(t,e){const n=e,{config:a,state:i,$el:{main:o}}=n;if(!t||n.hasArcType()||i.cancelClick){i.cancelClick&&(i.cancelClick=!1);return}const{index:s}=t;o.selectAll(`.${sn.shape}-${s}`).each(function(l){var c;(a.data_selection_grouped||n.isWithinShape(this,l))&&((c=n.toggleShape)==null||c.call(n,this,l,s),a.data_onclick.bind(n.api)(l,this))})},generateEventRectsForMultipleXs(t){const e=this,{config:n,state:a}=e;t.on("click",function(i){a.event=i,e.clickHandlerForMultipleXS.bind(this)(e)}).datum({multipleX:!0}),a.inputType==="mouse"&&t.on("mouseover mousemove",function(i){a.event=i,e.selectRectForMultipleXs(this)}).on("mouseout",i=>{a.event=i,!(!e.config||e.hasArcType()||!n.interaction_onout)&&e.unselectRect()})},clickHandlerForMultipleXS(t){const e=t,{config:n,state:a}=e,i=e.filterTargetsToShow(e.data.targets);if(e.hasArcType(i))return;const o=Hn(a.event,this),s=e.findClosestFromTargets(i,o),l=e.getPointSensitivity(s);s&&(e.isBarType(s.id)||e.dist(s,o)+t;var Dy={generateFlow(t){const e=this,{data:n,state:a,$el:i}=e;return function(){const o=t.flow.length;a.flowing=!0,n.targets.forEach(l=>{l.values.splice(0,o)}),e.updateXGrid&&e.updateXGrid(!0);const s={};["axis.x","grid.x","gridLines.x","region.list","text","bar","line","area","circle"].forEach(l=>{const c=l.split(".");let f=i[c[0]];f&&c.length>1&&(f=f[c[1]]),f!=null&&f.size()&&(s[l]=f)}),e.hideGridFocus(),e.setFlowList(s,t)}},setFlowList(t,e){const n=this,{flow:a,targets:i}=e,{duration:o=e.duration,index:s,length:l,orgDataCount:c}=a,f=n.getFlowTransform(i,c,s,l),g=ec();let v;g.add(Object.keys(t).map(m=>(v=t[m].transition().ease(My).duration(o),m==="axis.x"?v=v.call(S=>{n.axis.x.setTransition(S).create(S)}):m==="region.list"?v=v.filter(n.isRegionOnX).attr("transform",f):v=v.attr("transform",f),v))),v.call(g,()=>{n.cleanUpFlow(t,e)})},cleanUpFlow(t,e){const n=this,{config:a,state:i,$el:{svg:o}}=n,s=a.axis_rotated,{flow:l,shape:c,xv:f}=e,{cx:g,cy:v,xForText:m,yForText:S}=c.pos,{done:P=()=>{},length:N}=l;N&&(["circle","text","shape","eventRect"].forEach(L=>{const w=[];for(let X=0;X{const w=t[L];if(L!=="axis.x"&&w.attr("transform",null),L==="grid.x")w.attr(i.xgridAttr);else if(L==="gridLines.x")w.attr("x1",s?0:f).attr("x2",s?i.width:f),w.select("text").attr("x",s?i.width:0).attr("y",f);else if(/^(area|bar|line)$/.test(L))w.attr("d",c.type[L]);else if(L==="text")w.attr("x",m).attr("y",S).style("fill-opacity",n.opacityForText.bind(n));else if(L==="circle")if(n.isCirclePoint())w.attr("cx",g).attr("cy",v);else{const X=H=>g(H)-a.point_r,W=H=>v(H)-a.point_r;w.attr("x",X).attr("y",W)}else L==="region.list"&&w.select("rect").filter(n.isRegionOnX).attr("x",n.regionX.bind(n)).attr("width",n.regionWidth.bind(n))}),a.interaction_enabled&&n.redrawEventRect(),P.call(n.api),i.flowing=!1},getFlowTransform(t,e,n,a){const i=this,{data:o,scale:{x:s}}=i,l=o.targets[0].values;let c=i.getValueOnIndex(l,n),f=i.getValueOnIndex(l,n+a),g;const v=s.domain(),m=i.updateXDomain(t,!0,!0);e?e===1||(c==null?void 0:c.x)===(f==null?void 0:f.x)?g=s(v[0])-s(m[0]):g=i.axis.isTimeSeries()?s(v[0])-s(m[0]):s((c==null?void 0:c.x)||0)-s(f.x):l.length!==1?g=s(v[0])-s(m[0]):i.axis.isTimeSeries()?(c=i.getValueOnIndex(l,0),f=i.getValueOnIndex(l,l.length-1),g=s(c.x)-s(f.x)):g=Dr(m)/2;const S=Dr(v)/Dr(m);return`translate(${g},0) scale(${S},1)`}},Ly={initClip(){const t=this,{clip:e,datetimeId:n}=t.state;e.id=`${n}-clip`,e.idXAxis=`${e.id}-xaxis`,e.idYAxis=`${e.id}-yaxis`,e.idGrid=`${e.id}-grid`,e.path=t.getClipPath(e.id),e.pathXAxis=t.getClipPath(e.idXAxis),e.pathYAxis=t.getClipPath(e.idYAxis),e.pathGrid=t.getClipPath(e.idGrid)},getClipPath(t){const e=this,{config:n}=e;return!n.clipPath&&/-clip$/.test(t)||!n.axis_x_clipPath&&/-clip-xaxis$/.test(t)||!n.axis_y_clipPath&&/-clip-yaxis$/.test(t)?null:`url(#${t})`},appendClip(t,e){e&&t.append("clipPath").attr("id",e).append("rect")},setXAxisClipPath(t){const e=this,{config:n,state:{margin:a,width:i,height:o}}=e,s=n.axis_rotated,l=Math.max(30,a.left)-(s?0:20),c=(s?a.top+o+10:a.bottom)+20,f=s?-(1+l):-(l-1),g=-15,v=s?a.left+20:i+10+l;t.attr("x",f).attr("y",g).attr("width",v).attr("height",c)},setYAxisClipPath(t){const e=this,{config:n,state:{margin:a,width:i,height:o}}=e,s=n.axis_rotated,l=Math.max(30,a.left)-(s?20:0),c=n.axis_y_inner,f=c&&!s?n.axis_y_label.text?-20:-1:s?-(1+l):-(l-1),g=-(s?20:a.top),v=(s?i+15+l:a.left+20)+(c?20:0),m=(s?a.bottom+10:a.top+o)+10;t.attr("x",f).attr("y",g).attr("width",v).attr("height",m)},updateXAxisTickClip(){const t=this,{config:e,state:{clip:n,xAxisHeight:a},$el:{defs:i}}=t,o=t.getHorizontalAxisHeight("x");if(i&&!n.idXAxisTickTexts){const s=`${n.id}-xaxisticktexts`;t.appendClip(i,s),n.pathXAxisTickTexts=t.getClipPath(n.idXAxisTickTexts),n.idXAxisTickTexts=s}!e.axis_x_tick_multiline&&t.getAxisTickRotate("x")&&o!==a&&(t.setXAxisTickClipWidth(),t.setXAxisTickTextClipPathWidth()),t.state.xAxisHeight=o},setXAxisTickClipWidth(){const t=this,{config:e,state:{current:{maxTickSize:n}}}=t,a=t.getAxisTickRotate("x");if(!e.axis_x_tick_multiline&&a){const i=Math.sin(Math.PI/180*Math.abs(a));n.x.clipPath=(t.getHorizontalAxisHeight("x")-20)/i}else n.x.clipPath=null},setXAxisTickTextClipPathWidth(){const t=this,{state:{clip:e,current:n},$el:{svg:a}}=t;a&&a.select(`#${e.idXAxisTickTexts} rect`).attr("width",n.maxTickSize.x.clipPath).attr("height",30)}};const Ny=t=>De(t.position)||"end",Fy=t=>t.position==="start"?4:t.position==="middle"?0:-4;function Cu(t,e,n){return a=>{let i=t?0:e;return a.position==="start"?i=t?-n:0:a.position==="middle"&&(i=(t?-n:e)/2),i}}function Pu(t,e){e==="grid"&&t.each(function(){const n=ot(this);["x1","x2","y1","y2"].forEach(a=>n.attr(a,+n.attr(a)))})}var By={hasGrid(){const{config:t}=this;return["x","y"].some(e=>t[`grid_${e}_show`]||t[`grid_${e}_lines`].length)},initGrid(){const t=this;t.hasGrid()&&t.initGridLines(),t.initFocusGrid()},initGridLines(){const t=this,{config:e,state:{clip:n},$el:a}=t;(e.grid_x_lines.length||e.grid_y_lines.length)&&(a.gridLines.main=a.main.insert("g",`.${Se.chart}${e.grid_lines_front?" + *":""}`).attr("clip-path",n.pathGrid).attr("class",`${on.grid} ${on.gridLines}`),a.gridLines.main.append("g").attr("class",on.xgridLines),a.gridLines.main.append("g").attr("class",on.ygridLines),a.gridLines.x=Uc([]))},updateXGrid(t){const e=this,{config:n,scale:a,state:i,$el:{main:o,grid:s}}=e,l=n.axis_rotated,c=e.generateGridData(n.grid_x_type,a.x),f=e.axis.isCategorized()?e.axis.x.tickOffset():0,g=v=>(a.zoom||a.x)(v)+f*(l?-1:1);i.xgridAttr=l?{x1:0,x2:i.width,y1:g,y2:g}:{x1:g,x2:g,y1:0,y2:i.height},s.x=o.select(`.${on.xgrids}`).selectAll(`.${on.xgrid}`).data(c),s.x.exit().remove(),s.x=s.x.enter().append("line").attr("class",on.xgrid).merge(s.x),t||s.x.each(function(){const v=ot(this);Object.keys(i.xgridAttr).forEach(m=>{v.attr(m,i.xgridAttr[m]).style("opacity",()=>v.attr(l?"y1":"x1")===(l?i.height:0)?"0":null)})})},updateYGrid(){const t=this,{axis:e,config:n,scale:a,state:i,$el:{grid:o,main:s}}=t,l=n.axis_rotated,c=g=>a.y(g),f=e.y.getGeneratedTicks(n.grid_y_ticks)||t.scale.y.ticks(n.grid_y_ticks);o.y=s.select(`.${on.ygrids}`).selectAll(`.${on.ygrid}`).data(f),o.y.exit().remove(),o.y=o.y.enter().append("line").attr("class",on.ygrid).merge(o.y),o.y.attr("x1",l?c:0).attr("x2",l?c:i.width).attr("y1",l?0:c).attr("y2",l?i.height:c),Pu(o.y,"grid")},updateGrid(){const t=this,{$el:{grid:e,gridLines:n}}=t;!n.main&&t.initGridLines(),e.main.style("visibility",t.hasArcType()?"hidden":null),t.hideGridFocus(),t.updateGridLines("x"),t.updateGridLines("y")},updateGridLines(t){const e=this,{config:n,$el:{gridLines:a,main:i},$T:o}=e,s=n.axis_rotated,l=t==="x";n[`grid_${t}_show`]&&e[`update${t.toUpperCase()}Grid`]();let c=i.select(`.${on[`${t}gridLines`]}`).selectAll(`.${on[`${t}gridLine`]}`).data(n[`grid_${t}_lines`]);o(c.exit()).style("opacity","0").remove();const f=c.enter().append("g");f.append("line").style("opacity","0"),c=f.merge(c),c.each(function(g){const v=ot(this);v.select("text").empty()&&g.text&&v.append("text").style("opacity","0")}),o(c.attr("class",g=>`${on[`${t}gridLine`]} ${g.class||""}`.trim()).select("text").attr("text-anchor",Ny).attr("transform",()=>l?s?null:"rotate(-90)":s?"rotate(-90)":null).attr("dx",Fy).attr("dy",-5)).text(function(g){var v;return(v=g.text)!=null?v:this.remove()}),a[t]=c},redrawGrid(t){const e=this,{config:{axis_rotated:n},state:{width:a,height:i},$el:{gridLines:o},$T:s}=e,l=e.xv.bind(e),c=e.yv.bind(e);let f=o.x.select("line"),g=o.x.select("text"),v=o.y.select("line"),m=o.y.select("text");return f=s(f,t).attr("x1",n?0:l).attr("x2",n?a:l).attr("y1",n?l:0).attr("y2",n?l:i),g=s(g,t).attr("x",Cu(!n,a,i)).attr("y",l),v=s(v,t).attr("x1",n?c:0).attr("x2",n?c:a).attr("y1",n?0:c).attr("y2",n?i:c),m=s(m,t).attr("x",Cu(n,a,i)).attr("y",c),[f.style("opacity",null),g.style("opacity",null),v.style("opacity",null),m.style("opacity",null)]},initFocusGrid(){const t=this,{config:e,state:{clip:n},$el:a}=t,i=e.grid_front,o=`.${i&&a.gridLines.main?on.gridLines:Se.chart}${i?" + *":""}`,s=a.main.insert("g",o).attr("clip-path",n.pathGrid).attr("class",on.grid);if(a.grid.main=s,e.grid_x_show&&s.append("g").attr("class",on.xgrids),e.grid_y_show&&s.append("g").attr("class",on.ygrids),e.axis_tooltip){const l=s.append("g").attr("class","bb-axis-tooltip");l.append("line").attr("class","bb-axis-tooltip-x"),l.append("line").attr("class","bb-axis-tooltip-y")}e.interaction_enabled&&e.grid_focus_show&&!e.axis_tooltip&&(s.append("g").attr("class",qe.xgridFocus).append("line").attr("class",qe.xgridFocus),e.grid_focus_y&&!e.tooltip_grouped&&s.append("g").attr("class",qe.ygridFocus).append("line").attr("class",qe.ygridFocus))},showAxisGridFocus(){var t,e;const n=this,{config:a,format:i,state:{event:o,width:s,height:l}}=n,c=a.axis_rotated,[f,g]=Hn(o,(t=n.$el.eventRect)==null?void 0:t.node()),v={x:f,y:g};for(const[m,S]of Object.entries(n.$el.axisTooltip)){const P=m==="x"&&!c||m!=="x"&&c?"x":"y",N=v[P];let L=(e=n.scale[m])==null?void 0:e.invert(N);L&&(L=m==="x"&&n.axis.isTimeSeries()?i.xAxisTick(L):L==null?void 0:L.toFixed(2),S==null||S.attr(P,N).text(L))}n.$el.main.selectAll("line.bb-axis-tooltip-x, line.bb-axis-tooltip-y").style("visibility",null).each(function(m,S){const P=ot(this);S===0?P.attr("x1",f).attr("x2",f).attr("y1",S?0:l).attr("y2",S?l:0):P.attr("x1",S?0:s).attr("x2",S?s:0).attr("y1",g).attr("y2",g)})},hideAxisGridFocus(){const t=this;t.$el.main.selectAll("line.bb-axis-tooltip-x, line.bb-axis-tooltip-y").style("visibility","hidden"),Object.values(t.$el.axisTooltip).forEach(e=>e==null?void 0:e.style("display","none"))},showGridFocus(t){var e;const n=this,{config:a,state:{width:i,height:o}}=n,s=a.axis_rotated,l=n.$el.main.selectAll(`line.${qe.xgridFocus}, line.${qe.ygridFocus}`),c=(t||[l.datum()]).filter(v=>v&&De(n.getBaseValue(v)));if(!a.tooltip_show||c.length===0||!a.axis_x_forceAsSingle&&n.hasType("bubble")||n.hasArcType())return;const f=a.grid_focus_edge&&!a.tooltip_grouped,g=n.xx.bind(n);l.style("visibility",null).data(c.concat(c)).each(function(v){const m=ot(this),S={x:g(v),y:n.getYScaleById(v.id)(v.value)};let P;if(m.classed(qe.xgridFocus))P=s?[null,S.x,f?S.y:i,S.x]:[S.x,f?S.y:null,S.x,o];else{const N=n.axis.getId(v.id)==="y2";P=s?[S.y,f&&!N?S.x:null,S.y,f&&N?S.x:o]:[f&&N?S.x:null,S.y,f&&!N?S.x:i,S.y]}["x1","y1","x2","y2"].forEach((N,L)=>m.attr(N,P[L]))}),Pu(l,"grid"),(e=n.showCircleFocus)==null||e.call(n,t)},hideGridFocus(){var t;const e=this,{state:{inputType:n,resizing:a},$el:{main:i}}=e;(n==="mouse"||!a)&&(i.selectAll(`line.${qe.xgridFocus}, line.${qe.ygridFocus}`).style("visibility","hidden"),(t=e.hideCircleFocus)==null||t.call(e))},updateGridFocus(){var t;const e=this,{state:{inputType:n,width:a,height:i,resizing:o},$el:{grid:s}}=e,l=s.main.select(`line.${qe.xgridFocus}`);if(n==="touch")l.empty()?o&&((t=e.showCircleFocus)==null||t.call(e)):e.showGridFocus();else{const c=e.config.axis_rotated;l.attr("x1",c?0:-10).attr("x2",c?a:-10).attr("y1",c?-10:0).attr("y2",c?-10:i)}return!0},generateGridData(t,e){const n=this,a=n.$el.main.select(`.${Tn.axisX}`).selectAll(".tick").size();let i=[];if(t==="year"){const o=n.getXDomain(),[s,l]=o.map(c=>c.getFullYear());for(let c=s;c<=l;c++)i.push(new Date(`${c}-01-01 00:00:00`))}else i=e.ticks(10),i.length>a&&(i=i.filter(o=>String(o).indexOf(".")<0));return i},getGridFilterToRemove(t){return t?e=>{let n=!1;return(je(t)?t.concat():[t]).forEach(a=>{("value"in a&&e.value===a.value||"class"in a&&e.class===a.class)&&(n=!0)}),n}:()=>!0},removeGridLines(t,e){const n=this,{config:a,$T:i}=n,o=n.getGridFilterToRemove(t),s=g=>!o(g),l=e?on.xgridLines:on.ygridLines,c=e?on.xgridLine:on.ygridLine;i(n.$el.main.select(`.${l}`).selectAll(`.${c}`).filter(o)).style("opacity","0").remove();const f=`grid_${e?"x":"y"}_lines`;a[f]=a[f].filter(s)}},Uy={initRegion(){const t=this,{$el:e}=t;e.region.main=e.main.insert("g",":first-child").attr("clip-path",t.state.clip.path).attr("class",$a.regions)},updateRegion(){const t=this,{config:e,$el:{region:n},$T:a}=t;n.main||t.initRegion(),n.main.style("visibility",t.hasArcType()?"hidden":null);const i=n.main.selectAll(`.${$a.region}`).data(e.regions);a(i.exit()).style("opacity","0").remove();const o=i.enter().append("g");o.append("rect").style("fill-opacity","0"),n.list=o.merge(i).attr("class",t.classRegion.bind(t)),n.list.each(function(s){var l;ot(this).select("text").empty()&&((l=s.label)!=null&&l.text)&&ot(this).append("text").style("opacity","0")})},redrawRegion(t){const e=this,{$el:{region:n},$T:a}=e,i=e.regionX.bind(e),o=e.regionY.bind(e),s=["width","height"];let l=n.list.select("rect"),c=n.list.selectAll("text");return l=a(l,t).attr("x",i).attr("y",o).attr("width",e.regionWidth.bind(e)).attr("height",e.regionHeight.bind(e)),c=a(c,t).text(f=>{var g;return(g=f.label)==null?void 0:g.text}).attr("transform",({label:f})=>f.rotated?" rotate(-90)":null).attr("transform",function(f){var g;const{x:v=0,y:m=0,center:S=!1,rotated:P=!1}=(g=f.label)!=null?g:{},N=this.previousElementSibling,L={x:0,y:0};return ze(S)&&["x","y"].forEach((w,X)=>{S.indexOf(w)>-1&&(L[w]=(+N.getAttribute(s[X])-Ma(this)[s[X]])/2)}),`translate(${i(f)+L.x+v}, ${o(f)+L.y+m})${P?" rotate(-90)":""}`}).attr("text-anchor",({label:f})=>f!=null&&f.rotated?"end":null).attr("dy","1em").style("fill",({label:f})=>{var g;return(g=f==null?void 0:f.color)!=null?g:null}),[l.style("fill-opacity",f=>De(f.opacity)?f.opacity:null).on("end",function(){ot(this.parentNode).selectAll("rect:not([x])").remove()}),c.style("opacity",null)]},regionX(t){return this.getRegionSize("x",t)},regionY(t){return this.getRegionSize("y",t)},regionWidth(t){return this.getRegionSize("width",t)},regionHeight(t){return this.getRegionSize("height",t)},getRegionSize(t,e){const n=this,{config:a,scale:i,state:o}=n,s=a.axis_rotated,l=/(x|y|y2)/.test(t),c=l?t==="x":t==="width",f=!l&&n[c?"regionX":"regionY"](e);let g=l?"start":"end",v=l?0:o[t],m;if(e.axis==="y"||e.axis==="y2"?(!l&&!c?g="start":l&&!c&&(g="end"),(c?s:!s)&&g in e&&(m=i[e.axis])):(c?!s:s)&&g in e&&(m=i.zoom||i.x),m){let S=0;v=e[g],n.axis.isTimeSeries(e.axis)?v=Yn.call(n,v):/(x|width)/.test(t)&&n.axis.isCategorized()&&isNaN(v)&&(v=a.axis_x_categories.indexOf(v),S=n.axis.x.tickOffset()*(g==="start"?-1:1)),v=m(v)+S}return l?v:v0&&(!i.axis_x_tick_autorotate||a.needToRotateXAxisTickTexts());return(i.axis_x_tick_multiline||L)&&N.height>S&&(P+=N.height-S),P+(a.axis.getLabelPositionById(t).isInner?0:10)+(t==="y2"&&!f?-10:0)},getEventRectWidth(){const t=this,{config:e,axis:n}=t,a=e.axis_x_inverted,i=n.x.tickInterval();return Math.max(0,a?Math.abs(i):i)},getAxisTickRotate(t){const e=this,{axis:n,config:a,state:i,$el:o}=e;let s=a[`axis_${t}_tick_rotate`];if(t==="x"){const l=n.isCategorized()||n.isTimeSeries();if(a.axis_x_tick_fit&&l){const c=a.axis_x_tick_count,f=i.current.maxTickSize.x.ticks.length;let g=0;if(c?g=c>f?f:c:f&&(g=f),g!==i.axis.x.tickCount){const{targets:v}=e.data;i.axis.x.padding=e.getXDomainPadding([e.getXDomainMinMax(v,"min"),e.getXDomainMinMax(v,"max")],g)}i.axis.x.tickCount=g}o.svg&&a.axis_x_tick_autorotate&&a.axis_x_tick_fit&&!a.axis_x_tick_multiline&&!a.axis_x_tick_culling&&l&&(s=e.needToRotateXAxisTickTexts()?a.axis_x_tick_rotate:0)}return s},needToRotateXAxisTickTexts(){const t=this,{state:{axis:e,current:n,isLegendRight:a,legendItemWidth:i}}=t,o=a&&i,s=n.width-o-t.getCurrentPaddingByDirection("left")-t.getCurrentPaddingByDirection("right"),l=e.x.tickCount+e.x.padding.left+e.x.padding.right,{width:c}=t.axis.getMaxTickSize("x"),f=l?s/l:0;return c>f}},jy={axis_x_clipPath:!0,axis_x_show:!0,axis_x_forceAsSingle:!1,axis_x_type:"indexed",axis_x_localtime:!0,axis_x_categories:[],axis_x_tick_centered:!1,axis_x_tick_format:void 0,axis_x_tick_culling:{},axis_x_tick_culling_max:10,axis_x_tick_culling_lines:!0,axis_x_tick_count:void 0,axis_x_tick_show:!0,axis_x_tick_text_show:!0,axis_x_tick_text_inner:!1,axis_x_tick_text_position:{x:0,y:0},axis_x_tick_fit:!0,axis_x_tick_values:null,axis_x_tick_autorotate:!1,axis_x_tick_rotate:0,axis_x_tick_outer:!0,axis_x_tick_multiline:!0,axis_x_tick_width:null,axis_x_tick_tooltip:!1,axis_x_max:void 0,axis_x_min:void 0,axis_x_inverted:!1,axis_x_padding:{},axis_x_height:void 0,axis_x_extent:void 0,axis_x_label:{},axis_x_axes:[]},Vy={axis_y_clipPath:!0,axis_y_show:!0,axis_y_type:"indexed",axis_y_max:void 0,axis_y_min:void 0,axis_y_inverted:!1,axis_y_center:void 0,axis_y_inner:!1,axis_y_label:{},axis_y_tick_format:void 0,axis_y_tick_culling:!1,axis_y_tick_culling_max:5,axis_y_tick_culling_lines:!0,axis_y_tick_outer:!0,axis_y_tick_values:null,axis_y_tick_rotate:0,axis_y_tick_count:void 0,axis_y_tick_show:!0,axis_y_tick_stepSize:null,axis_y_tick_text_show:!0,axis_y_tick_text_position:{x:0,y:0},axis_y_tick_time_value:void 0,axis_y_padding:{},axis_y_default:void 0,axis_y_axes:[]},Gy={axis_y2_show:!1,axis_y2_type:"indexed",axis_y2_max:void 0,axis_y2_min:void 0,axis_y2_inverted:!1,axis_y2_center:void 0,axis_y2_inner:!1,axis_y2_label:{},axis_y2_tick_format:void 0,axis_y2_tick_culling:!1,axis_y2_tick_culling_max:5,axis_y2_tick_culling_lines:!0,axis_y2_tick_outer:!0,axis_y2_tick_values:null,axis_y2_tick_rotate:0,axis_y2_tick_count:void 0,axis_y2_tick_show:!0,axis_y2_tick_stepSize:null,axis_y2_tick_text_show:!0,axis_y2_tick_text_position:{x:0,y:0},axis_y2_padding:{},axis_y2_default:void 0,axis_y2_axes:[]},Xy=Object.defineProperty,wu=Object.getOwnPropertySymbols,Hy=Object.prototype.hasOwnProperty,Yy=Object.prototype.propertyIsEnumerable,Mu=(t,e,n)=>e in t?Xy(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,Ts=(t,e)=>{for(var n in e||(e={}))Hy.call(e,n)&&Mu(t,n,e[n]);if(wu)for(var n of wu(e))Yy.call(e,n)&&Mu(t,n,e[n]);return t},Wy=Ts(Ts(Ts({axis_evalTextSize:!0,axis_rotated:!1,axis_tooltip:!1},jy),Vy),Gy),Ky={grid_x_show:!1,grid_x_type:"tick",grid_x_lines:[],grid_y_show:!1,grid_y_lines:[],grid_y_ticks:void 0,grid_focus_edge:!1,grid_focus_show:!0,grid_focus_y:!1,grid_front:!1,grid_lines_front:!0},Zy={data_xs:{},data_xFormat:"%Y-%m-%d",data_xLocaltime:!0,data_xSort:!0,data_axes:{},data_regions:{},data_stack_normalize:!1};const Jy=[sy,ly,cy,uy,fy,dy,hy],Du={axis:Cy,clip:Ly,eventrect:wy,flow:Dy,grid:By,region:Uy,sizeAxis:zy},Lu={optDataAxis:Zy,optAxis:Wy,optGrid:Ky};var I1=Array.prototype.slice;function $s(t){return typeof t=="object"&&"length"in t?t:Array.from(t)}function Le(t){return function(){return t}}function Qy(t,e){return et?1:e>=t?0:NaN}function ky(t){return t}function qy(){var t=ky,e=Qy,n=null,a=Le(0),i=Le(zi),o=Le(0);function s(l){var c,f=(l=$s(l)).length,g,v,m=0,S=new Array(f),P=new Array(f),N=+a.apply(this,arguments),L=Math.min(zi,Math.max(-zi,i.apply(this,arguments)-N)),w,X=Math.min(Math.abs(L)/f,o.apply(this,arguments)),W=X*(L<0?-1:1),H;for(c=0;c0&&(m+=H);for(e!=null?S.sort(function(k,K){return e(P[k],P[K])}):n!=null&&S.sort(function(k,K){return n(l[k],l[K])}),c=0,v=m?(L-f*W)/m:0;c0?H*v:0)+W,P[g]={data:l[g],index:c,value:H,startAngle:N,endAngle:w,padAngle:X};return P}return s.value=function(l){return arguments.length?(t=typeof l=="function"?l:Le(+l),s):t},s.sortValues=function(l){return arguments.length?(e=l,n=null,s):e},s.sort=function(l){return arguments.length?(n=l,e=null,s):n},s.startAngle=function(l){return arguments.length?(a=typeof l=="function"?l:Le(+l),s):a},s.endAngle=function(l){return arguments.length?(i=typeof l=="function"?l:Le(+l),s):i},s.padAngle=function(l){return arguments.length?(o=typeof l=="function"?l:Le(+l),s):o},s}var _y=Math.pow;const Ss=Math.PI,As=2*Ss,Gr=1e-6,tx=As-Gr;function Nu(t){this._+=t[0];for(let e=1,n=t.length;e=0))throw new Error(`invalid digits: ${t}`);if(e>15)return Nu;const n=_y(10,e);return function(a){this._+=a[0];for(let i=1,o=a.length;iGr)if(!(Math.abs(v*c-f*g)>Gr)||!o)this._append`L${this._x1=e},${this._y1=n}`;else{let S=a-s,P=i-l,N=c*c+f*f,L=S*S+P*P,w=Math.sqrt(N),X=Math.sqrt(m),W=o*Math.tan((Ss-Math.acos((N+m-L)/(2*w*X)))/2),H=W/X,k=W/w;Math.abs(H-1)>Gr&&this._append`L${e+H*g},${n+H*v}`,this._append`A${o},${o},0,0,${+(v*S>g*P)},${this._x1=e+k*c},${this._y1=n+k*f}`}}arc(e,n,a,i,o,s){if(e=+e,n=+n,a=+a,s=!!s,a<0)throw new Error(`negative radius: ${a}`);let l=a*Math.cos(i),c=a*Math.sin(i),f=e+l,g=n+c,v=1^s,m=s?i-o:o-i;this._x1===null?this._append`M${f},${g}`:(Math.abs(this._x1-f)>Gr||Math.abs(this._y1-g)>Gr)&&this._append`L${f},${g}`,a&&(m<0&&(m=m%As+As),m>tx?this._append`A${a},${a},0,1,${v},${e-l},${n-c}A${a},${a},0,1,${v},${this._x1=f},${this._y1=g}`:m>Gr&&this._append`A${a},${a},0,${+(m>=Ss)},${v},${this._x1=e+a*Math.cos(o)},${this._y1=n+a*Math.sin(o)}`)}rect(e,n,a,i){this._append`M${this._x0=this._x1=+e},${this._y0=this._y1=+n}h${a=+a}v${+i}h${-a}Z`}toString(){return this._}}function nx(){return new Wi}nx.prototype=Wi.prototype;function O1(t=3){return new Wi(+t)}function Es(t){let e=3;return t.digits=function(n){if(!arguments.length)return e;if(n==null)e=null;else{const a=Math.floor(n);if(!(a>=0))throw new RangeError(`invalid digits: ${n}`);e=a}return t},()=>new Wi(e)}function rx(t){return t.innerRadius}function ax(t){return t.outerRadius}function ix(t){return t.startAngle}function ox(t){return t.endAngle}function sx(t){return t&&t.padAngle}function lx(t,e,n,a,i,o,s,l){var c=n-t,f=a-e,g=s-i,v=l-o,m=v*c-g*f;if(!(m*mQ*Q+St*St&&(ht=dt,$t=st),{cx:ht,cy:$t,x01:-g,y01:-v,x11:ht*(i/k-1),y11:$t*(i/k-1)}}function Fu(){var t=rx,e=ax,n=Le(0),a=null,i=ix,o=ox,s=sx,l=null,c=Es(f);function f(){var g,v,m=+t.apply(this,arguments),S=+e.apply(this,arguments),P=i.apply(this,arguments)-Ui,N=o.apply(this,arguments)-Ui,L=Hc(N-P),w=N>P;if(l||(l=g=c()),Sbn))l.moveTo(0,0);else if(L>zi-bn)l.moveTo(S*jr(P),S*rr(P)),l.arc(0,0,S,P,N,!w),m>bn&&(l.moveTo(m*jr(N),m*rr(N)),l.arc(0,0,m,N,P,w));else{var X=P,W=N,H=P,k=N,K=L,at=L,ht=s.apply(this,arguments)/2,$t=ht>bn&&(a?+a.apply(this,arguments):oa(m*m+S*S)),dt=fs(Hc(S-m)/2,+n.apply(this,arguments)),st=dt,Vt=dt,vt,Q;if($t>bn){var St=Yc($t/m*rr(ht)),ct=Yc($t/S*rr(ht));(K-=St*2)>bn?(St*=w?1:-1,H+=St,k-=St):(K=0,H=k=(P+N)/2),(at-=ct*2)>bn?(ct*=w?1:-1,X+=ct,W-=ct):(at=0,X=W=(P+N)/2)}var At=S*jr(X),Gt=S*rr(X),Bt=m*jr(k),Kt=m*rr(k);if(dt>bn){var ne=S*jr(W),le=S*rr(W),be=m*jr(H),Oe=m*rr(H),Ce;if(Lbn?Vt>bn?(vt=Ki(be,Oe,At,Gt,S,Vt,w),Q=Ki(ne,le,Bt,Kt,S,Vt,w),l.moveTo(vt.cx+vt.x01,vt.cy+vt.y01),Vtbn)||!(K>bn)?l.lineTo(Bt,Kt):st>bn?(vt=Ki(Bt,Kt,ne,le,m,-st,w),Q=Ki(At,Gt,be,Oe,m,-st,w),l.lineTo(vt.cx+vt.x01,vt.cy+vt.y01),ste in t?cx(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,gx=(t,e)=>{for(var n in e||(e={}))dx.call(e,n)&&Uu(t,n,e[n]);if(Bu)for(var n of Bu(e))hx.call(e,n)&&Uu(t,n,e[n]);return t},vx=(t,e)=>ux(t,fx(e));function zu(t=0){const e=this,{config:n,state:a}=e,i=e.hasMultiArcGauge(),o=a.gaugeArcWidth/e.filterTargetsToShow(e.data.targets).length,s=t?Math.min(a.radiusExpanded*t-a.radius,o*.8-(1-t)*100):0;return{inner(l){const{innerRadius:c}=e.getRadius(l);return i?a.radius-o*(l.index+1):he(c)?c:0},outer(l){const{outerRadius:c}=e.getRadius(l);let f;if(i)f=a.radius-o*l.index+s;else if(e.hasType("polar")&&!t)f=e.getPolarOuterRadius(l,c);else if(f=c,t){let{radiusExpanded:g}=a;a.radius!==c&&(g-=Math.abs(a.radius-c)),f=g*t}return f},corner(l,c){const{arc_cornerRadius_ratio:f=0,arc_cornerRadius:g=0}=n,{data:{id:v},value:m}=l;let S=0;return f?S=f*c:S=he(g)?g:g.call(e.api,v,m,c),S}}}function bs(t){return function(e){const n=({startAngle:i=0,endAngle:o=0,padAngle:s=0})=>({startAngle:i,endAngle:o,padAngle:s}),a=Qr(n(this._current),n(e));return this._current=e,function(i){const o=a(i),{data:s,index:l,value:c}=e;return t(vx(gx({},o),{data:s,index:l,value:c}))}}}var px={initPie(){const t=this,{config:e}=t,n=e.data_type,a=e[`${n}_padding`],i=e[`${n}_startingAngle`]||0,o=(a?a*.01:e[`${n}_padAngle`])||0;t.pie=qy().startAngle(i).endAngle(i+2*Math.PI).padAngle(o).value(s=>{var l,c;return(c=(l=s.values)==null?void 0:l.reduce((f,g)=>f+g.value,0))!=null?c:s}).sort(t.getSortCompareFn.bind(t)(!0))},updateRadius(){const t=this,{config:e,state:n}=t,a=e.data_type,i=e[`${a}_padding`],o=e.gauge_width||e.donut_width,s=t.filterTargetsToShow(t.data.targets).length*e.gauge_arcs_minWidth;n.radiusExpanded=Math.min(n.arcWidth,n.arcHeight)/2*(t.hasMultiArcGauge()&&e.gauge_label_show?.85:1),n.radius=n.radiusExpanded*.95,n.innerRadiusRatio=o?(n.radius-o)/n.radius:.6,n.gaugeArcWidth=o||(s<=n.radius-n.innerRadius?n.radius-n.innerRadius:s<=n.radius?s:n.radius);const l=e.pie_innerRadius||(i?i*(n.innerRadiusRatio+.1):0);n.outerRadius=e.pie_outerRadius,n.innerRadius=t.hasType("donut")||t.hasType("gauge")?n.radius*n.innerRadiusRatio:l},getRadius(t){const e=this,n=t==null?void 0:t.data;let{innerRadius:a,outerRadius:i}=e.state;return!he(a)&&n&&(a=a[n.id]||0),Be(i)&&n&&n.id in i?i=i[n.id]:he(i)||(i=e.state.radius),{innerRadius:a,outerRadius:i}},updateArc(){const t=this;t.updateRadius(),t.svgArc=t.getSvgArc(),t.svgArcExpanded=t.getSvgArcExpanded()},getArcLength(){const t=this,{config:e}=t,n=e.gauge_arcLength*3.6;let a=2*(n/360);return n<-360?a=-2:n>360&&(a=2),a*Math.PI},getStartingAngle(){const t=this,{config:e}=t,n=e.data_type,a=t.hasType("gauge")?e.gauge_fullCircle:!1,i=-1*Math.PI/2,o=Math.PI/2;let s=e[`${n}_startingAngle`]||0;return!a&&s<=i?s=i:!a&&s>=o?s=o:(s>Math.PI||s<-1*Math.PI)&&(s=Math.PI),s},updateAngle(t,e=!1){var n;const a=this,{config:i,state:o}=a,s=e&&a.hasType("gauge");let{pie:l}=a,c=t,f=!1;if(!i)return null;const g=a.getStartingAngle(),v=i.gauge_fullCircle||e&&!s?a.getArcLength():g*-2;if(c.data&&a.isGaugeType(c.data)&&!a.hasMultiArcGauge()){const{gauge_min:m,gauge_max:S}=i,P=a.getTotalDataSum(o.rendered),N=v*((P-m)/(S-m));l=l.startAngle(g).endAngle(N+g)}if(e===!1&&l(a.filterTargetsToShow()).forEach((m,S)=>{var P;!f&&m.data.id===((P=c.data)==null?void 0:P.id)&&(f=!0,c=m,c.index=S)}),isNaN(c.startAngle)&&(c.startAngle=0),isNaN(c.endAngle)&&(c.endAngle=c.startAngle),e||c.data&&(i.gauge_enforceMinMax||a.hasMultiArcGauge())){const{gauge_min:m,gauge_max:S}=i,P=e&&!s?a.getTotalDataSum(o.rendered):S,N=v/(P-m),L=(n=c.value)!=null?n:0,w=L{const l=e.updateAngle(s),c=a(l);let f=0;return l&&(f=i(l,c)),l?o.cornerRadius(f)(l):"M 0 0"}},getArc(t,e,n){return n||this.isArcType(t.data)?this.svgArc(t,e):"M 0 0"},redrawArcRangeText(){const t=this,{config:e,$el:{arcs:n},state:a,$T:i}=t,o=e.arc_rangeText_format,s=t.hasType("gauge")&&e.arc_rangeText_fixed;let l=e.arc_rangeText_values;if(l!=null&&l.length){const c=e.arc_rangeText_unit==="%",f=t.getTotalDataSum(a.rendered);c&&(l=l.map(m=>f/100*m));const g=t.pie(l).map((m,S)=>(m.index=S,m));let v=n.selectAll(`.${Ve.arcRange}`).data(l);v.exit(),v=i(v.enter().append("text").attr("class",Ve.arcRange).style("text-anchor","middle").style("pointer-events","none").style("opacity","0").text(m=>{const S=c?m/f*100:m;return ve(o)?o(S):`${S}${c?"%":""}`}).merge(v)),(!a.rendered||a.rendered&&!s)&&f>0&&v.attr("transform",(m,S)=>t.transformForArcLabel(g[S],!0)),v.style("opacity",m=>!s&&(m>f||f===0)?"0":null)}},transformForArcLabel(t,e=!1){var n,a,i;const o=this,{config:s,state:{radiusExpanded:l}}=o,c=o.updateAngle(t,e);let f="";if(c){if(e||o.hasMultiArcGauge()){const g=Math.sin(c.endAngle-Math.PI/2),v=s.arc_rangeText_position;let m=Math.cos(c.endAngle-Math.PI/2)*(l+(e?5:25)),S=g*(l+15-Math.abs(g*10))+3;if(e&&v){const P=s.arc_rangeText_values,N=ve(v)?v(P[t.index]):v;m+=(n=N==null?void 0:N.x)!=null?n:0,S+=(a=N==null?void 0:N.y)!=null?a:0}f=`translate(${m},${S})`}else if(!o.hasType("gauge")||o.data.targets.length>1){let{outerRadius:g}=o.getRadius(t);o.hasType("polar")&&(g=o.getPolarOuterRadius(t,g));const v=this.svgArc.centroid(c),[m,S]=v.map(L=>isNaN(L)?0:L),P=Math.sqrt(m*m+S*S);let N=(i=["donut","gauge","pie","polar"].filter(o.hasType.bind(o)).map(L=>s[`${L}_label_ratio`]))==null?void 0:i[0];N?N=ve(N)?N.bind(o.api)(t,g,P):N:N=g&&(P?(36/g>.375?1.175-36/g:.8)*g/P:0),f=`translate(${m*N},${S*N})`}}return f},convertToArcData(t){return this.addName({id:"data"in t?t.data.id:t.id,value:t.value,ratio:this.getRatio("arc",t),index:t.index})},textForArcLabel(t){const e=this,n=e.hasType("gauge");e.shouldShowArcLabel()&&t.style("fill",e.updateTextColor.bind(e)).attr("filter",a=>e.updateTextBGColor.bind(e)(a,e.config.data_labels_backgroundColors)).each(function(a){var i;const o=ot(this),s=e.updateAngle(a),l=e.getRatio("arc",s);if(e.meetsLabelThreshold(l,(i=["donut","gauge","pie","polar"].filter(e.hasType.bind(e)))==null?void 0:i[0])){const{value:f}=s||a,g=(e.getArcLabelFormat()||e.defaultArcValueFormat)(f,l,a.data.id).toString();wa(o,g,[-1,1],n)}else o.text("")})},expandArc(t){const e=this,{state:{transiting:n},$el:a}=e;if(n){const o=setInterval(()=>{n||(clearInterval(o),a.legend.selectAll(`.${qe.legendItemFocused}`).size()>0&&e.expandArc(t))},10);return}const i=e.mapToTargetIds(t);a.svg.selectAll(e.selectorTargets(i,`.${Ve.chartArc}`)).each(function(o){if(!e.shouldExpand(o.data.id))return;const s=e.getExpandConfig(o.data.id,"duration"),l=e.getSvgArcExpanded(e.getExpandConfig(o.data.id,"rate"));ot(this).selectAll("path").transition().duration(s).attrTween("d",bs(e.svgArcExpanded.bind(e))).transition().duration(s*2).attrTween("d",bs(l.bind(e)))})},unexpandArc(t){const e=this,{state:{transiting:n},$el:{svg:a}}=e;if(n)return;const i=e.mapToTargetIds(t);a.selectAll(e.selectorTargets(i,`.${Ve.chartArc}`)).selectAll("path").transition().duration(o=>e.getExpandConfig(o.data.id,"duration")).attrTween("d",bs(e.svgArc.bind(e))),a.selectAll(`${Ve.arc}`).style("opacity",null)},getExpandConfig(t,e){const n=this,{config:a}=n,i={duration:50,rate:.98};let o;return n.isDonutType(t)?o="donut":n.isGaugeType(t)?o="gauge":n.isPieType(t)&&(o="pie"),o?a[`${o}_expand_${e}`]:i[e]},shouldExpand(t){const e=this,{config:n}=e;return e.isDonutType(t)&&n.donut_expand||e.isGaugeType(t)&&n.gauge_expand||e.isPieType(t)&&n.pie_expand},shouldShowArcLabel(){const t=this,{config:e}=t;return["donut","gauge","pie","polar"].some(n=>t.hasType(n)&&e[`${n}_label_show`])},getArcLabelFormat(){const t=this,{config:e}=t;let n=a=>a;return["donut","gauge","pie","polar"].filter(t.hasType.bind(t)).forEach(a=>{n=e[`${a}_label_format`]}),ve(n)?n.bind(t.api):n},updateTargetsForArc(t){const e=this,{$el:n}=e,a=e.hasType("gauge"),i=e.getChartClass("Arc"),o=e.getClass("arcs",!0),s=e.classFocus.bind(e),l=n.main.select(`.${Ve.chartArcs}`),c=l.selectAll(`.${Ve.chartArc}`).data(e.pie(t)).attr("class",g=>i(g)+s(g.data)),f=c.enter().append("g").attr("class",i).call(this.setCssRule(!1,`.${Ve.chartArcs} text`,["pointer-events:none","text-anchor:middle"]));f.append("g").attr("class",o).merge(c),f.append("text").attr("dy",a&&!e.hasMultiTargets()?"-.1em":".35em").style("opacity","0").style("text-anchor",e.getStylePropValue("middle")).style("pointer-events",e.getStylePropValue("none")),n.text=l.selectAll(`.${Se.target} text`)},initArc(){const t=this,{$el:e}=t;e.arcs=e.main.select(`.${Se.chart}`).append("g").attr("class",Ve.chartArcs).attr("transform",t.getTranslate("arc")),t.setArcTitle()},setArcTitle(t){const e=this,n=t||e.getArcTitle(),a=e.hasType("gauge");if(n){const i=a?Un.chartArcsGaugeTitle:Ve.chartArcsTitle;let o=e.$el.arcs.select(`.${i}`);o.empty()&&(o=e.$el.arcs.append("text").attr("class",i).style("text-anchor","middle")),a&&o.attr("dy","-0.3em"),wa(o,n,a?void 0:[-.6,1.35],!0)}},getArcTitle(){const t=this,e=t.hasType("donut")&&"donut"||t.hasType("gauge")&&"gauge";return e?t.config[`${e}_title`]:""},getArcTitleWithNeedleValue(){const t=this,{config:e,state:n}=t,a=t.getArcTitle();if(a&&t.config.arc_needle_show&&/{=[A-Z_]+}/.test(a)){let i=n.current.needle;return he(i)||(i=e.arc_needle_value),bi(a,{NEEDLE_VALUE:he(i)?i:0})}return!1},redrawArc(t,e,n){const a=this,{config:i,state:o,$el:{main:s}}=a,l=i.interaction_enabled,c=l&&i.data_selection_isselectable;let f=s.selectAll(`.${Ve.arcs}`).selectAll(`.${Ve.arc}`).data(a.arcData.bind(a));f.exit().transition().duration(e).style("opacity","0").remove(),f=f.enter().append("path").attr("class",a.getClass("arc",!0)).style("fill",g=>a.color(g.data)).style("cursor",g=>{var v;return(v=c==null?void 0:c.bind)!=null&&v.call(c,a.api)(g)?"pointer":null}).style("opacity","0").each(function(g){a.isGaugeType(g.data)&&(g.startAngle=i.gauge_startingAngle,g.endAngle=i.gauge_startingAngle),this._current=g}).merge(f),a.hasType("gauge")&&(a.updateGaugeMax(),a.hasMultiArcGauge()&&a.redrawArcGaugeLine()),f.attr("transform",g=>!a.isGaugeType(g.data)&&n?"scale(0)":"").style("opacity",function(g){return g===this._current?"0":null}).each(()=>{o.transiting=!0}).transition().duration(t).attrTween("d",function(g){const v=a.updateAngle(g);if(!v)return()=>"M 0 0";isNaN(this._current.startAngle)&&(this._current.startAngle=0),isNaN(this._current.endAngle)&&(this._current.endAngle=this._current.startAngle);const m=Qr(this._current,v);return this._current=m(0),function(S){const P=m(S);return P.data=g.data,a.getArc(P,!0)}}).attr("transform",n?"scale(1)":"").style("fill",g=>{let v;return a.levelColor?(v=a.levelColor(g.data.values[0].value),i.data_colors[g.data.id]=v):v=a.color(g.data),v}).style("opacity",null).call(Si,function(){if(a.levelColor){const g=ot(this),v=g.datum(this._current);a.updateLegendItemColor(v.data.id,g.style("fill"))}o.transiting=!1,_e(i.onrendered,a.api)}),l&&a.bindArcEvent(f),a.hasType("polar")&&a.redrawPolar(),a.hasType("gauge")&&a.redrawBackgroundArcs(),i.arc_needle_show&&a.redrawNeedle(),a.redrawArcText(t),a.redrawArcRangeText()},redrawNeedle(){const t=this,{$el:e,config:n,state:{hiddenTargetIds:a,radius:i}}=t,o=(i-1)/100*n.arc_needle_length,s=a.length!==t.data.targets.length;let l=t.$el.arcs.select(`.${Ve.needle}`);const c=n.arc_needle_path,f=n.arc_needle_bottom_width/2,g=n.arc_needle_top_width/2,v=n.arc_needle_top_rx,m=n.arc_needle_top_ry,S=n.arc_needle_bottom_len,P=n.arc_needle_bottom_rx,N=n.arc_needle_bottom_ry,L=t.getNeedleAngle(),w=()=>{const X=t.getArcTitleWithNeedleValue();X&&t.setArcTitle(X)};if(w(),l.empty()&&(l=e.arcs.append("path").classed(Ve.needle,!0),e.needle=l,e.needle.updateHelper=(X,W=!1)=>{e.needle.style("display")!=="none"&&t.$T(e.needle).style("transform",`rotate(${t.getNeedleAngle(X)}deg)`).call(Si,()=>{W&&(n.arc_needle_value=X),w()})}),s){const X=ve(c)?c.call(t,o):`M-${f} ${S} A${P} ${N} 0 0 0 ${f} ${S} L${g} -${o} A${v} ${m} 0 0 0 -${g} -${o} L-${f} ${S} Z`;t.$T(l).attr("d",X).style("fill",n.arc_needle_color).style("display",null).style("transform",`rotate(${L}deg)`)}else l.style("display","none")},getNeedleAngle(t){const e=this,{config:n,state:a}=e,i=e.getArcLength(),o=e.hasType("gauge"),s=e.getTotalDataSum(!0);let l=Qe(t)?t:n.arc_needle_value,c=n[`${n.data_type}_startingAngle`]||0,f=0;if(he(l)||(l=o&&e.data.targets.length===1?s:0),a.current.needle=l,o){c=e.getStartingAngle();const g=n.gauge_fullCircle?i:c*-2,{gauge_min:v,gauge_max:m}=n;f=g*((l-v)/(m-v))}else f=i*(l/s);return(c+f)*(180/Math.PI)},redrawBackgroundArcs(){const t=this,{config:e,state:n}=t,a=t.hasMultiArcGauge(),i=e.gauge_fullCircle,o=t.filterTargetsToShow(t.data.targets).length===0&&!!e.data_empty_label_text,s=t.getStartingAngle(),l=i?s+t.getArcLength():s*-1;let c=t.$el.arcs.select(`${a?"g":""}.${Ve.chartArcsBackground}`);if(a){let f=0;c=c.selectAll(`path.${Ve.chartArcsBackground}`).data(t.data.targets),c.enter().append("path").attr("class",(g,v)=>`${Ve.chartArcsBackground} ${Ve.chartArcsBackground}-${v}`).merge(c).style("fill",e.gauge_background||null).attr("d",({id:g})=>{if(o||n.hiddenTargetIds.indexOf(g)>=0)return"M 0 0";const v={data:[{value:e.gauge_max}],startAngle:s,endAngle:l,index:f++};return t.getArc(v,!0,!0)}),c.exit().remove()}else c.attr("d",o?"M 0 0":()=>{const f={data:[{value:e.gauge_max}],startAngle:s,endAngle:l};return t.getArc(f,!0,!0)})},bindArcEvent(t){const e=this,{config:n,state:a}=e,i=a.inputType==="touch",o=a.inputType==="mouse";function s(c,f,g){e.expandArc(g),e.api.focus(g),e.toggleFocusLegend(g,!0),e.showTooltip([f],c)}function l(c){const f=(c==null?void 0:c.id)||void 0;e.unexpandArc(f),e.api.revert(),e.revertLegend(),e.hideTooltip()}if(t.on("click",function(c,f,g){var v;const m=e.updateAngle(f);let S;m&&(S=e.convertToArcData(m),(v=e.toggleShape)==null||v.call(e,this,S,g),n.data_onclick.bind(e.api)(S,this))}),o&&t.on("mouseover",function(c,f){if(a.transiting)return;a.event=c;const g=e.updateAngle(f),v=g?e.convertToArcData(g):null,m=(v==null?void 0:v.id)||void 0;s(this,v,m),e.setOverOut(!0,v)}).on("mouseout",(c,f)=>{if(a.transiting||!n.interaction_onout)return;a.event=c;const g=e.updateAngle(f),v=g?e.convertToArcData(g):null;l(),e.setOverOut(!1,v)}).on("mousemove",function(c,f){const g=e.updateAngle(f),v=g?e.convertToArcData(g):null;a.event=c,e.showTooltip([v],this)}),i&&e.hasArcType()&&!e.radars){const c=f=>{var g,v;const{clientX:m,clientY:S}=(v=(g=f.changedTouches)==null?void 0:g[0])!=null?v:{clientX:0,clientY:0};return ot(gn.elementFromPoint(m,S))};e.$el.svg.on("touchstart touchmove",function(f){if(a.transiting)return;a.event=f;const v=c(f).datum(),m=v!=null&&v.data&&v.data.id?e.updateAngle(v):null,S=m?e.convertToArcData(m):null,P=(S==null?void 0:S.id)||void 0;e.callOverOutForTouch(S),ln(P)?l():s(this,S,P)})}},redrawArcText(t){const e=this,{config:n,state:a,$el:{main:i,arcs:o}}=e,s=e.hasType("gauge"),l=e.hasMultiArcGauge();let c;if(s&&e.data.targets.length===1&&n.gauge_title||(c=i.selectAll(`.${Ve.chartArc}`).select("text").style("opacity","0").attr("class",f=>e.isGaugeType(f.data)?Un.gaugeValue:null).call(e.textForArcLabel.bind(e)).attr("transform",f=>e.transformForArcLabel.bind(e)(f)).style("font-size",f=>e.isGaugeType(f.data)&&e.data.targets.length===1&&!l?`${Math.round(a.radius/5)}px`:null).transition().duration(t).style("opacity",f=>e.isTargetToShow(f.data.id)&&e.isArcType(f.data)?null:"0"),l&&c.attr("dy","-.1em")),i.select(`.${Ve.chartArcsTitle}`).style("opacity",e.hasType("donut")||s?null:"0"),s){const f=n.gauge_fullCircle;f&&(c==null||c.attr("dy",`${l?0:Math.round(a.radius/14)}`)),n.gauge_label_show&&(o.select(`.${Un.chartArcsGaugeUnit}`).attr("dy",`${f?1.5:.75}em`).text(n.gauge_units),o.select(`.${Un.chartArcsGaugeMin}`).attr("dx",`${-1*(a.innerRadius+(a.radius-a.innerRadius)/(f?1:2))}px`).attr("dy","1.2em").text(e.textForGaugeMinMax(n.gauge_min,!1)),!f&&o.select(`.${Un.chartArcsGaugeMax}`).attr("dx",`${a.innerRadius+(a.radius-a.innerRadius)/2}px`).attr("dy","1.2em").text(e.textForGaugeMinMax(n.gauge_max,!0)))}},getArcElementByIdOrIndex(t){const e=this,{$el:{arcs:n}}=e,a=he(t)?i=>i.index===t:i=>i.data.id===t;return n==null?void 0:n.selectAll(`.${Se.target} path`).filter(a)}};function ju(t){return t[0]}function Vu(t){return t[1]}function Gu(t,e){var n=Le(!0),a=null,i=gs,o=null,s=Es(l);t=typeof t=="function"?t:t===void 0?ju:Le(t),e=typeof e=="function"?e:e===void 0?Vu:Le(e);function l(c){var f,g=(c=$s(c)).length,v,m=!1,S;for(a==null&&(o=i(S=s())),f=0;f<=g;++f)!(f=S;--P)l.point(W[P],H[P]);l.lineEnd(),l.areaEnd()}w&&(W[m]=+t(L,m,v),H[m]=+e(L,m,v),l.point(a?+a(L,m,v):W[m],n?+n(L,m,v):H[m]))}if(X)return l=null,X+""||null}function g(){return Gu().defined(i).curve(s).context(o)}return f.x=function(v){return arguments.length?(t=typeof v=="function"?v:Le(+v),a=null,f):t},f.x0=function(v){return arguments.length?(t=typeof v=="function"?v:Le(+v),f):t},f.x1=function(v){return arguments.length?(a=v==null?null:typeof v=="function"?v:Le(+v),f):a},f.y=function(v){return arguments.length?(e=typeof v=="function"?v:Le(+v),n=null,f):e},f.y0=function(v){return arguments.length?(e=typeof v=="function"?v:Le(+v),f):e},f.y1=function(v){return arguments.length?(n=v==null?null:typeof v=="function"?v:Le(+v),f):n},f.lineX0=f.lineY0=function(){return g().x(t).y(e)},f.lineY1=function(){return g().x(t).y(n)},f.lineX1=function(){return g().x(a).y(e)},f.defined=function(v){return arguments.length?(i=typeof v=="function"?v:Le(!!v),f):i},f.curve=function(v){return arguments.length?(s=v,o!=null&&(l=s(o)),f):s},f.context=function(v){return arguments.length?(v==null?o=l=null:l=s(o=v),f):o},f}var sa={initArea(t){const e=this,{config:n}=e;t.insert("g",`.${n.area_front?$n.circles:ur.lines}`).attr("class",e.getClass("areas",!0))},updateAreaColor(t){const e=this;return e.config.area_linearGradient?e.getGradienColortUrl(t.id):e.color(t)},updateArea(t,e=!1){const n=this,{config:a,state:i,$el:o,$T:s}=n,l=e?o.subchart:o;a.area_linearGradient&&n.updateLinearGradient();const c=l.main.selectAll(`.${ti.areas}`).selectAll(`.${ti.area}`).data(n.lineData.bind(n));s(c.exit(),t).style("opacity","0").remove(),l.area=c.enter().append("path").attr("class",n.getClass("area",!0)).style("fill",n.updateAreaColor.bind(n)).style("opacity",function(){return i.orgAreaOpacity=ot(this).style("opacity"),"0"}).merge(c),c.style("opacity",i.orgAreaOpacity),n.setRatioForGroupedData(l.area.data())},redrawArea(t,e,n=!1){const a=this,{area:i}=n?this.$el.subchart:this.$el,{orgAreaOpacity:o}=a.state;return[a.$T(i,e,gr()).attr("d",t).style("fill",a.updateAreaColor.bind(a)).style("opacity",s=>String(a.isAreaRangeType(s)?o/1.75:o))]},generateDrawArea(t,e){const n=this,{config:a}=n,i=a.line_connectNull,o=a.axis_rotated,s=n.generateGetAreaPoints(t,e),l=n.getYScaleById.bind(n),c=v=>(e?n.subxx:n.xx).call(n,v),f=(v,m)=>n.isGrouped(v.id)?s(v,m)[0][1]:l(v.id,e)(n.isAreaRangeType(v)?n.getRangedData(v,"high"):n.getShapeYMin(v.id)),g=(v,m)=>n.isGrouped(v.id)?s(v,m)[1][1]:l(v.id,e)(n.isAreaRangeType(v)?n.getRangedData(v,"low"):v.value);return v=>{let m=i?n.filterRemoveNull(v.values):v.values,S=0,P=0,N;if(n.isAreaType(v)){let L=mx();L=o?L.y(c).x0(f).x1(g):L.x(c).y0(a.area_above?0:a.area_below?n.state.height:f).y1(g),i||(L=L.defined(w=>n.getBaseValue(w)!==null)),n.isStepType(v)&&(m=n.convertValuesToStep(m)),N=L.curve(n.getCurve(v))(m)}else m[0]&&(S=n.scale.x(m[0].x),P=n.getYScaleById(v.id)(m[0].value)),N=o?`M ${P} ${S}`:`M ${S} ${P}`;return N||"M 0 0"}},generateGetAreaPoints(t,e){const n=this,{config:a}=n,i=n.getShapeX(0,t,e),o=n.getShapeY(!!e),s=n.getShapeOffset(n.isAreaType,t,e),l=n.getYScaleById.bind(n);return function(c,f){const g=l.call(n,c.id,e)(n.getShapeYMin(c.id)),v=s(c,f)||g,m=i(c),S=c.value;let P=o(c);return a.axis_rotated&&(S>0&&Pg.values.some(v=>he(v.value)||e.isBarRangeType(v)))).attr("class",g=>i(g)+s(g)).enter().append("g").attr("class",i).style("opacity","0").style("pointer-events",e.getStylePropValue("none")).append("g").attr("class",o).style("cursor",g=>{var v;return(v=l==null?void 0:l.bind)!=null&&v.call(l,e.api)(g)?"pointer":null}).call(e.setCssRule(!0,` .${Kn.bar}`,["fill"],e.color))},updateBar(t,e=!1){const n=this,{config:a,$el:i,$T:o}=n,s=e?i.subchart:i,l=n.getClass("bar",!0),c=n.initialOpacity.bind(n);a.bar_linearGradient&&n.updateLinearGradient();const f=s.main.selectAll(`.${Kn.bars}`).selectAll(`.${Kn.bar}`).data(n.labelishData.bind(n));o(f.exit(),t).style("opacity","0").remove(),s.bar=f.enter().append("path").attr("class",l).style("fill",n.updateBarColor.bind(n)).merge(f).style("opacity",c),n.setRatioForGroupedData(s.bar.data())},updateBarColor(t){const e=this,n=e.getStylePropValue(e.color);return e.config.bar_linearGradient?e.getGradienColortUrl(t.id):n?n(t):null},redrawBar(t,e,n=!1){const a=this,{bar:i}=n?a.$el.subchart:a.$el;return[a.$T(i,e,gr()).attr("d",o=>(he(o.value)||a.isBarRangeType(o))&&t(o)).style("fill",a.updateBarColor.bind(a)).style("clip-path",o=>o.clipPath).style("opacity",null)]},generateDrawBar(t,e){const n=this,{config:a}=n,i=n.generateGetBarPoints(t,e),o=a.axis_rotated,s=a.bar_radius,l=a.bar_radius_ratio,c=he(s)&&s>0?()=>s:he(l)?f=>f*l:null;return(f,g)=>{const v=i(f,g),m=+o,S=+!m,P=f.value<0,N=a[`axis_${n.axis.getId(f.id)}_inverted`],L=!N&&P||N&&!P,w=["",""],X=n.isGrouped(f.id),W=c&&X?n.isStackingRadiusData(f):!1,H=[v[0][m],v[0][S]];let k=0;if(f.clipPath=null,c){const ht=o?S:m,$t=v[2][ht]-v[0][ht];k=!X||W?c($t):0;const dt=`a${k} ${k} ${L?"1 0 0":"0 0 1"} `;w[+!o]=`${dt}${k},${k}`,w[+o]=`${dt}${[-k,k][o?"sort":"reverse"]()}`,L&&w.reverse()}const K=o?v[1][m]+(L?k:-k):v[1][S]+(L?-k:k);if(k){let ht="";o?L&&H[0]K&&(ht=`0 0 0 ${H[0]-K}px`):L&&H[1]>K?ht=`${H[1]-K}px 0 0 0`:!L&&H[1]-1){const m=n.bar.filter(S=>S.id===s&&S.value===c);return!m.empty()&&/a\d+/i.test(m.attr("d"))}const f=a.data_groups.find(m=>m.indexOf(s)>-1),v=e.orderTargets(e.filterTargetsToShow(i.targets.filter(e.isBarType,e))).filter(m=>f.indexOf(m.id)>-1).map(m=>m.values.filter(S=>S.index===l&&(he(c)&&c>0?S.value>0:S.value<0))[0]).filter(Boolean).map(m=>m.id);return c!==0&&v.indexOf(s)===v.length-1},generateGetBarPoints(t,e){const n=this,{config:a}=n,i=e?n.axis.subX:n.axis.x,o=n.getIndicesMax(t)+1,s=n.getBarW("bar",i,o),l=n.getShapeX(s,t,!!e),c=n.getShapeY(!!e),f=n.getShapeOffset(n.isBarType,t,!!e),g=n.getYScaleById.bind(n);return(v,m)=>{const{id:S}=v,P=g.call(n,S,e)(n.getShapeYMin(S)),N=f(v,m)||P,L=he(s)?s:s[v.id]||s._$width,w=a[`axis_${n.axis.getId(S)}_inverted`],X=v.value,W=l(v);let H=c(v);a.axis_rotated&&!w&&(X>0&&He.isBubbleZType(s)?e.getBubbleZData(s.value,"y"):Be(s.value)?s.value.mid:s.value)),i=n*n*Math.PI,o=(e.isBubbleZType(t)?e.getBubbleZData(t.value,"z"):t.value)*(i/a);return Math.sqrt(o/Math.PI)},getBubbleZData(t,e){return Be(t)?t[e]:t[e==="y"?0:1]}},Tx=Object.defineProperty,Xu=Object.getOwnPropertySymbols,$x=Object.prototype.hasOwnProperty,Sx=Object.prototype.propertyIsEnumerable,Hu=(t,e,n)=>e in t?Tx(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,Ax=(t,e)=>{for(var n in e||(e={}))$x.call(e,n)&&Hu(t,n,e[n]);if(Xu)for(var n of Xu(e))Sx.call(e,n)&&Hu(t,n,e[n]);return t},Ex={initCandlestick(){const{$el:t}=this;t.candlestick=t.main.select(`.${Se.chart}`).append("g").attr("class",cr.chartCandlesticks)},updateTargetsForCandlestick(t){const e=this,{$el:n}=e,a=e.getChartClass("Candlestick");n.candlestick||e.initCandlestick(),e.$el.main.select(`.${cr.chartCandlesticks}`).selectAll(`.${cr.chartCandlestick}`).data(t).enter().append("g").attr("class",a).style("pointer-events","none")},updateCandlestick(t,e=!1){const n=this,{$el:a,$T:i}=n,o=e?a.subchart:a,s=n.getClass("candlestick",!0),l=n.initialOpacity.bind(n),c=o.main.selectAll(`.${cr.chartCandlestick}`).selectAll(`.${cr.candlestick}`).data(n.labelishData.bind(n));i(c.exit(),t).style("opacity","0").remove();const f=c.enter().filter(g=>g.value).append("g").attr("class",s);f.append("line"),f.append("path"),o.candlestick=c.merge(f).style("opacity",l)},generateDrawCandlestick(t,e){const n=this,{config:a}=n,i=n.generateGetCandlestickPoints(t,e),o=a.axis_rotated,s=a.candlestick_color_down;return(l,c,f)=>{const g=i(l,c),v=n.getCandlestickData(l),m=v==null?void 0:v._isUp,S=+o,P=+!S;f.classed&&f.classed(cr[m?"valueUp":"valueDown"],!0);const N=o?`H${g[1][1]} V${g[1][0]} H${g[0][1]}`:`V${g[1][1]} H${g[1][0]} V${g[0][1]}`;f.select("path").attr("d",`M${g[0][S]},${g[0][P]}${N}z`).style("fill",X=>(m?n.color(X):Be(s)?s[X.id]:s)||n.color(X));const L=f.select("line"),w=o?{x1:g[2][1],x2:g[2][2],y1:g[2][0],y2:g[2][0]}:{x1:g[2][0],x2:g[2][0],y1:g[2][1],y2:g[2][2]};for(const X in w)L.attr(X,w[X])}},generateGetCandlestickPoints(t,e=!1){const n=this,a=e?n.axis.subX:n.axis.x,i=n.getIndicesMax(t)+1,o=n.getBarW("candlestick",a,i),s=n.getShapeX(o,t,!!e),l=n.getShapeY(!!e),c=n.getShapeOffset(n.isBarType,t,!!e),f=n.getYScaleById.bind(n);return(g,v)=>{const m=f.call(n,g.id,e)(n.getShapeYMin(g.id)),S=c(g,v)||m,P=he(o)?o:o[g.id]||o._$width,N=n.getCandlestickData(g);let L;if(N&&he(N.open)&&he(N.close)){const w={start:s(g),end:0};w.end=w.start+P;const X={start:l(N.open),end:l(N.close)},W={x:w.start+P/2,high:l(N.high),low:l(N.low)};X.start-=m-S,L=[[w.start,X.start],[w.end,X.end],[W.x,W.low,W.high]]}else L=[[0,0],[0,0],[0,0,0]];return L}},redrawCandlestick(t,e,n=!1){const a=this,{$el:i,$T:o}=a,{candlestick:s}=n?i.subchart:i,l=gr(!0);return[s.each(function(c,f){const g=o(ot(this),e,l);t(c,f,g)}).style("opacity",null)]},getCandlestickData({value:t}){let e;if(je(t)){const[n,a,i,o,s=!1]=t;e={open:n,high:a,low:i,close:o},s!==!1&&(e.volume=s)}else Be(t)&&(e=Ax({},t));return e&&(e._isUp=e.close>=e.open),e||null}},bx=Object.defineProperty,Yu=Object.getOwnPropertySymbols,Rx=Object.prototype.hasOwnProperty,Ix=Object.prototype.propertyIsEnumerable,Wu=(t,e,n)=>e in t?bx(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,Ox=(t,e)=>{for(var n in e||(e={}))Rx.call(e,n)&&Wu(t,n,e[n]);if(Yu)for(var n of Yu(e))Ix.call(e,n)&&Wu(t,n,e[n]);return t};function Zi(t=!1){const e=this,{config:n,state:{current:{width:a,height:i}}}=e,o=e.getCurrentPadding(),s=Ox({width:a-(o.left+o.right),height:i-(n.legend_show?e.getLegendHeight()+10:0)-(o.top+o.bottom)},o);if(t){const{width:l,height:c}=Ku.call(e,{width:s.width,height:s.height});s.width{let l=o;return Be(o)&&(l=t[s?"height":"width"]*o.ratio),l}),{width:a,height:i}}function Cx(t){const e=this,{top:n,left:a,width:i}=Zi.call(e,!0),o=[];return t.forEach((s,l)=>{const{ratio:c}=s,f=l>0?o[l-1][2][1]:n;o.push(s.coords=[[a,f],[a+i,f],[a+i,l>0?c+f:c+n],[a,l>0?c+f:c+n],[a,f]])}),o}function Zu(t=!1){const e=this,{width:n,height:a,top:i,left:o}=Zi.call(e,!0),s=Ku.call(e,{width:n,height:a}),l=(n-s.width)/2,c=(n+s.width)/2,f=a-s.height,g=[[0,0],[n,0],[c,f],[c,a],[l,a],[l,f],[0,0]];return t&&g.forEach(v=>{v[0]+=o,v[1]+=i}),`M${g.join("L")}z`}function Px(t){const e=this,{config:n}=e,a=t.map(i=>({id:i.id,value:i.values.reduce((o,s)=>o+s.value,0)}));return n.data_order&&a.sort(e.getSortCompareFn.bind(e)(!0)),Ju.call(e,a)}function Ju(t){const e=this,{height:n}=Zi.call(e),a=e.getTotalDataSum(!0);return t.forEach(i=>{i.ratio=i.value/a*n}),t}var wx={initFunnel(){const t=this,{$el:e}=t;e.funnel=e.main.select(`.${Se.chart}`).append("g").classed(Ta.chartFunnels,!0),e.funnel.background=e.funnel.append("path").classed(Ta.funnelBackground,!0),t.bindFunnelEvent()},bindFunnelEvent(){const t=this,{$el:{funnel:e},config:n,state:a}=t,i=o=>{var s;const l=o.isTrusted?o.target:(s=a.eventReceiver.rect)==null?void 0:s.node();let c;return/^path$/i.test(l.tagName)&&(a.event=o,c=ot(l).datum()),c};if(n.interaction_enabled){const o=a.inputType==="touch";e.on(o?"touchstart":"mouseover mousemove",s=>{const l=i(s);l&&(t.showTooltip([l],s.target),/^(touchstart|mouseover)$/.test(s.type)&&t.setOverOut(!0,l))}).on(o?"touchend":"mouseout",s=>{const l=i(s);n.interaction_onout&&(t.hideTooltip(),t.setOverOut(!1,l))})}},updateTargetsForFunnel(t){const e=this,{$el:{funnel:n}}=e,a=e.getChartClass("Funnel"),i=e.getClass("funnel",!0);n||e.initFunnel();const o=Px.call(e,t.filter(e.isFunnelType.bind(e))),s=n.selectAll(`.${Ta.chartFunnel}`).data(o);s.exit().remove();const l=s.enter().insert("g",`.${Ta.funnelBackground}`);l.append("path"),n.path=l.merge(s).attr("class",c=>a(c)).select("path").attr("class",i).style("opacity","0").style("fill",e.color)},updateFunnel(t){const e=this,{$el:{funnel:n}}=e,a=t.map(({id:i})=>i);n.path=n.path.filter(i=>a.indexOf(i.id)>=0)},generateGetFunnelPoints(){const t=this,{$el:{funnel:e}}=t,n=t.filterTargetsToShow(e.path),{top:a,left:i,right:o}=Zi.call(t),s=(i-o)/2,l={};let c=a!=null?a:0;return n.each((f,g)=>{var v;l[f.id]=[[s,c],[s,c+=((v=n==null?void 0:n[g])!=null?v:f).ratio]]}),f=>l[f.id]},redrawFunnel(){const t=this,{$T:e,$el:{funnel:n}}=t,a=t.filterTargetsToShow(n.path),i=Cx.call(t,Ju.call(t,a.data()));n.attr("clip-path",`path('${Zu.bind(t)()}')`),n.background.attr("d",Zu.call(t,!0)),e(a).attr("d",(o,s)=>`M${i[s].join("L")}z`).style("opacity","1"),n.selectAll("g").style("opacity",null)}},Mx={initGauge(){const t=this,{config:e,$el:{arcs:n}}=t,a=(i=null,o="")=>{n.append("text").attr("class",i).style("text-anchor","middle").style("pointer-events","none").text(o)};if(t.hasType("gauge")){const i=t.hasMultiArcGauge();n.append(i?"g":"path").attr("class",Ve.chartArcsBackground).style("fill",!i&&e.gauge_background||null),e.gauge_units&&a(Un.chartArcsGaugeUnit),e.gauge_label_show&&(a(Un.chartArcsGaugeMin),!e.gauge_fullCircle&&a(Un.chartArcsGaugeMax))}},updateGaugeMax(){const t=this,{config:e,state:n}=t,i=t.hasMultiArcGauge()?t.getMinMaxData().max[0].value:t.getTotalDataSum(n.rendered);!e.gauge_enforceMinMax&&i+e.gauge_min*(e.gauge_min>0?-1:1)>e.gauge_max&&(e.gauge_max=i-e.gauge_min)},redrawArcGaugeLine(){const t=this,{config:e,state:n,$el:a}=t,{hiddenTargetIds:i}=t.state,o=a.main.selectAll(`.${Ve.arcs}`).selectAll(`.${Ve.arcLabelLine}`).data(t.arcData.bind(t));o.enter().append("rect").attr("class",l=>`${Ve.arcLabelLine} ${Se.target} ${Se.target}-${l.data.id}`).merge(o).style("fill",l=>t.levelColor?t.levelColor(l.data.values[0].value):t.color(l.data)).style("display",e.gauge_label_show?null:"none").each(function(l){let c=0;const f=2;let g=0,v=0,m="";if(i.indexOf(l.data.id)<0){const S=t.updateAngle(l),P=n.gaugeArcWidth/t.filterTargetsToShow(t.data.targets).length*(S.index+1),N=S.endAngle-Math.PI/2,L=n.radius-P,w=N-(L===0?0:1/L);c=n.radiusExpanded-n.radius+P,g=Math.cos(w)*L,v=Math.sin(w)*L,m=`rotate(${N*180/Math.PI}, ${g}, ${v})`}ot(this).attr("x",g).attr("y",v).attr("width",c).attr("height",f).attr("transform",m).style("stroke-dasharray",`0, ${c+f}, 0`)})},textForGaugeMinMax(t,e){const n=this,{config:a}=n,i=a.gauge_label_extents;return ve(i)?i.bind(n.api)(t,e):t},getGaugeLabelHeight(){const{config:t}=this;return this.config.gauge_label_show&&!t.gauge_fullCircle?20:0},getPaddingBottomForGauge(){const t=this;return t.getGaugeLabelHeight()*(t.config.gauge_label_show?2:2.5)}};function Dx(t,e,n,a=!1){const i=t?[t,0]:n;for(let o=t||n.reduce((s,l)=>s+l);o<=e;)n.forEach(s=>{o+s<=e&&i.push(s),o+=s});return i.length%2!==0&&i.push(a?n[1]:0),{dash:i.join(" "),length:i.reduce((o,s)=>o+s,0)}}function Lx(t,e,n){const a=this,i=[],o="2 2";if(Qe(e)){const s=(l,c)=>ln(l)?c:n?Yn.call(a,l):l;for(let l=0,c;c=e[l];l++){const f=s(c.start,t[0].x),g=s(c.end,t[t.length-1].x),v=c.style||{dasharray:o};i[l]={start:f,end:g,style:v}}}return i}var Nx={initLine(){const{$el:t}=this;t.line=t.main.select(`.${Se.chart}`).append("g").attr("class",ur.chartLines).call(this.setCssRule(!1,`.${ur.chartLines}`,["pointer-events:none"]))},updateTargetsForLine(t){const e=this,{$el:{area:n,line:a,main:i}}=e,o=e.getChartClass("Line"),s=e.getClass("lines",!0),l=e.classFocus.bind(e);a||e.initLine();const c=t.filter(v=>!(e.isScatterType(v)||e.isBubbleType(v))),f=i.select(`.${ur.chartLines}`).selectAll(`.${ur.chartLine}`).data(c).attr("class",v=>o(v)+l(v)),g=f.enter().append("g").attr("class",o).style("opacity","0").style("pointer-events",e.getStylePropValue("none"));if(g.append("g").attr("class",s),e.hasTypeOf("Area")){const v=(!n&&g.empty()?f:g).filter(e.isAreaType.bind(e));e.initArea(v)}e.updateTargetForCircle(c,g)},updateLine(t,e=!1){const n=this,{format:{extraLineClasses:a},$el:i,$T:o}=n,s=e?i.subchart:i,l=s.main.selectAll(`.${ur.lines}`).selectAll(`.${ur.line}`).data(n.lineData.bind(n));o(l.exit(),t).style("opacity","0").remove(),s.line=l.enter().append("path").attr("class",c=>`${n.getClass("line",!0)(c)} ${a(c)||""}`).style("stroke",n.color).merge(l).style("opacity",n.initialOpacity.bind(n)).attr("transform",null)},redrawLine(t,e,n=!1){const a=this,{$el:i,$T:o}=a,{line:s}=n?i.subchart:i;return[o(s,e,gr()).attr("d",t).style("stroke",this.color).style("opacity",null)]},getCurve(t){const e=this;return e.config.axis_rotated&&e.isStepType(t)?a=>{const i=e.getInterpolate(t)(a);return i.orgPoint=i.point,i.pointRotated=function(o,s){this._point===1&&(this._point=2);const l=this._y*(1-this._t)+s*this._t;this._context.lineTo(this._x,l),this._context.lineTo(o,l),this._x=o,this._y=s},i.point=function(o,s){this._point===0?this.orgPoint(o,s):this.pointRotated(o,s)},i}:e.getInterpolate(t)},generateDrawLine(t,e){const n=this,{config:a,scale:i}=n,o=a.line_connectNull,s=a.axis_rotated,l=n.generateGetLinePoints(t,e),c=n.getYScaleById.bind(n),f=S=>(e?n.subxx:n.xx).call(n,S),g=(S,P)=>n.isGrouped(S.id)?l(S,P)[0][1]:c(S.id,e)(n.getBaseValue(S));let v=Gu();v=s?v.x(g).y(f):v.x(f).y(g),o||(v=v.defined(S=>n.getBaseValue(S)!==null));const m=e?i.subX:i.x;return S=>{const P=c(S.id,e);let N=o?n.filterRemoveNull(S.values):S.values,L=0,w=0,X;if(n.isLineType(S)){const W=a.data_regions[S.id];W?X=n.lineWithRegions(N,i.zoom||m,P,W):(n.isStepType(S)&&(N=n.convertValuesToStep(N)),X=v.curve(n.getCurve(S))(N))}else N[0]&&(L=m(N[0].x),w=P(N[0].value)),X=s?`M ${w} ${L}`:`M ${L} ${w}`;return X||"M 0 0"}},lineWithRegions(t,e,n,a){const i=this,{config:o}=i,s=o.axis_rotated,l=i.axis.isTimeSeries(),c="2 2",f=Lx.bind(i)(t,a,l),g=i.hasNullDataValue(t);let v,m,S,P;const N=s?dt=>n(dt.value):dt=>e(dt.x),L=s?dt=>e(dt.x):dt=>n(dt.value),w=dt=>`M${dt[0][0]},${dt[0][1]}L${dt[1][0]},${dt[1][1]}`,X=l?(dt,st,Vt,vt)=>{const Q=dt.x.getTime(),St=st.x-dt.x,ct=new Date(Q+St*Vt),At=new Date(Q+St*(Vt+vt)),Gt=s?[[n(m(Vt)),e(ct)],[n(m(Vt+S)),e(At)]]:[[e(ct),n(m(Vt))],[e(At),n(m(Vt+S))]];return w(Gt)}:(dt,st,Vt,vt)=>{const Q=e(st.x,!s),St=n(st.value,s),ct=Vt+vt,At=e(v(Vt),!s),Gt=n(m(Vt),s);let Bt=e(v(ct),!s),Kt=n(m(ct),s);Bt>Q&&(Bt=Q),dt.value>st.value&&(s?KtSt)&&(Kt=St);const ne=[[At,Gt],[Bt,Kt]];return s&&ne.forEach(le=>le.reverse()),w(ne)},W={x:i.axis.getAxisType("x"),y:i.axis.getAxisType("y")};let H="";const k=i.$el.line.filter(({id:dt})=>dt===t[0].id),K=k.clone().style("display","none"),at=(dt,st)=>dt.attr("d",st).node().getTotalLength(),ht={dash:[],lastLength:0};let $t=!1;for(let dt=0,st;st=t[dt];dt++){const Vt=t[dt-1],vt=Vt&&De(Vt.value);let Q=i.isWithinRegions(st.x,f);if(De(st.value)){if(ln(f)||!Q||!vt)H+=`${dt&&vt?"L":"M"}${N(st)},${L(st)}`;else if(vt)if(Q=((Q==null?void 0:Q.dasharray)||c).split(" ").map(Number),v=zr(W.x,Vt.x,st.x),m=zr(W.y,Vt.value,st.value),g){const St=e(st.x)-e(Vt.x),ct=n(st.value)-n(Vt.value),At=Math.sqrt(Math.pow(St,2)+Math.pow(ct,2));S=Q[0]/At,P=S*Q[1];for(let Gt=S;Gt<=1;Gt+=P)H+=X(Vt,st,Gt,S),Gt+P>=1&&(H+=X(Vt,st,1,0))}else{let St=[];if($t=st.x===t[t.length-1].x,l){const Bt=+Vt.x,Kt=new Date(Bt),ne=new Date(Bt+(+st.x-Bt));St=[[e(Kt),n(m(0))],[e(ne),n(m(1))]]}else St=[[e(v(0)),n(m(0))],[e(v(1)),n(m(1))]];s&&St.forEach(Bt=>Bt.reverse());const ct=at(K,H),At=at(K,H+=`L${St[1].join(",")}`),Gt=Dx(ct-ht.lastLength,At-ht.lastLength,Q,$t);ht.lastLength+=Gt.length,ht.dash.push(Gt.dash)}}}return ht.dash.length&&(!$t&&ht.dash.push(at(K,H)),K.remove(),k.attr("stroke-dasharray",ht.dash.join(" "))),H},isWithinRegions(t,e){for(let n=0,a;a=e[n];n++)if(a.startgr();var Ji={initialOpacityForCircle(t){const{config:e,state:{withoutFadeIn:n}}=this;let a=e.point_opacity;return ln(a)&&(a=this.getBaseValue(t)!==null&&n[t.id]?this.opacityForCircle(t):"0"),a},opacityForCircle(t){var e;const{config:n}=this;let a=n.point_opacity;return ln(a)&&(a=n.point_show&&!((e=this.isPointFocusOnly)!=null&&e.call(this))?null:"0",a=De(this.getBaseValue(t))?this.isBubbleType(t)||this.isScatterType(t)?"0.5":a:"0"),a},initCircle(){const t=this,{$el:{main:e}}=t;!t.point&&(t.point=t.generatePoint()),(t.hasType("bubble")||t.hasType("scatter"))&&e.select(`.${Se.chart} > .${$n.chartCircles}`).empty()&&e.select(`.${Se.chart}`).append("g").attr("class",$n.chartCircles)},updateTargetForCircle(t,e){const n=this,{config:a,data:i,$el:o}=n,s=a.interaction_enabled&&a.data_selection_enabled,l=s&&a.data_selection_isselectable,c=n.getClass("circles",!0);if(!a.point_show)return;n.initCircle();let f=t,g=e;if(!f){f=i.targets.filter(m=>this.isScatterType(m)||this.isBubbleType(m));const v=o.main.select(`.${$n.chartCircles}`).style("pointer-events","none").selectAll(`.${$n.circles}`).data(f);v.exit().remove(),g=v.enter()}s&&g.append("g").attr("class",v=>n.generateClass(tn.selectedCircles,v.id)),g.append("g").attr("class",c).call(v=>{n.setCssRule(!0,`.${$n.circles}`,["cursor:pointer"],l)(v),n.setCssRule(!0,` .${$n.circle}`,["fill","stroke"],n.color)(v)}).style("opacity",function(){return ot(this.parentNode).attr("class").indexOf($n.chartCircles)>-1?"0":null}),s&&f.forEach(v=>{o.main.selectAll(`.${tn.selectedCircles}${n.getTargetSelectorSuffix(v.id)}`).selectAll(`${tn.selectedCircle}`).each(m=>{m.value=v.values[m.index].value})})},updateCircle(t=!1){const e=this,{config:n,state:a,$el:i}=e,o=e.isPointFocusOnly(),s=t?i.subchart:i;if(n.point_show&&!a.toggling){n.point_radialGradient&&e.updateLinearGradient();const l=s.main.selectAll(`.${$n.circles}`).selectAll(`.${$n.circle}`).data(c=>e.isLineType(c)&&e.shouldDrawPointsForLine(c)||e.isBubbleType(c)||e.isRadarType(c)||e.isScatterType(c)?o?[c.values[0]]:c.values:[]);l.exit().remove(),l.enter().filter(Boolean).append(e.point("create",this,e.pointR.bind(e),e.updateCircleColor.bind(e))),s.circle=s.main.selectAll(`.${$n.circles} .${$n.circle}`).style("stroke",e.getStylePropValue(e.color)).style("opacity",e.initialOpacityForCircle.bind(e))}},updateCircleColor(t){const e=this,n=e.getStylePropValue(e.color);return e.config.point_radialGradient?e.getGradienColortUrl(t.id):n?n(t):null},redrawCircle(t,e,n,a,i=!1){const o=this,{state:{rendered:s},$el:l,$T:c}=o,f=i?l.subchart:l,g=f.main.selectAll(`.${tn.selectedCircle}`);if(!o.config.point_show)return[];const v=o.point("update",o,t,e,o.updateCircleColor.bind(o),n,a,g),m=o.isCirclePoint()?"c":"",S=gr(),P=o.opacityForCircle.bind(o),N=[];return f.circle.each(function(L){let w=v.bind(this)(L);w=c(w,n||!s,S).style("opacity",P),N.push(w)}),[N,c(g,n).attr(`${m}x`,t).attr(`${m}y`,e)]},showCircleFocus(t){const e=this,{state:{hasRadar:n,resizing:a,toggling:i,transiting:o},$el:s}=e;let{circle:l}=s;if(o===!1&&l&&e.isPointFocusOnly()){const c=(n?e.radarCircleX:e.circleX).bind(e),f=(n?e.radarCircleY:e.circleY).bind(e),g=i||ln(t),v=e.point("update",e,c,f,e.getStylePropValue(e.color),a?!1:g);t&&(l=l.filter(function(m){var S;const P=(S=t.filter)==null?void 0:S.call(t,N=>N.id===m.id);return P.length?ot(this).datum(P[0]):!1})),l.attr("class",this.updatePointClass.bind(this)).style("opacity",null).each(function(m){const{id:S,index:P,value:N}=m;let L="hidden";De(N)&&(v.bind(this)(m),e.expandCircles(P,S),L=""),this.style.visibility=L})}},hideCircleFocus(){const t=this,{$el:{circle:e}}=t;t.isPointFocusOnly()&&e&&(t.unexpandCircles(),e.style("visibility","hidden"))},circleX(t){return this.xx(t)},updateCircleY(t=!1){const e=this,n=e.generateGetLinePoints(e.getShapeIndices(e.isLineType),t);return(a,i)=>{const o=a.id;return e.isGrouped(o)?n(a,i)[0][1]:e.getYScaleById(o,t)(e.getBaseValue(a))}},expandCircles(t,e,n){const a=this,i=a.pointExpandedR.bind(a);n&&a.unexpandCircles();const o=a.getShapeByIndex("circle",t,e).classed(Se.EXPANDED,!0),s=i(o)/a.config.point_r,l=1-s;a.isCirclePoint()?o.attr("r",i):o.each(function(){const c=ot(this);if(this.tagName==="circle")c.attr("r",i);else{const{width:f,height:g}=this.getBBox(),v=l*(+c.attr("x")+f/2),m=l*(+c.attr("y")+g/2);c.attr("transform",`translate(${v} ${m}) scale(${s})`)}})},unexpandCircles(t){const e=this,n=e.pointR.bind(e),a=e.getShapeByIndex("circle",t).filter(function(){return ot(this).classed(Se.EXPANDED)}).classed(Se.EXPANDED,!1);if(a.attr("r",n),!e.isCirclePoint()){const i=n(a)/e.config.point_r;a.attr("transform",i!==1?`scale(${i})`:null)}},pointR(t){const e=this,{config:n}=e,a=n.point_r;let i=a;return e.isBubbleType(t)?i=e.getBubbleR(t):ve(a)&&(i=a.bind(e.api)(t)),t.r=i,i},pointExpandedR(t){const e=this,{config:n}=e,a=e.isBubbleType(t)?1.15:1.75;return n.point_focus_expand_enabled?n.point_focus_expand_r||e.pointR(t)*a:e.pointR(t)},pointSelectR(t){const e=this,n=e.config.point_select_r;return ve(n)?n(t):n||e.pointR(t)*4},isPointFocusOnly(){const t=this;return t.config.point_focus_only&&!t.hasType("bubble")&&!t.hasType("scatter")&&!t.hasArcType(null,["radar"])},isWithinCircle(t,e){const{state:n}=this,a=Hn(n.event,t),i=ot(t),o=this.isCirclePoint(t)?"c":"",s=this.getPointSensitivity(i==null?void 0:i.datum());let l=+i.attr(`${o}x`),c=+i.attr(`${o}y`);if(!(l||c)&&t.nodeType===1){const{x:f,y:g}=Ma(t);l=f,c=g}return Math.sqrt(Math.pow(l-a[0],2)+Math.pow(c-a[1],2))<(e||s)},getPointSensitivity(t){const e=this;let n=e.config.point_sensitivity;if(t)ve(n)?n=n.call(e.api,t):n==="radius"&&(n=t.r);else return n;return n},updatePointClass(t){const e=this,{circle:n}=e.$el;let a=!1;return(Be(t)||n)&&(a=t===!0?n.each(function(i){let o=e.getClass("circle",!0)(i);this.getAttribute("class").indexOf(Se.EXPANDED)>-1&&(o+=` ${Se.EXPANDED}`),this.setAttribute("class",o)}):e.getClass("circle",!0)(t)),a},generateGetLinePoints(t,e){const n=this,{config:a}=n,i=n.getShapeX(0,t,e),o=n.getShapeY(e),s=n.getShapeOffset(n.isLineType,t,e),l=n.getYScaleById.bind(n);return(c,f)=>{const g=l.call(n,c.id,e)(n.getShapeYMin(c.id)),v=s(c,f)||g,m=i(c);let S=o(c);a.axis_rotated&&(c.value>0&&SDe(S.value)?e(S)-c/2:0,v=S=>De(S.value)?n(S)-f/2:0;let m=t;return i&&(o&&m.attr("x",g),m=l.$T(m,i,la()),s&&l.$T(s,i,la())),m.attr("x",g).attr("y",v).style("fill",a)}},circle:{create(t,e,n){return t.append("circle").attr("class",this.updatePointClass.bind(this)).attr("r",e).style("fill",n).node()},update(t,e,n,a,i,o,s){const l=this;let c=t;return l.hasType("bubble")&&c.attr("r",l.pointR.bind(l)),i&&(o&&c.attr("cx",e),c.attr("cx")&&(c=l.$T(c,i,la())),s&&l.$T(c,i,la())),c.attr("cx",e).attr("cy",n).style("fill",a)}},rectangle:{create(t,e,n){const a=i=>e(i)*2;return t.append("rect").attr("class",this.updatePointClass.bind(this)).attr("width",a).attr("height",a).style("fill",n).node()},update(t,e,n,a,i,o,s){const l=this,c=l.config.point_r,f=m=>e(m)-c,g=m=>n(m)-c;let v=t;return i&&(o&&v.attr("x",f),v=l.$T(v,i,la()),s&&l.$T(s,i,la())),v.attr("x",f).attr("y",g).style("fill",a)}}};function Fx(t){return nr(t)&&ve(t.create)&&ve(t.update)}function Bx(t,e){var n;const a=this,i=(c,f)=>{const g=c.attributes;for(let v=0,m;m=g[v];v++)m=m.name,f.setAttribute(m,c.getAttribute(m))},s=new DOMParser().parseFromString(t,"image/svg+xml").documentElement,l=gn.createElementNS(ae.svg,s.nodeName.toLowerCase());if(l.id=e,l.style.fill="inherit",l.style.stroke="inherit",i(s,l),(n=s.childNodes)!=null&&n.length){const c=ot(l);"innerHTML"in l?c.html(s.innerHTML):Lr(s.childNodes).forEach(f=>{i(f,c.append(f.tagName).node())})}a.$el.defs.node().appendChild(l)}var ca={hasValidPointType(t){return/^(circle|rect(angle)?|polygon|ellipse|use)$/i.test(t||this.config.point_type)},hasLegendDefsPoint(){var t;const{config:e}=this;return e.legend_show&&((t=e.point_pattern)==null?void 0:t.length)&&e.legend_usePoint},getDefsPointId(t){const{state:{datetimeId:e}}=this;return`${e}-point${t}`},generatePoint(){const t=this,{$el:e,config:n}=t,a=[],i=cn(n.point_pattern)?n.point_pattern:[n.point_type];return function(o,s,...l){return function(c){var f,g,v,m;const S=t.getTargetSelectorSuffix(c.id||((f=c.data)==null?void 0:f.id)||c),P=ot(this);a.indexOf(S)<0&&a.push(S);let N=i[a.indexOf(S)%i.length];if(t.hasValidPointType(N))N=t[N];else if(!Fx(N||n.point_type)){const L=t.getDefsPointId(S);if(e.defs.select(`#${L}`).size()<1&&Bx.bind(t)(N,L),o==="create")return(g=t.custom)==null?void 0:g.create.bind(s)(P,L,...l);if(o==="update")return(v=t.custom)==null?void 0:v.update.bind(s)(P,...l)}return(m=N[o])==null?void 0:m.bind(s)(P,...l)}}}};function Qu(t){const e=t.config.polar_level_max;let n=t.getMinMaxData().max[0].value;return e&&e>n&&(n=e),n}var Ux={initPolar(){const t=this,{$el:{arcs:e},config:n}=t,a=n.polar_level_text_show,i=n.polar_level_text_backgroundColor;e.levels=e.append("g").attr("class",Tr.levels),a&&i&&t.generateTextBGColorFilter(i)},getPolarOuterRadius(t,e){var n;const a=Qu(this);return((n=t==null?void 0:t.data.values[0].value)!=null?n:0)/a*e},updateTargetsForPolar(t){this.updateTargetsForArc(t)},redrawPolar(){const t=this,{config:e}=t;e.polar_level_show&&t.updatePolarLevel()},updatePolarLevel(){const t=this,{config:e,state:n,$el:{arcs:{levels:a}}}=t,i=e.polar_level_depth,o=Qu(t),s=Ei(0,i),l=n.radius,c=s.map(m=>l*((m+1)/i)),f=(e.polar_level_text_format||function(){}).bind(t.api),g=a.selectAll(`.${Tr.level}`).data(s);g.exit().remove();const v=g.enter().append("g").attr("class",(m,S)=>`${Tr.level} ${Tr.level}-${S}`);if(v.append("circle"),v.merge(g).selectAll("circle").style("visibility",e.polar_level_show?null:"hidden").attr("cx",0).attr("cy",0).attr("r",m=>c[m]),e.polar_level_text_show){const m=e.polar_level_text_backgroundColor,S=`#${n.datetimeId}-labels-bg${t.getTargetSelectorSuffix(m)}`;v.append("text").style("text-anchor","middle"),v.merge(g).selectAll("text").attr("dy",P=>-c[P]+5).attr("filter",m?`url(${S})`:null).text(P=>f(o/s.length*(P+1)))}}};function zx(t,e,n,a,i,o){const s=t&&a>0?n-a:a,l=2*Math.PI;return i*(1-o*(e==="x"?Math.sin:Math.cos)(s*l/n))}const ua=Ln.radarPoints,ku=Ln.radarTextWidth;var jx={initRadar(){const t=this,{config:e,state:{current:n},$el:a}=t;t.hasType("radar")&&(a.radar=a.main.select(`.${Se.chart}`).append("g").attr("class",Qs.chartRadars),a.radar.levels=a.radar.append("g").attr("class",Tr.levels),a.radar.axes=a.radar.append("g").attr("class",Tn.axis),a.radar.shapes=a.radar.append("g").attr("class",sn.shapes),n.dataMax=e.radar_axis_max||t.getMinMaxData().max[0].value,e.radar_axis_text_show&&(e.interaction_enabled&&t.bindRadarEvent(),t.updateRadarLevel(),t.updateRadarAxes()))},getRadarSize(){const t=this,{config:e,state:{arcWidth:n,arcHeight:a}}=t,i=e.axis_x_categories.length<4?-20:10,o=(Math.min(n,a)-i)/2;return[o,o]},updateTargetsForRadar(t){const e=this,{config:n}=e;qn(n.axis_x_categories)&&(n.axis_x_categories=Ei(0,_n("max",t.map(a=>a.values.length)))),e.generateRadarPoints()},getRadarPosition(t,e,n,a){const i=this,{config:o}=i,[s,l]=i.getRadarSize(),c=o.axis_x_categories.length,f=o.radar_direction_clockwise,g=Lr(t).map(v=>zx(f,v,c,e,Qe(n)?n:t==="x"?s:l,he(a)?a:o.radar_size_ratio));return g.length===1?g[0]:g},generateRadarPoints(){const t=this,e=t.data.targets,[n,a]=t.getRadarSize(),i=t.cache.get(ua)||{},o=i._size;(!o||o.width!==n&&o.height!==a)&&(e.forEach(s=>{i[s.id]=s.values.map((l,c)=>t.getRadarPosition(["x","y"],c,void 0,t.getRatio("radar",l)))}),i._size={width:n,height:a},t.cache.add(ua,i))},redrawRadar(){const t=this,{radar:e,main:n}=t.$el,a=t.getTranslate("radar");a&&(e.attr("transform",a),n.select(`.${On.chartTexts}`).attr("transform",a),t.generateRadarPoints(),t.updateRadarLevel(),t.updateRadarAxes(),t.updateRadarShape())},generateGetRadarPoints(){const t=this.cache.get(ua);return(e,n)=>{const a=t[e.id][n];return[a,a,a,a]}},updateRadarLevel(){const t=this,{config:e,state:n,$el:{radar:a}}=t,[i,o]=t.getRadarSize(),s=e.radar_level_depth,l=e.axis_x_categories.length,c=e.radar_level_text_show,f=a.levels,g=Ei(0,s),v=e.radar_size_ratio*Math.min(i,o),m=g.map(w=>v*((w+1)/s)),S=(e.radar_level_text_format||function(){}).bind(t.api),P=g.map(w=>{const X=m[w];return Ei(0,l).map(H=>t.getRadarPosition(["x","y"],H,X,1).join(",")).join(" ")}),N=f.selectAll(`.${Tr.level}`).data(g);N.exit().remove();const L=N.enter().append("g").attr("class",(w,X)=>`${Tr.level} ${Tr.level}-${X}`);L.append("polygon").style("visibility",e.radar_level_show?null:"hidden"),c&&(f.select("text").empty()&&f.append("text").attr("dx","-.5em").attr("dy","-.7em").style("text-anchor","end").text(()=>S(0)),L.append("text").attr("dx","-.5em").style("text-anchor","end").text(w=>S(n.current.dataMax/g.length*(w+1)))),L.merge(N).attr("transform",w=>`translate(${i-m[w]}, ${o-m[w]})`).selectAll("polygon").attr("points",w=>P[w]),c&&f.selectAll("text").attr("x",w=>ln(w)?i:P[w].split(",")[0]).attr("y",w=>ln(w)?o:0)},updateRadarAxes(){const t=this,{config:e,$el:{radar:n}}=t,[a,i]=t.getRadarSize(),o=e.axis_x_categories;let s=n.axes.selectAll("g").data(o);s.exit().remove();const l=s.enter().append("g").attr("class",(c,f)=>`${Tn.axis}-${f}`);if(e.radar_axis_line_show&&l.append("line"),e.radar_axis_text_show&&l.append("text"),s=l.merge(s),e.radar_axis_line_show&&s.select("line").attr("x1",a).attr("y1",i).attr("x2",(c,f)=>t.getRadarPosition("x",f)).attr("y2",(c,f)=>t.getRadarPosition("y",f)),e.radar_axis_text_show){const{x:c=0,y:f=0}=e.radar_axis_text_position,g=t.cache.get(ku)||0;if(s.select("text").style("text-anchor","middle").attr("dy",".5em").call(v=>{v.each(function(m){wa(ot(this),String(m),[-.6,1.2])})}).datum((v,m)=>({index:m})).attr("transform",function(v){ln(this.width)&&(this.width=this.getBoundingClientRect().width/2);let m=t.getRadarPosition("x",v.index,void 0,1),S=Math.round(t.getRadarPosition("y",v.index,void 0,1));return m>a?m+=this.width+c:Math.round(m)i?(S/2===i&&this.firstChild.tagName==="tspan"&&this.firstChild.setAttribute("dy","0em"),S+=f):SYl(m.node()).width);v.every(m=>m>0)&&t.cache.add(ku,v[0]-v[1])}}},bindRadarEvent(){const t=this,{config:e,state:n,$el:{radar:a,svg:i}}=t,o=t.isPointFocusOnly(),{inputType:s,transiting:l}=n,c=s==="mouse",f=g=>{if(n.event=g,!e.interaction_onout)return;const v=t.getDataIndexFromEvent(g),m=ln(v);(c||m)&&(t.hideTooltip(),o?t.hideCircleFocus():t.unexpandCircles(),c?t.setOverOut(!1,v):m&&t.callOverOutForTouch())};a.axes.on(c?"mouseover ":"touchstart",g=>{if(l)return;n.event=g;const v=t.getDataIndexFromEvent(g);t.selectRectForSingle(i.node(),v),c?t.setOverOut(!0,v):t.callOverOutForTouch(v)}).on("mouseout",c?f:null),c||i.on("touchstart",f)},updateRadarShape(){const t=this,e=t.data.targets.filter(o=>t.isRadarType(o)),n=t.cache.get(ua),a=t.$el.radar.shapes.selectAll("polygon").data(e),i=a.enter().append("g").attr("class",t.getChartClass("Radar"));t.$T(a.exit()).remove(),i.append("polygon").merge(a).style("fill",t.color).style("stroke",t.color).attr("points",o=>n[o.id].join(" ")),t.updateTargetForCircle(e,i)},radarCircleX(t){return this.cache.get(ua)[t.id][t.index][0]},radarCircleY(t){return this.cache.get(ua)[t.id][t.index][1]}};function Vx(t){var e=0,n=t.children,a=n&&n.length;if(!a)e=1;else for(;--a>=0;)e+=n[a].value;t.value=e}function Gx(){return this.eachAfter(Vx)}function Xx(t,e){let n=-1;for(const a of this)t.call(e,a,++n,this);return this}function Hx(t,e){for(var n=this,a=[n],i,o,s=-1;n=a.pop();)if(t.call(e,n,++s,this),i=n.children)for(o=i.length-1;o>=0;--o)a.push(i[o]);return this}function Yx(t,e){for(var n=this,a=[n],i=[],o,s,l,c=-1;n=a.pop();)if(i.push(n),o=n.children)for(s=0,l=o.length;s=0;)n+=a[i].value;e.value=n})}function Zx(t){return this.eachBefore(function(e){e.children&&e.children.sort(t)})}function Jx(t){for(var e=this,n=Qx(e,t),a=[e];e!==n;)e=e.parent,a.push(e);for(var i=a.length;t!==n;)a.splice(i,0,t),t=t.parent;return a}function Qx(t,e){if(t===e)return t;var n=t.ancestors(),a=e.ancestors(),i=null;for(t=n.pop(),e=a.pop();t===e;)i=t,t=n.pop(),e=a.pop();return i}function kx(){for(var t=this,e=[t];t=t.parent;)e.push(t);return e}function qx(){return Array.from(this)}function _x(){var t=[];return this.eachBefore(function(e){e.children||t.push(e)}),t}function t0(){var t=this,e=[];return t.each(function(n){n!==t&&e.push({source:n.parent,target:n})}),e}function*e0(){var t=this,e,n=[t],a,i,o;do for(e=n.reverse(),n=[];t=e.pop();)if(yield t,a=t.children)for(i=0,o=a.length;i=0;--l)i.push(o=s[l]=new Qi(s[l])),o.parent=a,o.depth=a.depth+1;return n.eachBefore(o0)}function n0(){return Rs(this).eachBefore(i0)}function r0(t){return t.children}function a0(t){return Array.isArray(t)?t[1]:null}function i0(t){t.data.value!==void 0&&(t.value=t.data.value),t.data=t.data.data}function o0(t){var e=0;do t.height=e;while((t=t.parent)&&t.height<++e)}function Qi(t){this.data=t,this.depth=this.height=0,this.parent=null}Qi.prototype=Rs.prototype={constructor:Qi,count:Gx,each:Xx,eachAfter:Yx,eachBefore:Hx,find:Wx,sum:Kx,sort:Zx,path:Jx,ancestors:kx,descendants:qx,leaves:_x,links:t0,copy:n0,[Symbol.iterator]:e0};function s0(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function ki(t,e,n,a,i){for(var o=t.children,s,l=-1,c=o.length,f=t.value&&(a-e)/t.value;++lX&&(X=f),K=L*L*k,W=Math.max(X/K,K/w),W>H){L-=f;break}H=W}s.push(c={value:L,dice:S1?a:1)},n}(qu);function C1(t){return t==null?null:ef(t)}function ef(t){if(typeof t!="function")throw new Error;return t}function ja(){return 0}function Va(t){return function(){return t}}function l0(){var t=tf,e=!1,n=1,a=1,i=[0],o=ja,s=ja,l=ja,c=ja,f=ja;function g(m){return m.x0=m.y0=0,m.x1=n,m.y1=a,m.eachBefore(v),i=[0],e&&m.eachBefore(s0),m}function v(m){var S=i[m.depth],P=m.x0+S,N=m.y0+S,L=m.x1-S,w=m.y1-S;L=m-1){var X=o[v];X.x0=P,X.y0=N,X.x1=L,X.y1=w;return}for(var W=f[v],H=S/2+W,k=v+1,K=m-1;k>>1;f[at]w-N){var dt=S?(P*$t+L*ht)/S:L;g(v,k,ht,P,N,dt,w),g(k,m,$t,dt,N,L,w)}else{var st=S?(N*$t+w*ht)/S:w;g(v,k,ht,P,N,L,st),g(k,m,$t,P,st,L,w)}}}function c0(t,e,n,a,i){(t.depth&1?qi:ki)(t,e,n,a,i)}var u0=function t(e){function n(a,i,o,s,l){if((c=a._squarify)&&c.ratio===e)for(var c,f,g,v,m=-1,S,P=c.length,N=a.value;++m1?a:1)},n}(qu);function f0(t,e){const n=this,{scale:{x:a,y:i},state:{width:o}}=n;t.selectAll("g").attr("transform",s=>`translate(${s===e?"0,0":`${a(s.x0)},${i(s.y0)}`})`).select("rect").attr("width",s=>s===e?o:a(s.x1)-a(s.x0)).attr("height",s=>s===e?0:i(s.y1)-i(s.y0))}function d0(t){const e=this;return t.map(n=>{const{id:a,values:i}=n,{value:o}=i[0];return{name:a,id:a,value:o,ratio:e.getRatio("treemap",i[0])}})}function h0(t){const e=this,n=Rs(t).sum(i=>i.value),a=e.getSortCompareFn(!0);return[e.treemap(a?n.sort(a):n)]}var g0={initTreemap(){const t=this,{$el:e,state:{current:{width:n,height:a},clip:i,datetimeId:o}}=t;i.id=`${o}-clip`,t.treemap=l0().tile(t.getTreemapTile()),e.defs.append("clipPath").attr("id",i.id).append("rect").attr("width",n).attr("height",a),e.treemap=e.main.select(`.${Se.chart}`).attr("clip-path",`url(#${i.id})`).append("g").classed(qs.chartTreemaps,!0),t.bindTreemapEvent()},bindTreemapEvent(){const t=this,{$el:e,config:n,state:a}=t,i=o=>{var s;const l=o.isTrusted?o.target:(s=a.eventReceiver.rect)==null?void 0:s.node();let c;return/^rect$/i.test(l.tagName)&&(a.event=o,c=ot(l).datum()),c==null?void 0:c.data};if(n.interaction_enabled){const o=a.inputType==="touch";e.treemap.on(o?"touchstart":"mouseover mousemove",s=>{const l=i(s);l&&(t.showTooltip([l],s.currentTarget),/^(touchstart|mouseover)$/.test(s.type)&&t.setOverOut(!0,l))}).on(o?"touchend":"mouseout",s=>{const l=i(s);n.interaction_onout&&(t.hideTooltip(),t.setOverOut(!1,l))})}},getTreemapTile(){var t,e;const n=this,{config:a,state:{current:{width:i,height:o}}}=n,s=(e={binary:nf,dice:ki,slice:qi,sliceDice:c0,squarify:tf,resquarify:u0}[(t=a.treemap_tile)!=null?t:"binary"])!=null?e:nf;return(l,c,f,g,v)=>{s(l,0,0,i,o);for(const m of l.children)m.x0=c+m.x0/i*(g-c),m.x1=c+m.x1/i*(g-c),m.y0=f+m.y0/o*(v-f),m.y1=f+m.y1/o*(v-f)}},getTreemapData(t){const e=this;return{name:"root",children:d0.bind(e)(e.filterTargetsToShow(t.filter(e.isTreemapType,e)))}},updateTargetsForTreemap(t){const e=this,{$el:{treemap:n}}=e,a=h0.call(e,e.getTreemapData(t!=null?t:e.data.targets));n.data(a)},updateTreemap(t){const e=this,{$el:n,$T:a}=e,i=n.treemap.datum(),o=e.getChartClass("Treemap"),s=e.getClass("treemap",!0),l=n.treemap.selectAll("g").data(i.children);a(l.exit(),t).style("opacity","0").remove(),l.enter().append("g").append("rect"),n.treemap.selectAll("g").attr("class",o).select("rect").attr("class",s).attr("fill",c=>e.color(c.data.name))},generateGetTreemapPoints(){const t=this,{$el:e,scale:{x:n,y:a}}=t,i={};return e.treemap.selectAll("g").each(o=>{i[o.data.name]=[[n(o.x0),a(o.y0)],[n(o.x1),a(o.y1)]]}),o=>i[o.id]},redrawTreemap(t){const e=this,{$el:n,state:{current:{width:a,height:i}}}=e;return n.defs.select("rect").attr("width",a).attr("height",i),[e.$T(n.treemap,t,gr()).call(f0.bind(e),n.treemap.datum())]},treemapDataLabelFormat(t){const e=this,{config:n}=e,{id:a,value:i}=t,o=n.treemap_label_format,s=e.getRatio("treemap",t),l=(s*100).toFixed(2),c=n.treemap_label_show&&e.meetsLabelThreshold(s,"treemap")?null:"0";return function(f){return f.style("opacity",c),ve(o)?o.bind(e.api)(i,s,a):`${a} ${l}%`}}},Xr={point_show:!0,point_r:2.5,point_radialGradient:!1,point_sensitivity:10,point_focus_expand_enabled:!0,point_focus_expand_r:void 0,point_focus_only:!1,point_opacity:void 0,point_pattern:[],point_select_r:void 0,point_type:"circle"},fa={area_above:!1,area_below:!1,area_front:!0,area_linearGradient:!1,area_zerobased:!0},v0={bar_front:!1,bar_indices_removeNull:!1,bar_label_threshold:0,bar_linearGradient:!1,bar_overlap:!1,bar_padding:0,bar_radius:void 0,bar_radius_ratio:void 0,bar_sensitivity:2,bar_width:void 0,bar_width_ratio:.6,bar_width_max:void 0,bar_zerobased:!0},p0={bubble_maxR:35,bubble_zerobased:!1},m0={candlestick_width:void 0,candlestick_width_ratio:.6,candlestick_width_max:void 0,candlestick_color_down:"red"},y0={line_connectNull:!1,line_step_type:"step",line_step_tooltipMatch:!1,line_zerobased:!1,line_classes:void 0,line_point:!0},x0={scatter_zerobased:!1},Is={spline_interpolation_type:"cardinal"},_i={arc_cornerRadius:0,arc_cornerRadius_ratio:0,arc_needle_show:!1,arc_needle_color:void 0,arc_needle_value:void 0,arc_needle_path:void 0,arc_needle_length:100,arc_needle_top_rx:0,arc_needle_top_ry:0,arc_needle_top_width:0,arc_needle_bottom_rx:1,arc_needle_bottom_ry:1,arc_needle_bottom_width:15,arc_needle_bottom_len:0,arc_rangeText_values:void 0,arc_rangeText_unit:"absolute",arc_rangeText_fixed:!1,arc_rangeText_format:void 0,arc_rangeText_position:void 0},T0={donut_label_show:!0,donut_label_format:void 0,donut_label_threshold:.05,donut_label_ratio:void 0,donut_width:void 0,donut_title:"",donut_expand:{},donut_expand_rate:.98,donut_expand_duration:50,donut_padAngle:0,donut_startingAngle:0},$0={funnel_neck_width:0,funnel_neck_height:0},S0={gauge_background:"",gauge_fullCircle:!1,gauge_label_show:!0,gauge_label_extents:void 0,gauge_label_format:void 0,gauge_label_ratio:void 0,gauge_label_threshold:0,gauge_enforceMinMax:!1,gauge_min:0,gauge_max:100,gauge_type:"single",gauge_startingAngle:-1*Math.PI/2,gauge_arcLength:100,gauge_title:"",gauge_units:void 0,gauge_width:void 0,gauge_arcs_minWidth:5,gauge_expand:{},gauge_expand_rate:.98,gauge_expand_duration:50},A0={pie_label_show:!0,pie_label_format:void 0,pie_label_ratio:void 0,pie_label_threshold:.05,pie_expand:{},pie_expand_rate:.98,pie_expand_duration:50,pie_innerRadius:0,pie_outerRadius:void 0,pie_padAngle:0,pie_padding:0,pie_startingAngle:0},E0={polar_label_show:!0,polar_label_format:void 0,polar_label_threshold:.05,polar_label_ratio:void 0,polar_level_depth:3,polar_level_max:void 0,polar_level_show:!0,polar_level_text_backgroundColor:"#fff",polar_level_text_format:t=>t%1===0?t:t.toFixed(2),polar_level_text_show:!0,polar_padAngle:0,polar_padding:0,polar_startingAngle:0},b0={radar_axis_max:void 0,radar_axis_line_show:!0,radar_axis_text_show:!0,radar_axis_text_position:{},radar_level_depth:3,radar_level_show:!0,radar_level_text_format:t=>t%1===0?t:t.toFixed(2),radar_level_text_show:!0,radar_size_ratio:.87,radar_direction_clockwise:!1},R0={treemap_tile:"binary",treemap_label_format:void 0,treemap_label_threshold:.05,treemap_label_show:!0};function da(t,e){yn(Vr.prototype,Object.values(Du).concat(t)),yn(Er.prototype,Jy),Nr.setOptions(Object.values(Lu).concat(e||[]))}function mr(t,e){da([ca,Ji,Nx].concat(t||[])),Nr.setOptions([Xr,y0].concat(e||[]))}function ha(t,e){yn(Vr.prototype,[px,ca].concat(t||[])),Nr.setOptions([Xr].concat(e||[]))}let rf=()=>(mr(sa,[fa]),(rf=()=>oe.AREA)()),af=()=>(mr(sa,[fa]),(af=()=>oe.AREA_LINE_RANGE)()),of=()=>(mr(sa,[fa]),(of=()=>oe.AREA_STEP_RANGE)()),sf=()=>(mr(sa,[fa,Is]),(sf=()=>oe.AREA_SPLINE)()),lf=()=>(mr(sa,[fa,Is]),(lf=()=>oe.AREA_SPLINE_RANGE)()),cf=()=>(mr(sa,[fa]),(cf=()=>oe.AREA_STEP)()),uf=()=>(mr(),(uf=()=>oe.LINE)()),ff=()=>(mr(void 0,[Is]),(ff=()=>oe.SPLINE)()),df=()=>(mr(),(df=()=>oe.STEP)()),hf=()=>(ha(void 0,[_i,T0]),(hf=()=>oe.DONUT)()),gf=()=>(ha([Mx],[_i,S0]),(gf=()=>oe.GAUGE)()),vf=()=>(ha(void 0,[_i,A0]),(vf=()=>oe.PIE)()),pf=()=>(ha([Ux],[_i,E0]),(pf=()=>oe.POLAR)()),mf=()=>(ha([Du.eventrect,Ji,jx],[Xr,b0,{axis_x_categories:Lu.optAxis.axis_x_categories}]),(mf=()=>oe.RADAR)()),yf=()=>(da([yx,ca],[v0,Xr]),(yf=()=>oe.BAR)()),xf=()=>(da([ca,Ji,xx],[p0,Xr]),(xf=()=>oe.BUBBLE)()),Tf=()=>(da([Ex,ca],[m0,Xr]),(Tf=()=>oe.CANDLESTICK)()),$f=()=>(da([ca,Ji],[Xr,x0]),($f=()=>oe.SCATTER)()),Sf=()=>(ha([wx],[$0]),(Sf=()=>oe.FUNNEL)()),Af=()=>(da([g0],[R0]),(Af=()=>oe.TREEMAP)()),Os=Object.create(null);const Ef={version:"3.15.1",generate(t){const e=ea(Object.create(null),Os,t),n=new Er(e);return n.internal.charts=this.instance,this.instance.push(n),n},defaults(t){return Be(t)&&(Os=t),Os},instance:[],plugin:{}};Object.keys(d).forEach(t=>d[t]()),Object.keys(u).forEach(t=>u[t]())}],Xa={};function zn(x){var b=Xa[x];if(b!==void 0)return b.exports;var r=Xa[x]={exports:{}};return Cs[x].call(r.exports,r,r.exports,zn),r.exports}(function(){zn.d=function(x,b){for(var r in b)zn.o(b,r)&&!zn.o(x,r)&&Object.defineProperty(x,r,{enumerable:!0,get:b[r]})}})(),function(){zn.o=function(x,b){return Object.prototype.hasOwnProperty.call(x,b)}}(),function(){zn.r=function(x){typeof Symbol!="undefined"&&Symbol.toStringTag&&Object.defineProperty(x,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(x,"__esModule",{value:!0})}}(),zn(0);var Ha=zn(584);return Ha}()}); /*! * 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; 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\CodeCoverage; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Xml; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Version; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\WriteOperationFailedException; final class OpenClover { /** * @throws WriteOperationFailedException */ public function process(CodeCoverage $coverage, ?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', $name); } $xmlCoverage->appendChild($xmlProject); /** @var array $packages */ $packages = []; $report = $coverage->getReport(); foreach ($report as $item) { if (!$item instanceof File) { continue; } $xmlFile = $xmlDocument->createElement('file'); $xmlFile->setAttribute('name', basename($item->pathAsString())); $xmlFile->setAttribute('path', $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', 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', $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', $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 const PHP_EOL; use function serialize; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\CodeCoverage; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Filesystem; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\WriteOperationFailedException; final class PHP { /** * @param null|non-empty-string $target * * @throws WriteOperationFailedException */ public function process(CodeCoverage $coverage, ?string $target = null): string { $coverage->clearCache(); $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 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\CodeCoverage; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Node\File; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Util\Percentage; 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(CodeCoverage $coverage, bool $showColors = \false): string { $hasBranchCoverage = $coverage->getData(\true)->functionCoverage() !== []; $output = PHP_EOL . PHP_EOL; $report = $coverage->getReport(); $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); } $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 */ 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 */ 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 */ final readonly class Coverage { private XMLWriter $xmlWriter; private string $line; public function __construct(XMLWriter $xmlWriter, string $line) { $this->xmlWriter = $xmlWriter; $this->line = $line; } 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 */ 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 phpversion; 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\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 */ final class Facade { public const string XML_NAMESPACE = 'https://schema.phpunit.de/coverage/1.0'; private string $target; private Project $project; private readonly string $phpUnitVersion; private readonly bool $includeSource; public function __construct(string $version, bool $includeSource = \true) { $this->phpUnitVersion = $version; $this->includeSource = $includeSource; } /** * @throws XmlException */ public function process(CodeCoverage $coverage, string $target): void { if (substr($target, -1, 1) !== DIRECTORY_SEPARATOR) { $target .= DIRECTORY_SEPARATOR; } $this->target = $target; $this->initTargetDirectory($target); $report = $coverage->getReport(); $writer = new XMLWriter(); $writer->openUri($this->targetFilePath('index')); $writer->setIndent(\true); $writer->setIndentString(' '); $this->project = new Project($writer, $coverage->getReport()->name()); $this->setBuildInformation($coverage); $this->project->startProject(); $this->processTests($coverage->getTests()); $this->processDirectory($report, $this->project); $this->project->finalize(); } private function setBuildInformation(CodeCoverage $coverage): void { if ($coverage->driverIsPcov()) { $driverExtensionName = 'pcov'; $driverExtensionVersion = phpversion('pcov'); } elseif ($coverage->driverIsXdebug()) { $driverExtensionName = 'xdebug'; $driverExtensionVersion = phpversion('xdebug'); } else { // @codeCoverageIgnoreStart $driverExtensionName = 'unknown'; $driverExtensionVersion = 'unknown'; // @codeCoverageIgnoreEnd } $this->project->buildInformation(new Runtime(), new DateTimeImmutable(), $this->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', $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', $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 */ 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 XMLWriter; /** * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage */ final readonly class Method { 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', $name); $this->xmlWriter->writeAttribute('signature', $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 */ 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 */ 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 XMLWriter; /** * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage */ final class Report extends File { 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', basename($this->name)); $xmlWriter->writeAttribute('path', 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 */ 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 XMLWriter; /** * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage * * @phpstan-import-type TestType from CodeCoverage */ final readonly class Tests { 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', $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 */ 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 XMLWriter; /** * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage */ final readonly class Unit { 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', $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', $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\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 */ 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 */ 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; } return unserialize(file_get_contents($cacheFile), ['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 */ 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 */ 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); if ($linesOfCode === 0 && $sourceCode !== '') { $linesOfCode = 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(), $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 */ 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 */ 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 LinesType */ private array $ignoredLines; /** * @param array $interfaces * @param array $classes * @param array $traits * @param array $functions * @param LinesType $executableLines * @param LinesType $ignoredLines */ public function __construct(array $interfaces, array $classes, array $traits, array $functions, LinesOfCode $linesOfCode, array $executableLines, array $ignoredLines) { $this->interfaces = $interfaces; $this->classes = $classes; $this->traits = $traits; $this->functions = $functions; $this->linesOfCode = $linesOfCode; $this->executableLines = $executableLines; $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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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), $node->getStartLine(), $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, $node->getStartLine(), $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, $node->getStartLine(), $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(), $node->getStartLine(), $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), $node->getStartLine(), $node->getEndLine(), $this->signature($node), $this->cyclomaticComplexity($node)); } 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_|Trait_ $node, array $traits): void { $name = $node->namespacedName->toString(); if ($node instanceof Class_) { 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 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 PHPUnitPHAR\PhpParser\Node; use PHPUnitPHAR\PhpParser\NodeVisitorAbstract; /** * @internal This class is 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 $unsets = []; /** * @var array */ private array $commentsToCheckForUnset = []; public function __construct(string $source) { $this->source = $source; } public function enterNode(Node $node): null { 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_) { 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); } 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\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\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]); 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 (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_ || $node instanceof Node\Stmt\Case_) { if (null === $node->cond) { return null; } $this->setLineBranch($node->cond->getStartLine(), $node->cond->getStartLine(), ++$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; } $this->setLineBranch($node->getStartLine(), $node->getEndLine(), ++$this->nextBranch); 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); return null; } /** * @return LinesType */ public function executableLinesGroupedByBranch(): array { return $this->executableLinesGroupedByBranch; } private function setLineBranch(int $start, int $end, int $branch): void { foreach (range($start, $end) as $line) { $this->executableLinesGroupedByBranch[$line] = $branch; } } } * * 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 */ 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 Class_ || $node instanceof Trait_ || $node instanceof Interface_ || $node instanceof Attribute) { $this->ignoredLines[] = $node->getStartLine(); assert($node->name !== null); // Workaround for https://github.com/nikic/PHP-Parser/issues/886 $this->ignoredLines[] = $node->name->getStartLine(); } if (!$this->useAnnotationsForIgnoringCode) { return null; } if ($node instanceof Interface_) { 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 * * @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]; } 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)); } } 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\TestSize; /** * @immutable */ abstract class Known extends 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 PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestSize; /** * @immutable */ final class Large extends Known { public function isLarge(): true { return \true; } public function isGreaterThan(TestSize $other): bool { return !$other->isLarge(); } public function asString(): string { return 'large'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestSize; /** * @immutable */ final class Medium extends Known { public function isMedium(): true { return \true; } public function isGreaterThan(TestSize $other): bool { return $other->isSmall(); } public function asString(): string { return 'medium'; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestSize; /** * @immutable */ final class Small extends Known { public function isSmall(): true { return \true; } public function isGreaterThan(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 PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestSize; /** * @immutable */ abstract class TestSize { public static function unknown(): Unknown { return new Unknown(); } public static function small(): Small { return new Small(); } public static function medium(): Medium { return new Medium(); } public static function large(): Large { return new Large(); } /** * @phpstan-assert-if-true Known $this */ public function isKnown(): bool { return \false; } /** * @phpstan-assert-if-true Unknown $this */ public function isUnknown(): bool { return \false; } /** * @phpstan-assert-if-true Small $this */ public function isSmall(): bool { return \false; } /** * @phpstan-assert-if-true Medium $this */ public function isMedium(): bool { return \false; } /** * @phpstan-assert-if-true Large $this */ public function isLarge(): bool { return \false; } abstract public function asString(): string; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestSize; /** * @immutable */ final class Unknown extends 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 PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestStatus; /** * @immutable */ final class Failure extends Known { public function isFailure(): true { return \true; } 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 PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestStatus; /** * @immutable */ abstract class Known extends 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 PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestStatus; /** * @immutable */ final class Success extends Known { public function isSuccess(): true { return \true; } 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 PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestStatus; /** * @immutable */ abstract class TestStatus { public static function unknown(): self { return new Unknown(); } public static function success(): self { return new Success(); } public static function failure(): self { return new Failure(); } /** * @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 Failure $this */ public function isFailure(): 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 PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestStatus; /** * @immutable */ final class Unknown extends TestStatus { 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 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 */ 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 function sprintf; /** * @internal This class is 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 */ 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) { $message = 'Unable to generate the XML'; foreach (libxml_get_errors() as $error) { $message .= PHP_EOL . $error->message; } throw new XmlException($message); } 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; final class Version { private static string $version = ''; public static function id(): string { if (self::$version === '') { self::$version = (new VersionId('13.0.1', 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.0 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; 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; 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; 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 */ 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 */ 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; 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 */ 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 */ 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 */ 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 */ 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; 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; 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; 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; 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 */ 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 */ 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 */ 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 */ 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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; 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; 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 */ 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; 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; 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; 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; 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; 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; 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; 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; 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; 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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; 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; 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; 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; 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 */ 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; 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; 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; 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; 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 */ 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 */ 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; 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; 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; 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; 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; 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; 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 */ 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; 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 */ 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; 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; 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; 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; 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; 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; 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 */ 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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(); } 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); } } * * 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 */ 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; 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; 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; 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 */ 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 */ 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 */ 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 */ 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 */ 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. * * @throws ExpectationFailedException */ final public static function assertEquals(mixed $expected, mixed $actual, string $message = ''): void { $constraint = new IsEqual($expected); self::assertThat($actual, $constraint, $message); } /** * Asserts that two variables are equal (canonicalizing). * * @throws ExpectationFailedException */ final public static function assertEqualsCanonicalizing(mixed $expected, mixed $actual, string $message = ''): void { $constraint = new IsEqualCanonicalizing($expected); self::assertThat($actual, $constraint, $message); } /** * Asserts that two variables are equal (ignoring case). * * @throws ExpectationFailedException */ final public static function assertEqualsIgnoringCase(mixed $expected, mixed $actual, string $message = ''): void { $constraint = new IsEqualIgnoringCase($expected); self::assertThat($actual, $constraint, $message); } /** * Asserts that two variables are equal (with delta). * * @throws ExpectationFailedException */ final public static function assertEqualsWithDelta(mixed $expected, mixed $actual, float $delta, string $message = ''): void { $constraint = new IsEqualWithDelta($expected, $delta); self::assertThat($actual, $constraint, $message); } /** * Asserts that two variables are not equal. * * @throws ExpectationFailedException */ final public static function assertNotEquals(mixed $expected, mixed $actual, string $message = ''): void { $constraint = new LogicalNot(new IsEqual($expected)); self::assertThat($actual, $constraint, $message); } /** * Asserts that two variables are not equal (canonicalizing). * * @throws ExpectationFailedException */ final public static function assertNotEqualsCanonicalizing(mixed $expected, mixed $actual, string $message = ''): void { $constraint = new LogicalNot(new IsEqualCanonicalizing($expected)); self::assertThat($actual, $constraint, $message); } /** * Asserts that two variables are not equal (ignoring case). * * @throws ExpectationFailedException */ final public static function assertNotEqualsIgnoringCase(mixed $expected, mixed $actual, string $message = ''): void { $constraint = new LogicalNot(new IsEqualIgnoringCase($expected)); self::assertThat($actual, $constraint, $message); } /** * Asserts that two variables are not equal (with delta). * * @throws ExpectationFailedException */ final public static function assertNotEqualsWithDelta(mixed $expected, mixed $actual, float $delta, string $message = ''): void { $constraint = new LogicalNot(new IsEqualWithDelta($expected, $delta)); self::assertThat($actual, $constraint, $message); } /** * @throws ExpectationFailedException */ final public static function assertObjectEquals(object $expected, object $actual, string $method = 'equals', string $message = ''): void { self::assertThat($actual, self::objectEquals($expected, $method), $message); } /** * @throws ExpectationFailedException */ final public static function assertObjectNotEquals(object $expected, object $actual, string $method = 'equals', string $message = ''): void { self::assertThat($actual, self::logicalNot(self::objectEquals($expected, $method)), $message); } /** * Asserts that a variable is empty. * * @throws ExpectationFailedException * @throws GeneratorNotSupportedException */ final public static function assertEmpty(mixed $actual, string $message = ''): void { if ($actual instanceof Generator) { throw \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. * * @template ExpectedType * * @param ExpectedType $expected * * @throws ExpectationFailedException * * @phpstan-assert =ExpectedType $actual */ final public static function assertSame(mixed $expected, mixed $actual, string $message = ''): void { self::assertThat($actual, new IsIdentical($expected), $message); } /** * Asserts that two variables do not have the same type and value. * Used on objects, it asserts that two variables do not reference * the same object. * * @throws ExpectationFailedException */ final public static function assertNotSame(mixed $expected, mixed $actual, string $message = ''): void { if (is_bool($expected) && is_bool($actual)) { self::assertNotEquals($expected, $actual, $message); } self::assertThat($actual, new LogicalNot(new IsIdentical($expected)), $message); } /** * Asserts that a variable is of a given type. * * @template ExpectedType of object * * @param class-string $expected * * @throws Exception * @throws ExpectationFailedException * @throws UnknownClassOrInterfaceException * * @phpstan-assert =ExpectedType $actual */ final public static function assertInstanceOf(string $expected, mixed $actual, string $message = ''): void { if (!class_exists($expected) && !interface_exists($expected)) { throw new \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. * * @throws Exception * @throws ExpectationFailedException * @throws XmlException */ final public static function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void { $expected = (new XmlLoader())->loadFile($expectedFile); $actual = (new XmlLoader())->loadFile($actualFile); self::assertEquals($expected, $actual, $message); } /** * Asserts that two XML files are not equal. * * @throws \PHPUnit\Util\Exception * @throws ExpectationFailedException */ final public static function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void { $expected = (new XmlLoader())->loadFile($expectedFile); $actual = (new XmlLoader())->loadFile($actualFile); self::assertNotEquals($expected, $actual, $message); } /** * Asserts that two XML documents are equal. * * @throws ExpectationFailedException * @throws XmlException */ final public static function assertXmlStringEqualsXmlFile(string $expectedFile, string $actualXml, string $message = ''): void { $expected = (new XmlLoader())->loadFile($expectedFile); $actual = (new XmlLoader())->load($actualXml); self::assertEquals($expected, $actual, $message); } /** * Asserts that two XML documents are not equal. * * @throws ExpectationFailedException * @throws XmlException */ final public static function assertXmlStringNotEqualsXmlFile(string $expectedFile, string $actualXml, string $message = ''): void { $expected = (new XmlLoader())->loadFile($expectedFile); $actual = (new XmlLoader())->load($actualXml); self::assertNotEquals($expected, $actual, $message); } /** * Asserts that two XML documents are equal. * * @throws ExpectationFailedException * @throws XmlException */ final public static function assertXmlStringEqualsXmlString(string $expectedXml, string $actualXml, string $message = ''): void { $expected = (new XmlLoader())->load($expectedXml); $actual = (new XmlLoader())->load($actualXml); self::assertEquals($expected, $actual, $message); } /** * Asserts that two XML documents are not equal. * * @throws ExpectationFailedException * @throws XmlException */ final public static function assertXmlStringNotEqualsXmlString(string $expectedXml, string $actualXml, string $message = ''): void { $expected = (new XmlLoader())->load($expectedXml); $actual = (new XmlLoader())->load($actualXml); self::assertNotEquals($expected, $actual, $message); } /** * Evaluates a PHPUnit\Framework\Constraint matcher object. * * @throws ExpectationFailedException */ final public static function assertThat(mixed $value, Constraint $constraint, string $message = ''): void { self::$count += count($constraint); $constraint->evaluate($value, $message); } /** * Asserts that a string is a valid JSON string. * * @throws ExpectationFailedException */ final public static function assertJson(string $actual, string $message = ''): void { self::assertThat($actual, self::isJson(), $message); } /** * Asserts that two given JSON encoded objects or arrays are equal. * * @throws ExpectationFailedException */ final public static function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void { self::assertJson($expectedJson, $message); self::assertJson($actualJson, $message); self::assertThat($actualJson, new JsonMatches($expectedJson), $message); } /** * Asserts that two given JSON encoded objects or arrays are not equal. * * @throws ExpectationFailedException */ final public static function assertJsonStringNotEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void { self::assertJson($expectedJson, $message); self::assertJson($actualJson, $message); self::assertThat($actualJson, new LogicalNot(new JsonMatches($expectedJson)), $message); } /** * Asserts that the generated JSON encoded object and the content of the given file are equal. * * @throws ExpectationFailedException */ final public static function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void { self::assertFileExists($expectedFile, $message); $expectedJson = file_get_contents($expectedFile); self::assertIsString($expectedJson); self::assertJson($expectedJson, $message); self::assertJson($actualJson, $message); self::assertThat($actualJson, new JsonMatches($expectedJson), $message); } /** * Asserts that the generated JSON encoded object and the content of the given file are not equal. * * @throws ExpectationFailedException */ final public static function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void { self::assertFileExists($expectedFile, $message); $expectedJson = file_get_contents($expectedFile); self::assertIsString($expectedJson); self::assertJson($expectedJson, $message); self::assertJson($actualJson, $message); self::assertThat($actualJson, new LogicalNot(new JsonMatches($expectedJson)), $message); } /** * Asserts that two JSON files are equal. * * @throws ExpectationFailedException */ final public static function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void { self::assertFileExists($expectedFile, $message); $expectedJson = file_get_contents($expectedFile); self::assertIsString($expectedJson); self::assertJson($expectedJson, $message); self::assertFileExists($actualFile, $message); $actualJson = file_get_contents($actualFile); self::assertIsString($actualJson); self::assertJson($actualJson, $message); self::assertThat($actualJson, new JsonMatches($expectedJson), $message); } /** * Asserts that two JSON files are not equal. * * @throws ExpectationFailedException */ final public static function assertJsonFileNotEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void { self::assertFileExists($expectedFile, $message); $expectedJson = file_get_contents($expectedFile); self::assertIsString($expectedJson); self::assertJson($expectedJson, $message); self::assertFileExists($actualFile, $message); $actualJson = file_get_contents($actualFile); self::assertIsString($actualJson); self::assertJson($actualJson, $message); self::assertThat($actualJson, self::logicalNot(new JsonMatches($expectedJson)), $message); } /** * @throws Exception */ final public static function logicalAnd(mixed ...$constraints): LogicalAnd { return LogicalAnd::fromConstraints(...$constraints); } final public static function logicalOr(mixed ...$constraints): LogicalOr { return LogicalOr::fromConstraints(...$constraints); } final public static function logicalNot(Constraint $constraint): LogicalNot { return new LogicalNot($constraint); } final public static function logicalXor(mixed ...$constraints): LogicalXor { return LogicalXor::fromConstraints(...$constraints); } final public static function anything(): IsAnything { return new IsAnything(); } final public static function isTrue(): IsTrue { return new IsTrue(); } /** * @template CallbackInput of mixed * * @param callable(CallbackInput $callback): bool $callback * * @return Callback */ final public static function callback(callable $callback): Callback { return new Callback($callback); } final public static function isFalse(): IsFalse { return new IsFalse(); } final public static function isJson(): IsJson { return new IsJson(); } final public static function isNull(): IsNull { return new IsNull(); } final public static function isFinite(): IsFinite { return new IsFinite(); } final public static function isInfinite(): IsInfinite { return new IsInfinite(); } final public static function isNan(): IsNan { return new IsNan(); } final public static function containsEqual(mixed $value): TraversableContainsEqual { return new TraversableContainsEqual($value); } final public static function containsIdentical(mixed $value): TraversableContainsIdentical { return new TraversableContainsIdentical($value); } final public static function containsOnlyArray(): TraversableContainsOnly { return TraversableContainsOnly::forNativeType(\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. * * @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). * * @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). * * @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). * * @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. * * @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). * * @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). * * @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). * * @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. * * @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. * * @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. * * @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. * * @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. * * @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. * * @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. * * @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. * * @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; /** * @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_keys; use function array_values; use function is_array; use function ksort; use function sort; 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; } $expected = $this->expected; $actual = $other; if ($this->keysMatter && !$this->orderMatters) { $expectedKeys = array_keys($expected); $actualKeys = array_keys($actual); sort($expectedKeys); sort($actualKeys); if ($expectedKeys === $actualKeys) { sort($expected); sort($actual); } else { ksort($expected); ksort($actual); } } if (!$this->keysMatter) { $expected = array_values($expected); $actual = array_values($actual); if (!$this->orderMatters) { sort($expected); sort($actual); } } $success = $this->compareArrays($expected, $actual); 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(); } /** * Compares two arrays using the appropriate comparison method. */ abstract protected function compareArrays(mixed $expected, mixed $actual): bool; /** * @return 'equal'|'identical' */ abstract protected function comparisonType(): string; } * * 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 compareArrays(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 compareArrays(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_match; use function sprintf; /** * @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. */ protected function matches(mixed $other): bool { return preg_match($this->pattern, $other) > 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 explode; use function implode; use function preg_match; use function preg_quote; use function preg_replace; use function strtr; 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. */ protected function matches(mixed $other): bool { $other = $this->convertNewlines($other); $matches = preg_match($this->regularExpressionForFormatDescription($this->convertNewlines($this->formatDescription)), $other); return $matches > 0; } protected function failureDescription(mixed $other): string { return 'string matches format description'; } /** * Returns a cleaned up diff. * * The expected string can contain placeholders like %s and %d. * By using 'diff' such placeholders compared to the real output will * always be different, although we don't want to show them as different. * This method removes the expected differences by figuring out if a difference * is allowed by the use of a placeholder. * * The problem here are %A and %a multiline placeholders since we look at the * expected and actual output line by line. If differences allowed by those placeholders * stretch over multiple lines they will still end up in the final diff. * And since they mess up the line sync between the expected and actual output * all following allowed changes will not be detected/removed anymore. */ protected function additionalFailureDescription(mixed $other): string { $from = explode("\n", $this->formatDescription); $to = explode("\n", $this->convertNewlines($other)); foreach ($from as $index => $line) { // is the expected output line different from the actual output line if (isset($to[$index]) && $line !== $to[$index]) { $line = $this->regularExpressionForFormatDescription($line); // if the difference is allowed by a placeholder // overwrite the expected line with the actual line to prevent it from showing up in the diff if (preg_match($line, $to[$index]) > 0) { $from[$index] = $to[$index]; } } } $from = implode("\n", $from); $to = implode("\n", $to); return $this->differ()->diff($from, $to); } private function regularExpressionForFormatDescription(string $string): string { $string = strtr(preg_quote($string, '/'), ['%%' => '%', '%e' => preg_quote(DIRECTORY_SEPARATOR, '/'), '%s' => '[^\r\n]+', '%S' => '[^\r\n]*', '%a' => '.+?', '%A' => '.*?', '%w' => '\s*', '%i' => '[+-]?\d+', '%d' => '\d+', '%x' => '[0-9a-fA-F]+', '%f' => '[+-]?(?:\d+|(?=\.\d))(?:\.\d+)?(?:[Ee][+-]?\d+)?', '%c' => '.', '%0' => '\x00']); return '/^' . $string . '$/s'; } private function convertNewlines(string $text): string { $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")); } } * * 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. */ if ($name === '$' || $name === '$...') { $name = '$arg' . $i; } $default = ''; $reference = ''; $typeDeclaration = ''; assert(array_key_exists($i, $types)); if (!$types[$i]->type()->isUnknown()) { $typeDeclaration = $types[$i]->type()->asString() . ' '; } if ($parameter->isPassedByReference()) { $reference = '&'; } if ($parameter->isVariadic()) { $name = '...' . $name; } elseif ($parameter->isDefaultValueAvailable()) { $default = ' = ' . self::exportDefaultValue($parameter); } elseif ($parameter->isOptional()) { $default = ' = null'; } $parameters[] = $typeDeclaration . $reference . $name . $default; } return implode(', ', $parameters); } /** * Returns the parameters of a function or method. * * @throws ReflectionException */ private static function methodParametersForCall(ReflectionMethod $method): string { $parameters = []; foreach ($method->getParameters() as $i => $parameter) { $name = '$' . $parameter->getName(); /* Note: PHP extensions may use empty names for reference arguments * or "..." for methods taking a variable number of arguments. */ if ($name === '$' || $name === '$...') { $name = '$arg' . $i; } if ($parameter->isVariadic()) { continue; } if ($parameter->isPassedByReference()) { $parameters[] = '&' . $name; } else { $parameters[] = $name; } } return implode(', ', $parameters); } /** * @throws ReflectionException */ private static function exportDefaultValue(ReflectionParameter $parameter): string { try { $defaultValue = $parameter->getDefaultValue(); if (!is_object($defaultValue)) { return var_export($defaultValue, \true); } $parameterAsString = $parameter->__toString(); return explode(' = ', substr(substr($parameterAsString, strpos($parameterAsString, ' ') + strlen(' ')), 0, -2))[1]; // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new \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 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 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 ClassIsEnumerationException * @throws ClassIsFinalException * @throws DuplicateMethodException * @throws InvalidMethodNameException * @throws NameAlreadyInUseException * @throws ReflectionException * @throws RuntimeException * @throws UnknownTypeException */ public function testDouble(string $type, bool $mockObject, ?array $methods = [], array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = \true, bool $callOriginalClone = \true, bool $returnValueGeneration = \true): MockObject|Stub { if ($type === Traversable::class) { $type = Iterator::class; } $this->ensureKnownType($type); $this->ensureValidMethods($methods); $this->ensureNameForTestDoubleClassIsAvailable($mockClassName); $mock = $this->generate($type, $mockObject, $methods, $mockClassName, $callOriginalClone); $object = $this->instantiate($mock, $callOriginalConstructor, $arguments, $returnValueGeneration, $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 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, 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(), $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 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->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-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*~', (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 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->hasGetHook()) { $configurable[] = new ConfigurableMethod(sprintf('$%s::get', $property->name()), [], 0, $property->type()); } if ($property->hasSetHook()) { $configurable[] = new ConfigurableMethod(sprintf('$%s::set', $property->name()), [], 1, Type::fromName('void', \false)); } } return $configurable; } /** * @param ?ReflectionClass $class * * @return list */ private function properties(?ReflectionClass $class): array { if ($class === null) { return []; } $mapper = new ReflectionMapper(); $properties = []; foreach ($class->getProperties() as $property) { if (!$property->isPublic()) { continue; } if ($property->isFinal()) { continue; } if (!$property->hasHooks()) { continue; } $hasGetHook = \false; $hasSetHook = \false; $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, $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 ?Type $setterType; /** * @param non-empty-string $name */ public function __construct(string $name, Type $type, bool $getHook, bool $setHook, ?Type $setterType) { $this->name = $name; $this->type = $type; $this->getHook = $getHook; $this->setHook = $setHook; $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; } /** * @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->hasGetHook()) { $code .= sprintf(<<<'EOT' get { return $this->__phpunit_getInvocationHandler()->invoke( new \PHPUnit\Framework\MockObject\Invocation( '%s', '$%s::get', [], '%s', $this ) ); } EOT , $className, $property->name(), $property->type()->asString()); } if ($property->hasSetHook()) { $code .= sprintf(<<<'EOT' set (%s $value) { $this->__phpunit_getInvocationHandler()->invoke( new \PHPUnit\Framework\MockObject\Invocation( '%s', '$%s::set', [$value], 'void', $this ) ); } EOT , $property->setterType()->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\ClassIsEnumerationException; use PHPUnit\Framework\MockObject\Generator\ClassIsFinalException; use PHPUnit\Framework\MockObject\Generator\DuplicateMethodException; use PHPUnit\Framework\MockObject\Generator\InvalidMethodNameException; use PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException; use PHPUnit\Framework\MockObject\Generator\ReflectionException; use PHPUnit\Framework\MockObject\Generator\RuntimeException; use PHPUnit\Framework\MockObject\Generator\UnknownTypeException; use PHPUnit\Framework\TestCase; /** * @template MockedType * * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit */ final class MockBuilder extends \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 ClassIsEnumerationException * @throws ClassIsFinalException * @throws DuplicateMethodException * @throws InvalidArgumentException * @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([], \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; private readonly bool $generateReturnValues; private readonly bool $isMockObject; private ?\PHPUnit\Framework\MockObject\InvocationHandler $invocationHandler = null; /** * @param list $configurableMethods */ public function __construct(array $configurableMethods, bool $generateReturnValues, bool $isMockObject = \false) { $this->configurableMethods = $configurableMethods; $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->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 */ public function id(string $id): self; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @param non-empty-string $id * * @return $this */ public function after(string $id): self; } * * 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\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; private readonly bool $returnValueGeneration; private readonly bool $isMockObject; private bool $sealed = \false; /** * @param list $configurableMethods */ public function __construct(array $configurableMethods, bool $returnValueGeneration, bool $isMockObject = \false) { $this->configurableMethods = $configurableMethods; $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->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 ($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(); } } 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)); $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 */ public function id(string $id): \PHPUnit\Framework\MockObject\InvocationMocker { $this->invocationHandler->registerMatcher($id, $this->matcher); return $this; } /** * @param non-empty-string $id * * @return $this */ 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 ?non-empty-string */ private ?string $afterMatchBuilderId = null; private ?MethodName $methodNameRule = null; private ?ParametersRule $parametersRule = null; private ?Stub $stub = null; public function __construct(InvocationOrder $rule) { $this->invocationRule = $rule; } public function 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 failed for %s when %s\n%s", $this->methodNameRule->toString(), $this->invocationRule->toString(), $e->getMessage()), $e->getComparisonFailure()); } if ($this->stub !== null) { return $this->stub->invoke($invocation); } return $invocation->generateReturnValue(); } /** * @throws ExpectationFailedException * @throws MatchBuilderNotFoundException * @throws MethodNameNotConfiguredException * @throws RuntimeException */ public function matches(\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 failed for %s when %s\n%s", $this->methodNameRule->toString(), $this->invocationRule->toString(), $e->getMessage()), $e->getComparisonFailure()); } return \true; } /** * @throws ExpectationFailedException * @throws MethodNameNotConfiguredException */ public function verify(): void { if ($this->methodNameRule === null) { throw new \PHPUnit\Framework\MockObject\MethodNameNotConfiguredException(); } try { $this->invocationRule->verify(); if ($this->parametersRule === null) { $this->parametersRule = new AnyParameters(); } $invocationIsAny = $this->invocationRule instanceof AnyInvokedCount; $invocationIsNever = $this->invocationRule instanceof InvokedCount && $this->invocationRule->isNever(); $invocationIsAtMost = $this->invocationRule instanceof InvokedAtMostCount; if (!$invocationIsAny && !$invocationIsNever && !$invocationIsAtMost) { $this->parametersRule->verify(); } } catch (ExpectationFailedException $e) { throw new ExpectationFailedException(sprintf("Expectation failed for %s when %s.\n%s", $this->methodNameRule->toString(), $this->invocationRule->toString(), ThrowableToStringMapper::map($e))); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PHPUnit\Framework\MockObject; use function sprintf; use function strtolower; use PHPUnit\Framework\Constraint\Constraint; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class MethodNameConstraint extends Constraint { private string $methodName; public function __construct(string $methodName) { $this->methodName = $methodName; } public function toString(): string { return sprintf('is "%s"', $this->methodName); } protected function matches(mixed $other): bool { return strtolower($this->methodName) === strtolower((string) $other); } } * * 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(), $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 { return sprintf('invoked at most %d time%s', $this->allowedInvocations, $this->allowedInvocations !== 1 ? 's' : ''); } /** * Verifies that the current expectation is valid. If everything is OK the * code should just return, if not it must throw an exception. * * @throws ExpectationFailedException */ public function verify(): void { $actualInvocations = $this->numberOfInvocations(); if ($actualInvocations > $this->allowedInvocations) { throw new ExpectationFailedException(sprintf('Expected invocation at most %d time%s but it occurred %d time%s.', $this->allowedInvocations, $this->allowedInvocations !== 1 ? 's' : '', $actualInvocations, $actualInvocations !== 1 ? 's' : '')); } } public function matches(BaseInvocation $invocation): bool { return \true; } } * * 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 { return sprintf('invoked %d time%s', $this->expectedCount, $this->expectedCount !== 1 ? 's' : ''); } public function matches(BaseInvocation $invocation): bool { return \true; } /** * Verifies that the current expectation is valid. If everything is OK the * code should just return, if not it must throw an exception. * * @throws ExpectationFailedException */ public function verify(): void { $actualCount = $this->numberOfInvocations(); if ($actualCount !== $this->expectedCount) { throw new ExpectationFailedException(sprintf('Method was expected to be called %d time%s, actually called %d time%s.', $this->expectedCount, $this->expectedCount !== 1 ? 's' : '', $actualCount, $actualCount !== 1 ? 's' : '')); } } /** * @throws ExpectationFailedException */ protected function invokedDo(BaseInvocation $invocation): void { $count = $this->numberOfInvocations(); if ($count > $this->expectedCount) { $message = $invocation->toString() . ' '; $message .= match ($this->expectedCount) { 0 => 'was not expected to be called.', 1 => 'was not expected to be called more than once.', default => sprintf('was not expected to be called more than %d times.', $this->expectedCount), }; throw new ExpectationFailedException($message); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PHPUnit\Framework\MockObject\Rule; use function is_string; use PHPUnit\Framework\Constraint\Constraint; use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\InvalidArgumentException; use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; use PHPUnit\Framework\MockObject\MethodNameConstraint; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final readonly class MethodName { private Constraint $constraint; /** * @throws InvalidArgumentException */ public function __construct(Constraint|string $constraint) { if (is_string($constraint)) { $constraint = new MethodNameConstraint($constraint); } $this->constraint = $constraint; } public function toString(): string { return 'method name ' . $this->constraint->toString(); } /** * @throws ExpectationFailedException */ public function matches(BaseInvocation $invocation): bool { return $this->matchesName($invocation->methodName()); } /** * @throws ExpectationFailedException */ public function matchesName(string $methodName): bool { return (bool) $this->constraint->evaluate($methodName, '', \true); } } * * 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 count; use function sprintf; use Exception; use PHPUnit\Framework\Constraint\Callback; use PHPUnit\Framework\Constraint\Constraint; use PHPUnit\Framework\Constraint\IsAnything; use PHPUnit\Framework\Constraint\IsEqual; use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; use PHPUnit\Util\Test; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class Parameters implements \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())); } foreach ($this->parameters as $i => $parameter) { if ($parameter instanceof Callback && $parameter->isVariadic()) { $other = $this->invocation->parameters(); } else { $other = $this->invocation->parameters()[$i]; } $this->incrementAssertionCount(); $parameter->evaluate($other, sprintf('Parameter %s for invocation %s does not match expected value.', $i, $this->invocation->toString())); } return \true; } /** * @throws ExpectationFailedException */ private function guardAgainstDuplicateEvaluationOfParameterConstraints(): bool { if ($this->parameterVerificationResult instanceof ExpectationFailedException) { throw $this->parameterVerificationResult; } return (bool) $this->parameterVerificationResult; } private function incrementAssertionCount(): void { if ($this->useAssertionCount === \false) { return; } Test::currentTestCase()->addToAssertionCount(1); } } * * 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): self { if ($methods === []) { $this->emptyMethodsArray = \true; return $this; } try { $reflector = new ReflectionClass($this->type); // @codeCoverageIgnoreStart } catch (\ReflectionException $e) { throw new ReflectionException($e->getMessage(), $e->getCode(), $e); // @codeCoverageIgnoreEnd } foreach ($methods as $method) { if (!$reflector->hasMethod($method)) { throw new \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): self { $this->constructorArgs = $arguments; return $this; } /** * Disables the invocation of the original constructor. * * @return $this */ public function disableOriginalConstructor(): self { $this->originalConstructor = \false; return $this; } /** * Enables the invocation of the original constructor. * * @return $this */ public function enableOriginalConstructor(): self { $this->originalConstructor = \true; return $this; } /** * Disables the invocation of the original clone constructor. * * @return $this */ public function disableOriginalClone(): self { $this->originalClone = \false; return $this; } /** * Enables the invocation of the original clone constructor. * * @return $this */ public function enableOriginalClone(): self { $this->originalClone = \true; return $this; } /** * @return $this */ public function enableAutoReturnValueGeneration(): self { $this->returnValueGeneration = \true; return $this; } /** * @return $this */ public function disableAutoReturnValueGeneration(): self { $this->returnValueGeneration = \false; return $this; } protected function getTestDouble(?string $testDoubleClassName, bool $mockObject): \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\ClassIsEnumerationException; use PHPUnit\Framework\MockObject\Generator\ClassIsFinalException; use PHPUnit\Framework\MockObject\Generator\DuplicateMethodException; use PHPUnit\Framework\MockObject\Generator\InvalidMethodNameException; use PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException; use PHPUnit\Framework\MockObject\Generator\ReflectionException; use PHPUnit\Framework\MockObject\Generator\RuntimeException; use PHPUnit\Framework\MockObject\Generator\UnknownTypeException; /** * @template StubbedType * * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit */ final class TestStubBuilder extends \PHPUnit\Framework\MockObject\TestDoubleBuilder { /** * @var ?class-string */ private ?string $stubClassName = null; /** * Creates a test stub using a fluent interface. * * @throws ClassIsEnumerationException * @throws ClassIsFinalException * @throws DuplicateMethodException * @throws InvalidMethodNameException * @throws NameAlreadyInUseException * @throws ReflectionException * @throws RuntimeException * @throws UnknownTypeException * * @return Stub&StubbedType */ public function getStub(): \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\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; } \PHPUnit\Framework\IsolatedTestRunnerRegistry::run($this, $this->preserveGlobalState, $this->requiresXdebug()); } /** * @return list * * @internal This method is not covered by the backward compatibility promise for PHPUnit */ final public function groups(): array { return $this->groups; } /** * @param list $groups * * @internal This method is not covered by the backward compatibility promise for PHPUnit */ final public function setGroups(array $groups): void { $this->groups = $groups; } /** * @internal This method is not covered by the backward compatibility promise for PHPUnit */ final public function nameWithDataSet(): string { return $this->methodName . $this->dataSetAsString(); } /** * @return non-empty-string * * @internal This method is not covered by the backward compatibility promise for PHPUnit */ final public function name(): string { return $this->methodName; } /** * @internal This method is not covered by the backward compatibility promise for PHPUnit */ final public function size(): TestSize { return (new Groups())->size(static::class, $this->methodName); } /** * @internal This method is not covered by the backward compatibility promise for PHPUnit * * @phpstan-assert-if-true non-empty-string $this->output() */ final public function hasUnexpectedOutput(): bool { if ($this->output === '') { return \false; } if ($this->expectsOutput()) { return \false; } return \true; } /** * @internal This method is not covered by the backward compatibility promise for PHPUnit */ final public function output(): string { if (!$this->outputBufferingActive) { return $this->output; } return (string) ob_get_contents(); } /** * @internal This method is not covered by the backward compatibility promise for PHPUnit */ final public function doesNotPerformAssertions(): bool { return $this->doesNotPerformAssertions; } /** * @internal This method is not covered by the backward compatibility promise for PHPUnit */ final public function expectsOutput(): bool { return $this->hasExpectationOnOutput() || $this->outputRetrievedForAssertion; } /** * @throws Throwable * * @internal This method is not covered by the backward compatibility promise for PHPUnit */ final public function runBare(): void { $emitter = Event\Facade::emitter(); error_clear_last(); clearstatcache(); $emitter->testPreparationStarted($this->valueObjectForEvents()); $this->snapshotGlobalState(); $this->snapshotGlobalErrorExceptionHandlers(); $this->handleEnvironmentVariables(); $this->startOutputBuffering(); $hookMethods = (new HookMethods())->hookMethods(static::class); $hasMetRequirements = \false; $this->numberOfAssertionsPerformed = 0; $currentWorkingDirectory = getcwd(); try { $this->checkRequirements(); $hasMetRequirements = \true; if ($this->inIsolation) { // @codeCoverageIgnoreStart $this->invokeBeforeClassHookMethods($hookMethods, $emitter); // @codeCoverageIgnoreEnd } if (method_exists(static::class, $this->methodName) && MetadataRegistry::parser()->forClassAndMethod(static::class, $this->methodName)->isDoesNotPerformAssertions()->isNotEmpty()) { $this->doesNotPerformAssertions = \true; } $this->invokeBeforeTestHookMethods($hookMethods, $emitter); $this->invokePreConditionHookMethods($hookMethods, $emitter); $emitter->testPrepared($this->valueObjectForEvents()); $this->wasPrepared = \true; $this->testResult = $this->runTest(); $this->verifyDeprecationExpectations(); $this->verifyMockObjects(); $this->invokePostConditionHookMethods($hookMethods, $emitter); $this->status = TestStatus::success(); } catch (\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; $this->performAssertionsOnOutput(); } try { $this->mockObjects = []; /** @phpstan-ignore catch.neverThrown */ } catch (Throwable $e) { Event\Facade::emitter()->testErrored($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($e)); } // Tear down the fixture. An exception raised in tearDown() will be // caught and passed on when no exception was raised before. try { if ($hasMetRequirements) { $this->invokeAfterTestHookMethods($hookMethods, $emitter); if ($this->inIsolation) { // @codeCoverageIgnoreStart $this->invokeAfterClassHookMethods($hookMethods, $emitter); // @codeCoverageIgnoreEnd } } } catch (AssertionError|\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"', $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', $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'); $excludeList->addStaticProperty(ComparatorFactory::class, 'instance'); foreach ($this->backupStaticPropertiesExcludeList as $class => $properties) { foreach ($properties as $property) { $excludeList->addStaticProperty($class, $property); } } } try { return new Snapshot($excludeList, $backupGlobals, (bool) $this->backupStaticProperties, \false, \false, \false, \false, \false, \false, \false); } catch (Throwable $t) { Event\Facade::emitter()->testPreparationFailed($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($t)); Event\Facade::emitter()->testErrored($this->valueObjectForEvents(), Event\Code\ThrowableBuilder::from($t)); throw $t; } } private function compareGlobalStateSnapshots(Snapshot $before, Snapshot $after): void { $backupGlobals = $this->backupGlobals === null || $this->backupGlobals; if ($backupGlobals) { $this->compareGlobalStateSnapshotPart($before->globalVariables(), $after->globalVariables(), "--- Global variables before the test\n+++ Global variables after the test\n"); $this->compareGlobalStateSnapshotPart($before->superGlobalVariables(), $after->superGlobalVariables(), "--- Super-global variables before the test\n+++ Super-global variables after the test\n"); } if ($this->backupStaticProperties) { $this->compareGlobalStateSnapshotPart($before->staticProperties(), $after->staticProperties(), "--- Static properties before the test\n+++ Static properties after the test\n"); } } /** * @param array $before * @param array $after */ private function compareGlobalStateSnapshotPart(array $before, array $after, string $header): void { if ($before === $after) { return; } $differ = new Differ(new UnifiedDiffOutputBuilder($header)); Event\Facade::emitter()->testConsideredRisky($this->valueObjectForEvents(), 'This test modified global state but was not expected to do so' . PHP_EOL . trim($differ->diff(Exporter::export($before), Exporter::export($after)))); } private function handleEnvironmentVariables(): void { $withEnvironmentVariables = MetadataRegistry::parser()->forClassAndMethod(static::class, $this->methodName)->isWithEnvironmentVariable(); $environmentVariables = []; foreach ($withEnvironmentVariables as $metadata) { assert($metadata instanceof WithEnvironmentVariable); $environmentVariables[$metadata->environmentVariableName()] = $metadata->value(); } foreach ($environmentVariables as $environmentVariableName => $environmentVariableValue) { $this->backupEnvironmentVariables = [...$this->backupEnvironmentVariables, ...BackedUpEnvironmentVariable::create($environmentVariableName)]; if ($environmentVariableValue === null) { unset($_ENV[$environmentVariableName]); putenv($environmentVariableName); } else { $_ENV[$environmentVariableName] = $environmentVariableValue; putenv("{$environmentVariableName}={$environmentVariableValue}"); } } } private function restoreEnvironmentVariables(): void { foreach ($this->backupEnvironmentVariables as $backupEnvironmentVariable) { $backupEnvironmentVariable->restore(); } $this->backupEnvironmentVariables = []; } private function shouldInvocationMockerBeReset(MockObject $mock): bool { $enumerator = new Enumerator(); if (in_array($mock, $enumerator->enumerate($this->dependencyInput), \true)) { return \false; } if (!is_array($this->testResult) && !is_object($this->testResult)) { return \true; } return !in_array($mock, $enumerator->enumerate($this->testResult), \true); } private function unregisterCustomComparators(): void { $factory = ComparatorFactory::getInstance(); foreach ($this->customComparators as $comparator) { $factory->unregister($comparator); } $this->customComparators = []; } /** * @throws Exception */ private function shouldExceptionExpectationsBeVerified(Throwable $throwable): bool { $result = \false; if ($this->expectedException !== null || $this->expectedExceptionCode !== null || $this->expectedExceptionMessage !== null || $this->expectedExceptionMessageRegExp !== null) { $result = \true; } if ($throwable instanceof \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 trim; use function unserialize; use PHPUnit\Event\Code\TestMethodBuilder; use PHPUnit\Event\Code\ThrowableBuilder; use PHPUnit\Event\Emitter; use PHPUnit\Event\Facade; use PHPUnit\Runner\CodeCoverage; use PHPUnit\TestRunner\TestResult\PassedTests; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit */ final readonly class ChildProcessResultProcessor { private Facade $eventFacade; private Emitter $emitter; private PassedTests $passedTests; private CodeCoverage $codeCoverage; public function __construct(Facade $eventFacade, Emitter $emitter, PassedTests $passedTests, CodeCoverage $codeCoverage) { $this->eventFacade = $eventFacade; $this->emitter = $emitter; $this->passedTests = $passedTests; $this->codeCoverage = $codeCoverage; } public function process(\PHPUnit\Framework\Test $test, string $serializedProcessResult, string $stderr): 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; } $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; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This interface is not covered by the backward compatibility promise for PHPUnit */ interface IsolatedTestRunner { public function run(\PHPUnit\Framework\TestCase $test, bool $preserveGlobalState, bool $requiresXdebug): void; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PHPUnit\Framework; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class IsolatedTestRunnerRegistry { private static ?\PHPUnit\Framework\IsolatedTestRunner $runner = null; public static function run(\PHPUnit\Framework\TestCase $test, bool $preserveGlobalState, bool $requiresXdebug): void { if (self::$runner === null) { self::$runner = new \PHPUnit\Framework\SeparateProcessTestRunner(); } self::$runner->run($test, $preserveGlobalState, $requiresXdebug); } public static function set(\PHPUnit\Framework\IsolatedTestRunner $runner): void { self::$runner = $runner; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PHPUnit\Framework; use function assert; use function defined; use function get_include_path; use function hrtime; use function serialize; use function sys_get_temp_dir; use function tempnam; use function unlink; use function var_export; use PHPUnit\Event\NoPreviousThrowableException; use PHPUnit\Runner\CodeCoverage; use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; use PHPUnit\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 implements \PHPUnit\Framework\IsolatedTestRunner { 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(); $globals = GlobalState::getGlobalsAsString(); $includedFiles = GlobalState::getIncludedFilesAsString(); $iniSettings = GlobalState::getIniSettingsAsString(); } $coverage = CodeCoverage::instance()->isActive() ? 'true' : 'false'; if (defined('PHPUNIT_COMPOSER_INSTALL')) { $composerAutoload = var_export(PHPUNIT_COMPOSER_INSTALL, \true); } else { $composerAutoload = '\'\''; } if (defined('__PHPUNIT_PHAR__')) { $phar = var_export(__PHPUNIT_PHAR__, \true); } else { $phar = '\'\''; } $data = var_export(serialize($test->providedData()), \true); $dataName = var_export($test->dataName(), \true); $dependencyInput = var_export(serialize($test->dependencyInput()), \true); $includePath = var_export(get_include_path(), \true); // must do these fixes because TestCaseMethod.tpl has unserialize('{data}') in it, and we can't break BC // the lines above used to use addcslashes() rather than var_export(), which breaks null byte escape sequences $data = "'." . $data . ".'"; $dataName = "'.(" . $dataName . ").'"; $dependencyInput = "'." . $dependencyInput . ".'"; $includePath = "'." . $includePath . ".'"; $offset = hrtime(); $serializedConfiguration = $this->saveConfigurationForChildProcess(); $processResultFile = $this->pathForCachedSourceMap(); $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, '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); @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); $test = new {className}('{methodName}'); $test->setData('{dataName}', unserialize('{data}')); $test->setDependencyInput(unserialize('{dependencyInput}')); $test->setInIsolation(true); ob_end_clean(); $test->run(); $output = ''; if (!$test->expectsOutput()) { $output = $test->output(); } ini_set('xdebug.scream', '0'); // Not every STDOUT target stream is rewindable $hasRewound = @rewind(STDOUT); if ($hasRewound && $stdout = @stream_get_contents(STDOUT)) { $output = $stdout . $output; $streamMetaData = stream_get_meta_data(STDOUT); if (!empty($streamMetaData['stream_type']) && 'STDIO' === $streamMetaData['stream_type']) { @ftruncate(STDOUT, 0); @rewind(STDOUT); } } file_put_contents( '{processResultFile}', serialize( (object)[ 'testResult' => $test->result(), 'codeCoverage' => {collectCodeCoverageInformation} ? CodeCoverage::instance()->codeCoverage() : null, 'numAssertions' => $test->numberOfAssertionsPerformed(), 'output' => $output, 'events' => $dispatcher->flush(), 'passedTests' => PassedTests::instance() ] ) ); } function __phpunit_error_handler($errno, $errstr, $errfile, $errline) { return true; } set_error_handler('__phpunit_error_handler'); {constants} {included_files} {globals} restore_error_handler(); ConfigurationRegistry::loadFrom('{serializedConfiguration}'); if ('{sourceMapFile}' !== '') { SourceMapper::loadFrom('{sourceMapFile}', ConfigurationRegistry::get()->source()); } (new PhpHandler)->handle(ConfigurationRegistry::get()->php()); if ('{bootstrap}' !== '') { require_once '{bootstrap}'; } __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\Started; use PHPUnit\TextUI\Output\Printer; use PHPUnit\Util\Xml; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class JunitXmlLogger { private readonly Printer $printer; private DOMDocument $document; private DOMElement $root; /** * @var array */ private array $testSuites = []; /** * @var array */ private array $testSuiteTests = [0]; /** * @var array */ private array $testSuiteAssertions = [0]; /** * @var array */ private array $testSuiteErrors = [0]; /** * @var array */ private array $testSuiteFailures = [0]; /** * @var array */ private array $testSuiteSkipped = [0]; /** * @var array */ private array $testSuiteTimes = [0.0]; private int $testSuiteLevel = 0; private ?DOMElement $currentTestCase = null; private ?HRTime $time = null; private bool $prepared = \false; private bool $preparationFailed = \false; private ?string $unexpectedOutput = null; public function __construct(Printer $printer, Facade $facade) { $this->printer = $printer; $this->registerSubscribers($facade); $this->createDocument(); } public function flush(): void { $xml = $this->document->saveXML(); if ($xml === \false) { $xml = ''; } $this->printer->print($xml); $this->printer->flush(); } public function testSuiteStarted(Started $event): void { $testSuite = $this->document->createElement('testsuite'); $testSuite->setAttribute('name', $event->testSuite()->name()); if ($event->testSuite()->isForTestClass()) { $testSuite->setAttribute('file', $event->testSuite()->file()); } if ($this->testSuiteLevel > 0) { $this->testSuites[$this->testSuiteLevel]->appendChild($testSuite); } else { $this->root->appendChild($testSuite); } $this->testSuiteLevel++; $this->testSuites[$this->testSuiteLevel] = $testSuite; $this->testSuiteTests[$this->testSuiteLevel] = 0; $this->testSuiteAssertions[$this->testSuiteLevel] = 0; $this->testSuiteErrors[$this->testSuiteLevel] = 0; $this->testSuiteFailures[$this->testSuiteLevel] = 0; $this->testSuiteSkipped[$this->testSuiteLevel] = 0; $this->testSuiteTimes[$this->testSuiteLevel] = 0.0; } public function testSuiteFinished(): void { $this->testSuites[$this->testSuiteLevel]->setAttribute('tests', (string) $this->testSuiteTests[$this->testSuiteLevel]); $this->testSuites[$this->testSuiteLevel]->setAttribute('assertions', (string) $this->testSuiteAssertions[$this->testSuiteLevel]); $this->testSuites[$this->testSuiteLevel]->setAttribute('errors', (string) $this->testSuiteErrors[$this->testSuiteLevel]); $this->testSuites[$this->testSuiteLevel]->setAttribute('failures', (string) $this->testSuiteFailures[$this->testSuiteLevel]); $this->testSuites[$this->testSuiteLevel]->setAttribute('skipped', (string) $this->testSuiteSkipped[$this->testSuiteLevel]); $this->testSuites[$this->testSuiteLevel]->setAttribute('time', sprintf('%F', $this->testSuiteTimes[$this->testSuiteLevel])); if ($this->testSuiteLevel > 1) { $this->testSuiteTests[$this->testSuiteLevel - 1] += $this->testSuiteTests[$this->testSuiteLevel]; $this->testSuiteAssertions[$this->testSuiteLevel - 1] += $this->testSuiteAssertions[$this->testSuiteLevel]; $this->testSuiteErrors[$this->testSuiteLevel - 1] += $this->testSuiteErrors[$this->testSuiteLevel]; $this->testSuiteFailures[$this->testSuiteLevel - 1] += $this->testSuiteFailures[$this->testSuiteLevel]; $this->testSuiteSkipped[$this->testSuiteLevel - 1] += $this->testSuiteSkipped[$this->testSuiteLevel]; $this->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel]; } $this->testSuiteLevel--; } /** * @throws InvalidArgumentException */ public function testPreparationStarted(PreparationStarted $event): void { $this->createTestCase($event); $this->preparationFailed = \false; } public function testPreparationErrored(): void { $this->preparationFailed = \true; } public function testPreparationFailed(): void { $this->preparationFailed = \true; } public function testPrepared(): void { $this->prepared = \true; } public function testPrintedUnexpectedOutput(PrintedUnexpectedOutput $event): void { $this->unexpectedOutput = $event->output(); } /** * @throws InvalidArgumentException */ public function testFinished(Finished $event): void { if (!$this->prepared || $this->preparationFailed) { return; } $this->handleFinish($event->telemetryInfo(), $event->numberOfAssertionsPerformed()); } /** * @throws InvalidArgumentException */ public function testMarkedIncomplete(MarkedIncomplete $event): void { $this->handleIncompleteOrSkipped($event); } /** * @throws InvalidArgumentException */ public function testSkipped(Skipped $event): void { $this->handleIncompleteOrSkipped($event); } /** * @throws InvalidArgumentException */ public function testErrored(Errored $event): void { $this->handleFault($event, 'error'); $this->testSuiteErrors[$this->testSuiteLevel]++; } /** * @throws InvalidArgumentException */ public function testFailed(Failed $event): void { $this->handleFault($event, 'failure'); $this->testSuiteFailures[$this->testSuiteLevel]++; } /** * @throws InvalidArgumentException */ private function handleFinish(Info $telemetryInfo, int $numberOfAssertionsPerformed): void { assert($this->currentTestCase !== null); assert($this->time !== null); $time = $telemetryInfo->time()->duration($this->time)->asFloat(); $this->testSuiteAssertions[$this->testSuiteLevel] += $numberOfAssertionsPerformed; $this->currentTestCase->setAttribute('assertions', (string) $numberOfAssertionsPerformed); $this->currentTestCase->setAttribute('time', sprintf('%F', $time)); if ($this->unexpectedOutput !== null) { $systemOut = $this->document->createElement('system-out', Xml::prepareString($this->unexpectedOutput)); $this->currentTestCase->appendChild($systemOut); } $this->testSuites[$this->testSuiteLevel]->appendChild($this->currentTestCase); $this->testSuiteTests[$this->testSuiteLevel]++; $this->testSuiteTimes[$this->testSuiteLevel] += $time; $this->currentTestCase = null; $this->time = null; $this->preparationFailed = \false; $this->prepared = \false; $this->unexpectedOutput = null; } private function registerSubscribers(Facade $facade): void { $facade->registerSubscribers(new \PHPUnit\Logging\JUnit\TestSuiteStartedSubscriber($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\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 DIRECTORY_SEPARATOR; use const PHP_OS_FAMILY; use function assert; use function explode; use function fclose; use function function_exists; use function getenv; use function gethostname; use function is_resource; use function php_uname; use function posix_geteuid; use function posix_getpwuid; use function preg_split; use function proc_close; use function proc_open; use function str_contains; use function str_replace; use function str_starts_with; use function stream_get_contents; use function trim; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final readonly class InfrastructureInformationProvider { /** * @return non-empty-string */ public function operatingSystem(): string { $result = php_uname(); assert($result !== ''); return $result; } /** * @return non-empty-string */ public function hostName(): string { $candidate = gethostname(); if ($candidate === \false) { return 'unknown'; } $candidate = trim($candidate); if ($candidate === '') { return 'unknown'; } return $candidate; } /** * @return non-empty-string */ public function userName(): string { if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) { $candidate = trim(posix_getpwuid(posix_geteuid())['name']); } elseif (PHP_OS_FAMILY === 'Windows') { $candidate = trim((string) getenv('USERNAME')); } if (!isset($candidate) || $candidate === '') { return 'unknown'; } return $candidate; } /** * @return array{originUrl: non-empty-string, branch: non-empty-string, commit: non-empty-string, clean: bool, status: string}|false */ public function gitInformation(): array|false { $buffer = $this->executeGitCommand('remote show -n'); if ($buffer === \false) { return \false; } if (!str_contains($buffer, 'origin')) { return \false; } $buffer = $this->executeGitCommand('remote show -n origin'); if ($buffer === \false) { return \false; } $lines = preg_split("/\r\n|\n|\r/", $buffer); if (!isset($lines[1]) || !str_starts_with($lines[1], ' Fetch URL: ')) { return \false; } $originUrl = trim(str_replace(' Fetch URL: ', '', $lines[1])); if (str_contains($originUrl, '@')) { $originUrl = explode('@', $originUrl)[1]; } assert($originUrl !== ''); $branch = $this->executeGitCommand('symbolic-ref --short HEAD'); if ($branch === \false) { return \false; } $commit = $this->executeGitCommand('rev-parse HEAD'); if ($commit === \false) { return \false; } $status = $this->executeGitCommand('status --porcelain'); if ($status === \false) { return \false; } return ['originUrl' => $originUrl, 'branch' => $branch, 'commit' => $commit, 'clean' => $status === '', 'status' => $status]; } /** * @return false|non-empty-string */ private function executeGitCommand(string $command): false|string { $command = 'git ' . $command; if (DIRECTORY_SEPARATOR === '/') { $command = 'LC_ALL=en_US.UTF-8 ' . $command; } $process = @proc_open($command, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes); if (!is_resource($process)) { return \false; } assert(isset($pipes[1]) && is_resource($pipes[1])); assert(isset($pipes[2]) && is_resource($pipes[2])); $result = trim((string) stream_get_contents($pipes[1])); fclose($pipes[1]); fclose($pipes[2]); $returnCode = proc_close($process); if ($returnCode !== 0) { return \false; } return $result; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PHPUnit\Logging\OpenTestReporting; use const PHP_VERSION; use const ZEND_THREAD_SAFE; use function array_pop; use function assert; use function count; use function error_get_last; use function str_replace; use DateTimeImmutable; use DateTimeZone; use PHPUnit\Event\Code\Test; use PHPUnit\Event\Code\TestMethod; use PHPUnit\Event\Code\Throwable; use PHPUnit\Event\Facade; use PHPUnit\Event\Test\AfterLastTestMethodErrored; use PHPUnit\Event\Test\AfterLastTestMethodFailed; use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; use PHPUnit\Event\Test\Errored; use PHPUnit\Event\Test\Failed; use PHPUnit\Event\Test\MarkedIncomplete; use PHPUnit\Event\Test\PreparationErrored; use PHPUnit\Event\Test\PreparationFailed; use PHPUnit\Event\Test\Prepared as TestStarted; use PHPUnit\Event\Test\Skipped; use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; use PHPUnit\Event\TestSuite\TestSuiteForTestClass; use XMLWriter; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class OtrXmlLogger { private readonly XMLWriter $writer; /** * @var non-negative-int */ private int $idSequence = 0; /** * @var ?positive-int */ private ?int $parentId = null; /** * @var list */ private array $parentIdStack = []; /** * @var ?positive-int */ private ?int $testId = null; private ?Throwable $parentErrored = null; private ?Throwable $parentFailed = null; private bool $alreadyFinished = \false; private bool $includeGitInformation; /** * @param non-empty-string $uri * * @throws CannotOpenUriForWritingException */ public function __construct(Facade $facade, string $uri, bool $includeGitInformation) { $this->writer = new XMLWriter(); if (@$this->writer->openUri($uri) === \false) { throw new \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 { $infrastructure = new \PHPUnit\Logging\OpenTestReporting\InfrastructureInformationProvider(); $gitInformation = \false; if ($this->includeGitInformation) { $gitInformation = $infrastructure->gitInformation(); } $this->writer->startDocument(); $this->writer->startElement('e:events'); $this->writer->writeAttribute('xmlns', 'https://schemas.opentest4j.org/reporting/core/0.2.0'); $this->writer->writeAttribute('xmlns:e', 'https://schemas.opentest4j.org/reporting/events/0.2.0'); if ($gitInformation !== \false) { $this->writer->writeAttribute('xmlns:git', 'https://schemas.opentest4j.org/reporting/git/0.2.0'); } $this->writer->writeAttribute('xmlns:php', 'https://schema.phpunit.de/otr/php/0.0.1'); $this->writer->writeAttribute('xmlns:phpunit', 'https://schema.phpunit.de/otr/phpunit/0.0.1'); $this->writer->startElement('infrastructure'); $this->writer->writeElement('hostName', $infrastructure->hostName()); $this->writer->writeElement('userName', $infrastructure->userName()); $this->writer->writeElement('operatingSystem', $infrastructure->operatingSystem()); $this->writer->writeElement('php:phpVersion', PHP_VERSION); $this->writer->writeElement('php:threadModel', ZEND_THREAD_SAFE ? 'ZTS' : 'NTS'); if ($gitInformation !== \false) { $this->writer->startElement('git:repository'); $this->writer->writeAttribute('originUrl', $gitInformation['originUrl']); $this->writer->endElement(); $this->writer->writeElement('git:branch', $gitInformation['branch']); $this->writer->writeElement('git:commit', $gitInformation['commit']); $this->writer->startElement('git:status'); $this->writer->writeAttribute('clean', $gitInformation['clean'] === \true ? 'true' : 'false'); $this->writer->writeCdata($gitInformation['status']); $this->writer->endElement(); } $this->writer->endElement(); $this->writer->flush(); } public function testRunnerFinished(): void { $this->writer->endDocument(); $this->writer->flush(); } public function testSuiteStarted(TestSuiteStarted $event): void { $id = $this->nextId(); $this->writer->startElement('e:started'); $this->writer->writeAttribute('id', (string) $id); if ($this->parentId !== null) { $this->writer->writeAttribute('parentId', (string) $this->parentId); } $testSuite = $event->testSuite(); $this->writer->writeAttribute('name', $testSuite->name()); $this->writer->writeAttribute('time', $this->timestamp()); if ($testSuite->isForTestClass()) { assert($testSuite instanceof TestSuiteForTestClass); $this->writer->startElement('sources'); $this->writer->startElement('fileSource'); $this->writer->writeAttribute('path', $testSuite->file()); $this->writer->startElement('filePosition'); $this->writer->writeAttribute('line', (string) $testSuite->line()); $this->writer->endElement(); $this->writer->endElement(); $this->writer->startElement('phpunit:classSource'); $this->writer->writeAttribute('className', $testSuite->className()); $this->writer->endElement(); $this->writer->endElement(); } $this->writer->endElement(); $this->writer->flush(); $this->parentId = $id; $this->parentIdStack[] = $id; } public function testSuiteSkipped(TestSuiteSkipped $event): void { $this->writer->startElement('e:finished'); $this->writer->writeAttribute('id', (string) $this->parentId); $this->writer->writeAttribute('time', $this->timestamp()); $this->writer->startElement('result'); $this->writer->writeAttribute('status', 'SKIPPED'); $this->writer->writeElement('reason', $event->message()); $this->writer->endElement(); $this->writer->endElement(); $this->writer->flush(); $this->reduceTestSuiteLevel(); } public function testSuiteFinished(): void { $this->writer->startElement('e:finished'); $this->writer->writeAttribute('id', (string) $this->parentId); $this->writer->writeAttribute('time', $this->timestamp()); if ($this->parentErrored !== null) { $this->writer->startElement('result'); $this->writer->writeAttribute('status', 'ERRORED'); $this->writer->writeElement('reason', $this->parentErrored->message()); $this->writeThrowable($this->parentErrored, \false); $this->writer->endElement(); } elseif ($this->parentFailed !== null) { $this->writer->startElement('result'); $this->writer->writeAttribute('status', 'FAILED'); $this->writer->writeElement('reason', $this->parentFailed->message()); $this->writeThrowable($this->parentFailed, \true); $this->writer->endElement(); } $this->writer->endElement(); $this->writer->flush(); $this->parentErrored = null; $this->parentFailed = null; $this->reduceTestSuiteLevel(); } public function testPrepared(PreparationErrored|PreparationFailed|TestStarted $event): void { $this->testId = $this->nextId(); $this->writeTestStarted($event->test(), $this->testId, $this->parentId); } public function testFinished(): void { if (!$this->alreadyFinished) { $this->writer->startElement('e:finished'); $this->writer->writeAttribute('id', (string) $this->testId); $this->writer->writeAttribute('time', $this->timestamp()); $this->writer->startElement('result'); $this->writer->writeAttribute('status', \PHPUnit\Logging\OpenTestReporting\Status::Successful->value); $this->writer->endElement(); $this->writer->endElement(); } $this->alreadyFinished = \false; $this->testId = null; } public function testFailed(Failed $event): void { $this->writer->startElement('e:finished'); $this->writer->writeAttribute('id', (string) $this->testId); $this->writer->writeAttribute('time', $this->timestamp()); $this->writer->startElement('result'); $this->writer->writeAttribute('status', \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 { $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->alreadyFinished = \true; } public function markTestIncomplete(MarkedIncomplete $event): void { $this->writer->startElement('e:finished'); $this->writer->writeAttribute('id', (string) $this->testId); $this->writer->writeAttribute('time', $this->timestamp()); $this->writer->startElement('result'); $this->writer->writeAttribute('status', \PHPUnit\Logging\OpenTestReporting\Status::Aborted->value); $this->writer->writeElement('reason', $event->throwable()->message()); $this->writeThrowable($event->throwable(), \false); $this->writer->endElement(); $this->writer->endElement(); $this->writer->flush(); $this->alreadyFinished = \true; } public function parentErrored(AfterLastTestMethodErrored|BeforeFirstTestMethodErrored $event): void { $this->parentErrored = $event->throwable(); } public function parentFailed(AfterLastTestMethodFailed|BeforeFirstTestMethodFailed $event): void { $this->parentFailed = $event->throwable(); } private function registerSubscribers(Facade $facade): void { $facade->registerSubscribers(new \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\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()); $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; } } * * 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\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\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\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\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\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($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\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\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\ConsideredRisky; use PHPUnit\Event\Test\Errored; use PHPUnit\Event\Test\Failed; use PHPUnit\Event\Test\Finished; use PHPUnit\Event\Test\MarkedIncomplete; use PHPUnit\Event\Test\Prepared; use PHPUnit\Event\Test\Skipped; use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished; use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; use PHPUnit\Event\TestSuite\TestSuiteForTestClass; use PHPUnit\Event\TestSuite\TestSuiteForTestMethodWithDataProvider; use PHPUnit\Framework\Exception as FrameworkException; use PHPUnit\TextUI\Output\Printer; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TeamCityLogger { private readonly Printer $printer; private bool $isSummaryTestCountPrinted = \false; private ?HRTime $time = null; private ?int $flowId = null; public function __construct(Printer $printer, Facade $facade) { $this->printer = $printer; $this->registerSubscribers($facade); $this->setFlowId(); } public function testSuiteStarted(TestSuiteStarted $event): void { $testSuite = $event->testSuite(); if (!$this->isSummaryTestCountPrinted) { $this->isSummaryTestCountPrinted = \true; $this->writeMessage('testCount', ['count' => $testSuite->count()]); } $parameters = ['name' => $testSuite->name()]; if ($testSuite->isForTestClass()) { assert($testSuite instanceof TestSuiteForTestClass); $parameters['locationHint'] = sprintf('php_qn://%s::\%s', $testSuite->file(), $testSuite->name()); } elseif ($testSuite->isForTestMethodWithDataProvider()) { assert($testSuite instanceof TestSuiteForTestMethodWithDataProvider); $parameters['locationHint'] = sprintf('php_qn://%s::\%s', $testSuite->file(), $testSuite->name()); $parameters['name'] = $testSuite->methodName(); } $this->writeMessage('testSuiteStarted', $parameters); } public function testSuiteFinished(TestSuiteFinished $event): void { $testSuite = $event->testSuite(); $parameters = ['name' => $testSuite->name()]; if ($testSuite->isForTestMethodWithDataProvider()) { assert($testSuite instanceof TestSuiteForTestMethodWithDataProvider); $parameters['name'] = $testSuite->methodName(); } $this->writeMessage('testSuiteFinished', $parameters); } public function testPrepared(Prepared $event): void { $test = $event->test(); $parameters = ['name' => $test->name()]; if ($test->isTestMethod()) { assert($test instanceof TestMethod); $parameters['locationHint'] = sprintf('php_qn://%s::\%s::%s', $test->file(), $test->className(), $test->name()); } $this->writeMessage('testStarted', $parameters); $this->time = $event->telemetryInfo()->time(); } /** * @throws InvalidArgumentException */ public function testMarkedIncomplete(MarkedIncomplete $event): void { if ($this->time === null) { // @codeCoverageIgnoreStart $this->time = $event->telemetryInfo()->time(); // @codeCoverageIgnoreEnd } $this->writeMessage('testIgnored', ['name' => $event->test()->name(), 'message' => $event->throwable()->message(), 'details' => $this->details($event->throwable()), 'duration' => $this->duration($event)]); } /** * @throws InvalidArgumentException */ public function testSkipped(Skipped $event): void { if ($this->time === null) { $this->time = $event->telemetryInfo()->time(); } $parameters = ['name' => $event->test()->name(), 'message' => $event->message()]; $parameters['duration'] = $this->duration($event); $this->writeMessage('testIgnored', $parameters); } /** * @throws InvalidArgumentException */ public function testSuiteSkipped(TestSuiteSkipped $event): void { if ($this->time === null) { $this->time = $event->telemetryInfo()->time(); } $parameters = ['name' => $event->testSuite()->name(), 'message' => $event->message()]; $parameters['duration'] = $this->duration($event); $this->writeMessage('testIgnored', $parameters); $this->writeMessage('testSuiteFinished', $parameters); } /** * @throws InvalidArgumentException */ public function beforeFirstTestMethodErrored(BeforeFirstTestMethodErrored $event): void { if ($this->time === null) { $this->time = $event->telemetryInfo()->time(); } $parameters = ['name' => $event->testClassName(), 'message' => $this->message($event->throwable()), 'details' => $this->details($event->throwable()), 'duration' => $this->duration($event)]; $this->writeMessage('testFailed', $parameters); $this->writeMessage('testSuiteFinished', $parameters); } /** * @throws InvalidArgumentException */ public function testErrored(Errored $event): void { if ($this->time === null) { $this->time = $event->telemetryInfo()->time(); } $this->writeMessage('testFailed', ['name' => $event->test()->name(), 'message' => $this->message($event->throwable()), 'details' => $this->details($event->throwable()), 'duration' => $this->duration($event)]); } /** * @throws InvalidArgumentException */ public function testFailed(Failed $event): void { if ($this->time === null) { // @codeCoverageIgnoreStart $this->time = $event->telemetryInfo()->time(); // @codeCoverageIgnoreEnd } $parameters = ['name' => $event->test()->name(), 'message' => $this->message($event->throwable()), 'details' => $this->details($event->throwable()), 'duration' => $this->duration($event)]; if ($event->hasComparisonFailure()) { $parameters['type'] = 'comparisonFailure'; $parameters['actual'] = $event->comparisonFailure()->actual(); $parameters['expected'] = $event->comparisonFailure()->expected(); } $this->writeMessage('testFailed', $parameters); } /** * @throws InvalidArgumentException */ public function testConsideredRisky(ConsideredRisky $event): void { if ($this->time === null) { // @codeCoverageIgnoreStart $this->time = $event->telemetryInfo()->time(); // @codeCoverageIgnoreEnd } $this->writeMessage('testFailed', ['name' => $event->test()->name(), 'message' => $event->message(), 'details' => '', 'duration' => $this->duration($event)]); } /** * @throws InvalidArgumentException */ public function testFinished(Finished $event): void { $this->writeMessage('testFinished', ['name' => $event->test()->name(), 'duration' => $this->duration($event)]); $this->time = null; } public function flush(): void { $this->printer->flush(); } private function registerSubscribers(Facade $facade): void { $facade->registerSubscribers(new \PHPUnit\Logging\TeamCity\TestSuiteStartedSubscriber($this), new \PHPUnit\Logging\TeamCity\TestSuiteFinishedSubscriber($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)); } 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 $prettifiedClassName => $_tests) { $buffer .= sprintf(self::CLASS_HEADER, $prettifiedClassName); foreach ($this->reduce($_tests) as $prettifiedMethodName => $outcome) { $buffer .= sprintf("
    • %s
    • \n", $outcome, $prettifiedMethodName); } $buffer .= self::CLASS_FOOTER; } return $buffer . self::PAGE_FOOTER; } /** * @return array */ private function reduce(\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 ReflectionEnum; use ReflectionMethod; use ReflectionObject; use Throwable; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class NamePrettifier { /** * @var array */ private array $strings = []; /** * @var array */ private array $prettifiedTestCases = []; /** * @var array */ private array $erroredFormatters = []; /** * @param class-string $className */ public function prettifyTestClassName(string $className): string { if (class_exists($className)) { $classLevelTestDox = MetadataRegistry::parser()->forClass($className)->isTestDox(); if ($classLevelTestDox->isNotEmpty()) { $classLevelTestDox = $classLevelTestDox->asArray()[0]; assert($classLevelTestDox instanceof TestDox); return $classLevelTestDox->text(); } } $parts = explode('\\', $className); $className = array_pop($parts); if (str_ends_with($className, 'Test')) { $className = substr($className, 0, strlen($className) - strlen('Test')); } if (str_starts_with($className, 'Tests')) { $className = substr($className, strlen('Tests')); } elseif (str_starts_with($className, 'Test')) { $className = substr($className, strlen('Test')); } if ($className === '') { $className = 'UnnamedTests'; } if ($parts !== []) { $parts[] = $className; $fullyQualifiedName = implode('\\', $parts); } else { $fullyQualifiedName = $className; } $result = preg_replace('/(?<=[[:lower:]])(?=[[:upper:]])/u', ' ', $className); 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($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; $providedData['$_dataName'] = $test->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('$', '\$', $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 $prettifiedClassName => $_tests) { $buffer .= $prettifiedClassName . "\n"; foreach ($this->reduce($_tests) as $prettifiedMethodName => $outcome) { $buffer .= sprintf(' [%s] %s' . "\n", $outcome, $prettifiedMethodName); } $buffer .= "\n"; } return $buffer; } /** * @return array */ private function reduce(\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 ksort; use function uksort; use function usort; use PHPUnit\Event\Code\TestMethod; use PHPUnit\Event\Code\Throwable; use PHPUnit\Event\Facade; use PHPUnit\Event\InvalidArgumentException; use PHPUnit\Event\Test\ConsideredRisky; use PHPUnit\Event\Test\DeprecationTriggered; use PHPUnit\Event\Test\Errored; use PHPUnit\Event\Test\Failed; use PHPUnit\Event\Test\Finished; use PHPUnit\Event\Test\MarkedIncomplete; use PHPUnit\Event\Test\NoticeTriggered; use PHPUnit\Event\Test\Passed; use PHPUnit\Event\Test\PhpDeprecationTriggered; use PHPUnit\Event\Test\PhpNoticeTriggered; use PHPUnit\Event\Test\PhpunitDeprecationTriggered; use PHPUnit\Event\Test\PhpunitErrorTriggered; use PHPUnit\Event\Test\PhpunitWarningTriggered; use PHPUnit\Event\Test\PhpWarningTriggered; use PHPUnit\Event\Test\Prepared; use PHPUnit\Event\Test\Skipped; use PHPUnit\Event\Test\WarningTriggered; use PHPUnit\Framework\TestStatus\TestStatus; use PHPUnit\Logging\TestDox\TestResult as TestDoxTestMethod; use PHPUnit\TestRunner\IssueFilter; use ReflectionMethod; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class TestResultCollector { private readonly IssueFilter $issueFilter; /** * @var array> */ private array $tests = []; private ?TestStatus $status = null; private ?Throwable $throwable = null; private bool $prepared = \false; public function __construct(Facade $facade, IssueFilter $issueFilter) { $this->issueFilter = $issueFilter; $this->registerSubscribers($facade); } /** * @return array */ public function testMethodsGroupedByClass(): array { $result = []; foreach ($this->tests as $prettifiedClassName => $tests) { $testsByDeclaringClass = []; foreach ($tests as $test) { $declaringClassName = (new ReflectionMethod($test->test()->className(), $test->test()->methodName()))->getDeclaringClass()->getName(); if (!isset($testsByDeclaringClass[$declaringClassName])) { $testsByDeclaringClass[$declaringClassName] = []; } $testsByDeclaringClass[$declaringClassName][] = $test; } foreach ($testsByDeclaringClass as $declaringClassName) { usort($declaringClassName, static function (TestDoxTestMethod $a, TestDoxTestMethod $b): int { return $a->test()->line() <=> $b->test()->line(); }); } uksort( $testsByDeclaringClass, /** * @param class-string $a * @param class-string $b */ static function (string $a, string $b): int { if (is_subclass_of($b, $a)) { return -1; } if (is_subclass_of($a, $b)) { return 1; } return 0; } ); $tests = []; foreach ($testsByDeclaringClass as $_tests) { $tests = array_merge($tests, $_tests); } $result[$prettifiedClassName] = \PHPUnit\Logging\TestDox\TestResultCollection::fromArray($tests); } ksort($result); return $result; } public function testPrepared(Prepared $event): void { if (!$event->test()->isTestMethod()) { return; } $this->status = TestStatus::unknown(); $this->throwable = null; $this->prepared = \true; } public function testErrored(Errored $event): void { if (!$event->test()->isTestMethod()) { return; } $this->status = TestStatus::error($event->throwable()->message()); $this->throwable = $event->throwable(); if (!$this->prepared) { $test = $event->test(); assert($test instanceof TestMethod); $this->process($test); } } public function testFailed(Failed $event): void { if (!$event->test()->isTestMethod()) { return; } $this->status = TestStatus::failure($event->throwable()->message()); $this->throwable = $event->throwable(); } public function testPassed(Passed $event): void { if (!$event->test()->isTestMethod()) { return; } $this->updateTestStatus(TestStatus::success()); } public function testSkipped(Skipped $event): void { if (!$event->test()->isTestMethod()) { return; } $this->updateTestStatus(TestStatus::skipped($event->message())); } public function testMarkedIncomplete(MarkedIncomplete $event): void { if (!$event->test()->isTestMethod()) { return; } $this->updateTestStatus(TestStatus::incomplete($event->throwable()->message())); $this->throwable = $event->throwable(); } public function testConsideredRisky(ConsideredRisky $event): void { if (!$event->test()->isTestMethod()) { return; } $this->updateTestStatus(TestStatus::risky()); } public function testTriggeredDeprecation(DeprecationTriggered $event): void { if (!$this->issueFilter->shouldBeProcessed($event, \true)) { return; } if ($event->ignoredByBaseline()) { return; } $this->updateTestStatus(TestStatus::deprecation()); } public function testTriggeredNotice(NoticeTriggered $event): void { if (!$this->issueFilter->shouldBeProcessed($event, \true)) { return; } if ($event->ignoredByBaseline()) { return; } $this->updateTestStatus(TestStatus::notice()); } public function testTriggeredWarning(WarningTriggered $event): void { if (!$this->issueFilter->shouldBeProcessed($event, \true)) { return; } if ($event->ignoredByBaseline()) { return; } $this->updateTestStatus(TestStatus::warning()); } public function testTriggeredPhpDeprecation(PhpDeprecationTriggered $event): void { if (!$this->issueFilter->shouldBeProcessed($event, \true)) { return; } if ($event->ignoredByBaseline()) { return; } $this->updateTestStatus(TestStatus::deprecation()); } public function testTriggeredPhpNotice(PhpNoticeTriggered $event): void { if (!$this->issueFilter->shouldBeProcessed($event, \true)) { return; } if ($event->ignoredByBaseline()) { return; } $this->updateTestStatus(TestStatus::notice()); } public function testTriggeredPhpWarning(PhpWarningTriggered $event): void { if (!$this->issueFilter->shouldBeProcessed($event, \true)) { return; } if ($event->ignoredByBaseline()) { return; } $this->updateTestStatus(TestStatus::warning()); } public function testTriggeredPhpunitDeprecation(PhpunitDeprecationTriggered $event): void { if (!$event->test()->isTestMethod()) { return; } $this->updateTestStatus(TestStatus::deprecation()); } public function testTriggeredPhpunitError(PhpunitErrorTriggered $event): void { if (!$event->test()->isTestMethod()) { return; } $this->updateTestStatus(TestStatus::error()); } public function testTriggeredPhpunitWarning(PhpunitWarningTriggered $event): void { if (!$event->test()->isTestMethod()) { return; } if ($event->ignoredByTest()) { return; } $this->updateTestStatus(TestStatus::warning()); } /** * @throws InvalidArgumentException */ public function testFinished(Finished $event): void { if (!$event->test()->isTestMethod()) { return; } $test = $event->test(); assert($test instanceof TestMethod); $this->process($test); $this->status = null; $this->throwable = null; $this->prepared = \false; } private function registerSubscribers(Facade $facade): void { $facade->registerSubscribers(new \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->testDox()->prettifiedClassName()])) { $this->tests[$test->testDox()->prettifiedClassName()] = []; } $this->tests[$test->testDox()->prettifiedClassName()][] = 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\MetadataCollection; use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; use PHPUnit\Metadata\TestWith; use PHPUnit\Util\Test; use ReflectionMethod; use Throwable; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final readonly class DataProvider { /** * @param class-string $className * @param non-empty-string $methodName * * @throws InvalidDataProviderException * * @return ?array */ public function providedData(string $className, string $methodName): ?array { $metadataCollection = MetadataRegistry::parser()->forMethod($className, $methodName); $dataProvider = $metadataCollection->isDataProvider(); $testWith = $metadataCollection->isTestWith(); if ($dataProvider->isEmpty() && $testWith->isEmpty()) { return null; } $testMethod = new ReflectionMethod($className, $methodName); if ($dataProvider->isNotEmpty()) { if ($testWith->isNotEmpty()) { $this->triggerWarningForMixingOfDataProviderAndTestWith($testMethod); } return $this->dataProvidedByMethods($className, $testMethod, $dataProvider); } return $this->dataProvidedByMetadata($testMethod, $testWith); } /** * @param class-string $testClassName * * @throws InvalidDataProviderException * * @return array */ private function dataProvidedByMethods(string $testClassName, ReflectionMethod $testMethod, MetadataCollection $dataProvider): array { $testMethodValueObject = new Event\Code\ClassMethod($testClassName, $testMethod->getName()); $methodsCalled = []; $result = []; $testMethodNumberOfParameters = $testMethod->getNumberOfParameters(); $testMethodIsNonVariadic = !$testMethod->isVariadic(); foreach ($dataProvider as $_dataProvider) { assert($_dataProvider instanceof DataProviderMetadata); $providerLabel = $_dataProvider->className() . '::' . $_dataProvider->methodName(); $dataProviderMethod = new Event\Code\ClassMethod($_dataProvider->className(), $_dataProvider->methodName()); $validateArgumentCount = $testMethodIsNonVariadic && $_dataProvider->validateArgumentCount(); Event\Facade::emitter()->dataProviderMethodCalled($testMethodValueObject, $dataProviderMethod); $methodsCalled[] = $dataProviderMethod; try { $method = new ReflectionMethod($_dataProvider->className(), $_dataProvider->methodName()); $className = $_dataProvider->className(); $methodName = $_dataProvider->methodName(); if (Test::isTestMethod($method)) { Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Method %s::%s() used by test method %s::%s() is also a test method', $_dataProvider->className(), $_dataProvider->methodName(), $testMethod->getDeclaringClass()->getName(), $testMethod->getName())); } if (!$method->isPublic()) { throw new InvalidDataProviderException(sprintf('Data Provider method %s::%s() is not public', $className, $methodName)); } if (!$method->isStatic()) { throw new InvalidDataProviderException(sprintf('Data Provider method %s::%s() is not static', $className, $methodName)); } if ($method->getNumberOfParameters() > 0) { throw new InvalidDataProviderException(sprintf('Data Provider method %s::%s() expects an argument', $className, $methodName)); } /** @phpstan-ignore staticMethod.dynamicName */ $data = $className::$methodName(); if (!is_iterable($data)) { throw new InvalidDataProviderException(sprintf('Data Provider method %s::%s() does not return an iterable', $className, $methodName)); } } catch (Throwable $e) { Event\Facade::emitter()->dataProviderMethodFinished($testMethodValueObject, ...$methodsCalled); throw InvalidDataProviderException::forException($e, $providerLabel); } try { foreach ($data as $key => $value) { if (!is_int($key) && !is_string($key)) { throw new InvalidDataProviderException(sprintf('The key must be an integer or a string, %s given', get_debug_type($key))); } if (!is_array($value)) { throw new InvalidDataProviderException(sprintf('Data set %s provided by %s is invalid, expected array but got %s', $this->formatKey($key), $providerLabel, get_debug_type($value))); } if ($validateArgumentCount && $testMethodNumberOfParameters < count($value)) { $this->triggerWarningForArgumentCount($testMethod, $this->formatKey($key), $providerLabel, count($value), $testMethodNumberOfParameters); } if (is_int($key)) { $result[] = new \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); } } 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 PHPUnit\Metadata\Parser\Registry; use PHPUnit\Metadata\RequiresEnvironmentVariable; use PHPUnit\Metadata\RequiresFunction; use PHPUnit\Metadata\RequiresMethod; use PHPUnit\Metadata\RequiresOperatingSystem; use PHPUnit\Metadata\RequiresOperatingSystemFamily; use PHPUnit\Metadata\RequiresPhp; use PHPUnit\Metadata\RequiresPhpExtension; use PHPUnit\Metadata\RequiresPhpunit; use PHPUnit\Metadata\RequiresPhpunitExtension; use PHPUnit\Metadata\RequiresSetting; use PHPUnit\Runner\Version; use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final readonly class Requirements { /** * @param class-string $className * @param non-empty-string $methodName * * @return list */ public function requirementsNotSatisfiedFor(string $className, string $methodName): array { $notSatisfied = []; foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { if ($metadata->isRequiresPhp()) { assert($metadata instanceof RequiresPhp); if (!$metadata->versionRequirement()->isSatisfiedBy(PHP_VERSION)) { $notSatisfied[] = sprintf('PHP %s is required.', $metadata->versionRequirement()->asString()); } } if ($metadata->isRequiresPhpExtension()) { assert($metadata instanceof RequiresPhpExtension); $extensionVersion = phpversion($metadata->extension()); if ($extensionVersion === \false) { $extensionVersion = ''; } if (!extension_loaded($metadata->extension()) || $metadata->hasVersionRequirement() && !$metadata->versionRequirement()->isSatisfiedBy($extensionVersion)) { $notSatisfied[] = sprintf('PHP extension %s%s is required.', $metadata->extension(), $metadata->hasVersionRequirement() ? ' ' . $metadata->versionRequirement()->asString() : ''); } } if ($metadata->isRequiresPhpunit()) { assert($metadata instanceof RequiresPhpunit); if (!$metadata->versionRequirement()->isSatisfiedBy(Version::id())) { $notSatisfied[] = sprintf('PHPUnit %s is required.', $metadata->versionRequirement()->asString()); } } if ($metadata->isRequiresPhpunitExtension()) { assert($metadata instanceof RequiresPhpunitExtension); $configuration = ConfigurationRegistry::get(); $extensionBootstrappers = array_column($configuration->extensionBootstrappers(), 'className'); if ($configuration->noExtensions() || !in_array($metadata->extensionClass(), $extensionBootstrappers, \true)) { $notSatisfied[] = sprintf('PHPUnit extension "%s" is required.', $metadata->extensionClass()); } } if ($metadata->isRequiresEnvironmentVariable()) { assert($metadata instanceof RequiresEnvironmentVariable); if (!array_key_exists($metadata->environmentVariableName(), $_ENV) || $metadata->value() === null && $_ENV[$metadata->environmentVariableName()] === '') { $notSatisfied[] = sprintf('Environment variable "%s" is required.', $metadata->environmentVariableName()); continue; } if ($metadata->value() !== null && $_ENV[$metadata->environmentVariableName()] !== $metadata->value()) { $notSatisfied[] = sprintf('Environment variable "%s" is required to be "%s".', $metadata->environmentVariableName(), $metadata->value()); } } if ($metadata->isRequiresOperatingSystemFamily()) { assert($metadata instanceof RequiresOperatingSystemFamily); if ($metadata->operatingSystemFamily() !== PHP_OS_FAMILY) { $notSatisfied[] = sprintf('Operating system %s is required.', $metadata->operatingSystemFamily()); } } if ($metadata->isRequiresOperatingSystem()) { assert($metadata instanceof RequiresOperatingSystem); $pattern = sprintf('/%s/i', addcslashes($metadata->operatingSystem(), '/')); if (preg_match($pattern, PHP_OS) === 0) { $notSatisfied[] = sprintf('Operating system %s is required.', $metadata->operatingSystem()); } } if ($metadata->isRequiresFunction()) { assert($metadata instanceof RequiresFunction); if (!function_exists($metadata->functionName())) { $notSatisfied[] = sprintf('Function %s() is required.', $metadata->functionName()); } } if ($metadata->isRequiresMethod()) { assert($metadata instanceof RequiresMethod); if (!method_exists($metadata->className(), $metadata->methodName())) { $notSatisfied[] = sprintf('Method %s::%s() is required.', $metadata->className(), $metadata->methodName()); } } if ($metadata->isRequiresSetting()) { assert($metadata instanceof RequiresSetting); if (ini_get($metadata->setting()) !== $metadata->value()) { $notSatisfied[] = sprintf('Setting "%s" is required to be "%s".', $metadata->setting(), $metadata->value()); } } } return $notSatisfied; } public function requiresXdebug(string $className, string $methodName): bool { foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { if ($metadata->isRequiresPhpExtension()) { if ($metadata->extension() === 'xdebug') { return \true; } } } return \false; } } * * 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; /** * @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 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); } /** * @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 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 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\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 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; } } * * 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; /** * @no-named-arguments Parameter names are 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 { return $this->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 file_put_contents; use function sprintf; use function sys_get_temp_dir; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Framework\TestCase; use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; use PHPUnit\TextUI\Configuration\Configuration; use PHPUnit\TextUI\Output\Printer; use PHPUnit\Util\Filesystem; use 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\Clover as CloverReport; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Cobertura as CoberturaReport; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Crap4j as Crap4jReport; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html\Colors; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html\CustomCssFile; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Html\Facade as HtmlReport; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\OpenClover as OpenCloverReport; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\PHP as PhpReport; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Text as TextReport; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Thresholds; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Report\Xml\Facade as XmlReport; 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\TestSize; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestStatus\TestStatus; use PHPUnitPHAR\SebastianBergmann\Comparator\Comparator; 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(); } if ($codeCoverageFilterRegistry->get()->isEmpty()) { if (!$codeCoverageFilterRegistry->configured()) { EventFacade::emitter()->testRunnerTriggeredPhpunitWarning('No filter is configured, code coverage will not be processed'); } else { EventFacade::emitter()->testRunnerTriggeredPhpunitWarning('Incorrect filter configuration, code coverage will not be processed'); } $this->deactivate(); } if (isset($coverageCacheDirectory) && $configuration->includeUncoveredFiles()) { EventFacade::emitter()->testRunnerStartedStaticAnalysisForCodeCoverage(); /** @phpstan-ignore new.internalClass,method.internalClass */ $statistics = (new CacheWarmer())->warmCache($coverageCacheDirectory, !$configuration->disableCodeCoverageIgnore(), $configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage(), $codeCoverageFilterRegistry->get()); EventFacade::emitter()->testRunnerFinishedStaticAnalysisForCodeCoverage($statistics['cacheHits'], $statistics['cacheMisses']); } return \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'); try { $writer = new PhpReport(); $writer->process($this->codeCoverage(), $configuration->coveragePhp()); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } if ($configuration->hasCoverageClover()) { $this->codeCoverageGenerationStart($printer, 'Clover XML'); try { $writer = new CloverReport(); $writer->process($this->codeCoverage(), $configuration->coverageClover(), 'Clover Coverage'); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } if ($configuration->hasCoverageOpenClover()) { $this->codeCoverageGenerationStart($printer, 'OpenClover XML'); try { $writer = new OpenCloverReport(); $writer->process($this->codeCoverage(), $configuration->coverageOpenClover(), 'OpenClover Coverage'); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } if ($configuration->hasCoverageCobertura()) { $this->codeCoverageGenerationStart($printer, 'Cobertura XML'); try { $writer = new CoberturaReport(); $writer->process($this->codeCoverage(), $configuration->coverageCobertura()); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } if ($configuration->hasCoverageCrap4j()) { $this->codeCoverageGenerationStart($printer, 'Crap4J XML'); try { $writer = new Crap4jReport($configuration->coverageCrap4jThreshold()); $writer->process($this->codeCoverage(), $configuration->coverageCrap4j()); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } if ($configuration->hasCoverageHtml()) { $this->codeCoverageGenerationStart($printer, 'HTML'); try { $customCssFile = CustomCssFile::default(); if ($configuration->hasCoverageHtmlCustomCssFile()) { $customCssFile = CustomCssFile::from($configuration->coverageHtmlCustomCssFile()); } $writer = new HtmlReport(sprintf(' and PHPUnit %s', \PHPUnit\Runner\Version::id()), Colors::from($configuration->coverageHtmlColorSuccessLow(), $configuration->coverageHtmlColorSuccessMedium(), $configuration->coverageHtmlColorSuccessHigh(), $configuration->coverageHtmlColorWarning(), $configuration->coverageHtmlColorDanger()), Thresholds::from($configuration->coverageHtmlLowUpperBound(), $configuration->coverageHtmlHighLowerBound()), $customCssFile); $writer->process($this->codeCoverage(), $configuration->coverageHtml()); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } if ($configuration->hasCoverageText()) { $processor = new TextReport(Thresholds::default(), $configuration->coverageTextShowUncoveredFiles(), $configuration->coverageTextShowOnlySummary()); $textReport = $processor->process($this->codeCoverage(), $configuration->colors()); if ($configuration->coverageText() === 'php://stdout') { if (!$configuration->noOutput() && !$configuration->debug()) { $printer->print($textReport); } } else { file_put_contents($configuration->coverageText(), $textReport); } } if ($configuration->hasCoverageXml()) { $this->codeCoverageGenerationStart($printer, 'PHPUnit XML'); try { $writer = new XmlReport(\PHPUnit\Runner\Version::id(), $configuration->coverageXmlIncludeSource()); $writer->process($this->codeCoverage(), $configuration->coverageXml()); $this->codeCoverageGenerationSucceeded($printer); unset($writer); } catch (CodeCoverageException $e) { $this->codeCoverageGenerationFailed($printer, $e); } } } private function activate(Filter $filter, bool $pathCoverage): void { try { if ($pathCoverage) { $this->driver = (new Selector())->forLineAndPathCoverage($filter); } else { $this->driver = (new Selector())->forLineCoverage($filter); } $this->codeCoverage = new \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_values; use function assert; use function debug_backtrace; use function defined; use function error_reporting; use function preg_match; use function restore_error_handler; use function set_error_handler; use function sprintf; use PHPUnit\Event; use PHPUnit\Event\Code\IssueTrigger\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\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; 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; } /** * @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, $errorFile)); break; case E_USER_DEPRECATED: Event\Facade::emitter()->testTriggeredDeprecation($test, $errorString, $errorFile, $errorLine, $suppressed, $ignoredByBaseline, $ignoredByTest, $this->trigger($test, \true), $this->stackTrace()); break; case E_USER_ERROR: Event\Facade::emitter()->testTriggeredError($test, $errorString, $errorFile, $errorLine, $suppressed); throw new \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 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 $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, $trace); } /** * @param list $trace */ private function triggerForUserlandDeprecation(TestMethod $test, array $trace): IssueTrigger { $callee = null; $caller = null; if (isset($trace[0]['file'])) { $callee = $this->categorizeFile($trace[0]['file'], $test); } if (isset($trace[1]['file'])) { $caller = $this->categorizeFile($trace[1]['file'], $test); } return IssueTrigger::from($callee, $caller); } /** * @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 */ private function filteredStackTrace(): array { $trace = $this->errorStackTrace(); 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 */ private function errorStackTrace(): array { $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $i = 0; do { unset($trace[$i]); } while (self::class === ($trace[++$i]['class'] ?? null)); return array_values($trace); } /** * @param array{class? : class-string, function?: non-empty-string} $frame * @param non-empty-string $function */ private function frameIsFunction(array $frame, string $function): bool { return !isset($frame['class']) && isset($frame['function']) && $frame['function'] === $function; } /** * @param array{class? : class-string, function?: non-empty-string} $frame * @param array{className: class-string, methodName: non-empty-string} $method */ private function frameIsMethod(array $frame, array $method): bool { return isset($frame['class']) && $frame['class'] === $method['className'] && isset($frame['function']) && $frame['function'] === $method['methodName']; } /** * @return non-empty-string */ private function stackTrace(): string { $buffer = ''; 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 */ final class Facade { private bool $replacesOutput = \false; private bool $replacesProgressOutput = \false; private bool $replacesResultOutput = \false; private bool $requiresCodeCoverageCollection = \false; /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public function registerSubscribers(Subscriber ...$subscribers): void { EventFacade::instance()->registerSubscribers(...$subscribers); } /** * @throws EventFacadeIsSealedException * @throws UnknownSubscriberTypeException */ public function registerSubscriber(Subscriber $subscriber): void { EventFacade::instance()->registerSubscriber($subscriber); } /** * @throws EventFacadeIsSealedException */ public function registerTracer(Tracer $tracer): void { EventFacade::instance()->registerTracer($tracer); } public function replaceOutput(): void { $this->replacesOutput = \true; } public function replacesOutput(): bool { return $this->replacesOutput; } public function replaceProgressOutput(): void { $this->replacesProgressOutput = \true; } public function replacesProgressOutput(): bool { return $this->replacesOutput || $this->replacesProgressOutput; } public function replaceResultOutput(): void { $this->replacesResultOutput = \true; } public function replacesResultOutput(): bool { return $this->replacesOutput || $this->replacesResultOutput; } public function requireCodeCoverageCollection(): void { $this->requiresCodeCoverageCollection = \true; } public function requiresCodeCoverageCollection(): bool { return $this->requiresCodeCoverageCollection; } } * * 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]; } else { $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\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 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); } $contents = file_get_contents($testDirectory . $externalFilename); assert($contents !== \false && $contents !== ''); $sections[$section] = $contents; } } } /** * @param array $sections * * @throws InvalidPhptFileException */ private function validate(array $sections): void { if (!isset($sections['FILE'])) { throw new \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 PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; 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, array $files): void { $template = new Template(__DIR__ . '/templates/phpt.tpl'); $composerAutoload = '\'\''; if (defined('PHPUNIT_COMPOSER_INSTALL')) { $composerAutoload = var_export(PHPUNIT_COMPOSER_INSTALL, \true); } $phar = '\'\''; if (defined('__PHPUNIT_PHAR__')) { $phar = var_export(__PHPUNIT_PHAR__, \true); } if ($codeCoverageCacheDirectory === null) { $codeCoverageCacheDirectory = 'null'; } else { $codeCoverageCacheDirectory = "'" . $codeCoverageCacheDirectory . "'"; } $bootstrap = ''; if (ConfigurationRegistry::get()->hasBootstrap()) { $bootstrap = ConfigurationRegistry::get()->bootstrap(); } $template->setVar(['bootstrap' => $bootstrap, 'composerAutoload' => $composerAutoload, 'phar' => $phar, 'job' => $files['job'], 'coverageFile' => $files['coverage'], 'driverMethod' => $pathCoverage ? 'forLineAndPathCoverage' : 'forLineCoverage', 'codeCoverageCacheDirectory' => $codeCoverageCacheDirectory]); file_put_contents($files['job'], $job); $rendered = $template->render(); assert($rendered !== ''); $job = $rendered; } } * * 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\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\TestSize; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\Test\TestStatus\TestStatus; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\TestIdMissingException; use PHPUnitPHAR\SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException; use PHPUnitPHAR\staabm\SideEffectsDetector\SideEffect; use PHPUnitPHAR\staabm\SideEffectsDetector\SideEffectsDetector; use Throwable; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @see https://qa.php.net/phpt_details.php */ final readonly class TestCase implements Reorderable, SelfDescribing, Test { /** * @var non-empty-string */ private string $filename; /** * @param non-empty-string $filename */ public function __construct(string $filename) { $this->filename = $filename; $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($this->filename, $sections['FILE']); $xfail = \false; $environmentVariables = []; $phpSettings = $parser->parseIniSection($this->settings(CodeCoverage::instance()->isActive())); $input = null; $arguments = []; $emitter->testPrepared($this->valueObjectForEvents()); if (isset($sections['INI'])) { $phpSettings = $parser->parseIniSection($sections['INI'], $phpSettings); } if (isset($sections['ENV'])) { $environmentVariables = $parser->parseEnvSection($sections['ENV']); } if ($this->shouldTestBeSkipped($sections, $phpSettings)) { return; } if (isset($sections['XFAIL'])) { $xfail = trim($sections['XFAIL']); } if (isset($sections['STDIN'])) { $input = $sections['STDIN']; } if (isset($sections['ARGS'])) { $arguments = explode(' ', $sections['ARGS']); } if (CodeCoverage::instance()->isActive()) { $codeCoverageCacheDirectory = null; if (CodeCoverage::instance()->codeCoverage()->cachesStaticAnalysis()) { $codeCoverageCacheDirectory = CodeCoverage::instance()->codeCoverage()->cacheDirectory(); } (new \PHPUnit\Runner\Phpt\Renderer())->renderForCoverage($code, CodeCoverage::instance()->codeCoverage()->collectsBranchAndPathCoverage(), $codeCoverageCacheDirectory, $this->coverageFiles()); } $jobResult = JobRunnerRegistry::run(new Job($code, $this->stringifyIni($phpSettings), $environmentVariables, $arguments, $input, \true)); EventFacade::emitter()->childProcessFinished($jobResult->stdout(), $jobResult->stderr()); $output = $jobResult->stdout(); if (CodeCoverage::instance()->isActive()) { $coverage = $this->cleanupForCoverage(); CodeCoverage::instance()->codeCoverage()->start($this->filename, TestSize::large()); CodeCoverage::instance()->codeCoverage()->append($coverage, $this->filename, \true, TestStatus::unknown()); } $passed = \true; try { $this->assertPhptExpectation($sections, $output); } catch (AssertionFailedError $e) { $failure = $e; if ($xfail !== \false) { $failure = new IncompleteTestError($xfail, 0, $e); } elseif ($e instanceof ExpectationFailedException) { $comparisonFailure = $e->getComparisonFailure(); if ($comparisonFailure !== null) { $diff = $comparisonFailure->getDiff(); } else { $diff = $e->getMessage(); } $hint = $this->locationHintFromDiff($diff, $sections); $trace = array_merge($hint, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)); $failure = new PhptAssertionFailedError($e->getMessage(), 0, (string) $trace[0]['file'], (int) $trace[0]['line'], $trace, $comparisonFailure !== null ? $diff : ''); } if ($failure instanceof IncompleteTestError) { $emitter->testMarkedAsIncomplete($this->valueObjectForEvents(), ThrowableBuilder::from($failure)); } else { $emitter->testFailed($this->valueObjectForEvents(), ThrowableBuilder::from($failure), null); } $passed = \false; } catch (Throwable $t) { $emitter->testErrored($this->valueObjectForEvents(), ThrowableBuilder::from($t)); $passed = \false; } if ($passed) { $emitter->testPassed($this->valueObjectForEvents()); } $this->runClean($sections, CodeCoverage::instance()->isActive()); $emitter->testFinished($this->valueObjectForEvents(), 1); } /** * Returns the name of the test case. */ public function getName(): string { return $this->toString(); } /** * Returns a string representation of the test case. */ public function toString(): string { return $this->filename; } public function sortId(): string { return $this->filename; } /** * @return list */ public function provides(): array { return []; } /** * @return list */ public function requires(): array { return []; } /** * @internal This method is not covered by the backward compatibility promise for PHPUnit */ public function valueObjectForEvents(): Phpt { return new Phpt($this->filename); } /** * @param array $sections * * @throws Exception * @throws ExpectationFailedException */ private function assertPhptExpectation(array $sections, string $output): void { $assertions = ['EXPECT' => 'assertEquals', 'EXPECTF' => 'assertStringMatchesFormat', 'EXPECTREGEX' => 'assertMatchesRegularExpression']; $actual = preg_replace('/\r\n/', "\n", trim($output)); foreach ($assertions as $sectionName => $sectionAssertion) { if (isset($sections[$sectionName])) { $sectionContent = preg_replace('/\r\n/', "\n", trim($sections[$sectionName])); $expected = $sectionName === 'EXPECTREGEX' ? "/{$sectionContent}/" : $sectionContent; /** @phpstan-ignore staticMethod.dynamicName */ Assert::$sectionAssertion($expected, $actual); return; } } throw new \PHPUnit\Runner\Phpt\InvalidPhptFileException(); } /** * @param array $sections * @param array|non-empty-string> $settings */ private function shouldTestBeSkipped(array $sections, array $settings): bool { if (!isset($sections['SKIPIF'])) { return \false; } $skipIfCode = (new \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); } /** * @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']; if (extension_loaded('pcov')) { if ($collectCoverage) { $settings[] = 'pcov.enabled=1'; } else { $settings[] = 'pcov.enabled=0'; } } if (extension_loaded('xdebug')) { if ($collectCoverage) { $settings[] = 'xdebug.mode=coverage'; } } return $settings; } private function triggerRunnerWarningOnPhpErrors(string $section, string $output): void { if (str_contains($output, 'Parse error:')) { EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('%s section triggered a parse error: %s', $section, $output)); } if (str_contains($output, 'Fatal error:')) { EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('%s section triggered a fatal error: %s', $section, $output)); } } /** * @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}($filter), $filter ); if ({codeCoverageCacheDirectory}) { $coverage->cacheStaticAnalysis({codeCoverageCacheDirectory}); } $coverage->start(__FILE__); } register_shutdown_function( function() use ($coverage) { $output = null; if ($coverage) { $output = $coverage->stop(); } file_put_contents('{coverageFile}', serialize($output)); } ); ob_end_clean(); require '{job}'; * * 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 = null) { if ($filepath !== null && is_dir($filepath)) { $filepath .= DIRECTORY_SEPARATOR . self::DEFAULT_RESULT_CACHE_FILENAME; } $this->cacheFilename = $filepath ?? $_ENV['PHPUNIT_RESULT_CACHE'] ?? self::DEFAULT_RESULT_CACHE_FILENAME; } public function setStatus(\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; }); } } * * 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->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 ($loadedClasses === []) { return self::$declaredClasses; } return $loadedClasses; } } * * 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) { if (!$test instanceof Reorderable) { continue; } $sortId = $test->sortId(); if (!isset($this->defectSortOrder[$sortId])) { $this->defectSortOrder[$sortId] = $this->cache->status(ResultCacheId::fromReorderable($test))->asInt(); $max = max($max, $this->defectSortOrder[$sortId]); } } $this->defectSortOrder[$suite->sortId()] = $max; } /** * @param list $tests * * @return list */ private function reverse(array $tests): array { return array_reverse($tests); } /** * @param list $tests * * @return list */ private function randomize(array $tests): array { shuffle($tests); return $tests; } /** * @param list $tests * * @return list */ private function sortDefectsFirst(array $tests): array { usort($tests, fn(Test $left, Test $right) => $this->cmpDefectPriorityAndTime($left, $right)); return $tests; } /** * @param list $tests * * @return list */ private function sortByDuration(array $tests): array { usort($tests, fn(Test $left, Test $right) => $this->cmpDuration($left, $right)); return $tests; } /** * @param list $tests * * @return list */ private function sortBySize(array $tests): array { usort($tests, fn(Test $left, Test $right) => $this->cmpSize($left, $right)); return $tests; } /** * Comparator callback function to sort tests for "reach failure as fast as possible". * * 1. sort tests by defect weight defined in self::DEFECT_SORT_WEIGHT * 2. when tests are equally defective, sort the fastest to the front * 3. do not reorder successful tests */ private function cmpDefectPriorityAndTime(Test $a, Test $b): int { assert($a instanceof Reorderable); assert($b instanceof Reorderable); $priorityA = $this->defectSortOrder[$a->sortId()] ?? 0; $priorityB = $this->defectSortOrder[$b->sortId()] ?? 0; if (($priorityB <=> $priorityA) > 0) { // Sort defect weight descending return $priorityB <=> $priorityA; } if ($priorityA > 0 || $priorityB > 0) { return $this->cmpDuration($a, $b); } // do not change execution order return 0; } /** * Compares test duration for sorting tests by duration ascending. */ private function cmpDuration(Test $a, Test $b): int { if (!($a instanceof Reorderable && $b instanceof Reorderable)) { return 0; } return $this->cache->time(ResultCacheId::fromReorderable($a)) <=> $this->cache->time(ResultCacheId::fromReorderable($b)); } /** * Compares test size for sorting tests small->medium->large->unknown. */ private function cmpSize(Test $a, Test $b): int { $sizeA = $a instanceof TestCase || $a instanceof DataProviderTestSuite ? $a->size()->asString() : 'unknown'; $sizeB = $b instanceof TestCase || $b instanceof DataProviderTestSuite ? $b->size()->asString() : 'unknown'; return self::SIZE_SORT_WEIGHT[$sizeA] <=> self::SIZE_SORT_WEIGHT[$sizeB]; } /** * Reorder Tests within a TestCase in such a way as to resolve as many dependencies as possible. * The algorithm will leave the tests in original running order when it can. * For more details see the documentation for test dependencies. * * Short description of algorithm: * 1. Pick the next Test from remaining tests to be checked for dependencies. * 2. If the test has no dependencies: mark done, start again from the top * 3. If the test has dependencies but none left to do: mark done, start again from the top * 4. When we reach the end add any leftover tests to the end. These will be marked 'skipped' during execution. * * @param array $tests * * @return array */ private function resolveDependencies(array $tests): array { $newTestOrder = []; $i = 0; $provided = []; do { if ([] === array_diff($tests[$i]->requires(), $provided)) { $provided = array_merge($provided, $tests[$i]->provides()); $newTestOrder = array_merge($newTestOrder, array_splice($tests, $i, 1)); $i = 0; } else { $i++; } } while ($tests !== [] && $i < count($tests)); return array_merge($newTestOrder, $tests); } } * * 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.0.5'; private static string $version = ''; /** * @return non-empty-string */ public static function id(): string { if (self::$pharVersion !== '') { return self::$pharVersion; } if (self::$version === '') { self::$version = (new VersionId('13.0.5', 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 assert; use function class_exists; use function defined; use function dirname; use function explode; use function function_exists; use function is_file; use function method_exists; use function printf; use function realpath; use function sprintf; use function str_contains; use function str_starts_with; use function trim; use function unlink; use PHPUnit\Event\EventFacadeIsSealedException; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Event\UnknownSubscriberTypeException; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestSuite; use PHPUnit\Logging\EventLogger; use PHPUnit\Logging\JUnit\JunitXmlLogger; use PHPUnit\Logging\OpenTestReporting\CannotOpenUriForWritingException; use PHPUnit\Logging\OpenTestReporting\OtrXmlLogger; use PHPUnit\Logging\TeamCity\TeamCityLogger; use PHPUnit\Logging\TestDox\HtmlRenderer as TestDoxHtmlRenderer; use PHPUnit\Logging\TestDox\PlainTextRenderer as TestDoxTextRenderer; use PHPUnit\Logging\TestDox\TestResultCollector as TestDoxResultCollector; use PHPUnit\Runner\Baseline\CannotLoadBaselineException; use PHPUnit\Runner\Baseline\Generator as BaselineGenerator; use PHPUnit\Runner\Baseline\Reader; use PHPUnit\Runner\Baseline\Writer; use PHPUnit\Runner\CodeCoverage; use PHPUnit\Runner\CodeCoverageInitializationStatus; use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollector; use PHPUnit\Runner\DirectoryDoesNotExistException; use PHPUnit\Runner\ErrorHandler; use PHPUnit\Runner\Extension\ExtensionBootstrapper; use PHPUnit\Runner\Extension\Facade as ExtensionFacade; use PHPUnit\Runner\Extension\PharLoader; use PHPUnit\Runner\GarbageCollection\GarbageCollectionHandler; use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; use PHPUnit\Runner\ResultCache\DefaultResultCache; use PHPUnit\Runner\ResultCache\NullResultCache; use PHPUnit\Runner\ResultCache\ResultCache; use PHPUnit\Runner\ResultCache\ResultCacheHandler; use PHPUnit\Runner\TestSuiteSorter; use PHPUnit\Runner\Version; use PHPUnit\TestRunner\IssueFilter; use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade; use PHPUnit\TextUI\CliArguments\Builder; use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; use PHPUnit\TextUI\CliArguments\Exception as ArgumentsException; use PHPUnit\TextUI\CliArguments\XmlConfigurationFileFinder; use PHPUnit\TextUI\Command\AtLeastVersionCommand; use PHPUnit\TextUI\Command\CheckPhpConfigurationCommand; use PHPUnit\TextUI\Command\GenerateConfigurationCommand; use PHPUnit\TextUI\Command\ListGroupsCommand; use PHPUnit\TextUI\Command\ListTestFilesCommand; use PHPUnit\TextUI\Command\ListTestsAsTextCommand; use PHPUnit\TextUI\Command\ListTestsAsXmlCommand; use PHPUnit\TextUI\Command\ListTestSuitesCommand; use PHPUnit\TextUI\Command\MigrateConfigurationCommand; use PHPUnit\TextUI\Command\Result; use PHPUnit\TextUI\Command\ShowHelpCommand; use PHPUnit\TextUI\Command\ShowVersionCommand; use PHPUnit\TextUI\Command\VersionCheckCommand; use PHPUnit\TextUI\Command\WarmCodeCoverageCacheCommand; use PHPUnit\TextUI\Configuration\BootstrapLoader; use PHPUnit\TextUI\Configuration\BootstrapScriptDoesNotExistException; use PHPUnit\TextUI\Configuration\BootstrapScriptException; use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; use PHPUnit\TextUI\Configuration\Configuration; use PHPUnit\TextUI\Configuration\PhpHandler; use PHPUnit\TextUI\Configuration\Registry; use PHPUnit\TextUI\Configuration\TestSuiteBuilder; use PHPUnit\TextUI\Output\DefaultPrinter; use PHPUnit\TextUI\Output\Facade as OutputFacade; use PHPUnit\TextUI\Output\Printer; use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; use PHPUnit\TextUI\XmlConfiguration\DefaultConfiguration; use PHPUnit\TextUI\XmlConfiguration\Loader; use PHPUnit\Util\Http\PhpDownloader; use 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); $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(), \false)); } if ($configuration->hasLogEventsVerboseText()) { if (is_file($configuration->logEventsVerboseText())) { unlink($configuration->logEventsVerboseText()); } EventFacade::instance()->registerTracer(new EventLogger($configuration->logEventsVerboseText(), \true)); } if ($configuration->hasLogfileJunit()) { try { new JunitXmlLogger(OutputFacade::printerFor($configuration->logfileJunit()), EventFacade::instance()); } catch (DirectoryDoesNotExistException|\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' => []]; foreach ($configuration->source()->deprecationTriggers()['functions'] as $function) { if (!function_exists($function)) { EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Function %s cannot be configured as a deprecation trigger because it is not declared', $function)); continue; } $deprecationTriggers['functions'][] = $function; } foreach ($configuration->source()->deprecationTriggers()['methods'] as $method) { if (!str_contains($method, '::')) { EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('%s cannot be configured as a deprecation trigger because it is not in ClassName::methodName format', $method)); continue; } [$className, $methodName] = explode('::', $method); if (!class_exists($className) || !method_exists($className, $methodName)) { EventFacade::emitter()->testRunnerTriggeredPhpunitWarning(sprintf('Method %s::%s cannot be configured as a deprecation trigger because it is not declared', $className, $methodName)); continue; } $deprecationTriggers['methods'][] = ['className' => $className, 'methodName' => $methodName]; } if ($deprecationTriggers !== ['functions' => [], 'methods' => []]) { ErrorHandler::instance()->useDeprecationTriggers($deprecationTriggers); } } private function preload(): void { if (!defined('PHPUNIT_COMPOSER_INSTALL')) { return; } $classMapFile = dirname(PHPUNIT_COMPOSER_INSTALL) . '/composer/autoload_classmap.php'; if (!is_file($classMapFile)) { return; } foreach (require $classMapFile as $codeUnitName => $sourceCodeFile) { if (!str_starts_with($codeUnitName, 'PHPUnit\\') && !str_starts_with($codeUnitName, 'SebastianBergmann\\')) { continue; } if (str_contains($sourceCodeFile, '/tests/')) { continue; } require_once $sourceCodeFile; } } } * * 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; } 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 $includeGitInformationInOtrLogfile; private bool $listGroups; private bool $listSuites; private bool $listTestFiles; private bool $listTests; private ?string $listTestsXml; private ?bool $noCoverage; private ?bool $noExtensions; private ?bool $noOutput; private ?bool $noProgress; private ?bool $noResults; private ?bool $noLogging; private ?bool $processIsolation; private ?int $randomOrderSeed; private ?bool $reportUselessTests; private ?bool $resolveDependencies; private ?bool $reverseList; private ?bool $stderr; private ?bool $strictCoverage; private ?string $teamcityLogfile; private ?bool $teamCityPrinter; private ?string $testdoxHtmlFile; private ?string $testdoxTextFile; private ?bool $testdoxPrinter; private ?bool $testdoxPrinterSummary; /** * @var ?non-empty-list */ private ?array $testSuffixes; private ?string $testSuite; private ?string $excludeTestSuite; private bool $useDefaultConfiguration; private ?bool $displayDetailsOnAllIssues; private ?bool $displayDetailsOnIncompleteTests; private ?bool $displayDetailsOnSkippedTests; private ?bool $displayDetailsOnTestsThatTriggerDeprecations; private ?bool $displayDetailsOnPhpunitDeprecations; private ?bool $displayDetailsOnPhpunitNotices; private ?bool $displayDetailsOnTestsThatTriggerErrors; private ?bool $displayDetailsOnTestsThatTriggerNotices; private ?bool $displayDetailsOnTestsThatTriggerWarnings; private bool $version; private ?string $logEventsText; private ?string $logEventsVerboseText; private bool $debug; private bool $withTelemetry; /** * @var ?non-empty-list */ private ?array $extensions; /** * @param list $arguments * @param ?non-empty-list $excludeGroups * @param ?non-empty-list $groups * @param ?non-empty-list $testsCovering * @param ?non-empty-list $testsUsing * @param ?non-empty-list $testsRequiringPhpExtension * @param ?non-empty-array $iniSettings * @param ?non-empty-list $testSuffixes * @param ?non-empty-list $coverageFilter * @param ?non-empty-list $extensions */ public function __construct(array $arguments, ?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->includeGitInformationInOtrLogfile = $includeGitInformation; $this->listGroups = $listGroups; $this->listSuites = $listSuites; $this->listTestFiles = $listTestFiles; $this->listTests = $listTests; $this->listTestsXml = $listTestsXml; $this->noCoverage = $noCoverage; $this->noExtensions = $noExtensions; $this->noOutput = $noOutput; $this->noProgress = $noProgress; $this->noResults = $noResults; $this->noLogging = $noLogging; $this->processIsolation = $processIsolation; $this->randomOrderSeed = $randomOrderSeed; $this->reportUselessTests = $reportUselessTests; $this->resolveDependencies = $resolveDependencies; $this->reverseList = $reverseList; $this->stderr = $stderr; $this->strictCoverage = $strictCoverage; $this->teamcityLogfile = $teamcityLogfile; $this->testdoxHtmlFile = $testdoxHtmlFile; $this->testdoxTextFile = $testdoxTextFile; $this->testSuffixes = $testSuffixes; $this->testSuite = $testSuite; $this->excludeTestSuite = $excludeTestSuite; $this->useDefaultConfiguration = $useDefaultConfiguration; $this->displayDetailsOnAllIssues = $displayDetailsOnAllIssues; $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; $this->displayDetailsOnPhpunitDeprecations = $displayDetailsOnPhpunitDeprecations; $this->displayDetailsOnPhpunitNotices = $displayDetailsOnPhpunitNotices; $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; $this->version = $version; $this->logEventsText = $logEventsText; $this->logEventsVerboseText = $logEventsVerboseText; $this->teamCityPrinter = $printerTeamCity; $this->testdoxPrinter = $testdoxPrinter; $this->testdoxPrinterSummary = $testdoxPrinterSummary; $this->debug = $debug; $this->withTelemetry = $withTelemetry; $this->extensions = $extensions; } /** * @return list */ public function arguments(): array { return $this->arguments; } /** * @phpstan-assert-if-true !null $this->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->includeGitInformationInOtrLogfile */ public function hasIncludeGitInformationInOtrLogfile(): bool { return $this->includeGitInformationInOtrLogfile !== null; } /** * @throws Exception */ public function includeGitInformationInOtrLogfile(): bool { if (!$this->hasIncludeGitInformationInOtrLogfile()) { throw new \PHPUnit\TextUI\CliArguments\Exception(); } return $this->includeGitInformationInOtrLogfile; } public function listGroups(): bool { return $this->listGroups; } public function listSuites(): bool { return $this->listSuites; } public function listTestFiles(): bool { return $this->listTestFiles; } public function listTests(): bool { return $this->listTests; } /** * @phpstan-assert-if-true !null $this->listTestsXml */ public function hasListTestsXml(): bool { return $this->listTestsXml !== null; } /** * @throws Exception */ public function listTestsXml(): string { if (!$this->hasListTestsXml()) { throw new \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())->map($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 $coverageHtmlColorSuccessMedium; private string $coverageHtmlColorSuccessHigh; private string $coverageHtmlColorWarning; private string $coverageHtmlColorDanger; private ?string $coverageHtmlCustomCssFile; private ?string $coverageOpenClover; private ?string $coveragePhp; private ?string $coverageText; private bool $coverageTextShowUncoveredFiles; private bool $coverageTextShowOnlySummary; private ?string $coverageXml; private bool $coverageXmlIncludeSource; private string $testResultCacheFile; private bool $ignoreDeprecatedCodeUnitsFromCodeCoverage; private bool $disableCodeCoverageIgnore; private bool $failOnAllIssues; private bool $failOnDeprecation; private bool $failOnPhpunitDeprecation; private bool $failOnPhpunitNotice; private bool $failOnPhpunitWarning; private bool $failOnEmptyTestSuite; private bool $failOnIncomplete; private bool $failOnNotice; private bool $failOnRisky; private bool $failOnSkipped; private bool $failOnWarning; private bool $doNotFailOnDeprecation; private bool $doNotFailOnPhpunitDeprecation; private bool $doNotFailOnPhpunitNotice; private bool $doNotFailOnPhpunitWarning; private bool $doNotFailOnEmptyTestSuite; private bool $doNotFailOnIncomplete; private bool $doNotFailOnNotice; private bool $doNotFailOnRisky; private bool $doNotFailOnSkipped; private bool $doNotFailOnWarning; private bool $stopOnDefect; private bool $stopOnDeprecation; private ?string $specificDeprecationToStopOn; private bool $stopOnError; private bool $stopOnFailure; private bool $stopOnIncomplete; private bool $stopOnNotice; private bool $stopOnRisky; private bool $stopOnSkipped; private bool $stopOnWarning; private bool $outputToStandardErrorStream; private int $columns; private bool $noExtensions; /** * @var ?non-empty-string */ private ?string $pharExtensionDirectory; /** * @var list}> */ private array $extensionBootstrappers; private bool $backupGlobals; private bool $backupStaticProperties; private bool $beStrictAboutChangesToGlobalState; private bool $colors; private bool $processIsolation; private bool $enforceTimeLimit; private int $defaultTimeLimit; private int $timeoutForSmallTests; private int $timeoutForMediumTests; private int $timeoutForLargeTests; private bool $reportUselessTests; private bool $strictCoverage; private bool $disallowTestOutput; private bool $displayDetailsOnAllIssues; private bool $displayDetailsOnIncompleteTests; private bool $displayDetailsOnSkippedTests; private bool $displayDetailsOnTestsThatTriggerDeprecations; private bool $displayDetailsOnPhpunitDeprecations; private bool $displayDetailsOnPhpunitNotices; private bool $displayDetailsOnTestsThatTriggerErrors; private bool $displayDetailsOnTestsThatTriggerNotices; private bool $displayDetailsOnTestsThatTriggerWarnings; private bool $reverseDefectList; private bool $requireCoverageMetadata; private bool $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 $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 $coverageHtmlColorSuccessMedium, string $coverageHtmlColorSuccessHigh, string $coverageHtmlColorWarning, string $coverageHtmlColorDanger, ?string $coverageHtmlCustomCssFile, ?string $coverageOpenClover, ?string $coveragePhp, ?string $coverageText, bool $coverageTextShowUncoveredFiles, bool $coverageTextShowOnlySummary, ?string $coverageXml, bool $coverageXmlIncludeSource, bool $pathCoverage, bool $ignoreDeprecatedCodeUnitsFromCodeCoverage, bool $disableCodeCoverageIgnore, bool $failOnAllIssues, bool $failOnDeprecation, bool $failOnPhpunitDeprecation, bool $failOnPhpunitNotice, bool $failOnPhpunitWarning, bool $failOnEmptyTestSuite, bool $failOnIncomplete, bool $failOnNotice, bool $failOnRisky, bool $failOnSkipped, bool $failOnWarning, bool $doNotFailOnDeprecation, bool $doNotFailOnPhpunitDeprecation, bool $doNotFailOnPhpunitNotice, bool $doNotFailOnPhpunitWarning, bool $doNotFailOnEmptyTestSuite, bool $doNotFailOnIncomplete, bool $doNotFailOnNotice, bool $doNotFailOnRisky, bool $doNotFailOnSkipped, bool $doNotFailOnWarning, bool $stopOnDefect, bool $stopOnDeprecation, ?string $specificDeprecationToStopOn, bool $stopOnError, bool $stopOnFailure, bool $stopOnIncomplete, bool $stopOnNotice, bool $stopOnRisky, bool $stopOnSkipped, bool $stopOnWarning, bool $outputToStandardErrorStream, int $columns, bool $noExtensions, ?string $pharExtensionDirectory, array $extensionBootstrappers, bool $backupGlobals, bool $backupStaticProperties, bool $beStrictAboutChangesToGlobalState, bool $colors, bool $processIsolation, bool $enforceTimeLimit, int $defaultTimeLimit, int $timeoutForSmallTests, int $timeoutForMediumTests, int $timeoutForLargeTests, bool $reportUselessTests, bool $strictCoverage, bool $disallowTestOutput, bool $displayDetailsOnAllIssues, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnPhpunitDeprecations, bool $displayDetailsOnPhpunitNotices, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $reverseDefectList, bool $requireCoverageMetadata, bool $requireSealedMockObjects, bool $noProgress, bool $noResults, bool $noOutput, int $executionOrder, int $executionOrderDefects, bool $resolveDependencies, ?string $logfileTeamcity, ?string $logfileJunit, ?string $logfileOtr, bool $includeGitInformationInOtrLogfile, ?string $logfileTestdoxHtml, ?string $logfileTestdoxText, ?string $logEventsText, ?string $logEventsVerboseText, bool $teamCityOutput, bool $testDoxOutput, bool $testDoxOutputSummary, ?array $testsCovering, ?array $testsUsing, ?array $testsRequiringPhpExtension, ?string $filter, ?string $excludeFilter, array $groups, array $excludeGroups, int $randomOrderSeed, bool $includeUncoveredFiles, \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->coverageHtmlColorSuccessMedium = $coverageHtmlColorSuccessMedium; $this->coverageHtmlColorSuccessHigh = $coverageHtmlColorSuccessHigh; $this->coverageHtmlColorWarning = $coverageHtmlColorWarning; $this->coverageHtmlColorDanger = $coverageHtmlColorDanger; $this->coverageHtmlCustomCssFile = $coverageHtmlCustomCssFile; $this->coverageOpenClover = $coverageOpenClover; $this->coveragePhp = $coveragePhp; $this->coverageText = $coverageText; $this->coverageTextShowUncoveredFiles = $coverageTextShowUncoveredFiles; $this->coverageTextShowOnlySummary = $coverageTextShowOnlySummary; $this->coverageXml = $coverageXml; $this->coverageXmlIncludeSource = $coverageXmlIncludeSource; $this->pathCoverage = $pathCoverage; $this->ignoreDeprecatedCodeUnitsFromCodeCoverage = $ignoreDeprecatedCodeUnitsFromCodeCoverage; $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore; $this->failOnAllIssues = $failOnAllIssues; $this->failOnDeprecation = $failOnDeprecation; $this->failOnPhpunitDeprecation = $failOnPhpunitDeprecation; $this->failOnPhpunitNotice = $failOnPhpunitNotice; $this->failOnPhpunitWarning = $failOnPhpunitWarning; $this->failOnEmptyTestSuite = $failOnEmptyTestSuite; $this->failOnIncomplete = $failOnIncomplete; $this->failOnNotice = $failOnNotice; $this->failOnRisky = $failOnRisky; $this->failOnSkipped = $failOnSkipped; $this->failOnWarning = $failOnWarning; $this->doNotFailOnDeprecation = $doNotFailOnDeprecation; $this->doNotFailOnPhpunitDeprecation = $doNotFailOnPhpunitDeprecation; $this->doNotFailOnPhpunitNotice = $doNotFailOnPhpunitNotice; $this->doNotFailOnPhpunitWarning = $doNotFailOnPhpunitWarning; $this->doNotFailOnEmptyTestSuite = $doNotFailOnEmptyTestSuite; $this->doNotFailOnIncomplete = $doNotFailOnIncomplete; $this->doNotFailOnNotice = $doNotFailOnNotice; $this->doNotFailOnRisky = $doNotFailOnRisky; $this->doNotFailOnSkipped = $doNotFailOnSkipped; $this->doNotFailOnWarning = $doNotFailOnWarning; $this->stopOnDefect = $stopOnDefect; $this->stopOnDeprecation = $stopOnDeprecation; $this->specificDeprecationToStopOn = $specificDeprecationToStopOn; $this->stopOnError = $stopOnError; $this->stopOnFailure = $stopOnFailure; $this->stopOnIncomplete = $stopOnIncomplete; $this->stopOnNotice = $stopOnNotice; $this->stopOnRisky = $stopOnRisky; $this->stopOnSkipped = $stopOnSkipped; $this->stopOnWarning = $stopOnWarning; $this->outputToStandardErrorStream = $outputToStandardErrorStream; $this->columns = $columns; $this->noExtensions = $noExtensions; $this->pharExtensionDirectory = $pharExtensionDirectory; $this->extensionBootstrappers = $extensionBootstrappers; $this->backupGlobals = $backupGlobals; $this->backupStaticProperties = $backupStaticProperties; $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState; $this->colors = $colors; $this->processIsolation = $processIsolation; $this->enforceTimeLimit = $enforceTimeLimit; $this->defaultTimeLimit = $defaultTimeLimit; $this->timeoutForSmallTests = $timeoutForSmallTests; $this->timeoutForMediumTests = $timeoutForMediumTests; $this->timeoutForLargeTests = $timeoutForLargeTests; $this->reportUselessTests = $reportUselessTests; $this->strictCoverage = $strictCoverage; $this->disallowTestOutput = $disallowTestOutput; $this->displayDetailsOnAllIssues = $displayDetailsOnAllIssues; $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; $this->displayDetailsOnPhpunitDeprecations = $displayDetailsOnPhpunitDeprecations; $this->displayDetailsOnPhpunitNotices = $displayDetailsOnPhpunitNotices; $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; $this->reverseDefectList = $reverseDefectList; $this->requireCoverageMetadata = $requireCoverageMetadata; $this->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->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 coverageHtmlColorSuccessMedium(): string { return $this->coverageHtmlColorSuccessMedium; } public function coverageHtmlColorSuccessHigh(): string { return $this->coverageHtmlColorSuccessHigh; } public function coverageHtmlColorWarning(): string { return $this->coverageHtmlColorWarning; } public function coverageHtmlColorDanger(): string { return $this->coverageHtmlColorDanger; } /** * @phpstan-assert-if-true !null $this->coverageHtmlCustomCssFile */ public function hasCoverageHtmlCustomCssFile(): bool { return $this->coverageHtmlCustomCssFile !== null; } /** * @throws NoCustomCssFileException */ public function coverageHtmlCustomCssFile(): string { if (!$this->hasCoverageHtmlCustomCssFile()) { throw new \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; } /** * @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 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 assert; use function dirname; use function explode; use function is_int; use function realpath; use function time; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Runner\TestSuiteSorter; use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; use PHPUnit\TextUI\CliArguments\Exception; use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; use PHPUnit\TextUI\XmlConfiguration\LoadedFromFileConfiguration; use PHPUnit\TextUI\XmlConfiguration\SchemaDetector; use PHPUnit\Util\Filesystem; use 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(); } else { $failOnEmptyTestSuite = $xmlConfiguration->phpunit()->failOnEmptyTestSuite(); } if ($cliConfiguration->hasFailOnIncomplete()) { $failOnIncomplete = $cliConfiguration->failOnIncomplete(); } else { $failOnIncomplete = $xmlConfiguration->phpunit()->failOnIncomplete(); } if ($cliConfiguration->hasFailOnNotice()) { $failOnNotice = $cliConfiguration->failOnNotice(); } else { $failOnNotice = $xmlConfiguration->phpunit()->failOnNotice(); } if ($cliConfiguration->hasFailOnRisky()) { $failOnRisky = $cliConfiguration->failOnRisky(); } else { $failOnRisky = $xmlConfiguration->phpunit()->failOnRisky(); } if ($cliConfiguration->hasFailOnSkipped()) { $failOnSkipped = $cliConfiguration->failOnSkipped(); } else { $failOnSkipped = $xmlConfiguration->phpunit()->failOnSkipped(); } if ($cliConfiguration->hasFailOnWarning()) { $failOnWarning = $cliConfiguration->failOnWarning(); } else { $failOnWarning = $xmlConfiguration->phpunit()->failOnWarning(); } $doNotFailOnDeprecation = \false; if ($cliConfiguration->hasDoNotFailOnDeprecation()) { $doNotFailOnDeprecation = $cliConfiguration->doNotFailOnDeprecation(); } $doNotFailOnPhpunitDeprecation = \false; if ($cliConfiguration->hasDoNotFailOnPhpunitDeprecation()) { $doNotFailOnPhpunitDeprecation = $cliConfiguration->doNotFailOnPhpunitDeprecation(); } $doNotFailOnPhpunitNotice = \false; if ($cliConfiguration->hasDoNotFailOnPhpunitNotice()) { $doNotFailOnPhpunitNotice = $cliConfiguration->doNotFailOnPhpunitNotice(); } $doNotFailOnPhpunitWarning = \false; if ($cliConfiguration->hasDoNotFailOnPhpunitWarning()) { $doNotFailOnPhpunitWarning = $cliConfiguration->doNotFailOnPhpunitWarning(); } $doNotFailOnEmptyTestSuite = \false; if ($cliConfiguration->hasDoNotFailOnEmptyTestSuite()) { $doNotFailOnEmptyTestSuite = $cliConfiguration->doNotFailOnEmptyTestSuite(); } $doNotFailOnIncomplete = \false; if ($cliConfiguration->hasDoNotFailOnIncomplete()) { $doNotFailOnIncomplete = $cliConfiguration->doNotFailOnIncomplete(); } $doNotFailOnNotice = \false; if ($cliConfiguration->hasDoNotFailOnNotice()) { $doNotFailOnNotice = $cliConfiguration->doNotFailOnNotice(); } $doNotFailOnRisky = \false; if ($cliConfiguration->hasDoNotFailOnRisky()) { $doNotFailOnRisky = $cliConfiguration->doNotFailOnRisky(); } $doNotFailOnSkipped = \false; if ($cliConfiguration->hasDoNotFailOnSkipped()) { $doNotFailOnSkipped = $cliConfiguration->doNotFailOnSkipped(); } $doNotFailOnWarning = \false; if ($cliConfiguration->hasDoNotFailOnWarning()) { $doNotFailOnWarning = $cliConfiguration->doNotFailOnWarning(); } if ($cliConfiguration->hasStopOnDefect()) { $stopOnDefect = $cliConfiguration->stopOnDefect(); } else { $stopOnDefect = $xmlConfiguration->phpunit()->stopOnDefect(); } if ($cliConfiguration->hasStopOnDeprecation()) { $stopOnDeprecation = $cliConfiguration->stopOnDeprecation(); } else { $stopOnDeprecation = $xmlConfiguration->phpunit()->stopOnDeprecation(); } $specificDeprecationToStopOn = null; if ($cliConfiguration->hasSpecificDeprecationToStopOn()) { $specificDeprecationToStopOn = $cliConfiguration->specificDeprecationToStopOn(); } if ($cliConfiguration->hasStopOnError()) { $stopOnError = $cliConfiguration->stopOnError(); } else { $stopOnError = $xmlConfiguration->phpunit()->stopOnError(); } if ($cliConfiguration->hasStopOnFailure()) { $stopOnFailure = $cliConfiguration->stopOnFailure(); } else { $stopOnFailure = $xmlConfiguration->phpunit()->stopOnFailure(); } if ($cliConfiguration->hasStopOnIncomplete()) { $stopOnIncomplete = $cliConfiguration->stopOnIncomplete(); } else { $stopOnIncomplete = $xmlConfiguration->phpunit()->stopOnIncomplete(); } if ($cliConfiguration->hasStopOnNotice()) { $stopOnNotice = $cliConfiguration->stopOnNotice(); } else { $stopOnNotice = $xmlConfiguration->phpunit()->stopOnNotice(); } if ($cliConfiguration->hasStopOnRisky()) { $stopOnRisky = $cliConfiguration->stopOnRisky(); } else { $stopOnRisky = $xmlConfiguration->phpunit()->stopOnRisky(); } if ($cliConfiguration->hasStopOnSkipped()) { $stopOnSkipped = $cliConfiguration->stopOnSkipped(); } else { $stopOnSkipped = $xmlConfiguration->phpunit()->stopOnSkipped(); } if ($cliConfiguration->hasStopOnWarning()) { $stopOnWarning = $cliConfiguration->stopOnWarning(); } else { $stopOnWarning = $xmlConfiguration->phpunit()->stopOnWarning(); } if ($cliConfiguration->hasStderr() && $cliConfiguration->stderr()) { $outputToStandardErrorStream = \true; } else { $outputToStandardErrorStream = $xmlConfiguration->phpunit()->stderr(); } if ($cliConfiguration->hasColumns()) { $columns = $cliConfiguration->columns(); } else { $columns = $xmlConfiguration->phpunit()->columns(); } if ($columns === 'max') { $columns = (new Console())->getNumberOfColumns(); } if ($columns < 16) { $columns = 16; EventFacade::emitter()->testRunnerTriggeredPhpunitWarning('Less than 16 columns requested, number of columns set to 16'); } assert(is_int($columns)); $noExtensions = \false; if ($cliConfiguration->hasNoExtensions() && $cliConfiguration->noExtensions()) { $noExtensions = \true; } $pharExtensionDirectory = null; if ($xmlConfiguration->phpunit()->hasExtensionsDirectory()) { $pharExtensionDirectory = $xmlConfiguration->phpunit()->extensionsDirectory(); } $extensionBootstrappers = []; if ($cliConfiguration->hasExtensions()) { foreach ($cliConfiguration->extensions() as $extension) { $extensionBootstrappers[] = ['className' => $extension, 'parameters' => []]; } } foreach ($xmlConfiguration->extensions() as $extension) { $extensionBootstrappers[] = ['className' => $extension->className(), 'parameters' => $extension->parameters()]; } if ($cliConfiguration->hasPathCoverage() && $cliConfiguration->pathCoverage()) { $pathCoverage = $cliConfiguration->pathCoverage(); } else { $pathCoverage = $xmlConfiguration->codeCoverage()->pathCoverage(); } $defaultColors = Colors::default(); $defaultThresholds = Thresholds::default(); $coverageClover = null; $coverageCobertura = null; $coverageCrap4j = null; $coverageCrap4jThreshold = 30; $coverageHtml = null; $coverageHtmlLowUpperBound = $defaultThresholds->lowUpperBound(); $coverageHtmlHighLowerBound = $defaultThresholds->highLowerBound(); $coverageHtmlColorSuccessLow = $defaultColors->successLow(); $coverageHtmlColorSuccessMedium = $defaultColors->successMedium(); $coverageHtmlColorSuccessHigh = $defaultColors->successHigh(); $coverageHtmlColorWarning = $defaultColors->warning(); $coverageHtmlColorDanger = $defaultColors->danger(); $coverageHtmlCustomCssFile = null; $coverageOpenClover = null; $coveragePhp = null; $coverageText = null; $coverageTextShowUncoveredFiles = \false; $coverageTextShowOnlySummary = \false; $coverageXml = null; $coverageXmlIncludeSource = \true; $coverageFromXmlConfiguration = \true; if ($cliConfiguration->hasNoCoverage() && $cliConfiguration->noCoverage()) { $coverageFromXmlConfiguration = \false; } if ($cliConfiguration->hasCoverageClover()) { $coverageClover = $cliConfiguration->coverageClover(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasClover()) { $coverageClover = $xmlConfiguration->codeCoverage()->clover()->target()->path(); } if ($cliConfiguration->hasCoverageCobertura()) { $coverageCobertura = $cliConfiguration->coverageCobertura(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasCobertura()) { $coverageCobertura = $xmlConfiguration->codeCoverage()->cobertura()->target()->path(); } if ($xmlConfiguration->codeCoverage()->hasCrap4j()) { $coverageCrap4jThreshold = $xmlConfiguration->codeCoverage()->crap4j()->threshold(); } if ($cliConfiguration->hasCoverageCrap4J()) { $coverageCrap4j = $cliConfiguration->coverageCrap4J(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasCrap4j()) { $coverageCrap4j = $xmlConfiguration->codeCoverage()->crap4j()->target()->path(); } if ($xmlConfiguration->codeCoverage()->hasHtml()) { $coverageHtmlHighLowerBound = $xmlConfiguration->codeCoverage()->html()->highLowerBound(); $coverageHtmlLowUpperBound = $xmlConfiguration->codeCoverage()->html()->lowUpperBound(); if ($coverageHtmlLowUpperBound > $coverageHtmlHighLowerBound) { $coverageHtmlLowUpperBound = $defaultThresholds->lowUpperBound(); $coverageHtmlHighLowerBound = $defaultThresholds->highLowerBound(); } $coverageHtmlColorSuccessLow = $xmlConfiguration->codeCoverage()->html()->colorSuccessLow(); $coverageHtmlColorSuccessMedium = $xmlConfiguration->codeCoverage()->html()->colorSuccessMedium(); $coverageHtmlColorSuccessHigh = $xmlConfiguration->codeCoverage()->html()->colorSuccessHigh(); $coverageHtmlColorWarning = $xmlConfiguration->codeCoverage()->html()->colorWarning(); $coverageHtmlColorDanger = $xmlConfiguration->codeCoverage()->html()->colorDanger(); if ($xmlConfiguration->codeCoverage()->html()->hasCustomCssFile()) { $coverageHtmlCustomCssFile = $xmlConfiguration->codeCoverage()->html()->customCssFile(); } } if ($cliConfiguration->hasCoverageHtml()) { $coverageHtml = $cliConfiguration->coverageHtml(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasHtml()) { $coverageHtml = $xmlConfiguration->codeCoverage()->html()->target()->path(); } if ($cliConfiguration->hasCoverageOpenClover()) { $coverageOpenClover = $cliConfiguration->coverageOpenClover(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasOpenClover()) { $coverageOpenClover = $xmlConfiguration->codeCoverage()->openClover()->target()->path(); } if ($cliConfiguration->hasCoveragePhp()) { $coveragePhp = $cliConfiguration->coveragePhp(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasPhp()) { $coveragePhp = $xmlConfiguration->codeCoverage()->php()->target()->path(); } if ($xmlConfiguration->codeCoverage()->hasText()) { $coverageTextShowUncoveredFiles = $xmlConfiguration->codeCoverage()->text()->showUncoveredFiles(); $coverageTextShowOnlySummary = $xmlConfiguration->codeCoverage()->text()->showOnlySummary(); } if ($cliConfiguration->hasCoverageTextShowUncoveredFiles()) { $coverageTextShowUncoveredFiles = $cliConfiguration->coverageTextShowUncoveredFiles(); } if ($cliConfiguration->hasCoverageTextShowOnlySummary()) { $coverageTextShowOnlySummary = $cliConfiguration->coverageTextShowOnlySummary(); } if ($cliConfiguration->hasCoverageText()) { $coverageText = $cliConfiguration->coverageText(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasText()) { $coverageText = $xmlConfiguration->codeCoverage()->text()->target()->path(); } if ($cliConfiguration->hasCoverageXml()) { $coverageXml = $cliConfiguration->coverageXml(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasXml()) { $coverageXml = $xmlConfiguration->codeCoverage()->xml()->target()->path(); } if ($cliConfiguration->hasExcludeSourceFromXmlCoverage()) { $coverageXmlIncludeSource = !$cliConfiguration->excludeSourceFromXmlCoverage(); } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasXml()) { $coverageXmlIncludeSource = $xmlConfiguration->codeCoverage()->xml()->includeSource(); } if ($cliConfiguration->hasBackupGlobals()) { $backupGlobals = $cliConfiguration->backupGlobals(); } else { $backupGlobals = $xmlConfiguration->phpunit()->backupGlobals(); } if ($cliConfiguration->hasBackupStaticProperties()) { $backupStaticProperties = $cliConfiguration->backupStaticProperties(); } else { $backupStaticProperties = $xmlConfiguration->phpunit()->backupStaticProperties(); } if ($cliConfiguration->hasBeStrictAboutChangesToGlobalState()) { $beStrictAboutChangesToGlobalState = $cliConfiguration->beStrictAboutChangesToGlobalState(); } else { $beStrictAboutChangesToGlobalState = $xmlConfiguration->phpunit()->beStrictAboutChangesToGlobalState(); } if ($cliConfiguration->hasProcessIsolation()) { $processIsolation = $cliConfiguration->processIsolation(); } else { $processIsolation = $xmlConfiguration->phpunit()->processIsolation(); } if ($cliConfiguration->hasEnforceTimeLimit()) { $enforceTimeLimit = $cliConfiguration->enforceTimeLimit(); } else { $enforceTimeLimit = $xmlConfiguration->phpunit()->enforceTimeLimit(); } if ($enforceTimeLimit && !(new Invoker())->canInvokeWithTimeout()) { EventFacade::emitter()->testRunnerTriggeredPhpunitWarning('The pcntl extension is required for enforcing time limits'); } if ($cliConfiguration->hasDefaultTimeLimit()) { $defaultTimeLimit = $cliConfiguration->defaultTimeLimit(); } else { $defaultTimeLimit = $xmlConfiguration->phpunit()->defaultTimeLimit(); } $timeoutForSmallTests = $xmlConfiguration->phpunit()->timeoutForSmallTests(); $timeoutForMediumTests = $xmlConfiguration->phpunit()->timeoutForMediumTests(); $timeoutForLargeTests = $xmlConfiguration->phpunit()->timeoutForLargeTests(); if ($cliConfiguration->hasReportUselessTests()) { $reportUselessTests = $cliConfiguration->reportUselessTests(); } else { $reportUselessTests = $xmlConfiguration->phpunit()->beStrictAboutTestsThatDoNotTestAnything(); } if ($cliConfiguration->hasStrictCoverage()) { $strictCoverage = $cliConfiguration->strictCoverage(); } else { $strictCoverage = $xmlConfiguration->phpunit()->beStrictAboutCoverageMetadata(); } if ($cliConfiguration->hasDisallowTestOutput()) { $disallowTestOutput = $cliConfiguration->disallowTestOutput(); } else { $disallowTestOutput = $xmlConfiguration->phpunit()->beStrictAboutOutputDuringTests(); } if ($cliConfiguration->hasDisplayDetailsOnAllIssues()) { $displayDetailsOnAllIssues = $cliConfiguration->displayDetailsOnAllIssues(); } else { $displayDetailsOnAllIssues = $xmlConfiguration->phpunit()->displayDetailsOnAllIssues(); } if ($cliConfiguration->hasDisplayDetailsOnIncompleteTests()) { $displayDetailsOnIncompleteTests = $cliConfiguration->displayDetailsOnIncompleteTests(); } else { $displayDetailsOnIncompleteTests = $xmlConfiguration->phpunit()->displayDetailsOnIncompleteTests(); } if ($cliConfiguration->hasDisplayDetailsOnSkippedTests()) { $displayDetailsOnSkippedTests = $cliConfiguration->displayDetailsOnSkippedTests(); } else { $displayDetailsOnSkippedTests = $xmlConfiguration->phpunit()->displayDetailsOnSkippedTests(); } if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerDeprecations()) { $displayDetailsOnTestsThatTriggerDeprecations = $cliConfiguration->displayDetailsOnTestsThatTriggerDeprecations(); } else { $displayDetailsOnTestsThatTriggerDeprecations = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerDeprecations(); } if ($cliConfiguration->hasDisplayDetailsOnPhpunitDeprecations()) { $displayDetailsOnPhpunitDeprecations = $cliConfiguration->displayDetailsOnPhpunitDeprecations(); } else { $displayDetailsOnPhpunitDeprecations = $xmlConfiguration->phpunit()->displayDetailsOnPhpunitDeprecations(); } if ($cliConfiguration->hasDisplayDetailsOnPhpunitNotices()) { $displayDetailsOnPhpunitNotices = $cliConfiguration->displayDetailsOnPhpunitNotices(); } else { $displayDetailsOnPhpunitNotices = $xmlConfiguration->phpunit()->displayDetailsOnPhpunitNotices(); } if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerErrors()) { $displayDetailsOnTestsThatTriggerErrors = $cliConfiguration->displayDetailsOnTestsThatTriggerErrors(); } else { $displayDetailsOnTestsThatTriggerErrors = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerErrors(); } if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerNotices()) { $displayDetailsOnTestsThatTriggerNotices = $cliConfiguration->displayDetailsOnTestsThatTriggerNotices(); } else { $displayDetailsOnTestsThatTriggerNotices = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerNotices(); } if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerWarnings()) { $displayDetailsOnTestsThatTriggerWarnings = $cliConfiguration->displayDetailsOnTestsThatTriggerWarnings(); } else { $displayDetailsOnTestsThatTriggerWarnings = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerWarnings(); } if ($cliConfiguration->hasReverseList()) { $reverseDefectList = $cliConfiguration->reverseList(); } else { $reverseDefectList = $xmlConfiguration->phpunit()->reverseDefectList(); } $requireCoverageMetadata = $xmlConfiguration->phpunit()->requireCoverageMetadata(); $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(); } $includeGitInformationInOtrLogfile = \false; if ($cliConfiguration->hasIncludeGitInformationInOtrLogfile()) { $includeGitInformationInOtrLogfile = $cliConfiguration->includeGitInformationInOtrLogfile(); } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasOtr()) { $includeGitInformationInOtrLogfile = $xmlConfiguration->logging()->otr()->includeGitInformation(); } if ($cliConfiguration->hasTestdoxHtmlFile()) { $logfileTestdoxHtml = $cliConfiguration->testdoxHtmlFile(); } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasTestDoxHtml()) { $logfileTestdoxHtml = $xmlConfiguration->logging()->testDoxHtml()->target()->path(); } if ($cliConfiguration->hasTestdoxTextFile()) { $logfileTestdoxText = $cliConfiguration->testdoxTextFile(); } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasTestDoxText()) { $logfileTestdoxText = $xmlConfiguration->logging()->testDoxText()->target()->path(); } $logEventsText = null; if ($cliConfiguration->hasLogEventsText()) { $logEventsText = $cliConfiguration->logEventsText(); } $logEventsVerboseText = null; if ($cliConfiguration->hasLogEventsVerboseText()) { $logEventsVerboseText = $cliConfiguration->logEventsVerboseText(); } $teamCityOutput = \false; if ($cliConfiguration->hasTeamCityPrinter() && $cliConfiguration->teamCityPrinter()) { $teamCityOutput = \true; } if ($cliConfiguration->hasTestDoxPrinter() && $cliConfiguration->testdoxPrinter()) { $testDoxOutput = \true; } else { $testDoxOutput = $xmlConfiguration->phpunit()->testdoxPrinter(); } if ($cliConfiguration->hasTestDoxPrinterSummary() && $cliConfiguration->testdoxPrinterSummary()) { $testDoxOutputSummary = \true; } else { $testDoxOutputSummary = $xmlConfiguration->phpunit()->testdoxPrinterSummary(); } $noProgress = \false; if ($cliConfiguration->hasNoProgress() && $cliConfiguration->noProgress()) { $noProgress = \true; } $noResults = \false; if ($cliConfiguration->hasNoResults() && $cliConfiguration->noResults()) { $noResults = \true; } $noOutput = \false; if ($cliConfiguration->hasNoOutput() && $cliConfiguration->noOutput()) { $noOutput = \true; } $testsCovering = null; if ($cliConfiguration->hasTestsCovering()) { $testsCovering = $cliConfiguration->testsCovering(); } $testsUsing = null; if ($cliConfiguration->hasTestsUsing()) { $testsUsing = $cliConfiguration->testsUsing(); } $testsRequiringPhpExtension = null; if ($cliConfiguration->hasTestsRequiringPhpExtension()) { $testsRequiringPhpExtension = $cliConfiguration->testsRequiringPhpExtension(); } $filter = null; if ($cliConfiguration->hasFilter()) { $filter = $cliConfiguration->filter(); } $excludeFilter = null; if ($cliConfiguration->hasExcludeFilter()) { $excludeFilter = $cliConfiguration->excludeFilter(); } $ignoreTestSelectionInXmlConfiguration = \false; if ($cliConfiguration->hasAll()) { $ignoreTestSelectionInXmlConfiguration = \true; } $groups = []; if ($cliConfiguration->hasGroups()) { $groups = $cliConfiguration->groups(); } elseif (!$ignoreTestSelectionInXmlConfiguration) { $groups = $xmlConfiguration->groups()->include()->asArrayOfStrings(); } $excludeGroups = []; if ($cliConfiguration->hasExcludeGroups()) { $excludeGroups = $cliConfiguration->excludeGroups(); } elseif (!$ignoreTestSelectionInXmlConfiguration) { $excludeGroups = $xmlConfiguration->groups()->exclude()->asArrayOfStrings(); } $excludeGroups = array_diff($excludeGroups, $groups); if ($cliConfiguration->hasRandomOrderSeed()) { $randomOrderSeed = $cliConfiguration->randomOrderSeed(); } else { $randomOrderSeed = time(); } if ($xmlConfiguration->wasLoadedFromFile() && $xmlConfiguration->hasValidationErrors()) { if ((new SchemaDetector())->detect($xmlConfiguration->filename())->detected()) { EventFacade::emitter()->testRunnerTriggeredPhpunitDeprecation('Your XML configuration validates against a deprecated schema. Migrate your XML configuration using "--migrate-configuration"!'); } else { EventFacade::emitter()->testRunnerTriggeredPhpunitWarning("Test results may not be as expected because the XML configuration file did not pass validation:\n" . $xmlConfiguration->validationErrors()); } } $includeUncoveredFiles = $xmlConfiguration->codeCoverage()->includeUncoveredFiles(); $includePaths = []; if ($cliConfiguration->hasIncludePath()) { foreach (explode(PATH_SEPARATOR, $cliConfiguration->includePath()) as $includePath) { $includePaths[] = new \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()), $testResultCacheFile, $coverageClover, $coverageCobertura, $coverageCrap4j, $coverageCrap4jThreshold, $coverageHtml, $coverageHtmlLowUpperBound, $coverageHtmlHighLowerBound, $coverageHtmlColorSuccessLow, $coverageHtmlColorSuccessMedium, $coverageHtmlColorSuccessHigh, $coverageHtmlColorWarning, $coverageHtmlColorDanger, $coverageHtmlCustomCssFile, $coverageOpenClover, $coveragePhp, $coverageText, $coverageTextShowUncoveredFiles, $coverageTextShowOnlySummary, $coverageXml, $coverageXmlIncludeSource, $pathCoverage, $xmlConfiguration->codeCoverage()->ignoreDeprecatedCodeUnits(), $disableCodeCoverageIgnore, $failOnAllIssues, $failOnDeprecation, $failOnPhpunitDeprecation, $failOnPhpunitNotice, $failOnPhpunitWarning, $failOnEmptyTestSuite, $failOnIncomplete, $failOnNotice, $failOnRisky, $failOnSkipped, $failOnWarning, $doNotFailOnDeprecation, $doNotFailOnPhpunitDeprecation, $doNotFailOnPhpunitNotice, $doNotFailOnPhpunitWarning, $doNotFailOnEmptyTestSuite, $doNotFailOnIncomplete, $doNotFailOnNotice, $doNotFailOnRisky, $doNotFailOnSkipped, $doNotFailOnWarning, $stopOnDefect, $stopOnDeprecation, $specificDeprecationToStopOn, $stopOnError, $stopOnFailure, $stopOnIncomplete, $stopOnNotice, $stopOnRisky, $stopOnSkipped, $stopOnWarning, $outputToStandardErrorStream, $columns, $noExtensions, $pharExtensionDirectory, $extensionBootstrappers, $backupGlobals, $backupStaticProperties, $beStrictAboutChangesToGlobalState, $colors, $processIsolation, $enforceTimeLimit, $defaultTimeLimit, $timeoutForSmallTests, $timeoutForMediumTests, $timeoutForLargeTests, $reportUselessTests, $strictCoverage, $disallowTestOutput, $displayDetailsOnAllIssues, $displayDetailsOnIncompleteTests, $displayDetailsOnSkippedTests, $displayDetailsOnTestsThatTriggerDeprecations, $displayDetailsOnPhpunitDeprecations, $displayDetailsOnPhpunitNotices, $displayDetailsOnTestsThatTriggerErrors, $displayDetailsOnTestsThatTriggerNotices, $displayDetailsOnTestsThatTriggerWarnings, $reverseDefectList, $requireCoverageMetadata, $requireSealedMockObjects, $noProgress, $noResults, $noOutput, $executionOrder, $executionOrderDefects, $resolveDependencies, $logfileTeamcity, $logfileJunit, $logfileOtr, $includeGitInformationInOtrLogfile, $logfileTestdoxHtml, $logfileTestdoxText, $logEventsText, $logEventsVerboseText, $teamCityOutput, $testDoxOutput, $testDoxOutputSummary, $testsCovering, $testsUsing, $testsRequiringPhpExtension, $filter, $excludeFilter, $groups, $excludeGroups, $randomOrderSeed, $includeUncoveredFiles, $xmlConfiguration->testSuite(), $includeTestSuite, $excludeTestSuite, $xmlConfiguration->phpunit()->hasDefaultTestSuite() ? $xmlConfiguration->phpunit()->defaultTestSuite() : null, $ignoreTestSelectionInXmlConfiguration, $testSuffixes, new \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()); } } * * 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\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 function file_get_contents; use function file_put_contents; use function is_array; use function realpath; use function serialize; 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]) { foreach ((new FileIteratorFacade())->getFilesAsArray($path, $suffixes, $prefixes) as $file) { $file = realpath($file); if (!$file) { continue; } $files[$file] = \true; } } foreach ($source->includeFiles() as $file) { $file = realpath($file->path()); if (!$file) { continue; } $files[$file] = \true; } $directories = $this->aggregateDirectories($source->excludeDirectories()); foreach ($directories as $path => [$prefixes, $suffixes]) { foreach ((new FileIteratorFacade())->getFilesAsArray($path, $suffixes, $prefixes) as $file) { $file = realpath($file); if (!$file) { continue; } if (!isset($files[$file])) { continue; } unset($files[$file]); } } foreach ($source->excludeFiles() as $file) { $file = realpath($file->path()); if (!$file) { continue; } if (!isset($files[$file])) { continue; } unset($files[$file]); } self::$files[$source] = $files; return $files; } /** * @return array,list}> */ private function aggregateDirectories(\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; /** * @param non-empty-string $path */ public function __construct(string $path, string $prefix, string $suffix) { $this->path = $path; $this->prefix = $prefix; $this->suffix = $suffix; } /** * @return non-empty-string */ public function path(): string { return $this->path; } public function prefix(): string { return $this->prefix; } public function suffix(): string { return $this->suffix; } } * * 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 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\FileCollection $includeFiles; private \PHPUnit\TextUI\Configuration\FilterDirectoryCollection $excludeDirectories; private \PHPUnit\TextUI\Configuration\FileCollection $excludeFiles; private bool $restrictNotices; private bool $restrictWarnings; private bool $ignoreSuppressionOfDeprecations; private bool $ignoreSuppressionOfPhpDeprecations; private bool $ignoreSuppressionOfErrors; private bool $ignoreSuppressionOfNotices; private bool $ignoreSuppressionOfPhpNotices; private bool $ignoreSuppressionOfWarnings; private bool $ignoreSuppressionOfPhpWarnings; private bool $ignoreSelfDeprecations; private bool $ignoreDirectDeprecations; private bool $ignoreIndirectDeprecations; private bool $identifyIssueTrigger; /** * @var array{functions: list, methods: list} */ private array $deprecationTriggers; /** * @param ?non-empty-string $baseline * @param array{functions: list, methods: list} $deprecationTriggers */ public function __construct(?string $baseline, bool $ignoreBaseline, \PHPUnit\TextUI\Configuration\FilterDirectoryCollection $includeDirectories, \PHPUnit\TextUI\Configuration\FileCollection $includeFiles, \PHPUnit\TextUI\Configuration\FilterDirectoryCollection $excludeDirectories, \PHPUnit\TextUI\Configuration\FileCollection $excludeFiles, bool $restrictNotices, bool $restrictWarnings, bool $ignoreSuppressionOfDeprecations, bool $ignoreSuppressionOfPhpDeprecations, bool $ignoreSuppressionOfErrors, bool $ignoreSuppressionOfNotices, bool $ignoreSuppressionOfPhpNotices, bool $ignoreSuppressionOfWarnings, bool $ignoreSuppressionOfPhpWarnings, array $deprecationTriggers, bool $ignoreSelfDeprecations, bool $ignoreDirectDeprecations, bool $ignoreIndirectDeprecations, bool $identifyIssueTrigger) { $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; } /** * @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\FileCollection { return $this->includeFiles; } public function excludeDirectories(): \PHPUnit\TextUI\Configuration\FilterDirectoryCollection { return $this->excludeDirectories; } public function excludeFiles(): \PHPUnit\TextUI\Configuration\FileCollection { return $this->excludeFiles; } public function notEmpty(): bool { return $this->includeDirectories->notEmpty() || $this->includeFiles->notEmpty(); } public function restrictNotices(): bool { return $this->restrictNotices; } public function restrictWarnings(): bool { return $this->restrictWarnings; } public function ignoreSuppressionOfDeprecations(): bool { return $this->ignoreSuppressionOfDeprecations; } public function ignoreSuppressionOfPhpDeprecations(): bool { return $this->ignoreSuppressionOfPhpDeprecations; } public function ignoreSuppressionOfErrors(): bool { return $this->ignoreSuppressionOfErrors; } public function ignoreSuppressionOfNotices(): bool { return $this->ignoreSuppressionOfNotices; } public function ignoreSuppressionOfPhpNotices(): bool { return $this->ignoreSuppressionOfPhpNotices; } public function ignoreSuppressionOfWarnings(): bool { return $this->ignoreSuppressionOfWarnings; } public function ignoreSuppressionOfPhpWarnings(): bool { return $this->ignoreSuppressionOfPhpWarnings; } /** * @return array{functions: list, methods: list} */ public function deprecationTriggers(): array { return $this->deprecationTriggers; } public function ignoreSelfDeprecations(): bool { return $this->ignoreSelfDeprecations; } public function ignoreDirectDeprecations(): bool { return $this->ignoreDirectDeprecations; } public function ignoreIndirectDeprecations(): bool { return $this->ignoreIndirectDeprecations; } public function identifyIssueTrigger(): bool { return $this->identifyIssueTrigger; } } * * 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; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @immutable */ final readonly class Html { private Directory $target; private int $lowUpperBound; private int $highLowerBound; private string $colorSuccessLow; private string $colorSuccessMedium; private string $colorSuccessHigh; private string $colorWarning; private string $colorDanger; private ?string $customCssFile; public function __construct(Directory $target, int $lowUpperBound, int $highLowerBound, string $colorSuccessLow, string $colorSuccessMedium, string $colorSuccessHigh, string $colorWarning, string $colorDanger, ?string $customCssFile) { $this->target = $target; $this->lowUpperBound = $lowUpperBound; $this->highLowerBound = $highLowerBound; $this->colorSuccessLow = $colorSuccessLow; $this->colorSuccessMedium = $colorSuccessMedium; $this->colorSuccessHigh = $colorSuccessHigh; $this->colorWarning = $colorWarning; $this->colorDanger = $colorDanger; $this->customCssFile = $customCssFile; } public function target(): Directory { return $this->target; } public function lowUpperBound(): int { return $this->lowUpperBound; } public function highLowerBound(): int { return $this->highLowerBound; } public function colorSuccessLow(): string { return $this->colorSuccessLow; } public function colorSuccessMedium(): string { return $this->colorSuccessMedium; } public function colorSuccessHigh(): string { return $this->colorSuccessHigh; } public function colorWarning(): string { return $this->colorWarning; } public function colorDanger(): string { return $this->colorDanger; } /** * @phpstan-assert-if-true !null $this->customCssFile */ public function hasCustomCssFile(): bool { return $this->customCssFile !== null; } /** * @throws NoCustomCssFileException */ public function customCssFile(): string { if (!$this->hasCustomCssFile()) { throw new NoCustomCssFileException(); } return $this->customCssFile; } } * * 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\FileCollection; use PHPUnit\TextUI\Configuration\FilterDirectoryCollection as CodeCoverageFilterDirectoryCollection; use PHPUnit\TextUI\Configuration\GroupCollection; use PHPUnit\TextUI\Configuration\IniSettingCollection; use PHPUnit\TextUI\Configuration\Php; use PHPUnit\TextUI\Configuration\Source; use PHPUnit\TextUI\Configuration\TestSuiteCollection; use PHPUnit\TextUI\Configuration\VariableCollection; use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit * * @immutable */ final readonly class DefaultConfiguration extends \PHPUnit\TextUI\XmlConfiguration\Configuration { public static function create(): self { return new self(ExtensionBootstrapCollection::fromArray([]), new Source(null, \false, CodeCoverageFilterDirectoryCollection::fromArray([]), FileCollection::fromArray([]), CodeCoverageFilterDirectoryCollection::fromArray([]), FileCollection::fromArray([]), \false, \false, \false, \false, \false, \false, \false, \false, \false, ['functions' => [], 'methods' => []], \false, \false, \false, \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, 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\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); 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); } $deprecationTriggers = ['functions' => [], 'methods' => []]; $functionNodes = $xpath->query('source/deprecationTrigger/function'); assert($functionNodes instanceof DOMNodeList); foreach ($functionNodes as $functionNode) { assert($functionNode instanceof DOMElement); $deprecationTriggers['functions'][] = $functionNode->textContent; } $methodNodes = $xpath->query('source/deprecationTrigger/method'); assert($methodNodes instanceof DOMNodeList); foreach ($methodNodes as $methodNode) { assert($methodNode instanceof DOMElement); $deprecationTriggers['methods'][] = $methodNode->textContent; } return new Source($baseline, \false, $this->readFilterDirectories($filename, $xpath, 'source/include/directory'), $this->readFilterFiles($filename, $xpath, 'source/include/file'), $this->readFilterDirectories($filename, $xpath, 'source/exclude/directory'), $this->readFilterFiles($filename, $xpath, 'source/exclude/file'), $restrictNotices, $restrictWarnings, $ignoreSuppressionOfDeprecations, $ignoreSuppressionOfPhpDeprecations, $ignoreSuppressionOfErrors, $ignoreSuppressionOfNotices, $ignoreSuppressionOfPhpNotices, $ignoreSuppressionOfWarnings, $ignoreSuppressionOfPhpWarnings, $deprecationTriggers, $ignoreSelfDeprecations, $ignoreDirectDeprecations, $ignoreIndirectDeprecations, $identifyIssueTrigger); } private function codeCoverage(string $filename, DOMXPath $xpath): CodeCoverage { $pathCoverage = \false; $includeUncoveredFiles = \true; $ignoreDeprecatedCodeUnits = \false; $disableCodeCoverageIgnore = \false; $element = $this->element($xpath, 'coverage'); if ($element !== null) { $pathCoverage = $this->parseBooleanAttribute($element, 'pathCoverage', \false); $includeUncoveredFiles = $this->parseBooleanAttribute($element, 'includeUncoveredFiles', \true); $ignoreDeprecatedCodeUnits = $this->parseBooleanAttribute($element, 'ignoreDeprecatedCodeUnits', \false); $disableCodeCoverageIgnore = $this->parseBooleanAttribute($element, 'disableCodeCoverageIgnore', \false); } $clover = null; $element = $this->element($xpath, 'coverage/report/clover'); if ($element !== null) { $clover = new Clover(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); } $cobertura = null; $element = $this->element($xpath, 'coverage/report/cobertura'); if ($element !== null) { $cobertura = new Cobertura(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); } $crap4j = null; $element = $this->element($xpath, 'coverage/report/crap4j'); if ($element !== null) { $crap4j = new Crap4j(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile'))), $this->parseIntegerAttribute($element, 'threshold', 30)); } $html = null; $element = $this->element($xpath, 'coverage/report/html'); if ($element !== null) { $defaultColors = Colors::default(); $defaultThresholds = Thresholds::default(); $html = new CodeCoverageHtml(new Directory($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputDirectory'))), $this->parseIntegerAttribute($element, 'lowUpperBound', $defaultThresholds->lowUpperBound()), $this->parseIntegerAttribute($element, 'highLowerBound', $defaultThresholds->highLowerBound()), $this->parseStringAttributeWithDefault($element, 'colorSuccessLow', $defaultColors->successLow()), $this->parseStringAttributeWithDefault($element, 'colorSuccessMedium', $defaultColors->successMedium()), $this->parseStringAttributeWithDefault($element, 'colorSuccessHigh', $defaultColors->successHigh()), $this->parseStringAttributeWithDefault($element, 'colorWarning', $defaultColors->warning()), $this->parseStringAttributeWithDefault($element, 'colorDanger', $defaultColors->danger()), $this->parseStringAttribute($element, 'customCssFile')); } $openClover = null; $element = $this->element($xpath, 'coverage/report/openclover'); if ($element !== null) { $openClover = new OpenClover(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); } $php = null; $element = $this->element($xpath, 'coverage/report/php'); if ($element !== null) { $php = new CodeCoveragePhp(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile')))); } $text = null; $element = $this->element($xpath, 'coverage/report/text'); if ($element !== null) { $text = new CodeCoverageText(new File($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputFile'))), $this->parseBooleanAttribute($element, 'showUncoveredFiles', \false), $this->parseBooleanAttribute($element, 'showOnlySummary', \false)); } $xml = null; $element = $this->element($xpath, 'coverage/report/xml'); if ($element !== null) { $xml = new CodeCoverageXml(new Directory($this->toAbsolutePath($filename, (string) $this->parseStringAttribute($element, 'outputDirectory'))), $this->parseBooleanAttribute($element, 'includeSource', \true)); } return new CodeCoverage($pathCoverage, $includeUncoveredFiles, $ignoreDeprecatedCodeUnits, $disableCodeCoverageIgnore, $clover, $cobertura, $crap4j, $html, $openClover, $php, $text, $xml); } private function booleanFromString(string $value, bool $default): bool { if (strtolower($value) === 'false') { return \false; } if (strtolower($value) === 'true') { return \true; } return $default; } private function valueFromString(string $value): bool|string { if (strtolower($value) === 'false') { return \false; } if (strtolower($value) === 'true') { return \true; } return $value; } private function readFilterDirectories(string $filename, DOMXPath $xpath, string $query): FilterDirectoryCollection { $directories = []; $directoryNodes = $xpath->query($query); assert($directoryNodes instanceof DOMNodeList); foreach ($directoryNodes as $directoryNode) { assert($directoryNode instanceof DOMElement); $directoryPath = $directoryNode->textContent; if ($directoryPath === '') { continue; } $directories[] = new FilterDirectory($this->toAbsolutePath($filename, $directoryPath), $directoryNode->hasAttribute('prefix') ? $directoryNode->getAttribute('prefix') : '', $directoryNode->hasAttribute('suffix') ? $directoryNode->getAttribute('suffix') : '.php'); } return FilterDirectoryCollection::fromArray($directories); } private function readFilterFiles(string $filename, DOMXPath $xpath, string $query): FileCollection { $files = []; $fileNodes = $xpath->query($query); assert($fileNodes instanceof DOMNodeList); foreach ($fileNodes as $fileNode) { assert($fileNode instanceof DOMNode); $filePath = $fileNode->textContent; if ($filePath !== '') { $files[] = new File($this->toAbsolutePath($filename, $filePath)); } } return FileCollection::fromArray($files); } private function groups(DOMXPath $xpath): \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), $this->parseBooleanAttribute($document->documentElement, 'failOnIncomplete', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnNotice', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnRisky', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnSkipped', \false), $this->parseBooleanAttribute($document->documentElement, 'failOnWarning', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnDefect', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnDeprecation', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnError', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnFailure', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnIncomplete', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnNotice', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnRisky', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnSkipped', \false), $this->parseBooleanAttribute($document->documentElement, 'stopOnWarning', \false), $extensionsDirectory, $this->parseBooleanAttribute($document->documentElement, 'beStrictAboutChangesToGlobalState', \false), $this->parseBooleanAttribute($document->documentElement, 'beStrictAboutOutputDuringTests', \false), $this->parseBooleanAttribute($document->documentElement, 'beStrictAboutTestsThatDoNotTestAnything', \true), $beStrictAboutCoverageMetadata, $this->parseBooleanAttribute($document->documentElement, 'enforceTimeLimit', \false), $this->parseIntegerAttribute($document->documentElement, 'defaultTimeLimit', 1), $this->parseIntegerAttribute($document->documentElement, 'timeoutForSmallTests', 1), $this->parseIntegerAttribute($document->documentElement, 'timeoutForMediumTests', 10), $this->parseIntegerAttribute($document->documentElement, 'timeoutForLargeTests', 60), $this->parseStringAttribute($document->documentElement, 'defaultTestSuite'), $executionOrder, $resolveDependencies, $defectsFirst, $this->parseBooleanAttribute($document->documentElement, 'backupGlobals', \false), $backupStaticProperties, $this->parseBooleanAttribute($document->documentElement, 'testdox', \false), $this->parseBooleanAttribute($document->documentElement, 'testdoxSummary', \false), $this->parseBooleanAttribute($document->documentElement, 'controlGarbageCollector', \false), $this->parseIntegerAttribute($document->documentElement, 'numberOfTestsBeforeGarbageCollection', 100), $shortenArraysForExportThreshold); } private function parseColors(DOMDocument $document): string { $colors = Configuration::COLOR_DEFAULT; if ($document->documentElement->hasAttribute('colors')) { /* only allow boolean for compatibility with previous versions 'always' only allowed from command line */ if ($this->booleanFromString($document->documentElement->getAttribute('colors'), \false)) { $colors = Configuration::COLOR_AUTO; } else { $colors = Configuration::COLOR_NEVER; } } return $colors; } private function parseColumns(DOMDocument $document): int|string { $columns = 80; if ($document->documentElement->hasAttribute('columns')) { $columns = $document->documentElement->getAttribute('columns'); if ($columns !== 'max') { $columns = $this->parseInteger($columns, 80); } } return $columns; } /** * @return array */ private function bootstrapForTestSuite(string $filename, DOMXPath $xpath): array { $bootstrapForTestSuite = []; foreach ($this->parseTestSuiteElements($xpath) as $element) { if (!$element->hasAttribute('bootstrap')) { continue; } $name = $element->getAttribute('name'); $bootstrap = $element->getAttribute('bootstrap'); assert($name !== ''); assert($bootstrap !== ''); $bootstrapForTestSuite[$name] = $this->toAbsolutePath($filename, $bootstrap); } return $bootstrapForTestSuite; } private function testSuite(string $filename, DOMXPath $xpath): TestSuiteCollection { $testSuites = []; foreach ($this->parseTestSuiteElements($xpath) as $element) { $exclude = []; foreach ($element->getElementsByTagName('exclude') as $excludeNode) { $excludeFile = $excludeNode->textContent; if ($excludeFile !== '') { $exclude[] = new File($this->toAbsolutePath($filename, $excludeFile)); } } $directories = []; foreach ($element->getElementsByTagName('directory') as $directoryNode) { assert($directoryNode instanceof DOMElement); $directory = $directoryNode->textContent; if ($directory === '') { continue; } $prefix = ''; if ($directoryNode->hasAttribute('prefix')) { $prefix = $directoryNode->getAttribute('prefix'); } $suffix = 'Test.php'; if ($directoryNode->hasAttribute('suffix')) { $suffix = $directoryNode->getAttribute('suffix'); } $phpVersion = PHP_VERSION; if ($directoryNode->hasAttribute('phpVersion')) { $phpVersion = $directoryNode->getAttribute('phpVersion'); } $phpVersionOperator = new VersionComparisonOperator('>='); if ($directoryNode->hasAttribute('phpVersionOperator')) { $phpVersionOperator = new VersionComparisonOperator($directoryNode->getAttribute('phpVersionOperator')); } $groups = []; if ($directoryNode->hasAttribute('groups')) { foreach (explode(',', $directoryNode->getAttribute('groups')) as $group) { $group = trim($group); if ($group === '') { continue; } $groups[] = $group; } } $directories[] = new TestDirectory($this->toAbsolutePath($filename, $directory), $prefix, $suffix, $phpVersion, $phpVersionOperator, $groups); } $files = []; foreach ($element->getElementsByTagName('file') as $fileNode) { assert($fileNode instanceof DOMElement); $file = $fileNode->textContent; if ($file === '') { continue; } $phpVersion = PHP_VERSION; if ($fileNode->hasAttribute('phpVersion')) { $phpVersion = $fileNode->getAttribute('phpVersion'); } $phpVersionOperator = new VersionComparisonOperator('>='); if ($fileNode->hasAttribute('phpVersionOperator')) { $phpVersionOperator = new VersionComparisonOperator($fileNode->getAttribute('phpVersionOperator')); } $groups = []; if ($fileNode->hasAttribute('groups')) { foreach (explode(',', $fileNode->getAttribute('groups')) as $group) { $group = trim($group); if ($group === '') { continue; } $groups[] = $group; } } $files[] = new TestFile($this->toAbsolutePath($filename, $file), $phpVersion, $phpVersionOperator, $groups); } $name = $element->getAttribute('name'); assert($name !== ''); $testSuites[] = new TestSuiteConfiguration($name, TestDirectoryCollection::fromArray($directories), TestFileCollection::fromArray($files), FileCollection::fromArray($exclude)); } return TestSuiteCollection::fromArray($testSuites); } /** * @return list */ private function parseTestSuiteElements(DOMXPath $xpath): array { $elements = []; $testSuiteNodes = $xpath->query('testsuites/testsuite'); assert($testSuiteNodes instanceof DOMNodeList); if ($testSuiteNodes->length === 0) { $testSuiteNodes = $xpath->query('testsuite'); assert($testSuiteNodes instanceof DOMNodeList); } if ($testSuiteNodes->length === 1) { $element = $testSuiteNodes->item(0); assert($element instanceof DOMElement); $elements[] = $element; } else { foreach ($testSuiteNodes as $testSuiteNode) { assert($testSuiteNode instanceof DOMElement); $elements[] = $testSuiteNode; } } return $elements; } private function element(DOMXPath $xpath, string $element): ?DOMElement { $nodes = $xpath->query($element); assert($nodes instanceof DOMNodeList); if ($nodes->length === 1) { $node = $nodes->item(0); assert($node instanceof DOMElement); return $node; } return null; } } * * 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.5' => [\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 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'); } if ($origin->version() === Version::series()) { throw new \PHPUnit\TextUI\XmlConfiguration\Exception('The file does not need to be migrated'); } $configurationDocument = (new XmlLoader())->loadFile($filename); 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; } } * * 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 $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 $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->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 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' => '--random-order-seed ', 'desc' => 'Use the specified random seed when running tests in random order']], 'Reporting' => [['arg' => '--colors ', 'desc' => 'Use colors in output ("never", "auto" or "always")'], ['arg' => '--columns ', 'desc' => 'Number of columns to use for progress output'], ['arg' => '--columns max', 'desc' => 'Use maximum number of columns for progress output'], ['arg' => '--stderr', 'desc' => 'Write to STDERR instead of STDOUT'], ['spacer' => ''], ['arg' => '--no-progress', 'desc' => 'Disable output of test execution progress'], ['arg' => '--no-results', 'desc' => 'Disable output of test results'], ['arg' => '--no-output', 'desc' => 'Disable all output'], ['spacer' => ''], ['arg' => '--display-incomplete', 'desc' => 'Display details for incomplete tests'], ['arg' => '--display-skipped', 'desc' => 'Display details for skipped tests'], ['arg' => '--display-deprecations', 'desc' => 'Display details for deprecations triggered by tests'], ['arg' => '--display-phpunit-deprecations', 'desc' => 'Display details for PHPUnit deprecations'], ['arg' => '--display-phpunit-notices', 'desc' => 'Display details for PHPUnit notices'], ['arg' => '--display-errors', 'desc' => 'Display details for errors triggered by tests'], ['arg' => '--display-notices', 'desc' => 'Display details for notices triggered by tests'], ['arg' => '--display-warnings', 'desc' => 'Display details for warnings triggered by tests'], ['arg' => '--display-all-issues', 'desc' => 'Display details for all issues that are triggered'], ['arg' => '--reverse-list', 'desc' => 'Print defects in reverse order'], ['spacer' => ''], ['arg' => '--teamcity', 'desc' => 'Replace default progress and result output with TeamCity format'], ['arg' => '--testdox', 'desc' => 'Replace default result output with TestDox format'], ['arg' => '--testdox-summary', 'desc' => 'Repeat TestDox output for tests with errors, failures, or issues'], ['spacer' => ''], ['arg' => '--debug', 'desc' => 'Replace default progress and result output with debugging information'], ['arg' => '--with-telemetry', 'desc' => 'Include telemetry information in debugging information output']], 'Logging' => [['arg' => '--log-junit ', 'desc' => 'Write test results in JUnit XML format to file'], ['arg' => '--log-otr ', 'desc' => 'Write test results in Open Test Reporting XML format to file'], ['arg' => '--include-git-information', 'desc' => 'Include Git information in Open Test Reporting XML logfile'], ['arg' => '--log-teamcity ', 'desc' => 'Write test results in TeamCity format to file'], ['arg' => '--testdox-html ', 'desc' => 'Write test results in TestDox format (HTML) to file'], ['arg' => '--testdox-text ', 'desc' => 'Write test results in TestDox format (plain text) to file'], ['arg' => '--log-events-text ', 'desc' => 'Stream events as plain text to file'], ['arg' => '--log-events-verbose-text ', 'desc' => 'Stream events as plain text with extended information to file'], ['arg' => '--no-logging', 'desc' => 'Ignore logging configured in the XML configuration file']], 'Code Coverage' => [['arg' => '--coverage-clover ', 'desc' => 'Write code coverage report in Clover XML format to file'], ['arg' => '--coverage-openclover ', 'desc' => 'Write code coverage report in OpenClover XML format to file'], ['arg' => '--coverage-cobertura ', 'desc' => 'Write code coverage report in Cobertura XML format to file'], ['arg' => '--coverage-crap4j ', 'desc' => 'Write code coverage report in Crap4J XML format to file'], ['arg' => '--coverage-html ', 'desc' => 'Write code coverage report in HTML format to directory'], ['arg' => '--coverage-php ', 'desc' => 'Write serialized code coverage data to file'], ['arg' => '--coverage-text=', 'desc' => 'Write code coverage report in text format to file [default: standard output]'], ['arg' => '--only-summary-for-coverage-text', 'desc' => 'Option for code coverage report in text format: only show summary'], ['arg' => '--show-uncovered-for-coverage-text', 'desc' => 'Option for code coverage report in text format: show uncovered files'], ['arg' => '--coverage-xml ', 'desc' => 'Write code coverage report in XML format to directory'], ['arg' => '--exclude-source-from-xml-coverage', 'desc' => 'Exclude element from code coverage report in XML format'], ['arg' => '--warm-coverage-cache', 'desc' => 'Warm static analysis cache'], ['arg' => '--coverage-filter ', 'desc' => 'Include in code coverage reporting'], ['arg' => '--path-coverage', 'desc' => 'Report path coverage in addition to line coverage'], ['arg' => '--disable-coverage-ignore', 'desc' => 'Disable metadata for ignoring code coverage'], ['arg' => '--no-coverage', 'desc' => 'Ignore code coverage reporting configured in the XML configuration file']]]; if (defined('__PHPUNIT_PHAR__')) { $elements['PHAR'] = [['arg' => '--manifest', 'desc' => 'Print Software Bill of Materials (SBOM) in plain-text format'], ['arg' => '--sbom', 'desc' => 'Print Software Bill of Materials (SBOM) in CycloneDX XML format'], ['arg' => '--composer-lock', 'desc' => 'Print composer.lock file used to build the PHAR']]; } $elements['Miscellaneous'] = [['arg' => '-h|--help', 'desc' => 'Prints this usage information'], ['arg' => '--version', 'desc' => 'Prints the version and exits'], ['arg' => '--atleast-version ', 'desc' => 'Checks that version is greater than and exits'], ['arg' => '--check-version', 'desc' => 'Checks whether PHPUnit is the latest version and exits'], ['arg' => '--check-php-configuration', 'desc' => 'Checks whether PHP configuration follows best practices']]; return $elements; } } * * 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\BeforeFirstTestMethodErrored; use PHPUnit\Event\Test\ConsideredRisky; use PHPUnit\Event\Test\DeprecationTriggered; use PHPUnit\Event\Test\ErrorTriggered; use PHPUnit\Event\Test\NoticeTriggered; use PHPUnit\Event\Test\PhpDeprecationTriggered; use PHPUnit\Event\Test\PhpNoticeTriggered; use PHPUnit\Event\Test\PhpunitDeprecationTriggered; use PHPUnit\Event\Test\PhpunitErrorTriggered; use PHPUnit\Event\Test\PhpunitNoticeTriggered; use PHPUnit\Event\Test\PhpunitWarningTriggered; use PHPUnit\Event\Test\PhpWarningTriggered; use PHPUnit\Event\Test\WarningTriggered; use PHPUnit\TestRunner\TestResult\Issues\Issue; use PHPUnit\TestRunner\TestResult\TestResult; use PHPUnit\TextUI\Output\Printer; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final class ResultPrinter { private readonly Printer $printer; private readonly bool $displayPhpunitDeprecations; private readonly bool $displayPhpunitErrors; private readonly bool $displayPhpunitNotices; private readonly bool $displayPhpunitWarnings; private readonly bool $displayTestsWithErrors; private readonly bool $displayTestsWithFailedAssertions; private readonly bool $displayRiskyTests; private readonly bool $displayDetailsOnIncompleteTests; private readonly bool $displayDetailsOnSkippedTests; private readonly bool $displayDetailsOnTestsThatTriggerDeprecations; private readonly bool $displayDetailsOnTestsThatTriggerErrors; private readonly bool $displayDetailsOnTestsThatTriggerNotices; private readonly bool $displayDetailsOnTestsThatTriggerWarnings; private readonly bool $displayDefectsInReverseOrder; private bool $listPrinted = \false; public function __construct(Printer $printer, bool $displayPhpunitDeprecations, bool $displayPhpunitErrors, bool $displayPhpunitNotices, bool $displayPhpunitWarnings, bool $displayTestsWithErrors, bool $displayTestsWithFailedAssertions, bool $displayRiskyTests, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $displayDefectsInReverseOrder) { $this->printer = $printer; $this->displayPhpunitDeprecations = $displayPhpunitDeprecations; $this->displayPhpunitErrors = $displayPhpunitErrors; $this->displayPhpunitNotices = $displayPhpunitNotices; $this->displayPhpunitWarnings = $displayPhpunitWarnings; $this->displayTestsWithErrors = $displayTestsWithErrors; $this->displayTestsWithFailedAssertions = $displayTestsWithFailedAssertions; $this->displayRiskyTests = $displayRiskyTests; $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; $this->displayDefectsInReverseOrder = $displayDefectsInReverseOrder; } public function print(TestResult $result, bool $stackTraceForDeprecations = \false): void { if ($this->displayPhpunitErrors) { $this->printPhpunitErrors($result); } if ($this->displayPhpunitWarnings) { $this->printTestRunnerWarnings($result); } if ($this->displayPhpunitDeprecations) { $this->printTestRunnerDeprecations($result); } if ($this->displayPhpunitNotices) { $this->printTestRunnerNotices($result); } if ($this->displayTestsWithErrors) { $this->printTestsWithErrors($result); } if ($this->displayTestsWithFailedAssertions) { $this->printTestsWithFailedAssertions($result); } if ($this->displayPhpunitWarnings) { $this->printDetailsOnTestsThatTriggeredPhpunitWarnings($result); } if ($this->displayPhpunitDeprecations) { $this->printDetailsOnTestsThatTriggeredPhpunitDeprecations($result); } if ($this->displayRiskyTests) { $this->printRiskyTests($result); } if ($this->displayPhpunitNotices) { $this->printDetailsOnTestsThatTriggeredPhpunitNotices($result); } if ($this->displayDetailsOnIncompleteTests) { $this->printIncompleteTests($result); } if ($this->displayDetailsOnSkippedTests) { $this->printSkippedTestSuites($result); $this->printSkippedTests($result); } if ($this->displayDetailsOnTestsThatTriggerErrors) { $this->printIssueList('error', $result->errors()); } if ($this->displayDetailsOnTestsThatTriggerWarnings) { $this->printIssueList('PHP warning', $result->phpWarnings()); $this->printIssueList('warning', $result->warnings()); } if ($this->displayDetailsOnTestsThatTriggerNotices) { $this->printIssueList('PHP notice', $result->phpNotices()); $this->printIssueList('notice', $result->notices()); } if ($this->displayDetailsOnTestsThatTriggerDeprecations) { $this->printIssueList('PHP deprecation', $result->phpDeprecations()); $this->printIssueList('deprecation', $result->deprecations(), $stackTraceForDeprecations); } } private function printPhpunitErrors(TestResult $result): void { if (!$result->hasTestTriggeredPhpunitErrorEvents()) { return; } $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitErrorEvents()); $this->printListHeaderWithNumber($elements['numberOfTestsWithIssues'], 'PHPUnit error'); $this->printList($elements['elements']); } private function printDetailsOnTestsThatTriggeredPhpunitDeprecations(TestResult $result): void { if (!$result->hasTestTriggeredPhpunitDeprecationEvents()) { return; } $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitDeprecationEvents()); $this->printListHeaderWithNumberOfTestsAndNumberOfIssues($elements['numberOfTestsWithIssues'], $elements['numberOfIssues'], 'PHPUnit deprecation'); $this->printList($elements['elements']); } private function printDetailsOnTestsThatTriggeredPhpunitNotices(TestResult $result): void { if (!$result->hasTestTriggeredPhpunitNoticeEvents()) { return; } $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitNoticeEvents()); $this->printListHeaderWithNumberOfTestsAndNumberOfIssues($elements['numberOfTestsWithIssues'], $elements['numberOfIssues'], 'PHPUnit notice'); $this->printList($elements['elements']); } private function printTestRunnerNotices(TestResult $result): void { if (!$result->hasTestRunnerTriggeredNoticeEvents()) { return; } $elements = []; $messages = []; foreach ($result->testRunnerTriggeredNoticeEvents() as $event) { if (isset($messages[$event->message()])) { continue; } $elements[] = ['title' => $event->message(), 'body' => '']; $messages[$event->message()] = \true; } $this->printListHeaderWithNumber(count($elements), 'PHPUnit test runner notice'); $this->printList($elements); } private function printTestRunnerWarnings(TestResult $result): void { if (!$result->hasTestRunnerTriggeredWarningEvents()) { return; } $elements = []; $messages = []; foreach ($result->testRunnerTriggeredWarningEvents() as $event) { if (isset($messages[$event->message()])) { continue; } $elements[] = ['title' => $event->message(), 'body' => '']; $messages[$event->message()] = \true; } $this->printListHeaderWithNumber(count($elements), 'PHPUnit test runner warning'); $this->printList($elements); } private function printTestRunnerDeprecations(TestResult $result): void { if (!$result->hasTestRunnerTriggeredDeprecationEvents()) { return; } $elements = []; foreach ($result->testRunnerTriggeredDeprecationEvents() as $event) { $elements[] = ['title' => $event->message(), 'body' => '']; } $this->printListHeaderWithNumber(count($elements), 'PHPUnit test runner deprecation'); $this->printList($elements); } private function printDetailsOnTestsThatTriggeredPhpunitWarnings(TestResult $result): void { if (!$result->hasTestTriggeredPhpunitWarningEvents()) { return; } $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitWarningEvents()); $this->printListHeaderWithNumberOfTestsAndNumberOfIssues($elements['numberOfTestsWithIssues'], $elements['numberOfIssues'], 'PHPUnit warning'); $this->printList($elements['elements']); } private function printTestsWithErrors(TestResult $result): void { if (!$result->hasTestErroredEvents()) { return; } $elements = []; foreach ($result->testErroredEvents() as $event) { if ($event instanceof AfterLastTestMethodErrored || $event instanceof BeforeFirstTestMethodErrored) { $title = $event->testClassName(); } else { $title = $this->name($event->test()); } $elements[] = ['title' => $title, 'body' => $event->throwable()->asString()]; } $this->printListHeaderWithNumber(count($elements), 'error'); $this->printList($elements); } private function printTestsWithFailedAssertions(TestResult $result): void { if (!$result->hasTestFailedEvents()) { return; } $elements = []; foreach ($result->testFailedEvents() as $event) { $body = $event->throwable()->asString(); if (str_starts_with($body, 'AssertionError: ')) { $body = substr($body, strlen('AssertionError: ')); } $elements[] = ['title' => $this->name($event->test()), 'body' => $body]; } $this->printListHeaderWithNumber(count($elements), 'failure'); $this->printList($elements); } private function printRiskyTests(TestResult $result): void { if (!$result->hasTestConsideredRiskyEvents()) { return; } $elements = $this->mapTestsWithIssuesEventsToElements($result->testConsideredRiskyEvents()); $this->printListHeaderWithNumber($elements['numberOfTestsWithIssues'], 'risky test'); $this->printList($elements['elements']); } private function printIncompleteTests(TestResult $result): void { if (!$result->hasTestMarkedIncompleteEvents()) { return; } $elements = []; foreach ($result->testMarkedIncompleteEvents() as $event) { $elements[] = ['title' => $this->name($event->test()), 'body' => $event->throwable()->asString()]; } $this->printListHeaderWithNumber(count($elements), 'incomplete test'); $this->printList($elements); } private function printSkippedTestSuites(TestResult $result): void { if (!$result->hasTestSuiteSkippedEvents()) { return; } $elements = []; foreach ($result->testSuiteSkippedEvents() as $event) { $elements[] = ['title' => $event->testSuite()->name(), 'body' => $event->message()]; } $this->printListHeaderWithNumber(count($elements), 'skipped test suite'); $this->printList($elements); } private function printSkippedTests(TestResult $result): void { if (!$result->hasTestSkippedEvents()) { return; } $elements = []; foreach ($result->testSkippedEvents() as $event) { $elements[] = ['title' => $this->name($event->test()), 'body' => $event->message()]; } $this->printListHeaderWithNumber(count($elements), 'skipped test'); $this->printList($elements); } /** * @param non-empty-string $type * @param list $issues */ private function printIssueList(string $type, array $issues, bool $stackTrace = \false): void { if ($issues === []) { return; } $numberOfUniqueIssues = count($issues); $triggeringTests = []; foreach ($issues as $issue) { $triggeringTests = array_merge($triggeringTests, array_keys($issue->triggeringTests())); } $numberOfTests = count(array_unique($triggeringTests)); unset($triggeringTests); $this->printListHeader(sprintf('%d test%s triggered %d %s%s:' . PHP_EOL . PHP_EOL, $numberOfTests, $numberOfTests !== 1 ? 's' : '', $numberOfUniqueIssues, $type, $numberOfUniqueIssues !== 1 ? 's' : '')); $i = 1; foreach ($issues as $issue) { $title = sprintf('%s:%d', $issue->file(), $issue->line()); $body = trim($issue->description()) . PHP_EOL . PHP_EOL; if ($stackTrace && $issue->hasStackTrace()) { $body .= trim($issue->stackTrace()) . PHP_EOL . PHP_EOL; } if (!$issue->triggeredInTest()) { $body .= 'Triggered by:'; $triggeringTests = $issue->triggeringTests(); ksort($triggeringTests); foreach ($triggeringTests as $triggeringTest) { $body .= PHP_EOL . PHP_EOL . '* ' . $triggeringTest['test']->id(); if ($triggeringTest['count'] > 1) { $body .= sprintf(' (%d times)', $triggeringTest['count']); } if ($triggeringTest['test']->isTestMethod()) { $body .= PHP_EOL . ' ' . $triggeringTest['test']->file() . ':' . $triggeringTest['test']->line(); } } } $this->printIssueListElement($i++, $title, $body); $this->printer->print(PHP_EOL); } } private function printListHeaderWithNumberOfTestsAndNumberOfIssues(int $numberOfTestsWithIssues, int $numberOfIssues, string $type): void { $this->printListHeader(sprintf("%d test%s triggered %d %s%s:\n\n", $numberOfTestsWithIssues, $numberOfTestsWithIssues !== 1 ? 's' : '', $numberOfIssues, $type, $numberOfIssues !== 1 ? 's' : '')); } private function printListHeaderWithNumber(int $number, string $type): void { $this->printListHeader(sprintf("There %s %d %s%s:\n\n", $number === 1 ? 'was' : 'were', $number, $type, $number === 1 ? '' : 's')); } private function printListHeader(string $header): void { if ($this->listPrinted) { $this->printer->print("--\n\n"); } $this->listPrinted = \true; $this->printer->print($header); } /** * @param list $elements */ private function printList(array $elements): void { $i = 1; if ($this->displayDefectsInReverseOrder) { $elements = array_reverse($elements); } foreach ($elements as $element) { $this->printListElement($i++, $element['title'], $element['body']); } $this->printer->print("\n"); } private function printListElement(int $number, string $title, string $body): void { $body = trim($body); $this->printer->print(sprintf("%s%d) %s\n%s%s", $number > 1 ? "\n" : '', $number, $title, $body, $body !== '' ? "\n" : '')); } private function printIssueListElement(int $number, string $title, string $body): void { $body = trim($body); $this->printer->print(sprintf("%d) %s\n%s%s", $number, $title, $body, $body !== '' ? "\n" : '')); } private function name(Test $test): string { if ($test->isTestMethod()) { assert($test instanceof TestMethod); if (!$test->testData()->hasDataFromDataProvider()) { return $test->nameWithClass(); } return $test->className() . '::' . $test->methodName() . $test->testData()->dataFromDataProvider()->dataAsStringForResultOutput(); } return $test->name(); } /** * @param array> $events * * @return array{numberOfTestsWithIssues: int, numberOfIssues: int, elements: list} */ private function mapTestsWithIssuesEventsToElements(array $events): array { $elements = []; $issues = 0; foreach ($events as $reasons) { $test = $reasons[0]->test(); $testLocation = $this->testLocation($test); $title = $this->name($test); $body = ''; $first = \true; $single = count($reasons) === 1; foreach ($reasons as $reason) { if ($first) { $first = \false; } else { $body .= PHP_EOL; } $body .= $this->reasonMessage($reason, $single); $body .= $this->reasonLocation($reason, $single); $issues++; } if ($testLocation !== '') { $body .= $testLocation; } $elements[] = ['title' => $title, 'body' => $body]; } return ['numberOfTestsWithIssues' => count($events), 'numberOfIssues' => $issues, 'elements' => $elements]; } private function testLocation(Test $test): string { if (!$test->isTestMethod()) { return ''; } assert($test instanceof TestMethod); return sprintf('%s%s:%d%s', PHP_EOL, $test->file(), $test->line(), PHP_EOL); } private function reasonMessage(ConsideredRisky|DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpunitDeprecationTriggered|PhpunitErrorTriggered|PhpunitNoticeTriggered|PhpunitWarningTriggered|PhpWarningTriggered|WarningTriggered $reason, bool $single): string { $message = trim($reason->message()); if ($single) { return $message . PHP_EOL; } $lines = explode(PHP_EOL, $message); $buffer = '* ' . $lines[0] . PHP_EOL; if (count($lines) > 1) { foreach (range(1, count($lines) - 1) as $line) { $buffer .= ' ' . $lines[$line] . PHP_EOL; } } return $buffer; } private function reasonLocation(ConsideredRisky|DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpunitDeprecationTriggered|PhpunitErrorTriggered|PhpunitNoticeTriggered|PhpunitWarningTriggered|PhpWarningTriggered|WarningTriggered $reason, bool $single): string { if (!$reason instanceof DeprecationTriggered && !$reason instanceof PhpDeprecationTriggered && !$reason instanceof ErrorTriggered && !$reason instanceof NoticeTriggered && !$reason instanceof PhpNoticeTriggered && !$reason instanceof WarningTriggered && !$reason instanceof PhpWarningTriggered) { return ''; } return sprintf('%s%s:%d%s', $single ? '' : ' ', $reason->file(), $reason->line(), PHP_EOL); } } * * 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 $prettifiedClassName => $_tests) { $print = \true; if ($onlySummary) { $found = \false; foreach ($_tests as $test) { if ($test->status()->isSuccess()) { continue; } $found = \true; break; } if (!$found) { $print = \false; } } if (!$print) { continue; } $this->printPrettifiedClassName($prettifiedClassName); foreach ($_tests as $test) { if ($onlySummary && $test->status()->isSuccess()) { continue; } $this->printTestResult($test); } $this->printer->print(PHP_EOL); } } private function printPrettifiedClassName(string $prettifiedClassName): void { $buffer = $prettifiedClassName; if ($this->colors) { $buffer = Color::colorizeTextBox('underlined', $buffer); } $this->printer->print($buffer . PHP_EOL); } private function printTestResult(TestDoxTestResult $test): void { $this->printTestResultHeader($test); $this->printTestResultBody($test); } private function printTestResultHeader(TestDoxTestResult $test): void { $buffer = ' ' . $this->symbolFor($test->status()) . ' '; if ($this->colors) { $this->printer->print(Color::colorizeTextBox($this->colorFor($test->status()), $buffer)); } else { $this->printer->print($buffer); } $this->printer->print($test->test()->testDox()->prettifiedMethodName($this->colors) . PHP_EOL); } private function printTestResultBody(TestDoxTestResult $test): void { if ($test->status()->isSuccess()) { return; } if (!$test->hasThrowable()) { return; } $this->printTestResultBodyStart($test); $this->printThrowable($test->status(), $test->throwable()); $this->printTestResultBodyEnd($test); } private function printTestResultBodyStart(TestDoxTestResult $test): void { $this->printer->print($this->prefixLines($this->prefixFor('start', $test->status()), '')); $this->printer->print(PHP_EOL); } private function printTestResultBodyEnd(TestDoxTestResult $test): void { $this->printer->print(PHP_EOL); $this->printer->print($this->prefixLines($this->prefixFor('last', $test->status()), '')); $this->printer->print(PHP_EOL); } private function printThrowable(TestStatus $status, Throwable $throwable): void { $message = trim($throwable->description()); $stackTrace = $this->formatStackTrace($throwable->stackTrace()); $diff = ''; if ($message !== '' && $this->colors) { ['message' => $message, 'diff' => $diff] = $this->colorizeMessageAndDiff($message, $this->messageColorFor($status)); } if ($message !== '') { $this->printer->print($this->prefixLines($this->prefixFor('message', $status), $message)); $this->printer->print(PHP_EOL); } if ($diff !== '') { $this->printer->print($this->prefixLines($this->prefixFor('diff', $status), $diff)); $this->printer->print(PHP_EOL); } if ($stackTrace !== '') { if ($message !== '' || $diff !== '') { $tracePrefix = $this->prefixFor('default', $status); } else { $tracePrefix = $this->prefixFor('trace', $status); } $this->printer->print($this->prefixLines($tracePrefix, PHP_EOL . $stackTrace)); } if ($throwable->hasPrevious()) { $this->printer->print(PHP_EOL); $this->printer->print($this->prefixLines($this->prefixFor('default', $status), ' ')); $this->printer->print(PHP_EOL); $this->printer->print($this->prefixLines($this->prefixFor('default', $status), 'Caused by:')); $this->printer->print(PHP_EOL); $this->printThrowable($status, $throwable->previous()); } } /** * @return array{message: string, diff: string} */ private function colorizeMessageAndDiff(string $buffer, string $style): array { $lines = []; if ($buffer !== '') { $lines = array_map(\rtrim(...), explode(PHP_EOL, $buffer)); } $message = []; $diff = []; $insideDiff = \false; foreach ($lines as $line) { if ($line === '--- Expected') { $insideDiff = \true; } if (!$insideDiff) { $message[] = $line; } else { if (str_starts_with($line, '-')) { $line = Color::colorize('fg-red', Color::visualizeWhitespace($line, \true)); } elseif (str_starts_with($line, '+')) { $line = Color::colorize('fg-green', Color::visualizeWhitespace($line, \true)); } elseif ($line === '@@ @@') { $line = Color::colorize('fg-cyan', $line); } $diff[] = $line; } } $message = implode(PHP_EOL, $message); $diff = implode(PHP_EOL, $diff); if ($message !== '') { // Testdox output has a left-margin of 5; keep right-margin to prevent terminal scrolling $message = Color::colorizeTextBox($style, $message, $this->columns - 7); } return ['message' => $message, 'diff' => $diff]; } private function formatStackTrace(string $stackTrace): string { if (!$this->colors) { return rtrim($stackTrace); } $lines = []; $previousPath = ''; foreach (explode(PHP_EOL, $stackTrace) as $line) { if (preg_match('/^(.*):(\d+)$/', $line, $matches) > 0) { $lines[] = Color::colorizePath($matches[1], $previousPath) . Color::dim(':') . Color::colorize('fg-blue', $matches[2]) . "\n"; $previousPath = $matches[1]; continue; } $lines[] = $line; $previousPath = ''; } return rtrim(implode('', $lines)); } private function prefixLines(string $prefix, string $message): string { $lines = preg_split('/\r\n|\r|\n/', $message); if ($lines === \false) { $lines = []; } return implode(PHP_EOL, array_map(static fn(string $line) => ' ' . $prefix . ($line !== '' ? ' ' . $line : ''), $lines)); } /** * @param 'default'|'diff'|'last'|'message'|'start'|'trace' $type */ private function prefixFor(string $type, TestStatus $status): string { if (!$this->colors) { return '│'; } return Color::colorize($this->colorFor($status), match ($type) { 'default' => '│', 'start' => 'â”', 'message' => '├', 'diff' => '┊', 'trace' => '╵', 'last' => 'â”´', }); } private function colorFor(TestStatus $status): string { if ($status->isSuccess()) { return 'fg-green'; } if ($status->isError()) { return 'fg-yellow'; } if ($status->isFailure()) { return 'fg-red'; } if ($status->isSkipped()) { return 'fg-cyan'; } if ($status->isIncomplete() || $status->isDeprecation() || $status->isNotice() || $status->isRisky() || $status->isWarning()) { return 'fg-yellow'; } return 'fg-blue'; } private function messageColorFor(TestStatus $status): string { if ($status->isSuccess()) { return ''; } if ($status->isError()) { return 'bg-yellow,fg-black'; } if ($status->isFailure()) { return 'bg-red,fg-white'; } if ($status->isSkipped()) { return 'fg-cyan'; } if ($status->isIncomplete() || $status->isDeprecation() || $status->isNotice() || $status->isRisky() || $status->isWarning()) { return 'fg-yellow'; } return 'fg-white,bg-blue'; } private function symbolFor(TestStatus $status): string { if ($status->isSuccess()) { return '✔'; } if ($status->isError() || $status->isFailure()) { return '✘'; } if ($status->isSkipped()) { return '↩'; } if ($status->isDeprecation() || $status->isNotice() || $status->isRisky() || $status->isWarning()) { return 'âš '; } if ($status->isIncomplete()) { return '∅'; } return '?'; } /** * @param 'after-last-test'|'before-first-test' $type * @param array $errors */ private function printBeforeClassOrAfterClassErrors(string $type, array $errors): void { if ($errors === []) { return; } $this->printer->print(sprintf('These %s methods errored:' . PHP_EOL . PHP_EOL, $type)); $index = 0; foreach ($errors as $method => $error) { $this->printer->print(sprintf('%d) %s' . PHP_EOL, ++$index, $method)); $this->printer->print(trim($error->throwable()->description()) . PHP_EOL . PHP_EOL); $this->printer->print($this->formatStackTrace($error->throwable()->stackTrace()) . PHP_EOL); } $this->printer->print(PHP_EOL); } } * * 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 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 self::exporter()->export($value); } /** * @param array $data */ public static function shortenedRecursiveExport(array $data): string { return self::exporter()->shortenedRecursiveExport($data); } public static function shortenedExport(mixed $value): string { return self::exporter()->shortenedExport($value); } private static function exporter(): OriginalExporter { if (self::$exporter !== null) { return self::$exporter; } self::$exporter = new OriginalExporter(ConfigurationRegistry::get()->shortenArraysForExportThreshold()); return self::$exporter; } } * * 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; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final readonly class GlobalState { /** * @var non-empty-list */ private const array SUPER_GLOBAL_ARRAYS = ['_ENV', '_POST', '_GET', '_COOKIE', '_SERVER', '_FILES', '_REQUEST']; /** * @var non-empty-array> */ private const array DEPRECATED_INI_SETTINGS = ['7.3' => ['iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.func_overload' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'string.strip_tags' => \true], '7.4' => ['iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.func_overload' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'pdo_odbc.db2_instance_name' => \true, 'string.strip_tags' => \true], '8.0' => ['iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true], '8.1' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true], '8.2' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true], '8.3' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true], '8.4' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true], '8.5' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true], '8.6' => ['auto_detect_line_endings' => \true, 'filter.default' => \true, 'iconv.input_encoding' => \true, 'iconv.output_encoding' => \true, 'iconv.internal_encoding' => \true, 'mbstring.http_input' => \true, 'mbstring.http_output' => \true, 'mbstring.internal_encoding' => \true, 'oci8.old_oci_close_semantics' => \true]]; /** * @throws Exception */ public static function getIncludedFilesAsString(): string { return self::processIncludedFilesAsString(get_included_files()); } /** * @param list $files * * @throws Exception */ public static function processIncludedFilesAsString(array $files): string { $excludeList = new \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 getGlobalsAsString(): string { $result = ''; foreach (self::SUPER_GLOBAL_ARRAYS as $superGlobalArray) { if (isset($GLOBALS[$superGlobalArray]) && is_array($GLOBALS[$superGlobalArray])) { foreach ($GLOBALS[$superGlobalArray] as $key => $value) { if ($value instanceof Closure) { continue; } $result .= sprintf('$GLOBALS[\'%s\'][\'%s\'] = %s;' . "\n", $superGlobalArray, $key, self::exportVariable($GLOBALS[$superGlobalArray][$key])); } } } $excludeList = self::SUPER_GLOBAL_ARRAYS; $excludeList[] = 'GLOBALS'; foreach ($GLOBALS as $key => $value) { if (!$value instanceof Closure && !in_array($key, $excludeList, \true)) { $result .= sprintf('$GLOBALS[\'%s\'] = %s;' . "\n", $key, self::exportVariable($value)); } } return $result; } private static function exportVariable(mixed $variable): string { if (is_scalar($variable) || $variable === null || is_array($variable) && self::arrayOnlyContainsScalars($variable)) { return var_export($variable, \true); } return 'unserialize(' . var_export(serialize($variable), \true) . ')'; } /** * @param array $array */ private static function arrayOnlyContainsScalars(array $array): bool { $result = \true; foreach ($array as $element) { if (is_array($element)) { $result = self::arrayOnlyContainsScalars($element); } elseif (!is_scalar($element) && $element !== null) { $result = \false; } if (!$result) { break; } } return $result; } private static function isIniSettingDeprecated(string $iniSetting): bool { return isset(self::DEPRECATED_INI_SETTINGS[PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION][$iniSetting]); } } * * 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; use const PHP_BINARY; use const PHP_SAPI; use function array_any; use function array_keys; use function array_merge; use function array_values; use function assert; use function fclose; use function file_put_contents; use function function_exists; use function fwrite; use function ini_get_all; use function is_array; use function is_resource; use function proc_close; use function proc_open; use function str_starts_with; use function stream_get_contents; use function sys_get_temp_dir; use function tempnam; use function trim; use function unlink; use function xdebug_is_debugger_active; use PHPUnit\Event\Facade; use PHPUnit\Runner\CodeCoverage; use 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 DefaultJobRunner extends \PHPUnit\Util\PHP\JobRunner { /** * @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 = array_any($phpSettings, static fn(string $phpSetting) => str_starts_with($phpSetting, 'xdebug.mode')); if ($runtime->hasPCOV()) { $pcovSettings = ini_get_all('pcov'); assert($pcovSettings !== \false); $phpSettings = array_merge($phpSettings, $runtime->getCurrentSettings(array_keys($pcovSettings))); } elseif ($runtime->hasXdebug()) { assert(function_exists('xdebug_is_debugger_active')); $xdebugSettings = ini_get_all('xdebug'); assert($xdebugSettings !== \false); $phpSettings = array_merge($phpSettings, $runtime->getCurrentSettings(array_keys($xdebugSettings))); if (!$xdebugModeConfiguredExplicitly && !CodeCoverage::instance()->isActive() && xdebug_is_debugger_active() === \false && !$job->requiresXdebug()) { // disable xdebug to speedup test execution $phpSettings['xdebug.mode'] = 'xdebug.mode=off'; } } $command = array_merge($command, $this->settingsToParameters(array_values($phpSettings))); if (PHP_SAPI === 'phpdbg') { $command[] = '-qrr'; if ($file === null) { $command[] = 's='; } } if ($file !== null) { $command[] = '-f'; $command[] = $file; } if ($job->hasArguments()) { if ($file === null) { $command[] = '--'; } foreach ($job->arguments() as $argument) { $command[] = trim($argument); } } return $command; } /** * @param list $settings * * @return list */ private function settingsToParameters(array $settings): array { $buffer = []; foreach ($settings as $setting) { $buffer[] = '-d'; $buffer[] = $setting; } return $buffer; } } * * 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 function assert; use function file_get_contents; use function is_file; use function unlink; use PHPUnit\Event\Facade as EventFacade; use PHPUnit\Framework\ChildProcessResultProcessor; use PHPUnit\Framework\Test; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ abstract readonly class JobRunner { private ChildProcessResultProcessor $processor; public function __construct(ChildProcessResultProcessor $processor) { $this->processor = $processor; } /** * @param non-empty-string $processResultFile */ final public function runTestJob(\PHPUnit\Util\PHP\Job $job, string $processResultFile, Test $test): void { $result = $this->run($job); $processResult = ''; if (is_file($processResultFile)) { $processResult = file_get_contents($processResultFile); assert($processResult !== \false); @unlink($processResultFile); } $this->processor->process($test, $processResult, $result->stderr()); EventFacade::emitter()->childProcessFinished($result->stdout(), $result->stderr()); } abstract public function run(\PHPUnit\Util\PHP\Job $job): \PHPUnit\Util\PHP\Result; } * * 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 */ public static function runTestJob(\PHPUnit\Util\PHP\Job $job, string $processResultFile, Test $test): void { self::runner()->runTestJob($job, $processResultFile, $test); } 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\DefaultJobRunner(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 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 function error_reporting; use function file_get_contents; use function libxml_get_errors; use function libxml_use_internal_errors; use function sprintf; use function trim; use DOMDocument; /** * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit * * @internal This class is not covered by the backward compatibility promise for PHPUnit */ final readonly class Loader { /** * @throws XmlException */ public function loadFile(string $filename): DOMDocument { $reporting = error_reporting(0); $contents = file_get_contents($filename); error_reporting($reporting); if ($contents === \false) { throw new \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); } /** * @throws XmlException */ public function load(string $actual): 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); 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); } return $document; } } * * 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.0.5 The PHP Unit Testing framework. BSD-3-Clause pkg:composer/phpunit/phpunit@13.0.5 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 13.0.1 Library that provides collection, processing, and rendering functionality for PHP code coverage information. BSD-3-Clause pkg:composer/phpunit/php-code-coverage@13.0.1 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.0.0 Provides the functionality to compare PHP values for equality BSD-3-Clause pkg:composer/sebastian/comparator@8.0.0 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.0.0 Diff implementation BSD-3-Clause pkg:composer/sebastian/diff@8.0.0 sebastian environment 9.0.0 Provides functionality to handle HHVM/PHP environments BSD-3-Clause pkg:composer/sebastian/environment@9.0.0 sebastian exporter 8.0.0 Provides the functionality to export PHP variables for visualization BSD-3-Clause pkg:composer/sebastian/exporter@8.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.0 Library for counting the lines of code in PHP source code BSD-3-Clause pkg:composer/sebastian/lines-of-code@5.0.0 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.0 Collection of value objects that represent the types of the PHP type system BSD-3-Clause pkg:composer/sebastian/type@7.0.0 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 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 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_key_exists; use function assert; use function is_array; use function sort; use function sprintf; use function str_replace; use function trim; 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)); if ($canonicalize) { sort($expected); sort($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)) { $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); $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) { $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) { $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.'); } } private function indent(string $lines): string { return trim(str_replace("\n", "\n ", $lines)); } } * * 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); /** @phpstan-ignore equal.notAllowed */ if ($expected == $actual) { return; } $expectedReflector = new ReflectionFunction($expected); $actualReflector = new ReflectionFunction($actual); $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)); } } * * 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; } } * * 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\UnifiedDiffOutputBuilder; /** * @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; public function __construct(mixed $expected, mixed $actual, string $expectedAsString, string $actualAsString, string $message = '') { parent::__construct($message); $this->expected = $expected; $this->actual = $actual; $this->expectedAsString = $expectedAsString; $this->actualAsString = $actualAsString; } 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 UnifiedDiffOutputBuilder("\n--- Expected\n+++ Actual\n")); 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)); } } /** * 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 { $document = new DOMDocument(); try { $c14n = $node->C14N(); assert($c14n !== \false && $c14n !== ''); @$document->loadXML($c14n); // @codeCoverageIgnoreStart } catch (ValueError) { // @codeCoverageIgnoreEnd } $document->formatOutput = \true; $document->normalizeDocument(); $text = $document->saveXML(); assert($text !== \false); if ($ignoreCase) { return mb_strtolower($text, 'UTF-8'); } return $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 floor; 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); $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.'); } } } * * 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)); } } * * 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 = []; public static function getInstance(): self { if (self::$instance === null) { self::$instance = new self(); // @codeCoverageIgnore } return self::$instance; } public function __construct() { $this->registerDefaultComparators(); } 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 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.'); } } } * * 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))); } } 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)); } // 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.' ); } } } /** * @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)); } } } * * 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.'); } /** @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)) ); } } /** * @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.'); } } 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.'); } } } } * * 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)) ); } } } * * 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; 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; 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 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 = [ '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 'fromFile' => null, 'fromFileDate' => null, 'toFile' => null, 'toFileDate' => null, ]; private bool $changed; private bool $collapseRanges; /** * @var positive-int */ private int $commonLineThreshold; private string $header; /** * @var positive-int */ private int $contextLines; public function __construct(array $options = []) { $options = array_merge(self::$default, $options); 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']); } $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->collapseRanges = $options['collapseRanges']; $this->commonLineThreshold = $options['commonLineThreshold']; $this->contextLines = $options['contextLines']; } public function getDiff(array $diff): string { if (0 === count($diff)) { return ''; } $this->changed = \false; $buffer = fopen('php://memory', 'r+b'); assert(is_resource($buffer)); fwrite($buffer, $this->header); $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)); 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"); 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) { $this->changed = \true; fwrite($output, $diff[$i][0]); } // } elseif ($diff[$i][1] === Differ::DIFF_LINE_END_WARNING) { // custom comment inserted by PHPUnit/diff package // skip // } else { // unknown/invalid // } } } 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 = 3; private string $header; private bool $addLineNumbers; public function __construct(string $header = "--- Original\n+++ New\n", bool $addLineNumbers = \false) { $this->header = $header; $this->addLineNumbers = $addLineNumbers; } 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"); } } if (0 !== count($diff)) { $this->writeDiffHunks($buffer, $diff); } $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; } 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, "\n"); // $diff[$i][0] } else { /* Not changed (old) Differ::OLD or Warning Differ::DIFF_LINE_END_WARNING */ fwrite($output, ' ' . $diff[$i][0]); } } } } * * 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; 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; } if (isset($_SERVER['NO_COLOR']) || \false !== getenv('NO_COLOR')) { return \false; } 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(STDOUT); 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'); 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'); 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; } } 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 PHP_BINARY; use const PHP_SAPI; use const PHP_VERSION; 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 is_array; use function parse_ini_file; use function php_ini_loaded_file; use function php_ini_scanned_files; use function phpversion; use function sprintf; use function strrpos; use function version_compare; use function xdebug_info; final class Runtime { /** * 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 for * a list of all configuration settings loaded from files * at startup. Then checks for each php.ini setting passed * via the `$values` parameter whether this setting has * been changed at runtime. Returns an array of strings * where each string has the format `key=value` denoting * the name of a changed php.ini setting with its new value. * * @param list $values * * @return array */ public function getCurrentSettings(array $values): array { $diff = []; $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))); } foreach ($files as $ini) { $config = parse_ini_file($ini, \true); foreach ($values as $value) { $set = ini_get($value); if ($set === \false || $set === '') { continue; } if (!isset($config[$value]) || $set !== $config[$value]) { $diff[$value] = sprintf('%s=%s', $value, $set); } } } return $diff; } 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; } } * * 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_object; use function is_resource; use function is_string; use function mb_strlen; use function mb_substr; use function preg_match; use function spl_object_id; use function sprintf; use function str_repeat; use function str_replace; 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; } $array = []; foreach ((array) $value as $key => $val) { // 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 ("\x00Error\x00trace" === $key || "\x00Exception\x00trace" === $key) { continue; } // properties are transformed to keys in the following way: // private $propertyName => "\0ClassName\0propertyName" // protected $propertyName => "\0*\0propertyName" // public $propertyName => "propertyName" if (preg_match('/\0.+\0(.+)/', (string) $key, $matches) === 1) { $key = $matches[1]; } // See https://github.com/php/php-src/commit/5721132 if ($key === "\x00gcdata") { continue; } $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) { foreach ($value as $_value) { $array['Object #' . spl_object_id($_value)] = ['obj' => $_value, 'inf' => $value->getInfo()]; } $value->rewind(); } 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()); } /** * @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 { $precisionBackup = ini_get('precision'); ini_set('precision', '-1'); $valueAsString = @(string) $value; ini_set('precision', $precisionBackup); if ((string) @(int) $value === $valueAsString) { return $valueAsString . '.0'; } return $valueAsString; } private function exportString(string $value): string { // Match for most non-printable chars somewhat taking multibyte chars into account if (preg_match('/[^\x09-\x0d\x1b\x20-\xff]/', $value) === 1) { return 'Binary String: 0x' . bin2hex($value); } return "'" . strtr($value, ["\r\n" => '\r\n' . "\n", "\n\r" => '\n\r' . "\n", "\r" => '\r' . "\n", "\n" => '\n' . "\n"]) . "'"; } /** * @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\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 { $commentLinesOfCode = 0; foreach ($this->comments() as $comment) { $commentLinesOfCode += $comment->getEndLine() - $comment->getStartLine() + 1; } $nonCommentLinesOfCode = $this->linesOfCode - $commentLinesOfCode; $logicalLinesOfCode = count(array_unique($this->linesWithStatements)); assert($commentLinesOfCode >= 0); 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 is_subclass_of; use function strcasecmp; /** * @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) { 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 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; } } * * 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(); } } ?Å?%×e—÷C†¹Z'_^øfÿwR1|ÔïÜwF¶kn”J9Œ$Á<\¼×­ÆOèI°h'¨Ï¦!†vòuùÁGBMB