summaryrefslogtreecommitdiff
path: root/vendor/phpunit/phpunit/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/phpunit/phpunit/src')
-rw-r--r--vendor/phpunit/phpunit/src/Exception.php19
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Assert.php2854
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Assert/Functions.php3035
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Boolean/IsFalse.php35
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Boolean/IsTrue.php35
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Callback.php52
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/Count.php142
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/GreaterThan.php50
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/IsEmpty.php70
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/LessThan.php50
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/SameSize.php21
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php269
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqual.php138
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualCanonicalizing.php108
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualIgnoringCase.php108
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php100
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Exception/Exception.php85
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionCode.php67
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionMessage.php78
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionMessageRegularExpression.php74
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/DirectoryExists.php54
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/FileExists.php54
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/IsReadable.php54
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/IsWritable.php54
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/IsAnything.php51
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php137
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php109
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatchesErrorMessageProvider.php72
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsFinite.php37
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsInfinite.php37
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsNan.php37
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Object/ClassHasAttribute.php88
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Object/ClassHasStaticAttribute.php59
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Object/ObjectEquals.php151
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasAttribute.php29
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Operator/BinaryOperator.php148
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalAnd.php51
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalNot.php136
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalOr.php51
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalXor.php63
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Operator/Operator.php55
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Operator/UnaryOperator.php140
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/String/IsJson.php77
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/String/RegularExpression.php51
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/String/StringContains.php85
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/String/StringEndsWith.php48
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/String/StringMatchesFormatDescription.php109
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/String/StringStartsWith.php53
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/ArrayHasKey.php77
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContains.php63
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsEqual.php40
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsIdentical.php39
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsOnly.php91
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsInstanceOf.php87
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsNull.php35
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsType.php210
-rw-r--r--vendor/phpunit/phpunit/src/Framework/DataProviderTestSuite.php75
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Error/Deprecated.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Error/Error.php26
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Error/Notice.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Error/Warning.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/ErrorTestCase.php66
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/ActualValueIsNotAnObjectException.php32
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/AssertionFailedError.php24
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/CodeCoverageException.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotAcceptParameterTypeException.php38
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php37
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php37
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareParameterTypeException.php37
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotExistException.php37
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/CoveredCodeNotExecutedException.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/Error.php24
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/Exception.php81
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/ExpectationFailedException.php42
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/IncompleteTestError.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/InvalidArgumentException.php46
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/InvalidCoversTargetException.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/InvalidDataProviderException.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/MissingCoversAnnotationException.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/NoChildTestSuiteException.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/OutputError.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/PHPTAssertionFailedError.php32
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/RiskyTestError.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/SkippedTestError.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/SkippedTestSuiteError.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/SyntheticError.php61
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/SyntheticSkippedError.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/UnintentionallyCoveredCodeError.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Exception/Warning.php24
-rw-r--r--vendor/phpunit/phpunit/src/Framework/ExceptionWrapper.php122
-rw-r--r--vendor/phpunit/phpunit/src/Framework/ExecutionOrderDependency.php206
-rw-r--r--vendor/phpunit/phpunit/src/Framework/IncompleteTest.php19
-rw-r--r--vendor/phpunit/phpunit/src/Framework/IncompleteTestCase.php66
-rw-r--r--vendor/phpunit/phpunit/src/Framework/InvalidParameterGroupException.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Api/Api.php97
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Api/Method.php30
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Api/MockedCloneMethod.php21
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Api/UnmockedCloneMethod.php23
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Builder/Identity.php25
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationMocker.php306
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationStubber.php65
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Builder/MethodNameMatch.php26
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Builder/ParametersMatch.php58
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Builder/Stub.php24
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/ConfigurableMethod.php53
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/BadMethodCallException.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/CannotUseAddMethodsException.php29
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/CannotUseOnlyMethodsException.php29
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ClassAlreadyExistsException.php28
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ClassIsFinalException.php28
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ConfigurableMethodsAlreadyInitializedException.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/DuplicateMethodException.php32
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/Exception.php19
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/IncompatibleReturnValueException.php33
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/InvalidMethodNameException.php28
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MatchBuilderNotFoundException.php28
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MatcherAlreadyRegisteredException.php28
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodCannotBeConfiguredException.php28
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodNameAlreadyConfiguredException.php21
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodNameNotConfiguredException.php21
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodParametersAlreadyConfiguredException.php21
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/OriginalConstructorInvocationRequiredException.php21
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ReflectionException.php19
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ReturnValueNotConfiguredException.php27
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/RuntimeException.php17
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/SoapExtensionNotAvailableException.php23
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownClassException.php28
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownTraitException.php28
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownTypeException.php28
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php1004
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Generator/deprecation.tpl2
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_class.tpl6
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_method.tpl22
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_method_void.tpl20
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_static_method.tpl5
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Generator/proxied_method.tpl22
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Generator/proxied_method_void.tpl22
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Generator/trait_class.tpl6
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Generator/wsdl_class.tpl9
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Generator/wsdl_method.tpl4
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Invocation.php254
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/InvocationHandler.php186
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Matcher.php272
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/MethodNameConstraint.php48
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/MockBuilder.php516
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/MockClass.php69
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/MockMethod.php398
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/MockMethodSet.php45
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/MockObject.php27
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/MockTrait.php54
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/MockType.php21
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/AnyInvokedCount.php36
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/AnyParameters.php31
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ConsecutiveParameters.php130
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvocationOrder.php47
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtIndex.php75
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastCount.php64
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastOnce.php50
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtMostCount.php64
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedCount.php102
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/MethodName.php68
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/Parameters.php160
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ParametersRule.php28
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Stub.php26
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ConsecutiveCalls.php57
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Stub/Exception.php46
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnArgument.php41
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnCallback.php59
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnReference.php45
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnSelf.php32
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnStub.php45
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnValueMap.php53
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Stub/Stub.php27
-rw-r--r--vendor/phpunit/phpunit/src/Framework/MockObject/Verifiable.php26
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Reorderable.php28
-rw-r--r--vendor/phpunit/phpunit/src/Framework/SelfDescribing.php21
-rw-r--r--vendor/phpunit/phpunit/src/Framework/SkippedTest.php19
-rw-r--r--vendor/phpunit/phpunit/src/Framework/SkippedTestCase.php66
-rw-r--r--vendor/phpunit/phpunit/src/Framework/Test.php23
-rw-r--r--vendor/phpunit/phpunit/src/Framework/TestBuilder.php239
-rw-r--r--vendor/phpunit/phpunit/src/Framework/TestCase.php2581
-rw-r--r--vendor/phpunit/phpunit/src/Framework/TestFailure.php155
-rw-r--r--vendor/phpunit/phpunit/src/Framework/TestListener.php45
-rw-r--r--vendor/phpunit/phpunit/src/Framework/TestListenerDefaultImplementation.php59
-rw-r--r--vendor/phpunit/phpunit/src/Framework/TestResult.php1318
-rw-r--r--vendor/phpunit/phpunit/src/Framework/TestSuite.php914
-rw-r--r--vendor/phpunit/phpunit/src/Framework/TestSuiteIterator.php83
-rw-r--r--vendor/phpunit/phpunit/src/Framework/WarningTestCase.php66
-rw-r--r--vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php161
-rw-r--r--vendor/phpunit/phpunit/src/Runner/DefaultTestResultCache.php157
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Exception.php19
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Extension/ExtensionHandler.php117
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Extension/PharLoader.php75
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Filter/ExcludeGroupFilterIterator.php23
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Filter/Factory.php61
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Filter/GroupFilterIterator.php58
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Filter/IncludeGroupFilterIterator.php23
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Filter/NameFilterIterator.php136
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/AfterIncompleteTestHook.php24
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/AfterLastTestHook.php24
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/AfterRiskyTestHook.php24
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/AfterSkippedTestHook.php24
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/AfterSuccessfulTestHook.php24
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/AfterTestErrorHook.php24
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/AfterTestFailureHook.php24
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/AfterTestHook.php30
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/AfterTestWarningHook.php24
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/BeforeFirstTestHook.php24
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/BeforeTestHook.php24
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/Hook.php23
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/TestHook.php23
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Hook/TestListenerAdapter.php141
-rw-r--r--vendor/phpunit/phpunit/src/Runner/NullTestResultCache.php42
-rw-r--r--vendor/phpunit/phpunit/src/Runner/PhptTestCase.php864
-rw-r--r--vendor/phpunit/phpunit/src/Runner/ResultCacheExtension.php110
-rw-r--r--vendor/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php123
-rw-r--r--vendor/phpunit/phpunit/src/Runner/TestResultCache.php28
-rw-r--r--vendor/phpunit/phpunit/src/Runner/TestSuiteLoader.php24
-rw-r--r--vendor/phpunit/phpunit/src/Runner/TestSuiteSorter.php394
-rw-r--r--vendor/phpunit/phpunit/src/Runner/Version.php65
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php887
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/CliArguments/Configuration.php2107
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/CliArguments/Exception.php19
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/CliArguments/Mapper.php365
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/Command.php903
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php592
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/Exception/Exception.php19
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/Exception/ReflectionException.php19
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/Exception/RuntimeException.php17
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/Exception/TestDirectoryNotFoundException.php29
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/Exception/TestFileNotFoundException.php29
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/Help.php265
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/ResultPrinter.php23
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/TestRunner.php1272
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/TestSuiteMapper.php103
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/CodeCoverage.php362
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/Directory.php65
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/DirectoryCollection.php57
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/DirectoryCollectionIterator.php66
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/FilterMapper.php45
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Clover.php34
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Cobertura.php34
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Crap4j.php45
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Html.php56
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Php.php34
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Text.php56
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Xml.php34
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Configuration.php151
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Exception.php19
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/Directory.php32
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/DirectoryCollection.php62
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/DirectoryCollectionIterator.php66
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/File.php32
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/FileCollection.php62
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/FileCollectionIterator.php66
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Generator.php73
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/Group.php32
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/GroupCollection.php69
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/GroupCollectionIterator.php66
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/Groups.php53
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Loader.php1264
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Junit.php34
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Logging.php146
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TeamCity.php34
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Html.php34
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Text.php34
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Xml.php34
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Text.php34
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilder.php73
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilderException.php19
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationException.php19
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/ConvertLogTypes.php53
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageCloverToReport.php31
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageCrap4jToReport.php33
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageHtmlToReport.php33
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoveragePhpToReport.php31
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageTextToReport.php33
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageXmlToReport.php31
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/IntroduceCoverageElement.php28
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/LogToReportMigration.php79
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/Migration.php20
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php51
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromRootToCoverage.php47
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistDirectoriesToCoverage.php49
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistExcludesToCoverage.php70
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveCacheTokensAttribute.php27
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveEmptyFilter.php54
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveLogTypes.php37
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/UpdateSchemaLocationTo93.php27
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrator.php57
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Constant.php43
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/ConstantCollection.php57
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/ConstantCollectionIterator.php66
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSetting.php43
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSettingCollection.php57
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSettingCollectionIterator.php66
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Php.php142
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/PhpHandler.php121
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Variable.php54
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/VariableCollection.php57
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/VariableCollectionIterator.php66
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/Extension.php71
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/ExtensionCollection.php50
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/ExtensionCollectionIterator.php66
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/PHPUnit.php714
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectory.php78
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectoryCollection.php62
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectoryCollectionIterator.php66
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFile.php56
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFileCollection.php62
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFileCollectionIterator.php66
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuite.php65
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuiteCollection.php62
-rw-r--r--vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuiteCollectionIterator.php66
-rw-r--r--vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php551
-rw-r--r--vendor/phpunit/phpunit/src/Util/Annotation/Registry.php93
-rw-r--r--vendor/phpunit/phpunit/src/Util/Blacklist.php41
-rw-r--r--vendor/phpunit/phpunit/src/Util/Color.php159
-rw-r--r--vendor/phpunit/phpunit/src/Util/ErrorHandler.php156
-rw-r--r--vendor/phpunit/phpunit/src/Util/Exception.php19
-rw-r--r--vendor/phpunit/phpunit/src/Util/ExcludeList.php261
-rw-r--r--vendor/phpunit/phpunit/src/Util/FileLoader.php83
-rw-r--r--vendor/phpunit/phpunit/src/Util/Filesystem.php41
-rw-r--r--vendor/phpunit/phpunit/src/Util/Filter.php115
-rw-r--r--vendor/phpunit/phpunit/src/Util/GlobalState.php203
-rw-r--r--vendor/phpunit/phpunit/src/Util/InvalidDataSetException.php19
-rw-r--r--vendor/phpunit/phpunit/src/Util/Json.php98
-rw-r--r--vendor/phpunit/phpunit/src/Util/Log/JUnit.php424
-rw-r--r--vendor/phpunit/phpunit/src/Util/Log/TeamCity.php383
-rw-r--r--vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php416
-rw-r--r--vendor/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php236
-rw-r--r--vendor/phpunit/phpunit/src/Util/PHP/Template/PhptTestCase.tpl57
-rw-r--r--vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseClass.tpl119
-rw-r--r--vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseMethod.tpl122
-rw-r--r--vendor/phpunit/phpunit/src/Util/PHP/WindowsPhpProcess.php52
-rw-r--r--vendor/phpunit/phpunit/src/Util/Printer.php116
-rw-r--r--vendor/phpunit/phpunit/src/Util/RegularExpression.php31
-rw-r--r--vendor/phpunit/phpunit/src/Util/Test.php784
-rw-r--r--vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php381
-rw-r--r--vendor/phpunit/phpunit/src/Util/TestDox/HtmlResultPrinter.php140
-rw-r--r--vendor/phpunit/phpunit/src/Util/TestDox/NamePrettifier.php312
-rw-r--r--vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php343
-rw-r--r--vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php388
-rw-r--r--vendor/phpunit/phpunit/src/Util/TestDox/TextResultPrinter.php52
-rw-r--r--vendor/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php261
-rw-r--r--vendor/phpunit/phpunit/src/Util/TextTestListRenderer.php54
-rw-r--r--vendor/phpunit/phpunit/src/Util/Type.php52
-rw-r--r--vendor/phpunit/phpunit/src/Util/VersionComparisonOperator.php57
-rw-r--r--vendor/phpunit/phpunit/src/Util/XdebugFilterScriptGenerator.php81
-rw-r--r--vendor/phpunit/phpunit/src/Util/Xml.php193
-rw-r--r--vendor/phpunit/phpunit/src/Util/Xml/Exception.php19
-rw-r--r--vendor/phpunit/phpunit/src/Util/Xml/FailedSchemaDetectionResult.php19
-rw-r--r--vendor/phpunit/phpunit/src/Util/Xml/Loader.php117
-rw-r--r--vendor/phpunit/phpunit/src/Util/Xml/SchemaDetectionResult.php31
-rw-r--r--vendor/phpunit/phpunit/src/Util/Xml/SchemaDetector.php39
-rw-r--r--vendor/phpunit/phpunit/src/Util/Xml/SchemaFinder.php53
-rw-r--r--vendor/phpunit/phpunit/src/Util/Xml/SnapshotNodeList.php48
-rw-r--r--vendor/phpunit/phpunit/src/Util/Xml/SuccessfulSchemaDetectionResult.php38
-rw-r--r--vendor/phpunit/phpunit/src/Util/Xml/ValidationResult.php69
-rw-r--r--vendor/phpunit/phpunit/src/Util/Xml/Validator.php35
-rw-r--r--vendor/phpunit/phpunit/src/Util/XmlTestListRenderer.php90
361 files changed, 46290 insertions, 0 deletions
diff --git a/vendor/phpunit/phpunit/src/Exception.php b/vendor/phpunit/phpunit/src/Exception.php
new file mode 100644
index 000000000..4e7c33353
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Exception.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit;
+
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface Exception extends Throwable
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Assert.php b/vendor/phpunit/phpunit/src/Framework/Assert.php
new file mode 100644
index 000000000..8053f2840
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Assert.php
@@ -0,0 +1,2854 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use const DEBUG_BACKTRACE_IGNORE_ARGS;
+use const PHP_EOL;
+use function array_shift;
+use function array_unshift;
+use function assert;
+use function class_exists;
+use function count;
+use function debug_backtrace;
+use function explode;
+use function file_get_contents;
+use function func_get_args;
+use function implode;
+use function interface_exists;
+use function is_array;
+use function is_bool;
+use function is_int;
+use function is_iterable;
+use function is_object;
+use function is_string;
+use function preg_match;
+use function preg_split;
+use function sprintf;
+use function strpos;
+use ArrayAccess;
+use Countable;
+use DOMAttr;
+use DOMDocument;
+use DOMElement;
+use PHPUnit\Framework\Constraint\ArrayHasKey;
+use PHPUnit\Framework\Constraint\Callback;
+use PHPUnit\Framework\Constraint\ClassHasAttribute;
+use PHPUnit\Framework\Constraint\ClassHasStaticAttribute;
+use PHPUnit\Framework\Constraint\Constraint;
+use PHPUnit\Framework\Constraint\Count;
+use PHPUnit\Framework\Constraint\DirectoryExists;
+use PHPUnit\Framework\Constraint\FileExists;
+use PHPUnit\Framework\Constraint\GreaterThan;
+use PHPUnit\Framework\Constraint\IsAnything;
+use PHPUnit\Framework\Constraint\IsEmpty;
+use PHPUnit\Framework\Constraint\IsEqual;
+use PHPUnit\Framework\Constraint\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\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\ObjectHasAttribute;
+use PHPUnit\Framework\Constraint\RegularExpression;
+use PHPUnit\Framework\Constraint\SameSize;
+use PHPUnit\Framework\Constraint\StringContains;
+use PHPUnit\Framework\Constraint\StringEndsWith;
+use PHPUnit\Framework\Constraint\StringMatchesFormatDescription;
+use PHPUnit\Framework\Constraint\StringStartsWith;
+use PHPUnit\Framework\Constraint\TraversableContainsEqual;
+use PHPUnit\Framework\Constraint\TraversableContainsIdentical;
+use PHPUnit\Framework\Constraint\TraversableContainsOnly;
+use PHPUnit\Util\Type;
+use PHPUnit\Util\Xml;
+use PHPUnit\Util\Xml\Loader as XmlLoader;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+abstract class Assert
+{
+ /**
+ * @var int
+ */
+ private static $count = 0;
+
+ /**
+ * Asserts that an array has a specified key.
+ *
+ * @param int|string $key
+ * @param array|ArrayAccess $array
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertArrayHasKey($key, $array, string $message = ''): void
+ {
+ if (!(is_int($key) || is_string($key))) {
+ throw InvalidArgumentException::create(
+ 1,
+ 'integer or string'
+ );
+ }
+
+ if (!(is_array($array) || $array instanceof ArrayAccess)) {
+ throw InvalidArgumentException::create(
+ 2,
+ 'array or ArrayAccess'
+ );
+ }
+
+ $constraint = new ArrayHasKey($key);
+
+ static::assertThat($array, $constraint, $message);
+ }
+
+ /**
+ * Asserts that an array does not have a specified key.
+ *
+ * @param int|string $key
+ * @param array|ArrayAccess $array
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertArrayNotHasKey($key, $array, string $message = ''): void
+ {
+ if (!(is_int($key) || is_string($key))) {
+ throw InvalidArgumentException::create(
+ 1,
+ 'integer or string'
+ );
+ }
+
+ if (!(is_array($array) || $array instanceof ArrayAccess)) {
+ throw InvalidArgumentException::create(
+ 2,
+ 'array or ArrayAccess'
+ );
+ }
+
+ $constraint = new LogicalNot(
+ new ArrayHasKey($key)
+ );
+
+ static::assertThat($array, $constraint, $message);
+ }
+
+ /**
+ * Asserts that a haystack contains a needle.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertContains($needle, iterable $haystack, string $message = ''): void
+ {
+ $constraint = new TraversableContainsIdentical($needle);
+
+ static::assertThat($haystack, $constraint, $message);
+ }
+
+ public static function assertContainsEquals($needle, iterable $haystack, string $message = ''): void
+ {
+ $constraint = new TraversableContainsEqual($needle);
+
+ static::assertThat($haystack, $constraint, $message);
+ }
+
+ /**
+ * Asserts that a haystack does not contain a needle.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertNotContains($needle, iterable $haystack, string $message = ''): void
+ {
+ $constraint = new LogicalNot(
+ new TraversableContainsIdentical($needle)
+ );
+
+ static::assertThat($haystack, $constraint, $message);
+ }
+
+ public static function assertNotContainsEquals($needle, iterable $haystack, string $message = ''): void
+ {
+ $constraint = new LogicalNot(new TraversableContainsEqual($needle));
+
+ static::assertThat($haystack, $constraint, $message);
+ }
+
+ /**
+ * Asserts that a haystack contains only values of a given type.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertContainsOnly(string $type, iterable $haystack, ?bool $isNativeType = null, string $message = ''): void
+ {
+ if ($isNativeType === null) {
+ $isNativeType = Type::isType($type);
+ }
+
+ static::assertThat(
+ $haystack,
+ new TraversableContainsOnly(
+ $type,
+ $isNativeType
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a haystack contains only instances of a given class name.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertContainsOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void
+ {
+ static::assertThat(
+ $haystack,
+ new TraversableContainsOnly(
+ $className,
+ false
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a haystack does not contain only values of a given type.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertNotContainsOnly(string $type, iterable $haystack, ?bool $isNativeType = null, string $message = ''): void
+ {
+ if ($isNativeType === null) {
+ $isNativeType = Type::isType($type);
+ }
+
+ static::assertThat(
+ $haystack,
+ new LogicalNot(
+ new TraversableContainsOnly(
+ $type,
+ $isNativeType
+ )
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts the number of elements of an array, Countable or Traversable.
+ *
+ * @param Countable|iterable $haystack
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertCount(int $expectedCount, $haystack, string $message = ''): void
+ {
+ if (!$haystack instanceof Countable && !is_iterable($haystack)) {
+ throw InvalidArgumentException::create(2, 'countable or iterable');
+ }
+
+ static::assertThat(
+ $haystack,
+ new Count($expectedCount),
+ $message
+ );
+ }
+
+ /**
+ * Asserts the number of elements of an array, Countable or Traversable.
+ *
+ * @param Countable|iterable $haystack
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertNotCount(int $expectedCount, $haystack, string $message = ''): void
+ {
+ if (!$haystack instanceof Countable && !is_iterable($haystack)) {
+ throw InvalidArgumentException::create(2, 'countable or iterable');
+ }
+
+ $constraint = new LogicalNot(
+ new Count($expectedCount)
+ );
+
+ static::assertThat($haystack, $constraint, $message);
+ }
+
+ /**
+ * Asserts that two variables are equal.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertEquals($expected, $actual, string $message = ''): void
+ {
+ $constraint = new IsEqual($expected);
+
+ static::assertThat($actual, $constraint, $message);
+ }
+
+ /**
+ * Asserts that two variables are equal (canonicalizing).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertEqualsCanonicalizing($expected, $actual, string $message = ''): void
+ {
+ $constraint = new IsEqualCanonicalizing($expected);
+
+ static::assertThat($actual, $constraint, $message);
+ }
+
+ /**
+ * Asserts that two variables are equal (ignoring case).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertEqualsIgnoringCase($expected, $actual, string $message = ''): void
+ {
+ $constraint = new IsEqualIgnoringCase($expected);
+
+ static::assertThat($actual, $constraint, $message);
+ }
+
+ /**
+ * Asserts that two variables are equal (with delta).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertEqualsWithDelta($expected, $actual, float $delta, string $message = ''): void
+ {
+ $constraint = new IsEqualWithDelta(
+ $expected,
+ $delta
+ );
+
+ static::assertThat($actual, $constraint, $message);
+ }
+
+ /**
+ * Asserts that two variables are not equal.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertNotEquals($expected, $actual, string $message = ''): void
+ {
+ $constraint = new LogicalNot(
+ new IsEqual($expected)
+ );
+
+ static::assertThat($actual, $constraint, $message);
+ }
+
+ /**
+ * Asserts that two variables are not equal (canonicalizing).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertNotEqualsCanonicalizing($expected, $actual, string $message = ''): void
+ {
+ $constraint = new LogicalNot(
+ new IsEqualCanonicalizing($expected)
+ );
+
+ static::assertThat($actual, $constraint, $message);
+ }
+
+ /**
+ * Asserts that two variables are not equal (ignoring case).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertNotEqualsIgnoringCase($expected, $actual, string $message = ''): void
+ {
+ $constraint = new LogicalNot(
+ new IsEqualIgnoringCase($expected)
+ );
+
+ static::assertThat($actual, $constraint, $message);
+ }
+
+ /**
+ * Asserts that two variables are not equal (with delta).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertNotEqualsWithDelta($expected, $actual, float $delta, string $message = ''): void
+ {
+ $constraint = new LogicalNot(
+ new IsEqualWithDelta(
+ $expected,
+ $delta
+ )
+ );
+
+ static::assertThat($actual, $constraint, $message);
+ }
+
+ /**
+ * @throws ExpectationFailedException
+ */
+ public static function assertObjectEquals(object $expected, object $actual, string $method = 'equals', string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ static::objectEquals($expected, $method),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is empty.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert empty $actual
+ */
+ public static function assertEmpty($actual, string $message = ''): void
+ {
+ static::assertThat($actual, static::isEmpty(), $message);
+ }
+
+ /**
+ * Asserts that a variable is not empty.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !empty $actual
+ */
+ public static function assertNotEmpty($actual, string $message = ''): void
+ {
+ static::assertThat($actual, static::logicalNot(static::isEmpty()), $message);
+ }
+
+ /**
+ * Asserts that a value is greater than another value.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertGreaterThan($expected, $actual, string $message = ''): void
+ {
+ static::assertThat($actual, static::greaterThan($expected), $message);
+ }
+
+ /**
+ * Asserts that a value is greater than or equal to another value.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertGreaterThanOrEqual($expected, $actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ static::greaterThanOrEqual($expected),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a value is smaller than another value.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertLessThan($expected, $actual, string $message = ''): void
+ {
+ static::assertThat($actual, static::lessThan($expected), $message);
+ }
+
+ /**
+ * Asserts that a value is smaller than or equal to another value.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertLessThanOrEqual($expected, $actual, string $message = ''): void
+ {
+ static::assertThat($actual, static::lessThanOrEqual($expected), $message);
+ }
+
+ /**
+ * Asserts that the contents of one file is equal to the contents of another
+ * file.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertFileEquals(string $expected, string $actual, string $message = ''): void
+ {
+ static::assertFileExists($expected, $message);
+ static::assertFileExists($actual, $message);
+
+ $constraint = new IsEqual(file_get_contents($expected));
+
+ static::assertThat(file_get_contents($actual), $constraint, $message);
+ }
+
+ /**
+ * Asserts that the contents of one file is equal to the contents of another
+ * file (canonicalizing).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertFileEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void
+ {
+ static::assertFileExists($expected, $message);
+ static::assertFileExists($actual, $message);
+
+ $constraint = new IsEqualCanonicalizing(
+ file_get_contents($expected)
+ );
+
+ static::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 \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertFileEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void
+ {
+ static::assertFileExists($expected, $message);
+ static::assertFileExists($actual, $message);
+
+ $constraint = new IsEqualIgnoringCase(file_get_contents($expected));
+
+ static::assertThat(file_get_contents($actual), $constraint, $message);
+ }
+
+ /**
+ * Asserts that the contents of one file is not equal to the contents of
+ * another file.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertFileNotEquals(string $expected, string $actual, string $message = ''): void
+ {
+ static::assertFileExists($expected, $message);
+ static::assertFileExists($actual, $message);
+
+ $constraint = new LogicalNot(
+ new IsEqual(file_get_contents($expected))
+ );
+
+ static::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 \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertFileNotEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void
+ {
+ static::assertFileExists($expected, $message);
+ static::assertFileExists($actual, $message);
+
+ $constraint = new LogicalNot(
+ new IsEqualCanonicalizing(file_get_contents($expected))
+ );
+
+ static::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 \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertFileNotEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void
+ {
+ static::assertFileExists($expected, $message);
+ static::assertFileExists($actual, $message);
+
+ $constraint = new LogicalNot(
+ new IsEqualIgnoringCase(file_get_contents($expected))
+ );
+
+ static::assertThat(file_get_contents($actual), $constraint, $message);
+ }
+
+ /**
+ * Asserts that the contents of a string is equal
+ * to the contents of a file.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringEqualsFile(string $expectedFile, string $actualString, string $message = ''): void
+ {
+ static::assertFileExists($expectedFile, $message);
+
+ $constraint = new IsEqual(file_get_contents($expectedFile));
+
+ static::assertThat($actualString, $constraint, $message);
+ }
+
+ /**
+ * Asserts that the contents of a string is equal
+ * to the contents of a file (canonicalizing).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void
+ {
+ static::assertFileExists($expectedFile, $message);
+
+ $constraint = new IsEqualCanonicalizing(file_get_contents($expectedFile));
+
+ static::assertThat($actualString, $constraint, $message);
+ }
+
+ /**
+ * Asserts that the contents of a string is equal
+ * to the contents of a file (ignoring case).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void
+ {
+ static::assertFileExists($expectedFile, $message);
+
+ $constraint = new IsEqualIgnoringCase(file_get_contents($expectedFile));
+
+ static::assertThat($actualString, $constraint, $message);
+ }
+
+ /**
+ * Asserts that the contents of a string is not equal
+ * to the contents of a file.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringNotEqualsFile(string $expectedFile, string $actualString, string $message = ''): void
+ {
+ static::assertFileExists($expectedFile, $message);
+
+ $constraint = new LogicalNot(
+ new IsEqual(file_get_contents($expectedFile))
+ );
+
+ static::assertThat($actualString, $constraint, $message);
+ }
+
+ /**
+ * Asserts that the contents of a string is not equal
+ * to the contents of a file (canonicalizing).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringNotEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void
+ {
+ static::assertFileExists($expectedFile, $message);
+
+ $constraint = new LogicalNot(
+ new IsEqualCanonicalizing(file_get_contents($expectedFile))
+ );
+
+ static::assertThat($actualString, $constraint, $message);
+ }
+
+ /**
+ * Asserts that the contents of a string is not equal
+ * to the contents of a file (ignoring case).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringNotEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void
+ {
+ static::assertFileExists($expectedFile, $message);
+
+ $constraint = new LogicalNot(
+ new IsEqualIgnoringCase(file_get_contents($expectedFile))
+ );
+
+ static::assertThat($actualString, $constraint, $message);
+ }
+
+ /**
+ * Asserts that a file/dir is readable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertIsReadable(string $filename, string $message = ''): void
+ {
+ static::assertThat($filename, new IsReadable, $message);
+ }
+
+ /**
+ * Asserts that a file/dir exists and is not readable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertIsNotReadable(string $filename, string $message = ''): void
+ {
+ static::assertThat($filename, new LogicalNot(new IsReadable), $message);
+ }
+
+ /**
+ * Asserts that a file/dir exists and is not readable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4062
+ */
+ public static function assertNotIsReadable(string $filename, string $message = ''): void
+ {
+ self::createWarning('assertNotIsReadable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertIsNotReadable() instead.');
+
+ static::assertThat($filename, new LogicalNot(new IsReadable), $message);
+ }
+
+ /**
+ * Asserts that a file/dir exists and is writable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertIsWritable(string $filename, string $message = ''): void
+ {
+ static::assertThat($filename, new IsWritable, $message);
+ }
+
+ /**
+ * Asserts that a file/dir exists and is not writable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertIsNotWritable(string $filename, string $message = ''): void
+ {
+ static::assertThat($filename, new LogicalNot(new IsWritable), $message);
+ }
+
+ /**
+ * Asserts that a file/dir exists and is not writable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4065
+ */
+ public static function assertNotIsWritable(string $filename, string $message = ''): void
+ {
+ self::createWarning('assertNotIsWritable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertIsNotWritable() instead.');
+
+ static::assertThat($filename, new LogicalNot(new IsWritable), $message);
+ }
+
+ /**
+ * Asserts that a directory exists.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertDirectoryExists(string $directory, string $message = ''): void
+ {
+ static::assertThat($directory, new DirectoryExists, $message);
+ }
+
+ /**
+ * Asserts that a directory does not exist.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertDirectoryDoesNotExist(string $directory, string $message = ''): void
+ {
+ static::assertThat($directory, new LogicalNot(new DirectoryExists), $message);
+ }
+
+ /**
+ * Asserts that a directory does not exist.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4068
+ */
+ public static function assertDirectoryNotExists(string $directory, string $message = ''): void
+ {
+ self::createWarning('assertDirectoryNotExists() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDirectoryDoesNotExist() instead.');
+
+ static::assertThat($directory, new LogicalNot(new DirectoryExists), $message);
+ }
+
+ /**
+ * Asserts that a directory exists and is readable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ 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 \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertDirectoryIsNotReadable(string $directory, string $message = ''): void
+ {
+ self::assertDirectoryExists($directory, $message);
+ self::assertIsNotReadable($directory, $message);
+ }
+
+ /**
+ * Asserts that a directory exists and is not readable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4071
+ */
+ public static function assertDirectoryNotIsReadable(string $directory, string $message = ''): void
+ {
+ self::createWarning('assertDirectoryNotIsReadable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDirectoryIsNotReadable() instead.');
+
+ self::assertDirectoryExists($directory, $message);
+ self::assertIsNotReadable($directory, $message);
+ }
+
+ /**
+ * Asserts that a directory exists and is writable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ 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 \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertDirectoryIsNotWritable(string $directory, string $message = ''): void
+ {
+ self::assertDirectoryExists($directory, $message);
+ self::assertIsNotWritable($directory, $message);
+ }
+
+ /**
+ * Asserts that a directory exists and is not writable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4074
+ */
+ public static function assertDirectoryNotIsWritable(string $directory, string $message = ''): void
+ {
+ self::createWarning('assertDirectoryNotIsWritable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDirectoryIsNotWritable() instead.');
+
+ self::assertDirectoryExists($directory, $message);
+ self::assertIsNotWritable($directory, $message);
+ }
+
+ /**
+ * Asserts that a file exists.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertFileExists(string $filename, string $message = ''): void
+ {
+ static::assertThat($filename, new FileExists, $message);
+ }
+
+ /**
+ * Asserts that a file does not exist.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertFileDoesNotExist(string $filename, string $message = ''): void
+ {
+ static::assertThat($filename, new LogicalNot(new FileExists), $message);
+ }
+
+ /**
+ * Asserts that a file does not exist.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4077
+ */
+ public static function assertFileNotExists(string $filename, string $message = ''): void
+ {
+ self::createWarning('assertFileNotExists() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertFileDoesNotExist() instead.');
+
+ static::assertThat($filename, new LogicalNot(new FileExists), $message);
+ }
+
+ /**
+ * Asserts that a file exists and is readable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ 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 \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertFileIsNotReadable(string $file, string $message = ''): void
+ {
+ self::assertFileExists($file, $message);
+ self::assertIsNotReadable($file, $message);
+ }
+
+ /**
+ * Asserts that a file exists and is not readable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4080
+ */
+ public static function assertFileNotIsReadable(string $file, string $message = ''): void
+ {
+ self::createWarning('assertFileNotIsReadable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertFileIsNotReadable() instead.');
+
+ self::assertFileExists($file, $message);
+ self::assertIsNotReadable($file, $message);
+ }
+
+ /**
+ * Asserts that a file exists and is writable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ 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 \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertFileIsNotWritable(string $file, string $message = ''): void
+ {
+ self::assertFileExists($file, $message);
+ self::assertIsNotWritable($file, $message);
+ }
+
+ /**
+ * Asserts that a file exists and is not writable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4083
+ */
+ public static function assertFileNotIsWritable(string $file, string $message = ''): void
+ {
+ self::createWarning('assertFileNotIsWritable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertFileIsNotWritable() instead.');
+
+ self::assertFileExists($file, $message);
+ self::assertIsNotWritable($file, $message);
+ }
+
+ /**
+ * Asserts that a condition is true.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert true $condition
+ */
+ public static function assertTrue($condition, string $message = ''): void
+ {
+ static::assertThat($condition, static::isTrue(), $message);
+ }
+
+ /**
+ * Asserts that a condition is not true.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !true $condition
+ */
+ public static function assertNotTrue($condition, string $message = ''): void
+ {
+ static::assertThat($condition, static::logicalNot(static::isTrue()), $message);
+ }
+
+ /**
+ * Asserts that a condition is false.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert false $condition
+ */
+ public static function assertFalse($condition, string $message = ''): void
+ {
+ static::assertThat($condition, static::isFalse(), $message);
+ }
+
+ /**
+ * Asserts that a condition is not false.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !false $condition
+ */
+ public static function assertNotFalse($condition, string $message = ''): void
+ {
+ static::assertThat($condition, static::logicalNot(static::isFalse()), $message);
+ }
+
+ /**
+ * Asserts that a variable is null.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert null $actual
+ */
+ public static function assertNull($actual, string $message = ''): void
+ {
+ static::assertThat($actual, static::isNull(), $message);
+ }
+
+ /**
+ * Asserts that a variable is not null.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !null $actual
+ */
+ public static function assertNotNull($actual, string $message = ''): void
+ {
+ static::assertThat($actual, static::logicalNot(static::isNull()), $message);
+ }
+
+ /**
+ * Asserts that a variable is finite.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertFinite($actual, string $message = ''): void
+ {
+ static::assertThat($actual, static::isFinite(), $message);
+ }
+
+ /**
+ * Asserts that a variable is infinite.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertInfinite($actual, string $message = ''): void
+ {
+ static::assertThat($actual, static::isInfinite(), $message);
+ }
+
+ /**
+ * Asserts that a variable is nan.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertNan($actual, string $message = ''): void
+ {
+ static::assertThat($actual, static::isNan(), $message);
+ }
+
+ /**
+ * Asserts that a class has a specified attribute.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertClassHasAttribute(string $attributeName, string $className, string $message = ''): void
+ {
+ if (!self::isValidClassAttributeName($attributeName)) {
+ throw InvalidArgumentException::create(1, 'valid attribute name');
+ }
+
+ if (!class_exists($className)) {
+ throw InvalidArgumentException::create(2, 'class name');
+ }
+
+ static::assertThat($className, new ClassHasAttribute($attributeName), $message);
+ }
+
+ /**
+ * Asserts that a class does not have a specified attribute.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertClassNotHasAttribute(string $attributeName, string $className, string $message = ''): void
+ {
+ if (!self::isValidClassAttributeName($attributeName)) {
+ throw InvalidArgumentException::create(1, 'valid attribute name');
+ }
+
+ if (!class_exists($className)) {
+ throw InvalidArgumentException::create(2, 'class name');
+ }
+
+ static::assertThat(
+ $className,
+ new LogicalNot(
+ new ClassHasAttribute($attributeName)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a class has a specified static attribute.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertClassHasStaticAttribute(string $attributeName, string $className, string $message = ''): void
+ {
+ if (!self::isValidClassAttributeName($attributeName)) {
+ throw InvalidArgumentException::create(1, 'valid attribute name');
+ }
+
+ if (!class_exists($className)) {
+ throw InvalidArgumentException::create(2, 'class name');
+ }
+
+ static::assertThat(
+ $className,
+ new ClassHasStaticAttribute($attributeName),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a class does not have a specified static attribute.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertClassNotHasStaticAttribute(string $attributeName, string $className, string $message = ''): void
+ {
+ if (!self::isValidClassAttributeName($attributeName)) {
+ throw InvalidArgumentException::create(1, 'valid attribute name');
+ }
+
+ if (!class_exists($className)) {
+ throw InvalidArgumentException::create(2, 'class name');
+ }
+
+ static::assertThat(
+ $className,
+ new LogicalNot(
+ new ClassHasStaticAttribute($attributeName)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that an object has a specified attribute.
+ *
+ * @param object $object
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertObjectHasAttribute(string $attributeName, $object, string $message = ''): void
+ {
+ if (!self::isValidObjectAttributeName($attributeName)) {
+ throw InvalidArgumentException::create(1, 'valid attribute name');
+ }
+
+ if (!is_object($object)) {
+ throw InvalidArgumentException::create(2, 'object');
+ }
+
+ static::assertThat(
+ $object,
+ new ObjectHasAttribute($attributeName),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that an object does not have a specified attribute.
+ *
+ * @param object $object
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertObjectNotHasAttribute(string $attributeName, $object, string $message = ''): void
+ {
+ if (!self::isValidObjectAttributeName($attributeName)) {
+ throw InvalidArgumentException::create(1, 'valid attribute name');
+ }
+
+ if (!is_object($object)) {
+ throw InvalidArgumentException::create(2, 'object');
+ }
+
+ static::assertThat(
+ $object,
+ new LogicalNot(
+ new ObjectHasAttribute($attributeName)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that two variables have the same type and value.
+ * Used on objects, it asserts that two variables reference
+ * the same object.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-template ExpectedType
+ * @psalm-param ExpectedType $expected
+ * @psalm-assert =ExpectedType $actual
+ */
+ public static function assertSame($expected, $actual, string $message = ''): void
+ {
+ static::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 \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertNotSame($expected, $actual, string $message = ''): void
+ {
+ if (is_bool($expected) && is_bool($actual)) {
+ static::assertNotEquals($expected, $actual, $message);
+ }
+
+ static::assertThat(
+ $actual,
+ new LogicalNot(
+ new IsIdentical($expected)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of a given type.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ *
+ * @psalm-template ExpectedType of object
+ * @psalm-param class-string<ExpectedType> $expected
+ * @psalm-assert =ExpectedType $actual
+ */
+ public static function assertInstanceOf(string $expected, $actual, string $message = ''): void
+ {
+ if (!class_exists($expected) && !interface_exists($expected)) {
+ throw InvalidArgumentException::create(1, 'class or interface name');
+ }
+
+ static::assertThat(
+ $actual,
+ new IsInstanceOf($expected),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of a given type.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ *
+ * @psalm-template ExpectedType of object
+ * @psalm-param class-string<ExpectedType> $expected
+ * @psalm-assert !ExpectedType $actual
+ */
+ public static function assertNotInstanceOf(string $expected, $actual, string $message = ''): void
+ {
+ if (!class_exists($expected) && !interface_exists($expected)) {
+ throw InvalidArgumentException::create(1, 'class or interface name');
+ }
+
+ static::assertThat(
+ $actual,
+ new LogicalNot(
+ new IsInstanceOf($expected)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type array.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert array $actual
+ */
+ public static function assertIsArray($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_ARRAY),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type bool.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert bool $actual
+ */
+ public static function assertIsBool($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_BOOL),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type float.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert float $actual
+ */
+ public static function assertIsFloat($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_FLOAT),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type int.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert int $actual
+ */
+ public static function assertIsInt($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_INT),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type numeric.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert numeric $actual
+ */
+ public static function assertIsNumeric($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_NUMERIC),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type object.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert object $actual
+ */
+ public static function assertIsObject($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_OBJECT),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type resource.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert resource $actual
+ */
+ public static function assertIsResource($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_RESOURCE),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type resource and is closed.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert resource $actual
+ */
+ public static function assertIsClosedResource($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_CLOSED_RESOURCE),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type string.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert string $actual
+ */
+ public static function assertIsString($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_STRING),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type scalar.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert scalar $actual
+ */
+ public static function assertIsScalar($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_SCALAR),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type callable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert callable $actual
+ */
+ public static function assertIsCallable($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_CALLABLE),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is of type iterable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert iterable $actual
+ */
+ public static function assertIsIterable($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new IsType(IsType::TYPE_ITERABLE),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type array.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !array $actual
+ */
+ public static function assertIsNotArray($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_ARRAY)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type bool.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !bool $actual
+ */
+ public static function assertIsNotBool($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_BOOL)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type float.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !float $actual
+ */
+ public static function assertIsNotFloat($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_FLOAT)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type int.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !int $actual
+ */
+ public static function assertIsNotInt($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_INT)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type numeric.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !numeric $actual
+ */
+ public static function assertIsNotNumeric($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_NUMERIC)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type object.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !object $actual
+ */
+ public static function assertIsNotObject($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_OBJECT)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type resource.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !resource $actual
+ */
+ public static function assertIsNotResource($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_RESOURCE)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type resource.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !resource $actual
+ */
+ public static function assertIsNotClosedResource($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_CLOSED_RESOURCE)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type string.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !string $actual
+ */
+ public static function assertIsNotString($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_STRING)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type scalar.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !scalar $actual
+ */
+ public static function assertIsNotScalar($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_SCALAR)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type callable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !callable $actual
+ */
+ public static function assertIsNotCallable($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_CALLABLE)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a variable is not of type iterable.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-assert !iterable $actual
+ */
+ public static function assertIsNotIterable($actual, string $message = ''): void
+ {
+ static::assertThat(
+ $actual,
+ new LogicalNot(new IsType(IsType::TYPE_ITERABLE)),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a string matches a given regular expression.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertMatchesRegularExpression(string $pattern, string $string, string $message = ''): void
+ {
+ static::assertThat($string, new RegularExpression($pattern), $message);
+ }
+
+ /**
+ * Asserts that a string matches a given regular expression.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4086
+ */
+ public static function assertRegExp(string $pattern, string $string, string $message = ''): void
+ {
+ self::createWarning('assertRegExp() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertMatchesRegularExpression() instead.');
+
+ static::assertThat($string, new RegularExpression($pattern), $message);
+ }
+
+ /**
+ * Asserts that a string does not match a given regular expression.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertDoesNotMatchRegularExpression(string $pattern, string $string, string $message = ''): void
+ {
+ static::assertThat(
+ $string,
+ new LogicalNot(
+ new RegularExpression($pattern)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a string does not match a given regular expression.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4089
+ */
+ public static function assertNotRegExp(string $pattern, string $string, string $message = ''): void
+ {
+ self::createWarning('assertNotRegExp() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDoesNotMatchRegularExpression() instead.');
+
+ static::assertThat(
+ $string,
+ new LogicalNot(
+ new RegularExpression($pattern)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Assert that the size of two arrays (or `Countable` or `Traversable` objects)
+ * is the same.
+ *
+ * @param Countable|iterable $expected
+ * @param Countable|iterable $actual
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertSameSize($expected, $actual, string $message = ''): void
+ {
+ if (!$expected instanceof Countable && !is_iterable($expected)) {
+ throw InvalidArgumentException::create(1, 'countable or iterable');
+ }
+
+ if (!$actual instanceof Countable && !is_iterable($actual)) {
+ throw InvalidArgumentException::create(2, 'countable or iterable');
+ }
+
+ static::assertThat(
+ $actual,
+ new SameSize($expected),
+ $message
+ );
+ }
+
+ /**
+ * Assert that the size of two arrays (or `Countable` or `Traversable` objects)
+ * is not the same.
+ *
+ * @param Countable|iterable $expected
+ * @param Countable|iterable $actual
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertNotSameSize($expected, $actual, string $message = ''): void
+ {
+ if (!$expected instanceof Countable && !is_iterable($expected)) {
+ throw InvalidArgumentException::create(1, 'countable or iterable');
+ }
+
+ if (!$actual instanceof Countable && !is_iterable($actual)) {
+ throw InvalidArgumentException::create(2, 'countable or iterable');
+ }
+
+ static::assertThat(
+ $actual,
+ new LogicalNot(
+ new SameSize($expected)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a string matches a given format string.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringMatchesFormat(string $format, string $string, string $message = ''): void
+ {
+ static::assertThat($string, new StringMatchesFormatDescription($format), $message);
+ }
+
+ /**
+ * Asserts that a string does not match a given format string.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringNotMatchesFormat(string $format, string $string, string $message = ''): void
+ {
+ static::assertThat(
+ $string,
+ new LogicalNot(
+ new StringMatchesFormatDescription($format)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a string matches a given format file.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringMatchesFormatFile(string $formatFile, string $string, string $message = ''): void
+ {
+ static::assertFileExists($formatFile, $message);
+
+ static::assertThat(
+ $string,
+ new StringMatchesFormatDescription(
+ file_get_contents($formatFile)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a string does not match a given format string.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringNotMatchesFormatFile(string $formatFile, string $string, string $message = ''): void
+ {
+ static::assertFileExists($formatFile, $message);
+
+ static::assertThat(
+ $string,
+ new LogicalNot(
+ new StringMatchesFormatDescription(
+ file_get_contents($formatFile)
+ )
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that a string starts with a given prefix.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringStartsWith(string $prefix, string $string, string $message = ''): void
+ {
+ static::assertThat($string, new StringStartsWith($prefix), $message);
+ }
+
+ /**
+ * Asserts that a string starts not with a given prefix.
+ *
+ * @param string $prefix
+ * @param string $string
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringStartsNotWith($prefix, $string, string $message = ''): void
+ {
+ static::assertThat(
+ $string,
+ new LogicalNot(
+ new StringStartsWith($prefix)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringContainsString(string $needle, string $haystack, string $message = ''): void
+ {
+ $constraint = new StringContains($needle, false);
+
+ static::assertThat($haystack, $constraint, $message);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void
+ {
+ $constraint = new StringContains($needle, true);
+
+ static::assertThat($haystack, $constraint, $message);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringNotContainsString(string $needle, string $haystack, string $message = ''): void
+ {
+ $constraint = new LogicalNot(new StringContains($needle));
+
+ static::assertThat($haystack, $constraint, $message);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringNotContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void
+ {
+ $constraint = new LogicalNot(new StringContains($needle, true));
+
+ static::assertThat($haystack, $constraint, $message);
+ }
+
+ /**
+ * Asserts that a string ends with a given suffix.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringEndsWith(string $suffix, string $string, string $message = ''): void
+ {
+ static::assertThat($string, new StringEndsWith($suffix), $message);
+ }
+
+ /**
+ * Asserts that a string ends not with a given suffix.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertStringEndsNotWith(string $suffix, string $string, string $message = ''): void
+ {
+ static::assertThat(
+ $string,
+ new LogicalNot(
+ new StringEndsWith($suffix)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that two XML files are equal.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ * @throws ExpectationFailedException
+ */
+ public static function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void
+ {
+ $expected = (new XmlLoader)->loadFile($expectedFile);
+ $actual = (new XmlLoader)->loadFile($actualFile);
+
+ static::assertEquals($expected, $actual, $message);
+ }
+
+ /**
+ * Asserts that two XML files are not equal.
+ *
+ * @throws \PHPUnit\Util\Exception
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void
+ {
+ $expected = (new XmlLoader)->loadFile($expectedFile);
+ $actual = (new XmlLoader)->loadFile($actualFile);
+
+ static::assertNotEquals($expected, $actual, $message);
+ }
+
+ /**
+ * Asserts that two XML documents are equal.
+ *
+ * @param DOMDocument|string $actualXml
+ *
+ * @throws \PHPUnit\Util\Xml\Exception
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertXmlStringEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void
+ {
+ if (!is_string($actualXml)) {
+ self::createWarning('Passing an argument of type DOMDocument for the $actualXml parameter is deprecated. Support for this will be removed in PHPUnit 10.');
+
+ $actual = $actualXml;
+ } else {
+ $actual = (new XmlLoader)->load($actualXml);
+ }
+
+ $expected = (new XmlLoader)->loadFile($expectedFile);
+
+ static::assertEquals($expected, $actual, $message);
+ }
+
+ /**
+ * Asserts that two XML documents are not equal.
+ *
+ * @param DOMDocument|string $actualXml
+ *
+ * @throws \PHPUnit\Util\Xml\Exception
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertXmlStringNotEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void
+ {
+ if (!is_string($actualXml)) {
+ self::createWarning('Passing an argument of type DOMDocument for the $actualXml parameter is deprecated. Support for this will be removed in PHPUnit 10.');
+
+ $actual = $actualXml;
+ } else {
+ $actual = (new XmlLoader)->load($actualXml);
+ }
+
+ $expected = (new XmlLoader)->loadFile($expectedFile);
+
+ static::assertNotEquals($expected, $actual, $message);
+ }
+
+ /**
+ * Asserts that two XML documents are equal.
+ *
+ * @param DOMDocument|string $expectedXml
+ * @param DOMDocument|string $actualXml
+ *
+ * @throws \PHPUnit\Util\Xml\Exception
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertXmlStringEqualsXmlString($expectedXml, $actualXml, string $message = ''): void
+ {
+ if (!is_string($expectedXml)) {
+ self::createWarning('Passing an argument of type DOMDocument for the $expectedXml parameter is deprecated. Support for this will be removed in PHPUnit 10.');
+
+ $expected = $expectedXml;
+ } else {
+ $expected = (new XmlLoader)->load($expectedXml);
+ }
+
+ if (!is_string($actualXml)) {
+ self::createWarning('Passing an argument of type DOMDocument for the $actualXml parameter is deprecated. Support for this will be removed in PHPUnit 10.');
+
+ $actual = $actualXml;
+ } else {
+ $actual = (new XmlLoader)->load($actualXml);
+ }
+
+ static::assertEquals($expected, $actual, $message);
+ }
+
+ /**
+ * Asserts that two XML documents are not equal.
+ *
+ * @param DOMDocument|string $expectedXml
+ * @param DOMDocument|string $actualXml
+ *
+ * @throws \PHPUnit\Util\Xml\Exception
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, string $message = ''): void
+ {
+ if (!is_string($expectedXml)) {
+ self::createWarning('Passing an argument of type DOMDocument for the $expectedXml parameter is deprecated. Support for this will be removed in PHPUnit 10.');
+
+ $expected = $expectedXml;
+ } else {
+ $expected = (new XmlLoader)->load($expectedXml);
+ }
+
+ if (!is_string($actualXml)) {
+ self::createWarning('Passing an argument of type DOMDocument for the $actualXml parameter is deprecated. Support for this will be removed in PHPUnit 10.');
+
+ $actual = $actualXml;
+ } else {
+ $actual = (new XmlLoader)->load($actualXml);
+ }
+
+ static::assertNotEquals($expected, $actual, $message);
+ }
+
+ /**
+ * Asserts that a hierarchy of DOMElements matches.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws AssertionFailedError
+ * @throws ExpectationFailedException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4091
+ */
+ public static function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement, bool $checkAttributes = false, string $message = ''): void
+ {
+ self::createWarning('assertEqualXMLStructure() is deprecated and will be removed in PHPUnit 10.');
+
+ $expectedElement = Xml::import($expectedElement);
+ $actualElement = Xml::import($actualElement);
+
+ static::assertSame(
+ $expectedElement->tagName,
+ $actualElement->tagName,
+ $message
+ );
+
+ if ($checkAttributes) {
+ static::assertSame(
+ $expectedElement->attributes->length,
+ $actualElement->attributes->length,
+ sprintf(
+ '%s%sNumber of attributes on node "%s" does not match',
+ $message,
+ !empty($message) ? "\n" : '',
+ $expectedElement->tagName
+ )
+ );
+
+ for ($i = 0; $i < $expectedElement->attributes->length; $i++) {
+ $expectedAttribute = $expectedElement->attributes->item($i);
+ $actualAttribute = $actualElement->attributes->getNamedItem($expectedAttribute->name);
+
+ assert($expectedAttribute instanceof DOMAttr);
+
+ if (!$actualAttribute) {
+ static::fail(
+ sprintf(
+ '%s%sCould not find attribute "%s" on node "%s"',
+ $message,
+ !empty($message) ? "\n" : '',
+ $expectedAttribute->name,
+ $expectedElement->tagName
+ )
+ );
+ }
+ }
+ }
+
+ Xml::removeCharacterDataNodes($expectedElement);
+ Xml::removeCharacterDataNodes($actualElement);
+
+ static::assertSame(
+ $expectedElement->childNodes->length,
+ $actualElement->childNodes->length,
+ sprintf(
+ '%s%sNumber of child nodes of "%s" differs',
+ $message,
+ !empty($message) ? "\n" : '',
+ $expectedElement->tagName
+ )
+ );
+
+ for ($i = 0; $i < $expectedElement->childNodes->length; $i++) {
+ static::assertEqualXMLStructure(
+ $expectedElement->childNodes->item($i),
+ $actualElement->childNodes->item($i),
+ $checkAttributes,
+ $message
+ );
+ }
+ }
+
+ /**
+ * Evaluates a PHPUnit\Framework\Constraint matcher object.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertThat($value, Constraint $constraint, string $message = ''): void
+ {
+ self::$count += count($constraint);
+
+ $constraint->evaluate($value, $message);
+ }
+
+ /**
+ * Asserts that a string is a valid JSON string.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertJson(string $actualJson, string $message = ''): void
+ {
+ static::assertThat($actualJson, static::isJson(), $message);
+ }
+
+ /**
+ * Asserts that two given JSON encoded objects or arrays are equal.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void
+ {
+ static::assertJson($expectedJson, $message);
+ static::assertJson($actualJson, $message);
+
+ static::assertThat($actualJson, new JsonMatches($expectedJson), $message);
+ }
+
+ /**
+ * Asserts that two given JSON encoded objects or arrays are not equal.
+ *
+ * @param string $expectedJson
+ * @param string $actualJson
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, string $message = ''): void
+ {
+ static::assertJson($expectedJson, $message);
+ static::assertJson($actualJson, $message);
+
+ static::assertThat(
+ $actualJson,
+ new LogicalNot(
+ new JsonMatches($expectedJson)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that the generated JSON encoded object and the content of the given file are equal.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void
+ {
+ static::assertFileExists($expectedFile, $message);
+ $expectedJson = file_get_contents($expectedFile);
+
+ static::assertJson($expectedJson, $message);
+ static::assertJson($actualJson, $message);
+
+ static::assertThat($actualJson, new JsonMatches($expectedJson), $message);
+ }
+
+ /**
+ * Asserts that the generated JSON encoded object and the content of the given file are not equal.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void
+ {
+ static::assertFileExists($expectedFile, $message);
+ $expectedJson = file_get_contents($expectedFile);
+
+ static::assertJson($expectedJson, $message);
+ static::assertJson($actualJson, $message);
+
+ static::assertThat(
+ $actualJson,
+ new LogicalNot(
+ new JsonMatches($expectedJson)
+ ),
+ $message
+ );
+ }
+
+ /**
+ * Asserts that two JSON files are equal.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void
+ {
+ static::assertFileExists($expectedFile, $message);
+ static::assertFileExists($actualFile, $message);
+
+ $actualJson = file_get_contents($actualFile);
+ $expectedJson = file_get_contents($expectedFile);
+
+ static::assertJson($expectedJson, $message);
+ static::assertJson($actualJson, $message);
+
+ $constraintExpected = new JsonMatches(
+ $expectedJson
+ );
+
+ $constraintActual = new JsonMatches($actualJson);
+
+ static::assertThat($expectedJson, $constraintActual, $message);
+ static::assertThat($actualJson, $constraintExpected, $message);
+ }
+
+ /**
+ * Asserts that two JSON files are not equal.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public static function assertJsonFileNotEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void
+ {
+ static::assertFileExists($expectedFile, $message);
+ static::assertFileExists($actualFile, $message);
+
+ $actualJson = file_get_contents($actualFile);
+ $expectedJson = file_get_contents($expectedFile);
+
+ static::assertJson($expectedJson, $message);
+ static::assertJson($actualJson, $message);
+
+ $constraintExpected = new JsonMatches(
+ $expectedJson
+ );
+
+ $constraintActual = new JsonMatches($actualJson);
+
+ static::assertThat($expectedJson, new LogicalNot($constraintActual), $message);
+ static::assertThat($actualJson, new LogicalNot($constraintExpected), $message);
+ }
+
+ /**
+ * @throws Exception
+ */
+ public static function logicalAnd(): LogicalAnd
+ {
+ $constraints = func_get_args();
+
+ $constraint = new LogicalAnd;
+ $constraint->setConstraints($constraints);
+
+ return $constraint;
+ }
+
+ public static function logicalOr(): LogicalOr
+ {
+ $constraints = func_get_args();
+
+ $constraint = new LogicalOr;
+ $constraint->setConstraints($constraints);
+
+ return $constraint;
+ }
+
+ public static function logicalNot(Constraint $constraint): LogicalNot
+ {
+ return new LogicalNot($constraint);
+ }
+
+ public static function logicalXor(): LogicalXor
+ {
+ $constraints = func_get_args();
+
+ $constraint = new LogicalXor;
+ $constraint->setConstraints($constraints);
+
+ return $constraint;
+ }
+
+ public static function anything(): IsAnything
+ {
+ return new IsAnything;
+ }
+
+ public static function isTrue(): IsTrue
+ {
+ return new IsTrue;
+ }
+
+ /**
+ * @psalm-template CallbackInput of mixed
+ *
+ * @psalm-param callable(CallbackInput $callback): bool $callback
+ *
+ * @psalm-return Callback<CallbackInput>
+ */
+ public static function callback(callable $callback): Callback
+ {
+ return new Callback($callback);
+ }
+
+ public static function isFalse(): IsFalse
+ {
+ return new IsFalse;
+ }
+
+ public static function isJson(): IsJson
+ {
+ return new IsJson;
+ }
+
+ public static function isNull(): IsNull
+ {
+ return new IsNull;
+ }
+
+ public static function isFinite(): IsFinite
+ {
+ return new IsFinite;
+ }
+
+ public static function isInfinite(): IsInfinite
+ {
+ return new IsInfinite;
+ }
+
+ public static function isNan(): IsNan
+ {
+ return new IsNan;
+ }
+
+ public static function containsEqual($value): TraversableContainsEqual
+ {
+ return new TraversableContainsEqual($value);
+ }
+
+ public static function containsIdentical($value): TraversableContainsIdentical
+ {
+ return new TraversableContainsIdentical($value);
+ }
+
+ public static function containsOnly(string $type): TraversableContainsOnly
+ {
+ return new TraversableContainsOnly($type);
+ }
+
+ public static function containsOnlyInstancesOf(string $className): TraversableContainsOnly
+ {
+ return new TraversableContainsOnly($className, false);
+ }
+
+ /**
+ * @param int|string $key
+ */
+ public static function arrayHasKey($key): ArrayHasKey
+ {
+ return new ArrayHasKey($key);
+ }
+
+ public static function equalTo($value): IsEqual
+ {
+ return new IsEqual($value, 0.0, false, false);
+ }
+
+ public static function equalToCanonicalizing($value): IsEqualCanonicalizing
+ {
+ return new IsEqualCanonicalizing($value);
+ }
+
+ public static function equalToIgnoringCase($value): IsEqualIgnoringCase
+ {
+ return new IsEqualIgnoringCase($value);
+ }
+
+ public static function equalToWithDelta($value, float $delta): IsEqualWithDelta
+ {
+ return new IsEqualWithDelta($value, $delta);
+ }
+
+ public static function isEmpty(): IsEmpty
+ {
+ return new IsEmpty;
+ }
+
+ public static function isWritable(): IsWritable
+ {
+ return new IsWritable;
+ }
+
+ public static function isReadable(): IsReadable
+ {
+ return new IsReadable;
+ }
+
+ public static function directoryExists(): DirectoryExists
+ {
+ return new DirectoryExists;
+ }
+
+ public static function fileExists(): FileExists
+ {
+ return new FileExists;
+ }
+
+ public static function greaterThan($value): GreaterThan
+ {
+ return new GreaterThan($value);
+ }
+
+ public static function greaterThanOrEqual($value): LogicalOr
+ {
+ return static::logicalOr(
+ new IsEqual($value),
+ new GreaterThan($value)
+ );
+ }
+
+ public static function classHasAttribute(string $attributeName): ClassHasAttribute
+ {
+ return new ClassHasAttribute($attributeName);
+ }
+
+ public static function classHasStaticAttribute(string $attributeName): ClassHasStaticAttribute
+ {
+ return new ClassHasStaticAttribute($attributeName);
+ }
+
+ public static function objectHasAttribute($attributeName): ObjectHasAttribute
+ {
+ return new ObjectHasAttribute($attributeName);
+ }
+
+ public static function identicalTo($value): IsIdentical
+ {
+ return new IsIdentical($value);
+ }
+
+ public static function isInstanceOf(string $className): IsInstanceOf
+ {
+ return new IsInstanceOf($className);
+ }
+
+ public static function isType(string $type): IsType
+ {
+ return new IsType($type);
+ }
+
+ public static function lessThan($value): LessThan
+ {
+ return new LessThan($value);
+ }
+
+ public static function lessThanOrEqual($value): LogicalOr
+ {
+ return static::logicalOr(
+ new IsEqual($value),
+ new LessThan($value)
+ );
+ }
+
+ public static function matchesRegularExpression(string $pattern): RegularExpression
+ {
+ return new RegularExpression($pattern);
+ }
+
+ public static function matches(string $string): StringMatchesFormatDescription
+ {
+ return new StringMatchesFormatDescription($string);
+ }
+
+ public static function stringStartsWith($prefix): StringStartsWith
+ {
+ return new StringStartsWith($prefix);
+ }
+
+ public static function stringContains(string $string, bool $case = true): StringContains
+ {
+ return new StringContains($string, $case);
+ }
+
+ public static function stringEndsWith(string $suffix): StringEndsWith
+ {
+ return new StringEndsWith($suffix);
+ }
+
+ public static function countOf(int $count): Count
+ {
+ return new Count($count);
+ }
+
+ public static function objectEquals(object $object, string $method = 'equals'): ObjectEquals
+ {
+ return new ObjectEquals($object, $method);
+ }
+
+ /**
+ * Fails a test with the given message.
+ *
+ * @throws AssertionFailedError
+ *
+ * @psalm-return never-return
+ */
+ public static function fail(string $message = ''): void
+ {
+ self::$count++;
+
+ throw new AssertionFailedError($message);
+ }
+
+ /**
+ * Mark the test as incomplete.
+ *
+ * @throws IncompleteTestError
+ *
+ * @psalm-return never-return
+ */
+ public static function markTestIncomplete(string $message = ''): void
+ {
+ throw new IncompleteTestError($message);
+ }
+
+ /**
+ * Mark the test as skipped.
+ *
+ * @throws SkippedTestError
+ * @throws SyntheticSkippedError
+ *
+ * @psalm-return never-return
+ */
+ public static function markTestSkipped(string $message = ''): void
+ {
+ if ($hint = self::detectLocationHint($message)) {
+ $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+ array_unshift($trace, $hint);
+
+ throw new SyntheticSkippedError($hint['message'], 0, $hint['file'], (int) $hint['line'], $trace);
+ }
+
+ throw new SkippedTestError($message);
+ }
+
+ /**
+ * Return the current assertion count.
+ */
+ public static function getCount(): int
+ {
+ return self::$count;
+ }
+
+ /**
+ * Reset the assertion counter.
+ */
+ public static function resetCount(): void
+ {
+ self::$count = 0;
+ }
+
+ private static function detectLocationHint(string $message): ?array
+ {
+ $hint = null;
+ $lines = preg_split('/\r\n|\r|\n/', $message);
+
+ while (strpos($lines[0], '__OFFSET') !== false) {
+ $offset = explode('=', array_shift($lines));
+
+ if ($offset[0] === '__OFFSET_FILE') {
+ $hint['file'] = $offset[1];
+ }
+
+ if ($offset[0] === '__OFFSET_LINE') {
+ $hint['line'] = $offset[1];
+ }
+ }
+
+ if ($hint) {
+ $hint['message'] = implode(PHP_EOL, $lines);
+ }
+
+ return $hint;
+ }
+
+ private static function isValidObjectAttributeName(string $attributeName): bool
+ {
+ return (bool) preg_match('/[^\x00-\x1f\x7f-\x9f]+/', $attributeName);
+ }
+
+ private static function isValidClassAttributeName(string $attributeName): bool
+ {
+ return (bool) preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName);
+ }
+
+ /**
+ * @codeCoverageIgnore
+ */
+ private static function createWarning(string $warning): void
+ {
+ foreach (debug_backtrace() as $step) {
+ if (isset($step['object']) && $step['object'] instanceof TestCase) {
+ assert($step['object'] instanceof TestCase);
+
+ $step['object']->addWarning($warning);
+
+ break;
+ }
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php b/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php
new file mode 100644
index 000000000..7c4831d0f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php
@@ -0,0 +1,3035 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use function func_get_args;
+use ArrayAccess;
+use Countable;
+use DOMDocument;
+use DOMElement;
+use PHPUnit\Framework\Constraint\ArrayHasKey;
+use PHPUnit\Framework\Constraint\Callback;
+use PHPUnit\Framework\Constraint\ClassHasAttribute;
+use PHPUnit\Framework\Constraint\ClassHasStaticAttribute;
+use PHPUnit\Framework\Constraint\Constraint;
+use PHPUnit\Framework\Constraint\Count;
+use PHPUnit\Framework\Constraint\DirectoryExists;
+use PHPUnit\Framework\Constraint\FileExists;
+use PHPUnit\Framework\Constraint\GreaterThan;
+use PHPUnit\Framework\Constraint\IsAnything;
+use PHPUnit\Framework\Constraint\IsEmpty;
+use PHPUnit\Framework\Constraint\IsEqual;
+use PHPUnit\Framework\Constraint\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\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\ObjectHasAttribute;
+use PHPUnit\Framework\Constraint\RegularExpression;
+use PHPUnit\Framework\Constraint\StringContains;
+use PHPUnit\Framework\Constraint\StringEndsWith;
+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\InvokedAtIndex as InvokedAtIndexMatcher;
+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\ConsecutiveCalls as ConsecutiveCallsStub;
+use PHPUnit\Framework\MockObject\Stub\Exception as ExceptionStub;
+use PHPUnit\Framework\MockObject\Stub\ReturnArgument as ReturnArgumentStub;
+use PHPUnit\Framework\MockObject\Stub\ReturnCallback as ReturnCallbackStub;
+use PHPUnit\Framework\MockObject\Stub\ReturnSelf as ReturnSelfStub;
+use PHPUnit\Framework\MockObject\Stub\ReturnStub;
+use PHPUnit\Framework\MockObject\Stub\ReturnValueMap as ReturnValueMapStub;
+use Throwable;
+
+if (!function_exists('PHPUnit\Framework\assertArrayHasKey')) {
+ /**
+ * Asserts that an array has a specified key.
+ *
+ * @param int|string $key
+ * @param array|ArrayAccess $array
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertArrayHasKey
+ */
+ function assertArrayHasKey($key, $array, string $message = ''): void
+ {
+ Assert::assertArrayHasKey(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertArrayNotHasKey')) {
+ /**
+ * Asserts that an array does not have a specified key.
+ *
+ * @param int|string $key
+ * @param array|ArrayAccess $array
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertArrayNotHasKey
+ */
+ function assertArrayNotHasKey($key, $array, string $message = ''): void
+ {
+ Assert::assertArrayNotHasKey(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertContains')) {
+ /**
+ * Asserts that a haystack contains a needle.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertContains
+ */
+ function assertContains($needle, iterable $haystack, string $message = ''): void
+ {
+ Assert::assertContains(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertContainsEquals')) {
+ function assertContainsEquals($needle, iterable $haystack, string $message = ''): void
+ {
+ Assert::assertContainsEquals(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotContains')) {
+ /**
+ * Asserts that a haystack does not contain a needle.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotContains
+ */
+ function assertNotContains($needle, iterable $haystack, string $message = ''): void
+ {
+ Assert::assertNotContains(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotContainsEquals')) {
+ function assertNotContainsEquals($needle, iterable $haystack, string $message = ''): void
+ {
+ Assert::assertNotContainsEquals(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertContainsOnly')) {
+ /**
+ * Asserts that a haystack contains only values of a given type.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertContainsOnly
+ */
+ function assertContainsOnly(string $type, iterable $haystack, ?bool $isNativeType = null, string $message = ''): void
+ {
+ Assert::assertContainsOnly(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertContainsOnlyInstancesOf')) {
+ /**
+ * Asserts that a haystack contains only instances of a given class name.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertContainsOnlyInstancesOf(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotContainsOnly')) {
+ /**
+ * Asserts that a haystack does not contain only values of a given type.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotContainsOnly
+ */
+ function assertNotContainsOnly(string $type, iterable $haystack, ?bool $isNativeType = null, string $message = ''): void
+ {
+ Assert::assertNotContainsOnly(...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 ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertCount
+ */
+ function assertCount(int $expectedCount, $haystack, string $message = ''): void
+ {
+ 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 ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotCount
+ */
+ function assertNotCount(int $expectedCount, $haystack, string $message = ''): void
+ {
+ Assert::assertNotCount(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertEquals')) {
+ /**
+ * Asserts that two variables are equal.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertEquals
+ */
+ function assertEquals($expected, $actual, string $message = ''): void
+ {
+ Assert::assertEquals(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertEqualsCanonicalizing')) {
+ /**
+ * Asserts that two variables are equal (canonicalizing).
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertEqualsCanonicalizing
+ */
+ function assertEqualsCanonicalizing($expected, $actual, string $message = ''): void
+ {
+ Assert::assertEqualsCanonicalizing(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertEqualsIgnoringCase')) {
+ /**
+ * Asserts that two variables are equal (ignoring case).
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertEqualsIgnoringCase
+ */
+ function assertEqualsIgnoringCase($expected, $actual, string $message = ''): void
+ {
+ Assert::assertEqualsIgnoringCase(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertEqualsWithDelta')) {
+ /**
+ * Asserts that two variables are equal (with delta).
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertEqualsWithDelta
+ */
+ function assertEqualsWithDelta($expected, $actual, float $delta, string $message = ''): void
+ {
+ Assert::assertEqualsWithDelta(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotEquals')) {
+ /**
+ * Asserts that two variables are not equal.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotEquals
+ */
+ function assertNotEquals($expected, $actual, string $message = ''): void
+ {
+ Assert::assertNotEquals(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotEqualsCanonicalizing')) {
+ /**
+ * Asserts that two variables are not equal (canonicalizing).
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotEqualsCanonicalizing
+ */
+ function assertNotEqualsCanonicalizing($expected, $actual, string $message = ''): void
+ {
+ Assert::assertNotEqualsCanonicalizing(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotEqualsIgnoringCase')) {
+ /**
+ * Asserts that two variables are not equal (ignoring case).
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotEqualsIgnoringCase
+ */
+ function assertNotEqualsIgnoringCase($expected, $actual, string $message = ''): void
+ {
+ Assert::assertNotEqualsIgnoringCase(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotEqualsWithDelta')) {
+ /**
+ * Asserts that two variables are not equal (with delta).
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotEqualsWithDelta
+ */
+ function assertNotEqualsWithDelta($expected, $actual, float $delta, string $message = ''): void
+ {
+ 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
+ {
+ Assert::assertObjectEquals(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertEmpty')) {
+ /**
+ * Asserts that a variable is empty.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert empty $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertEmpty
+ */
+ function assertEmpty($actual, string $message = ''): void
+ {
+ Assert::assertEmpty(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotEmpty')) {
+ /**
+ * Asserts that a variable is not empty.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !empty $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotEmpty
+ */
+ function assertNotEmpty($actual, string $message = ''): void
+ {
+ Assert::assertNotEmpty(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertGreaterThan')) {
+ /**
+ * Asserts that a value is greater than another value.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertGreaterThan
+ */
+ function assertGreaterThan($expected, $actual, string $message = ''): void
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertGreaterThanOrEqual
+ */
+ function assertGreaterThanOrEqual($expected, $actual, string $message = ''): void
+ {
+ Assert::assertGreaterThanOrEqual(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertLessThan')) {
+ /**
+ * Asserts that a value is smaller than another value.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertLessThan
+ */
+ function assertLessThan($expected, $actual, string $message = ''): void
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertLessThanOrEqual
+ */
+ function assertLessThanOrEqual($expected, $actual, string $message = ''): void
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertStringNotEqualsFileIgnoringCase(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsReadable')) {
+ /**
+ * Asserts that a file/dir is readable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertIsReadable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotReadable')) {
+ /**
+ * Asserts that a file/dir exists and is not readable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertIsNotReadable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotIsReadable')) {
+ /**
+ * Asserts that a file/dir exists and is not readable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4062
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotIsReadable
+ */
+ function assertNotIsReadable(string $filename, string $message = ''): void
+ {
+ Assert::assertNotIsReadable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsWritable')) {
+ /**
+ * Asserts that a file/dir exists and is writable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertIsWritable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotWritable')) {
+ /**
+ * Asserts that a file/dir exists and is not writable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertIsNotWritable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotIsWritable')) {
+ /**
+ * Asserts that a file/dir exists and is not writable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4065
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotIsWritable
+ */
+ function assertNotIsWritable(string $filename, string $message = ''): void
+ {
+ Assert::assertNotIsWritable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertDirectoryExists')) {
+ /**
+ * Asserts that a directory exists.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertDirectoryExists(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertDirectoryDoesNotExist')) {
+ /**
+ * Asserts that a directory does not exist.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertDirectoryDoesNotExist(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertDirectoryNotExists')) {
+ /**
+ * Asserts that a directory does not exist.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4068
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertDirectoryNotExists
+ */
+ function assertDirectoryNotExists(string $directory, string $message = ''): void
+ {
+ Assert::assertDirectoryNotExists(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertDirectoryIsReadable')) {
+ /**
+ * Asserts that a directory exists and is readable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertDirectoryIsReadable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertDirectoryIsNotReadable')) {
+ /**
+ * Asserts that a directory exists and is not readable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertDirectoryIsNotReadable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertDirectoryNotIsReadable')) {
+ /**
+ * Asserts that a directory exists and is not readable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4071
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertDirectoryNotIsReadable
+ */
+ function assertDirectoryNotIsReadable(string $directory, string $message = ''): void
+ {
+ Assert::assertDirectoryNotIsReadable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertDirectoryIsWritable')) {
+ /**
+ * Asserts that a directory exists and is writable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertDirectoryIsWritable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertDirectoryIsNotWritable')) {
+ /**
+ * Asserts that a directory exists and is not writable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertDirectoryIsNotWritable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertDirectoryNotIsWritable')) {
+ /**
+ * Asserts that a directory exists and is not writable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4074
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertDirectoryNotIsWritable
+ */
+ function assertDirectoryNotIsWritable(string $directory, string $message = ''): void
+ {
+ Assert::assertDirectoryNotIsWritable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertFileExists')) {
+ /**
+ * Asserts that a file exists.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertFileExists(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertFileDoesNotExist')) {
+ /**
+ * Asserts that a file does not exist.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertFileDoesNotExist(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertFileNotExists')) {
+ /**
+ * Asserts that a file does not exist.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4077
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertFileNotExists
+ */
+ function assertFileNotExists(string $filename, string $message = ''): void
+ {
+ Assert::assertFileNotExists(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertFileIsReadable')) {
+ /**
+ * Asserts that a file exists and is readable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertFileIsReadable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertFileIsNotReadable')) {
+ /**
+ * Asserts that a file exists and is not readable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertFileIsNotReadable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertFileNotIsReadable')) {
+ /**
+ * Asserts that a file exists and is not readable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4080
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertFileNotIsReadable
+ */
+ function assertFileNotIsReadable(string $file, string $message = ''): void
+ {
+ Assert::assertFileNotIsReadable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertFileIsWritable')) {
+ /**
+ * Asserts that a file exists and is writable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertFileIsWritable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertFileIsNotWritable')) {
+ /**
+ * Asserts that a file exists and is not writable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertFileIsNotWritable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertFileNotIsWritable')) {
+ /**
+ * Asserts that a file exists and is not writable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4083
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertFileNotIsWritable
+ */
+ function assertFileNotIsWritable(string $file, string $message = ''): void
+ {
+ Assert::assertFileNotIsWritable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertTrue')) {
+ /**
+ * Asserts that a condition is true.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert true $condition
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertTrue
+ */
+ function assertTrue($condition, string $message = ''): void
+ {
+ Assert::assertTrue(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotTrue')) {
+ /**
+ * Asserts that a condition is not true.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !true $condition
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotTrue
+ */
+ function assertNotTrue($condition, string $message = ''): void
+ {
+ Assert::assertNotTrue(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertFalse')) {
+ /**
+ * Asserts that a condition is false.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert false $condition
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertFalse
+ */
+ function assertFalse($condition, string $message = ''): void
+ {
+ Assert::assertFalse(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotFalse')) {
+ /**
+ * Asserts that a condition is not false.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !false $condition
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotFalse
+ */
+ function assertNotFalse($condition, string $message = ''): void
+ {
+ Assert::assertNotFalse(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNull')) {
+ /**
+ * Asserts that a variable is null.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert null $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNull
+ */
+ function assertNull($actual, string $message = ''): void
+ {
+ Assert::assertNull(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotNull')) {
+ /**
+ * Asserts that a variable is not null.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !null $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotNull
+ */
+ function assertNotNull($actual, string $message = ''): void
+ {
+ Assert::assertNotNull(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertFinite')) {
+ /**
+ * Asserts that a variable is finite.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertFinite
+ */
+ function assertFinite($actual, string $message = ''): void
+ {
+ Assert::assertFinite(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertInfinite')) {
+ /**
+ * Asserts that a variable is infinite.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertInfinite
+ */
+ function assertInfinite($actual, string $message = ''): void
+ {
+ Assert::assertInfinite(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNan')) {
+ /**
+ * Asserts that a variable is nan.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNan
+ */
+ function assertNan($actual, string $message = ''): void
+ {
+ Assert::assertNan(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertClassHasAttribute')) {
+ /**
+ * Asserts that a class has a specified attribute.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertClassHasAttribute
+ */
+ function assertClassHasAttribute(string $attributeName, string $className, string $message = ''): void
+ {
+ Assert::assertClassHasAttribute(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertClassNotHasAttribute')) {
+ /**
+ * Asserts that a class does not have a specified attribute.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertClassNotHasAttribute
+ */
+ function assertClassNotHasAttribute(string $attributeName, string $className, string $message = ''): void
+ {
+ Assert::assertClassNotHasAttribute(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertClassHasStaticAttribute')) {
+ /**
+ * Asserts that a class has a specified static attribute.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertClassHasStaticAttribute
+ */
+ function assertClassHasStaticAttribute(string $attributeName, string $className, string $message = ''): void
+ {
+ Assert::assertClassHasStaticAttribute(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertClassNotHasStaticAttribute')) {
+ /**
+ * Asserts that a class does not have a specified static attribute.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertClassNotHasStaticAttribute
+ */
+ function assertClassNotHasStaticAttribute(string $attributeName, string $className, string $message = ''): void
+ {
+ Assert::assertClassNotHasStaticAttribute(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertObjectHasAttribute')) {
+ /**
+ * Asserts that an object has a specified attribute.
+ *
+ * @param object $object
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertObjectHasAttribute
+ */
+ function assertObjectHasAttribute(string $attributeName, $object, string $message = ''): void
+ {
+ Assert::assertObjectHasAttribute(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertObjectNotHasAttribute')) {
+ /**
+ * Asserts that an object does not have a specified attribute.
+ *
+ * @param object $object
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertObjectNotHasAttribute
+ */
+ function assertObjectNotHasAttribute(string $attributeName, $object, string $message = ''): void
+ {
+ Assert::assertObjectNotHasAttribute(...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.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-template ExpectedType
+ * @psalm-param ExpectedType $expected
+ * @psalm-assert =ExpectedType $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertSame
+ */
+ function assertSame($expected, $actual, string $message = ''): void
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotSame
+ */
+ function assertNotSame($expected, $actual, string $message = ''): void
+ {
+ Assert::assertNotSame(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertInstanceOf')) {
+ /**
+ * Asserts that a variable is of a given type.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @psalm-template ExpectedType of object
+ * @psalm-param class-string<ExpectedType> $expected
+ * @psalm-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, $actual, string $message = ''): void
+ {
+ Assert::assertInstanceOf(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotInstanceOf')) {
+ /**
+ * Asserts that a variable is not of a given type.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @psalm-template ExpectedType of object
+ * @psalm-param class-string<ExpectedType> $expected
+ * @psalm-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, $actual, string $message = ''): void
+ {
+ Assert::assertNotInstanceOf(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsArray')) {
+ /**
+ * Asserts that a variable is of type array.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert array $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsArray
+ */
+ function assertIsArray($actual, string $message = ''): void
+ {
+ Assert::assertIsArray(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsBool')) {
+ /**
+ * Asserts that a variable is of type bool.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert bool $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsBool
+ */
+ function assertIsBool($actual, string $message = ''): void
+ {
+ Assert::assertIsBool(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsFloat')) {
+ /**
+ * Asserts that a variable is of type float.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert float $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsFloat
+ */
+ function assertIsFloat($actual, string $message = ''): void
+ {
+ Assert::assertIsFloat(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsInt')) {
+ /**
+ * Asserts that a variable is of type int.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert int $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsInt
+ */
+ function assertIsInt($actual, string $message = ''): void
+ {
+ Assert::assertIsInt(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNumeric')) {
+ /**
+ * Asserts that a variable is of type numeric.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert numeric $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNumeric
+ */
+ function assertIsNumeric($actual, string $message = ''): void
+ {
+ Assert::assertIsNumeric(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsObject')) {
+ /**
+ * Asserts that a variable is of type object.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert object $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsObject
+ */
+ function assertIsObject($actual, string $message = ''): void
+ {
+ Assert::assertIsObject(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsResource')) {
+ /**
+ * Asserts that a variable is of type resource.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert resource $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsResource
+ */
+ function assertIsResource($actual, string $message = ''): void
+ {
+ Assert::assertIsResource(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsClosedResource')) {
+ /**
+ * Asserts that a variable is of type resource and is closed.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert resource $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsClosedResource
+ */
+ function assertIsClosedResource($actual, string $message = ''): void
+ {
+ Assert::assertIsClosedResource(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsString')) {
+ /**
+ * Asserts that a variable is of type string.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert string $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsString
+ */
+ function assertIsString($actual, string $message = ''): void
+ {
+ Assert::assertIsString(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsScalar')) {
+ /**
+ * Asserts that a variable is of type scalar.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert scalar $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsScalar
+ */
+ function assertIsScalar($actual, string $message = ''): void
+ {
+ Assert::assertIsScalar(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsCallable')) {
+ /**
+ * Asserts that a variable is of type callable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert callable $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsCallable
+ */
+ function assertIsCallable($actual, string $message = ''): void
+ {
+ Assert::assertIsCallable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsIterable')) {
+ /**
+ * Asserts that a variable is of type iterable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert iterable $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsIterable
+ */
+ function assertIsIterable($actual, string $message = ''): void
+ {
+ Assert::assertIsIterable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotArray')) {
+ /**
+ * Asserts that a variable is not of type array.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !array $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotArray
+ */
+ function assertIsNotArray($actual, string $message = ''): void
+ {
+ Assert::assertIsNotArray(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotBool')) {
+ /**
+ * Asserts that a variable is not of type bool.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !bool $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotBool
+ */
+ function assertIsNotBool($actual, string $message = ''): void
+ {
+ Assert::assertIsNotBool(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotFloat')) {
+ /**
+ * Asserts that a variable is not of type float.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !float $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotFloat
+ */
+ function assertIsNotFloat($actual, string $message = ''): void
+ {
+ Assert::assertIsNotFloat(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotInt')) {
+ /**
+ * Asserts that a variable is not of type int.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !int $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotInt
+ */
+ function assertIsNotInt($actual, string $message = ''): void
+ {
+ Assert::assertIsNotInt(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotNumeric')) {
+ /**
+ * Asserts that a variable is not of type numeric.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !numeric $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotNumeric
+ */
+ function assertIsNotNumeric($actual, string $message = ''): void
+ {
+ Assert::assertIsNotNumeric(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotObject')) {
+ /**
+ * Asserts that a variable is not of type object.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !object $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotObject
+ */
+ function assertIsNotObject($actual, string $message = ''): void
+ {
+ Assert::assertIsNotObject(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotResource')) {
+ /**
+ * Asserts that a variable is not of type resource.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !resource $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotResource
+ */
+ function assertIsNotResource($actual, string $message = ''): void
+ {
+ Assert::assertIsNotResource(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotClosedResource')) {
+ /**
+ * Asserts that a variable is not of type resource.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !resource $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotClosedResource
+ */
+ function assertIsNotClosedResource($actual, string $message = ''): void
+ {
+ Assert::assertIsNotClosedResource(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotString')) {
+ /**
+ * Asserts that a variable is not of type string.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !string $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotString
+ */
+ function assertIsNotString($actual, string $message = ''): void
+ {
+ Assert::assertIsNotString(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotScalar')) {
+ /**
+ * Asserts that a variable is not of type scalar.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !scalar $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotScalar
+ */
+ function assertIsNotScalar($actual, string $message = ''): void
+ {
+ Assert::assertIsNotScalar(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotCallable')) {
+ /**
+ * Asserts that a variable is not of type callable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !callable $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotCallable
+ */
+ function assertIsNotCallable($actual, string $message = ''): void
+ {
+ Assert::assertIsNotCallable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertIsNotIterable')) {
+ /**
+ * Asserts that a variable is not of type iterable.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @psalm-assert !iterable $actual
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertIsNotIterable
+ */
+ function assertIsNotIterable($actual, string $message = ''): void
+ {
+ Assert::assertIsNotIterable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertMatchesRegularExpression')) {
+ /**
+ * Asserts that a string matches a given regular expression.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertMatchesRegularExpression(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertRegExp')) {
+ /**
+ * Asserts that a string matches a given regular expression.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4086
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertRegExp
+ */
+ function assertRegExp(string $pattern, string $string, string $message = ''): void
+ {
+ Assert::assertRegExp(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertDoesNotMatchRegularExpression')) {
+ /**
+ * Asserts that a string does not match a given regular expression.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertDoesNotMatchRegularExpression(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertNotRegExp')) {
+ /**
+ * Asserts that a string does not match a given regular expression.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4089
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotRegExp
+ */
+ function assertNotRegExp(string $pattern, string $string, string $message = ''): void
+ {
+ Assert::assertNotRegExp(...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 ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertSameSize
+ */
+ function assertSameSize($expected, $actual, string $message = ''): void
+ {
+ 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 ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertNotSameSize
+ */
+ function assertNotSameSize($expected, $actual, string $message = ''): void
+ {
+ Assert::assertNotSameSize(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringMatchesFormat')) {
+ /**
+ * Asserts that a string matches a given format string.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertStringMatchesFormat(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringNotMatchesFormat')) {
+ /**
+ * Asserts that a string does not match a given format string.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertStringNotMatchesFormat
+ */
+ function assertStringNotMatchesFormat(string $format, string $string, string $message = ''): void
+ {
+ Assert::assertStringNotMatchesFormat(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringMatchesFormatFile')) {
+ /**
+ * Asserts that a string matches a given format file.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertStringMatchesFormatFile(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringNotMatchesFormatFile')) {
+ /**
+ * Asserts that a string does not match a given format string.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertStringNotMatchesFormatFile
+ */
+ function assertStringNotMatchesFormatFile(string $formatFile, string $string, string $message = ''): void
+ {
+ Assert::assertStringNotMatchesFormatFile(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringStartsWith')) {
+ /**
+ * Asserts that a string starts with a given prefix.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\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
+ {
+ Assert::assertStringStartsWith(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringStartsNotWith')) {
+ /**
+ * Asserts that a string starts not with a given prefix.
+ *
+ * @param string $prefix
+ * @param string $string
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertStringStartsNotWith
+ */
+ function assertStringStartsNotWith($prefix, $string, string $message = ''): void
+ {
+ Assert::assertStringStartsNotWith(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringContainsString')) {
+ /**
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertStringContainsString(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringContainsStringIgnoringCase')) {
+ /**
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertStringContainsStringIgnoringCase(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringNotContainsString')) {
+ /**
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertStringNotContainsString(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringNotContainsStringIgnoringCase')) {
+ /**
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertStringNotContainsStringIgnoringCase(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringEndsWith')) {
+ /**
+ * Asserts that a string ends with a given suffix.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\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
+ {
+ Assert::assertStringEndsWith(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertStringEndsNotWith')) {
+ /**
+ * Asserts that a string ends not with a given suffix.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\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
+ {
+ Assert::assertStringEndsNotWith(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertXmlFileEqualsXmlFile')) {
+ /**
+ * Asserts that two XML files are equal.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ *
+ * @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
+ {
+ Assert::assertXmlFileEqualsXmlFile(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertXmlFileNotEqualsXmlFile')) {
+ /**
+ * Asserts that two XML files are not equal.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws \PHPUnit\Util\Exception
+ *
+ * @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
+ {
+ Assert::assertXmlFileNotEqualsXmlFile(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertXmlStringEqualsXmlFile')) {
+ /**
+ * Asserts that two XML documents are equal.
+ *
+ * @param DOMDocument|string $actualXml
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws \PHPUnit\Util\Xml\Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertXmlStringEqualsXmlFile
+ */
+ function assertXmlStringEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void
+ {
+ Assert::assertXmlStringEqualsXmlFile(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertXmlStringNotEqualsXmlFile')) {
+ /**
+ * Asserts that two XML documents are not equal.
+ *
+ * @param DOMDocument|string $actualXml
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws \PHPUnit\Util\Xml\Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertXmlStringNotEqualsXmlFile
+ */
+ function assertXmlStringNotEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void
+ {
+ Assert::assertXmlStringNotEqualsXmlFile(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertXmlStringEqualsXmlString')) {
+ /**
+ * Asserts that two XML documents are equal.
+ *
+ * @param DOMDocument|string $expectedXml
+ * @param DOMDocument|string $actualXml
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws \PHPUnit\Util\Xml\Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertXmlStringEqualsXmlString
+ */
+ function assertXmlStringEqualsXmlString($expectedXml, $actualXml, string $message = ''): void
+ {
+ Assert::assertXmlStringEqualsXmlString(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertXmlStringNotEqualsXmlString')) {
+ /**
+ * Asserts that two XML documents are not equal.
+ *
+ * @param DOMDocument|string $expectedXml
+ * @param DOMDocument|string $actualXml
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws \PHPUnit\Util\Xml\Exception
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertXmlStringNotEqualsXmlString
+ */
+ function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, string $message = ''): void
+ {
+ Assert::assertXmlStringNotEqualsXmlString(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertEqualXMLStructure')) {
+ /**
+ * Asserts that a hierarchy of DOMElements matches.
+ *
+ * @throws AssertionFailedError
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @codeCoverageIgnore
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4091
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertEqualXMLStructure
+ */
+ function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement, bool $checkAttributes = false, string $message = ''): void
+ {
+ Assert::assertEqualXMLStructure(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertThat')) {
+ /**
+ * Evaluates a PHPUnit\Framework\Constraint matcher object.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertThat
+ */
+ function assertThat($value, Constraint $constraint, string $message = ''): void
+ {
+ Assert::assertThat(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertJson')) {
+ /**
+ * Asserts that a string is a valid JSON string.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertJson
+ */
+ function assertJson(string $actualJson, string $message = ''): void
+ {
+ Assert::assertJson(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertJsonStringEqualsJsonString')) {
+ /**
+ * Asserts that two given JSON encoded objects or arrays are equal.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertJsonStringEqualsJsonString(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertJsonStringNotEqualsJsonString')) {
+ /**
+ * Asserts that two given JSON encoded objects or arrays are not equal.
+ *
+ * @param string $expectedJson
+ * @param string $actualJson
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see Assert::assertJsonStringNotEqualsJsonString
+ */
+ function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, string $message = ''): void
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ 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
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertJsonStringNotEqualsJsonFile(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertJsonFileEqualsJsonFile')) {
+ /**
+ * Asserts that two JSON files are equal.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertJsonFileEqualsJsonFile(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\assertJsonFileNotEqualsJsonFile')) {
+ /**
+ * Asserts that two JSON files are not equal.
+ *
+ * @throws ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @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
+ {
+ Assert::assertJsonFileNotEqualsJsonFile(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\logicalAnd')) {
+ function logicalAnd(): LogicalAnd
+ {
+ return Assert::logicalAnd(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\logicalOr')) {
+ function logicalOr(): LogicalOr
+ {
+ return Assert::logicalOr(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\logicalNot')) {
+ function logicalNot(Constraint $constraint): LogicalNot
+ {
+ return Assert::logicalNot(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\logicalXor')) {
+ function logicalXor(): LogicalXor
+ {
+ return Assert::logicalXor(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\anything')) {
+ function anything(): IsAnything
+ {
+ return Assert::anything(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isTrue')) {
+ function isTrue(): IsTrue
+ {
+ return Assert::isTrue(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\callback')) {
+ function callback(callable $callback): Callback
+ {
+ return Assert::callback(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isFalse')) {
+ function isFalse(): IsFalse
+ {
+ return Assert::isFalse(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isJson')) {
+ function isJson(): IsJson
+ {
+ return Assert::isJson(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isNull')) {
+ function isNull(): IsNull
+ {
+ return Assert::isNull(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isFinite')) {
+ function isFinite(): IsFinite
+ {
+ return Assert::isFinite(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isInfinite')) {
+ function isInfinite(): IsInfinite
+ {
+ return Assert::isInfinite(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isNan')) {
+ function isNan(): IsNan
+ {
+ return Assert::isNan(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\containsEqual')) {
+ function containsEqual($value): TraversableContainsEqual
+ {
+ return Assert::containsEqual(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\containsIdentical')) {
+ function containsIdentical($value): TraversableContainsIdentical
+ {
+ return Assert::containsIdentical(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\containsOnly')) {
+ function containsOnly(string $type): TraversableContainsOnly
+ {
+ return Assert::containsOnly(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\containsOnlyInstancesOf')) {
+ function containsOnlyInstancesOf(string $className): TraversableContainsOnly
+ {
+ return Assert::containsOnlyInstancesOf(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\arrayHasKey')) {
+ function arrayHasKey($key): ArrayHasKey
+ {
+ return Assert::arrayHasKey(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\equalTo')) {
+ function equalTo($value): IsEqual
+ {
+ return Assert::equalTo(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\equalToCanonicalizing')) {
+ function equalToCanonicalizing($value): IsEqualCanonicalizing
+ {
+ return Assert::equalToCanonicalizing(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\equalToIgnoringCase')) {
+ function equalToIgnoringCase($value): IsEqualIgnoringCase
+ {
+ return Assert::equalToIgnoringCase(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\equalToWithDelta')) {
+ function equalToWithDelta($value, float $delta): IsEqualWithDelta
+ {
+ return Assert::equalToWithDelta(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isEmpty')) {
+ function isEmpty(): IsEmpty
+ {
+ return Assert::isEmpty(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isWritable')) {
+ function isWritable(): IsWritable
+ {
+ return Assert::isWritable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isReadable')) {
+ function isReadable(): IsReadable
+ {
+ return Assert::isReadable(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\directoryExists')) {
+ function directoryExists(): DirectoryExists
+ {
+ return Assert::directoryExists(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\fileExists')) {
+ function fileExists(): FileExists
+ {
+ return Assert::fileExists(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\greaterThan')) {
+ function greaterThan($value): GreaterThan
+ {
+ return Assert::greaterThan(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\greaterThanOrEqual')) {
+ function greaterThanOrEqual($value): LogicalOr
+ {
+ return Assert::greaterThanOrEqual(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\classHasAttribute')) {
+ function classHasAttribute(string $attributeName): ClassHasAttribute
+ {
+ return Assert::classHasAttribute(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\classHasStaticAttribute')) {
+ function classHasStaticAttribute(string $attributeName): ClassHasStaticAttribute
+ {
+ return Assert::classHasStaticAttribute(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\objectHasAttribute')) {
+ function objectHasAttribute($attributeName): ObjectHasAttribute
+ {
+ return Assert::objectHasAttribute(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\identicalTo')) {
+ function identicalTo($value): IsIdentical
+ {
+ return Assert::identicalTo(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isInstanceOf')) {
+ function isInstanceOf(string $className): IsInstanceOf
+ {
+ return Assert::isInstanceOf(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\isType')) {
+ function isType(string $type): IsType
+ {
+ return Assert::isType(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\lessThan')) {
+ function lessThan($value): LessThan
+ {
+ return Assert::lessThan(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\lessThanOrEqual')) {
+ function lessThanOrEqual($value): LogicalOr
+ {
+ return Assert::lessThanOrEqual(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\matchesRegularExpression')) {
+ function matchesRegularExpression(string $pattern): RegularExpression
+ {
+ return Assert::matchesRegularExpression(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\matches')) {
+ function matches(string $string): StringMatchesFormatDescription
+ {
+ return Assert::matches(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\stringStartsWith')) {
+ function stringStartsWith($prefix): StringStartsWith
+ {
+ return Assert::stringStartsWith(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\stringContains')) {
+ function stringContains(string $string, bool $case = true): StringContains
+ {
+ return Assert::stringContains(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\stringEndsWith')) {
+ function stringEndsWith(string $suffix): StringEndsWith
+ {
+ return Assert::stringEndsWith(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\countOf')) {
+ function countOf(int $count): Count
+ {
+ return Assert::countOf(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\objectEquals')) {
+ function objectEquals(object $object, string $method = 'equals'): ObjectEquals
+ {
+ return Assert::objectEquals(...func_get_args());
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\any')) {
+ /**
+ * Returns a matcher that matches when the method is executed
+ * zero or more times.
+ */
+ 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
+ {
+ 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\at')) {
+ /**
+ * Returns a matcher that matches when the method is executed
+ * at the given index.
+ */
+ function at(int $index): InvokedAtIndexMatcher
+ {
+ return new InvokedAtIndexMatcher($index);
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\returnValue')) {
+ function returnValue($value): ReturnStub
+ {
+ return new ReturnStub($value);
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\returnValueMap')) {
+ function returnValueMap(array $valueMap): ReturnValueMapStub
+ {
+ return new ReturnValueMapStub($valueMap);
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\returnArgument')) {
+ function returnArgument(int $argumentIndex): ReturnArgumentStub
+ {
+ return new ReturnArgumentStub($argumentIndex);
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\returnCallback')) {
+ function returnCallback($callback): ReturnCallbackStub
+ {
+ return new ReturnCallbackStub($callback);
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\returnSelf')) {
+ /**
+ * Returns the current object.
+ *
+ * This method is useful when mocking a fluent interface.
+ */
+ function returnSelf(): ReturnSelfStub
+ {
+ return new ReturnSelfStub;
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\throwException')) {
+ function throwException(Throwable $exception): ExceptionStub
+ {
+ return new ExceptionStub($exception);
+ }
+}
+
+if (!function_exists('PHPUnit\Framework\onConsecutiveCalls')) {
+ function onConsecutiveCalls(): ConsecutiveCallsStub
+ {
+ $args = func_get_args();
+
+ return new ConsecutiveCallsStub($args);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Boolean/IsFalse.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Boolean/IsFalse.php
new file mode 100644
index 000000000..212e2bcb4
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Boolean/IsFalse.php
@@ -0,0 +1,35 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'is false';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return $other === false;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Boolean/IsTrue.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Boolean/IsTrue.php
new file mode 100644
index 000000000..e1d6b2691
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Boolean/IsTrue.php
@@ -0,0 +1,35 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'is true';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return $other === true;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Callback.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Callback.php
new file mode 100644
index 000000000..b7cf95a12
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Callback.php
@@ -0,0 +1,52 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+/**
+ * @psalm-template CallbackInput of mixed
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class Callback extends Constraint
+{
+ /**
+ * @var callable
+ *
+ * @psalm-var callable(CallbackInput $input): bool
+ */
+ private $callback;
+
+ /** @psalm-param callable(CallbackInput $input): bool $callback */
+ public function __construct(callable $callback)
+ {
+ $this->callback = $callback;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'is accepted by specified callback';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $value. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ *
+ * @psalm-param CallbackInput $other
+ */
+ protected function matches($other): bool
+ {
+ return ($this->callback)($other);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/Count.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/Count.php
new file mode 100644
index 000000000..8e27fbfd4
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/Count.php
@@ -0,0 +1,142 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function count;
+use function is_array;
+use function iterator_count;
+use function sprintf;
+use Countable;
+use EmptyIterator;
+use Generator;
+use Iterator;
+use IteratorAggregate;
+use PHPUnit\Framework\Exception;
+use Traversable;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+class Count extends Constraint
+{
+ /**
+ * @var int
+ */
+ private $expectedCount;
+
+ public function __construct(int $expected)
+ {
+ $this->expectedCount = $expected;
+ }
+
+ public function toString(): string
+ {
+ return sprintf(
+ 'count matches %d',
+ $this->expectedCount
+ );
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @throws Exception
+ */
+ protected function matches($other): bool
+ {
+ return $this->expectedCount === $this->getCountOf($other);
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected function getCountOf($other): ?int
+ {
+ if ($other instanceof Countable || is_array($other)) {
+ return count($other);
+ }
+
+ if ($other instanceof EmptyIterator) {
+ return 0;
+ }
+
+ if ($other instanceof Traversable) {
+ while ($other instanceof IteratorAggregate) {
+ try {
+ $other = $other->getIterator();
+ } catch (\Exception $e) {
+ throw new Exception(
+ $e->getMessage(),
+ $e->getCode(),
+ $e
+ );
+ }
+ }
+
+ $iterator = $other;
+
+ if ($iterator instanceof Generator) {
+ return $this->getCountOfGenerator($iterator);
+ }
+
+ if (!$iterator instanceof Iterator) {
+ return iterator_count($iterator);
+ }
+
+ $key = $iterator->key();
+ $count = iterator_count($iterator);
+
+ // Manually rewind $iterator to previous key, since iterator_count
+ // moves pointer.
+ if ($key !== null) {
+ $iterator->rewind();
+
+ while ($iterator->valid() && $key !== $iterator->key()) {
+ $iterator->next();
+ }
+ }
+
+ return $count;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the total number of iterations from a generator.
+ * This will fully exhaust the generator.
+ */
+ protected function getCountOfGenerator(Generator $generator): int
+ {
+ for ($count = 0; $generator->valid(); $generator->next()) {
+ $count++;
+ }
+
+ return $count;
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ */
+ protected function failureDescription($other): string
+ {
+ return sprintf(
+ 'actual size %d matches expected size %d',
+ (int) $this->getCountOf($other),
+ $this->expectedCount
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/GreaterThan.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/GreaterThan.php
new file mode 100644
index 000000000..31df50201
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/GreaterThan.php
@@ -0,0 +1,50 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 GreaterThan extends Constraint
+{
+ /**
+ * @var float|int
+ */
+ private $value;
+
+ /**
+ * @param float|int $value
+ */
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ return 'is greater than ' . $this->exporter()->export($this->value);
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return $this->value < $other;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/IsEmpty.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/IsEmpty.php
new file mode 100644
index 000000000..e6371d536
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/IsEmpty.php
@@ -0,0 +1,70 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function count;
+use function gettype;
+use function sprintf;
+use function strpos;
+use Countable;
+use EmptyIterator;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class IsEmpty extends Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'is empty';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ if ($other instanceof EmptyIterator) {
+ return true;
+ }
+
+ if ($other instanceof Countable) {
+ return count($other) === 0;
+ }
+
+ return empty($other);
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ */
+ protected function failureDescription($other): string
+ {
+ $type = gettype($other);
+
+ return sprintf(
+ '%s %s %s',
+ strpos($type, 'a') === 0 || strpos($type, 'o') === 0 ? 'an' : 'a',
+ $type,
+ $this->toString()
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/LessThan.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/LessThan.php
new file mode 100644
index 000000000..c7884ba1d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/LessThan.php
@@ -0,0 +1,50 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 LessThan extends Constraint
+{
+ /**
+ * @var float|int
+ */
+ private $value;
+
+ /**
+ * @param float|int $value
+ */
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ return 'is less than ' . $this->exporter()->export($this->value);
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return $this->value > $other;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/SameSize.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/SameSize.php
new file mode 100644
index 000000000..a54679425
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/SameSize.php
@@ -0,0 +1,21 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 SameSize extends Count
+{
+ public function __construct(iterable $expected)
+ {
+ parent::__construct((int) $this->getCountOf($expected));
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php
new file mode 100644
index 000000000..f4fab056e
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php
@@ -0,0 +1,269 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function sprintf;
+use Countable;
+use PHPUnit\Framework\ExpectationFailedException;
+use PHPUnit\Framework\SelfDescribing;
+use SebastianBergmann\Comparator\ComparisonFailure;
+use SebastianBergmann\Exporter\Exporter;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+abstract class Constraint implements Countable, SelfDescribing
+{
+ /**
+ * @var ?Exporter
+ */
+ private $exporter;
+
+ /**
+ * Evaluates the constraint for parameter $other.
+ *
+ * If $returnResult is set to false (the default), an exception is thrown
+ * in case of a failure. null is returned otherwise.
+ *
+ * If $returnResult is true, the result of the evaluation is returned as
+ * a boolean value instead: true in case of success, false in case of a
+ * failure.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public function evaluate($other, string $description = '', bool $returnResult = false): ?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;
+ }
+
+ protected function exporter(): Exporter
+ {
+ if ($this->exporter === null) {
+ $this->exporter = new Exporter;
+ }
+
+ return $this->exporter;
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * This method can be overridden to implement the evaluation algorithm.
+ *
+ * @param mixed $other value or object to evaluate
+ * @codeCoverageIgnore
+ */
+ protected function matches($other): bool
+ {
+ return false;
+ }
+
+ /**
+ * Throws an exception for the given compared value and test description.
+ *
+ * @param mixed $other evaluated value or object
+ * @param string $description Additional information about the test
+ * @param ComparisonFailure $comparisonFailure
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-return never-return
+ */
+ protected function fail($other, $description, ComparisonFailure $comparisonFailure = null): void
+ {
+ $failureDescription = sprintf(
+ 'Failed asserting that %s.',
+ $this->failureDescription($other)
+ );
+
+ $additionalFailureDescription = $this->additionalFailureDescription($other);
+
+ if ($additionalFailureDescription) {
+ $failureDescription .= "\n" . $additionalFailureDescription;
+ }
+
+ if (!empty($description)) {
+ $failureDescription = $description . "\n" . $failureDescription;
+ }
+
+ throw new ExpectationFailedException(
+ $failureDescription,
+ $comparisonFailure
+ );
+ }
+
+ /**
+ * Return additional failure description where needed.
+ *
+ * The function can be overridden to provide additional failure
+ * information like a diff
+ *
+ * @param mixed $other evaluated value or object
+ */
+ protected function additionalFailureDescription($other): string
+ {
+ return '';
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * To provide additional failure information additionalFailureDescription
+ * can be used.
+ *
+ * @param mixed $other evaluated value or object
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function failureDescription($other): string
+ {
+ return $this->exporter()->export($other) . ' ' . $this->toString();
+ }
+
+ /**
+ * 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.
+ *
+ * @param Operator $operator the $operator of the expression
+ * @param mixed $role role of $this constraint in the $operator expression
+ */
+ protected function toStringInContext(Operator $operator, $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.
+ *
+ * @param Operator $operator the $operator of the expression
+ * @param mixed $role role of $this constraint in the $operator expression
+ * @param mixed $other evaluated value or object
+ */
+ protected function failureDescriptionInContext(Operator $operator, $role, $other): string
+ {
+ $string = $this->toStringInContext($operator, $role);
+
+ if ($string === '') {
+ return '';
+ }
+
+ return $this->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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqual.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqual.php
new file mode 100644
index 000000000..6a61ebfba
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqual.php
@@ -0,0 +1,138 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function is_string;
+use function sprintf;
+use function strpos;
+use function trim;
+use PHPUnit\Framework\ExpectationFailedException;
+use SebastianBergmann\Comparator\ComparisonFailure;
+use SebastianBergmann\Comparator\Factory as ComparatorFactory;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class IsEqual extends Constraint
+{
+ /**
+ * @var mixed
+ */
+ private $value;
+
+ /**
+ * @var float
+ */
+ private $delta;
+
+ /**
+ * @var bool
+ */
+ private $canonicalize;
+
+ /**
+ * @var bool
+ */
+ private $ignoreCase;
+
+ public function __construct($value, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false)
+ {
+ $this->value = $value;
+ $this->delta = $delta;
+ $this->canonicalize = $canonicalize;
+ $this->ignoreCase = $ignoreCase;
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other.
+ *
+ * If $returnResult is set to false (the default), an exception is thrown
+ * in case of a failure. null is returned otherwise.
+ *
+ * If $returnResult is true, the result of the evaluation is returned as
+ * a boolean value instead: true in case of success, false in case of a
+ * failure.
+ *
+ * @throws ExpectationFailedException
+ *
+ * @return bool
+ */
+ public function evaluate($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,
+ $this->canonicalize,
+ $this->ignoreCase
+ );
+ } catch (ComparisonFailure $f) {
+ if ($returnResult) {
+ return false;
+ }
+
+ throw new ExpectationFailedException(
+ trim($description . "\n" . $f->getMessage()),
+ $f
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ $delta = '';
+
+ if (is_string($this->value)) {
+ if (strpos($this->value, "\n") !== false) {
+ return 'is equal to <text>';
+ }
+
+ return sprintf(
+ "is equal to '%s'",
+ $this->value
+ );
+ }
+
+ if ($this->delta != 0) {
+ $delta = sprintf(
+ ' with delta <%F>',
+ $this->delta
+ );
+ }
+
+ return sprintf(
+ 'is equal to %s%s',
+ $this->exporter()->export($this->value),
+ $delta
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualCanonicalizing.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualCanonicalizing.php
new file mode 100644
index 000000000..57bb91ca1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualCanonicalizing.php
@@ -0,0 +1,108 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function is_string;
+use function sprintf;
+use function strpos;
+use function trim;
+use PHPUnit\Framework\ExpectationFailedException;
+use SebastianBergmann\Comparator\ComparisonFailure;
+use SebastianBergmann\Comparator\Factory as ComparatorFactory;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class IsEqualCanonicalizing extends Constraint
+{
+ /**
+ * @var mixed
+ */
+ private $value;
+
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other.
+ *
+ * If $returnResult is set to false (the default), an exception is thrown
+ * in case of a failure. null is returned otherwise.
+ *
+ * If $returnResult is true, the result of the evaluation is returned as
+ * a boolean value instead: true in case of success, false in case of a
+ * failure.
+ *
+ * @throws ExpectationFailedException
+ */
+ public function evaluate($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,
+ false
+ );
+ } catch (ComparisonFailure $f) {
+ if ($returnResult) {
+ return false;
+ }
+
+ throw new ExpectationFailedException(
+ trim($description . "\n" . $f->getMessage()),
+ $f
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ if (is_string($this->value)) {
+ if (strpos($this->value, "\n") !== false) {
+ return 'is equal to <text>';
+ }
+
+ return sprintf(
+ "is equal to '%s'",
+ $this->value
+ );
+ }
+
+ return sprintf(
+ 'is equal to %s',
+ $this->exporter()->export($this->value)
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualIgnoringCase.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualIgnoringCase.php
new file mode 100644
index 000000000..d657e96a2
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualIgnoringCase.php
@@ -0,0 +1,108 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function is_string;
+use function sprintf;
+use function strpos;
+use function trim;
+use PHPUnit\Framework\ExpectationFailedException;
+use SebastianBergmann\Comparator\ComparisonFailure;
+use SebastianBergmann\Comparator\Factory as ComparatorFactory;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class IsEqualIgnoringCase extends Constraint
+{
+ /**
+ * @var mixed
+ */
+ private $value;
+
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other.
+ *
+ * If $returnResult is set to false (the default), an exception is thrown
+ * in case of a failure. null is returned otherwise.
+ *
+ * If $returnResult is true, the result of the evaluation is returned as
+ * a boolean value instead: true in case of success, false in case of a
+ * failure.
+ *
+ * @throws ExpectationFailedException
+ */
+ public function evaluate($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.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ if (is_string($this->value)) {
+ if (strpos($this->value, "\n") !== false) {
+ return 'is equal to <text>';
+ }
+
+ return sprintf(
+ "is equal to '%s'",
+ $this->value
+ );
+ }
+
+ return sprintf(
+ 'is equal to %s',
+ $this->exporter()->export($this->value)
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php
new file mode 100644
index 000000000..0370b5118
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php
@@ -0,0 +1,100 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 SebastianBergmann\Comparator\ComparisonFailure;
+use SebastianBergmann\Comparator\Factory as ComparatorFactory;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class IsEqualWithDelta extends Constraint
+{
+ /**
+ * @var mixed
+ */
+ private $value;
+
+ /**
+ * @var float
+ */
+ private $delta;
+
+ public function __construct($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($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.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ return sprintf(
+ 'is equal to %s with delta <%F>>',
+ $this->exporter()->export($this->value),
+ $this->delta
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/Exception.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/Exception.php
new file mode 100644
index 000000000..860c0030f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/Exception.php
@@ -0,0 +1,85 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function get_class;
+use function sprintf;
+use PHPUnit\Util\Filter;
+use Throwable;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class Exception extends Constraint
+{
+ /**
+ * @var string
+ */
+ private $className;
+
+ public function __construct(string $className)
+ {
+ $this->className = $className;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return sprintf(
+ 'exception of type "%s"',
+ $this->className
+ );
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return $other instanceof $this->className;
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ */
+ protected function failureDescription($other): string
+ {
+ if ($other !== null) {
+ $message = '';
+
+ if ($other instanceof Throwable) {
+ $message = '. Message was: "' . $other->getMessage() . '" at'
+ . "\n" . Filter::getFilteredStacktrace($other);
+ }
+
+ return sprintf(
+ 'exception of type "%s" matches expected exception "%s"%s',
+ get_class($other),
+ $this->className,
+ $message
+ );
+ }
+
+ return sprintf(
+ 'exception of type "%s" is thrown',
+ $this->className
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionCode.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionCode.php
new file mode 100644
index 000000000..b8054a949
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionCode.php
@@ -0,0 +1,67 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function sprintf;
+use Throwable;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class ExceptionCode extends Constraint
+{
+ /**
+ * @var int|string
+ */
+ private $expectedCode;
+
+ /**
+ * @param int|string $expected
+ */
+ public function __construct($expected)
+ {
+ $this->expectedCode = $expected;
+ }
+
+ public function toString(): string
+ {
+ return 'exception code is ';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param Throwable $other
+ */
+ protected function matches($other): bool
+ {
+ return (string) $other->getCode() === (string) $this->expectedCode;
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function failureDescription($other): string
+ {
+ return sprintf(
+ '%s is equal to expected exception code %s',
+ $this->exporter()->export($other->getCode()),
+ $this->exporter()->export($this->expectedCode)
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionMessage.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionMessage.php
new file mode 100644
index 000000000..030beff98
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionMessage.php
@@ -0,0 +1,78 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function sprintf;
+use function strpos;
+use Throwable;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class ExceptionMessage extends Constraint
+{
+ /**
+ * @var string
+ */
+ private $expectedMessage;
+
+ public function __construct(string $expected)
+ {
+ $this->expectedMessage = $expected;
+ }
+
+ public function toString(): string
+ {
+ if ($this->expectedMessage === '') {
+ return 'exception message is empty';
+ }
+
+ return 'exception message contains ';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param Throwable $other
+ */
+ protected function matches($other): bool
+ {
+ if ($this->expectedMessage === '') {
+ return $other->getMessage() === '';
+ }
+
+ return strpos((string) $other->getMessage(), $this->expectedMessage) !== false;
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ */
+ protected function failureDescription($other): string
+ {
+ if ($this->expectedMessage === '') {
+ return sprintf(
+ "exception message is empty but is '%s'",
+ $other->getMessage()
+ );
+ }
+
+ return sprintf(
+ "exception message '%s' contains '%s'",
+ $other->getMessage(),
+ $this->expectedMessage
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionMessageRegularExpression.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionMessageRegularExpression.php
new file mode 100644
index 000000000..fd0db1c8f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionMessageRegularExpression.php
@@ -0,0 +1,74 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function sprintf;
+use Exception;
+use PHPUnit\Util\RegularExpression as RegularExpressionUtil;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class ExceptionMessageRegularExpression extends Constraint
+{
+ /**
+ * @var string
+ */
+ private $expectedMessageRegExp;
+
+ public function __construct(string $expected)
+ {
+ $this->expectedMessageRegExp = $expected;
+ }
+
+ public function toString(): string
+ {
+ return 'exception message matches ';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param \PHPUnit\Framework\Exception $other
+ *
+ * @throws \PHPUnit\Framework\Exception
+ * @throws Exception
+ */
+ protected function matches($other): bool
+ {
+ $match = RegularExpressionUtil::safeMatch($this->expectedMessageRegExp, $other->getMessage());
+
+ if ($match === false) {
+ throw new \PHPUnit\Framework\Exception(
+ "Invalid expected exception message regex given: '{$this->expectedMessageRegExp}'"
+ );
+ }
+
+ return $match === 1;
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ */
+ protected function failureDescription($other): string
+ {
+ return sprintf(
+ "exception message '%s' matches '%s'",
+ $other->getMessage(),
+ $this->expectedMessageRegExp
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/DirectoryExists.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/DirectoryExists.php
new file mode 100644
index 000000000..ef4b2baf0
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/DirectoryExists.php
@@ -0,0 +1,54 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'directory exists';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return is_dir($other);
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ */
+ protected function failureDescription($other): string
+ {
+ return sprintf(
+ 'directory "%s" exists',
+ $other
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/FileExists.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/FileExists.php
new file mode 100644
index 000000000..41b3136e9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/FileExists.php
@@ -0,0 +1,54 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'file exists';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return file_exists($other);
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ */
+ protected function failureDescription($other): string
+ {
+ return sprintf(
+ 'file "%s" exists',
+ $other
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/IsReadable.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/IsReadable.php
new file mode 100644
index 000000000..e33d7e045
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/IsReadable.php
@@ -0,0 +1,54 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'is readable';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return is_readable($other);
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ */
+ protected function failureDescription($other): string
+ {
+ return sprintf(
+ '"%s" is readable',
+ $other
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/IsWritable.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/IsWritable.php
new file mode 100644
index 000000000..93981224a
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Filesystem/IsWritable.php
@@ -0,0 +1,54 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'is writable';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return is_writable($other);
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ */
+ protected function failureDescription($other): string
+ {
+ return sprintf(
+ '"%s" is writable',
+ $other
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/IsAnything.php b/vendor/phpunit/phpunit/src/Framework/Constraint/IsAnything.php
new file mode 100644
index 000000000..db84a7431
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/IsAnything.php
@@ -0,0 +1,51 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class IsAnything extends Constraint
+{
+ /**
+ * Evaluates the constraint for parameter $other.
+ *
+ * If $returnResult is set to false (the default), an exception is thrown
+ * in case of a failure. null is returned otherwise.
+ *
+ * If $returnResult is true, the result of the evaluation is returned as
+ * a boolean value instead: true in case of success, false in case of a
+ * failure.
+ *
+ * @throws ExpectationFailedException
+ */
+ public function evaluate($other, string $description = '', bool $returnResult = false): ?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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php b/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php
new file mode 100644
index 000000000..565f1a3a8
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php
@@ -0,0 +1,137 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 PHP_FLOAT_EPSILON;
+use function abs;
+use function get_class;
+use function is_array;
+use function is_float;
+use function is_infinite;
+use function is_nan;
+use function is_object;
+use function is_string;
+use function sprintf;
+use PHPUnit\Framework\ExpectationFailedException;
+use SebastianBergmann\Comparator\ComparisonFailure;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class IsIdentical extends Constraint
+{
+ /**
+ * @var mixed
+ */
+ private $value;
+
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other.
+ *
+ * If $returnResult is set to false (the default), an exception is thrown
+ * in case of a failure. null is returned otherwise.
+ *
+ * If $returnResult is true, the result of the evaluation is returned as
+ * a boolean value instead: true in case of success, false in case of a
+ * failure.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
+ {
+ if (is_float($this->value) && is_float($other) &&
+ !is_infinite($this->value) && !is_infinite($other) &&
+ !is_nan($this->value) && !is_nan($other)) {
+ $success = abs($this->value - $other) < PHP_FLOAT_EPSILON;
+ } else {
+ $success = $this->value === $other;
+ }
+
+ if ($returnResult) {
+ return $success;
+ }
+
+ if (!$success) {
+ $f = null;
+
+ // if both values are strings, make sure a diff is generated
+ if (is_string($this->value) && is_string($other)) {
+ $f = new ComparisonFailure(
+ $this->value,
+ $other,
+ sprintf("'%s'", $this->value),
+ sprintf("'%s'", $other)
+ );
+ }
+
+ // if both values are array, make sure a diff is generated
+ if (is_array($this->value) && is_array($other)) {
+ $f = new ComparisonFailure(
+ $this->value,
+ $other,
+ $this->exporter()->export($this->value),
+ $this->exporter()->export($other)
+ );
+ }
+
+ $this->fail($other, $description, $f);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ if (is_object($this->value)) {
+ return 'is identical to an object of class "' .
+ get_class($this->value) . '"';
+ }
+
+ return 'is identical to ' . $this->exporter()->export($this->value);
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function failureDescription($other): string
+ {
+ if (is_object($this->value) && is_object($other)) {
+ return 'two variables reference the same object';
+ }
+
+ if (is_string($this->value) && is_string($other)) {
+ return 'two strings are identical';
+ }
+
+ if (is_array($this->value) && is_array($other)) {
+ return 'two arrays are identical';
+ }
+
+ return parent::failureDescription($other);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php b/vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php
new file mode 100644
index 000000000..23a4de7e9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php
@@ -0,0 +1,109 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function json_decode;
+use function sprintf;
+use PHPUnit\Framework\ExpectationFailedException;
+use PHPUnit\Util\Json;
+use SebastianBergmann\Comparator\ComparisonFailure;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class JsonMatches extends Constraint
+{
+ /**
+ * @var string
+ */
+ private $value;
+
+ public function __construct(string $value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * Returns a string representation of the object.
+ */
+ public function toString(): string
+ {
+ return sprintf(
+ 'matches JSON string "%s"',
+ $this->value
+ );
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * This method can be overridden to implement the evaluation algorithm.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ [$error, $recodedOther] = Json::canonicalize($other);
+
+ if ($error) {
+ return false;
+ }
+
+ [$error, $recodedValue] = Json::canonicalize($this->value);
+
+ if ($error) {
+ return false;
+ }
+
+ return $recodedOther == $recodedValue;
+ }
+
+ /**
+ * Throws an exception for the given compared value and test description.
+ *
+ * @param mixed $other evaluated value or object
+ * @param string $description Additional information about the test
+ * @param ComparisonFailure $comparisonFailure
+ *
+ * @throws \PHPUnit\Framework\Exception
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ *
+ * @psalm-return never-return
+ */
+ protected function fail($other, $description, ComparisonFailure $comparisonFailure = null): void
+ {
+ if ($comparisonFailure === null) {
+ [$error, $recodedOther] = Json::canonicalize($other);
+
+ if ($error) {
+ parent::fail($other, $description);
+ }
+
+ [$error, $recodedValue] = Json::canonicalize($this->value);
+
+ if ($error) {
+ parent::fail($other, $description);
+ }
+
+ $comparisonFailure = new ComparisonFailure(
+ json_decode($this->value),
+ json_decode($other),
+ Json::prettify($recodedValue),
+ Json::prettify($recodedOther),
+ false,
+ 'Failed asserting that two json values are equal.'
+ );
+ }
+
+ parent::fail($other, $description, $comparisonFailure);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatchesErrorMessageProvider.php b/vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatchesErrorMessageProvider.php
new file mode 100644
index 000000000..8ded556ce
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatchesErrorMessageProvider.php
@@ -0,0 +1,72 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use const JSON_ERROR_CTRL_CHAR;
+use const JSON_ERROR_DEPTH;
+use const JSON_ERROR_NONE;
+use const JSON_ERROR_STATE_MISMATCH;
+use const JSON_ERROR_SYNTAX;
+use const JSON_ERROR_UTF8;
+use function strtolower;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class JsonMatchesErrorMessageProvider
+{
+ /**
+ * Translates JSON error to a human readable string.
+ */
+ public static function determineJsonError(string $error, string $prefix = ''): ?string
+ {
+ switch ($error) {
+ case JSON_ERROR_NONE:
+ return null;
+ case JSON_ERROR_DEPTH:
+ return $prefix . 'Maximum stack depth exceeded';
+ case JSON_ERROR_STATE_MISMATCH:
+ return $prefix . 'Underflow or the modes mismatch';
+ case JSON_ERROR_CTRL_CHAR:
+ return $prefix . 'Unexpected control character found';
+ case JSON_ERROR_SYNTAX:
+ return $prefix . 'Syntax error, malformed JSON';
+ case JSON_ERROR_UTF8:
+ return $prefix . 'Malformed UTF-8 characters, possibly incorrectly encoded';
+
+ default:
+ return $prefix . 'Unknown error';
+ }
+ }
+
+ /**
+ * Translates a given type to a human readable message prefix.
+ */
+ public static function translateTypeToPrefix(string $type): string
+ {
+ switch (strtolower($type)) {
+ case 'expected':
+ $prefix = 'Expected value JSON decode error - ';
+
+ break;
+ case 'actual':
+ $prefix = 'Actual value JSON decode error - ';
+
+ break;
+
+ default:
+ $prefix = '';
+
+ break;
+ }
+
+ return $prefix;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsFinite.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsFinite.php
new file mode 100644
index 000000000..9a2f32866
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsFinite.php
@@ -0,0 +1,37 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'is finite';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return is_finite($other);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsInfinite.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsInfinite.php
new file mode 100644
index 000000000..c718514c2
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsInfinite.php
@@ -0,0 +1,37 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'is infinite';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return is_infinite($other);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsNan.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsNan.php
new file mode 100644
index 000000000..0062c5b5c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Math/IsNan.php
@@ -0,0 +1,37 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'is nan';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return is_nan($other);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ClassHasAttribute.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ClassHasAttribute.php
new file mode 100644
index 000000000..daa14027d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ClassHasAttribute.php
@@ -0,0 +1,88 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function get_class;
+use function is_object;
+use function sprintf;
+use PHPUnit\Framework\Exception;
+use ReflectionClass;
+use ReflectionException;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+class ClassHasAttribute extends Constraint
+{
+ /**
+ * @var string
+ */
+ private $attributeName;
+
+ public function __construct(string $attributeName)
+ {
+ $this->attributeName = $attributeName;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return sprintf(
+ 'has attribute "%s"',
+ $this->attributeName
+ );
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ try {
+ return (new ReflectionClass($other))->hasProperty($this->attributeName);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ */
+ protected function failureDescription($other): string
+ {
+ return sprintf(
+ '%sclass "%s" %s',
+ is_object($other) ? 'object of ' : '',
+ is_object($other) ? get_class($other) : $other,
+ $this->toString()
+ );
+ }
+
+ protected function attributeName(): string
+ {
+ return $this->attributeName;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ClassHasStaticAttribute.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ClassHasStaticAttribute.php
new file mode 100644
index 000000000..cacd0d752
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ClassHasStaticAttribute.php
@@ -0,0 +1,59 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function sprintf;
+use PHPUnit\Framework\Exception;
+use ReflectionClass;
+use ReflectionException;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class ClassHasStaticAttribute extends ClassHasAttribute
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return sprintf(
+ 'has static attribute "%s"',
+ $this->attributeName()
+ );
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ try {
+ $class = new ReflectionClass($other);
+
+ if ($class->hasProperty($this->attributeName())) {
+ return $class->getProperty($this->attributeName())->isStatic();
+ }
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ return false;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ObjectEquals.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ObjectEquals.php
new file mode 100644
index 000000000..30f3a330c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ObjectEquals.php
@@ -0,0 +1,151 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function get_class;
+use function is_object;
+use 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 Constraint
+{
+ /**
+ * @var object
+ */
+ private $expected;
+
+ /**
+ * @var string
+ */
+ private $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($other): bool
+ {
+ if (!is_object($other)) {
+ throw new ActualValueIsNotAnObjectException;
+ }
+
+ $object = new ReflectionObject($other);
+
+ if (!$object->hasMethod($this->method)) {
+ throw new ComparisonMethodDoesNotExistException(
+ get_class($other),
+ $this->method
+ );
+ }
+
+ /** @noinspection PhpUnhandledExceptionInspection */
+ $method = $object->getMethod($this->method);
+
+ if (!$method->hasReturnType()) {
+ throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
+ get_class($other),
+ $this->method
+ );
+ }
+
+ $returnType = $method->getReturnType();
+
+ if (!$returnType instanceof ReflectionNamedType) {
+ throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
+ get_class($other),
+ $this->method
+ );
+ }
+
+ if ($returnType->allowsNull()) {
+ throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
+ get_class($other),
+ $this->method
+ );
+ }
+
+ if ($returnType->getName() !== 'bool') {
+ throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
+ get_class($other),
+ $this->method
+ );
+ }
+
+ if ($method->getNumberOfParameters() !== 1 || $method->getNumberOfRequiredParameters() !== 1) {
+ throw new ComparisonMethodDoesNotDeclareExactlyOneParameterException(
+ get_class($other),
+ $this->method
+ );
+ }
+
+ $parameter = $method->getParameters()[0];
+
+ if (!$parameter->hasType()) {
+ throw new ComparisonMethodDoesNotDeclareParameterTypeException(
+ get_class($other),
+ $this->method
+ );
+ }
+
+ $type = $parameter->getType();
+
+ if (!$type instanceof ReflectionNamedType) {
+ throw new ComparisonMethodDoesNotDeclareParameterTypeException(
+ get_class($other),
+ $this->method
+ );
+ }
+
+ $typeName = $type->getName();
+
+ if ($typeName === 'self') {
+ $typeName = get_class($other);
+ }
+
+ if (!$this->expected instanceof $typeName) {
+ throw new ComparisonMethodDoesNotAcceptParameterTypeException(
+ get_class($other),
+ $this->method,
+ get_class($this->expected)
+ );
+ }
+
+ return $other->{$this->method}($this->expected);
+ }
+
+ protected function failureDescription($other): string
+ {
+ return $this->toString();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasAttribute.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasAttribute.php
new file mode 100644
index 000000000..5fbc0888c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Object/ObjectHasAttribute.php
@@ -0,0 +1,29 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use ReflectionObject;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class ObjectHasAttribute extends ClassHasAttribute
+{
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return (new ReflectionObject($other))->hasProperty($this->attributeName());
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/BinaryOperator.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/BinaryOperator.php
new file mode 100644
index 000000000..11c86b526
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/BinaryOperator.php
@@ -0,0 +1,148 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 array_values;
+use function count;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+abstract class BinaryOperator extends Operator
+{
+ /**
+ * @var Constraint[]
+ */
+ private $constraints = [];
+
+ public static function fromConstraints(Constraint ...$constraints): self
+ {
+ $constraint = new static;
+
+ $constraint->constraints = $constraints;
+
+ return $constraint;
+ }
+
+ /**
+ * @param mixed[] $constraints
+ */
+ public function setConstraints(array $constraints): void
+ {
+ $this->constraints = array_map(function ($constraint): Constraint
+ {
+ return $this->checkConstraint($constraint);
+ }, array_values($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;
+ }
+
+ /**
+ * Returns the nested constraints.
+ */
+ final protected function constraints(): array
+ {
+ return $this->constraints;
+ }
+
+ /**
+ * Returns true if the $constraint needs to be wrapped with braces.
+ */
+ final protected function constraintNeedsParentheses(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(): Constraint
+ {
+ if ($this->arity() === 1 && $this->constraints[0] instanceof Operator) {
+ return $this->constraints[0]->reduce();
+ }
+
+ return parent::reduce();
+ }
+
+ /**
+ * Returns string representation of given operand in context of this operator.
+ *
+ * @param Constraint $constraint operand constraint
+ * @param int $position position of $constraint in this expression
+ */
+ private function constraintToString(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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalAnd.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalAnd.php
new file mode 100644
index 000000000..a1af4dd32
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalAnd.php
@@ -0,0 +1,51 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 BinaryOperator
+{
+ /**
+ * 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.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ foreach ($this->constraints() as $constraint) {
+ if (!$constraint->evaluate($other, '', true)) {
+ return false;
+ }
+ }
+
+ return [] !== $this->constraints();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalNot.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalNot.php
new file mode 100644
index 000000000..7560ce2a1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalNot.php
@@ -0,0 +1,136 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+use function preg_match;
+use function preg_quote;
+use function preg_replace;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class LogicalNot extends UnaryOperator
+{
+ 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);
+
+ $positives = array_map(static function (string $s)
+ {
+ return '/\\b' . preg_quote($s, '/') . '/';
+ }, $positives);
+
+ if (count($matches) > 0) {
+ $nonInput = $matches[2];
+
+ $negatedString = preg_replace(
+ '/' . preg_quote($nonInput, '/') . '/',
+ preg_replace(
+ $positives,
+ $negatives,
+ $nonInput
+ ),
+ $string
+ );
+ } else {
+ $negatedString = preg_replace(
+ $positives,
+ $negatives,
+ $string
+ );
+ }
+
+ 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.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($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(): Constraint
+ {
+ $constraint = $this->constraint();
+
+ if ($constraint instanceof self) {
+ return $constraint->constraint()->reduce();
+ }
+
+ return parent::reduce();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalOr.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalOr.php
new file mode 100644
index 000000000..2932de675
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalOr.php
@@ -0,0 +1,51 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 LogicalOr extends BinaryOperator
+{
+ /**
+ * 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.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ public function matches($other): bool
+ {
+ foreach ($this->constraints() as $constraint) {
+ if ($constraint->evaluate($other, '', true)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalXor.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalXor.php
new file mode 100644
index 000000000..fbdb479bc
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/LogicalXor.php
@@ -0,0 +1,63 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class LogicalXor extends BinaryOperator
+{
+ /**
+ * 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.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ public function matches($other): bool
+ {
+ $constraints = $this->constraints();
+
+ $initial = array_shift($constraints);
+
+ if ($initial === null) {
+ return false;
+ }
+
+ return array_reduce(
+ $constraints,
+ static function (bool $matches, Constraint $constraint) use ($other): bool
+ {
+ return $matches xor $constraint->evaluate($other, '', true);
+ },
+ $initial->evaluate($other, '', true)
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/Operator.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/Operator.php
new file mode 100644
index 000000000..3f51a0f40
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/Operator.php
@@ -0,0 +1,55 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 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($constraint): Constraint
+ {
+ if (!$constraint instanceof Constraint) {
+ return new IsEqual($constraint);
+ }
+
+ return $constraint;
+ }
+
+ /**
+ * Returns true if the $constraint needs to be wrapped with braces.
+ */
+ protected function constraintNeedsParentheses(Constraint $constraint): bool
+ {
+ return $constraint instanceof self &&
+ $constraint->arity() > 1 &&
+ $this->precedence() <= $constraint->precedence();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/UnaryOperator.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/UnaryOperator.php
new file mode 100644
index 000000000..0a7a5fa2f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/UnaryOperator.php
@@ -0,0 +1,140 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Operator
+{
+ /**
+ * @var Constraint
+ */
+ private $constraint;
+
+ /**
+ * @param Constraint|mixed $constraint
+ */
+ public function __construct($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.
+ *
+ * @param mixed $other evaluated value or object
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function failureDescription($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 memeber 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().
+ *
+ * @param string $string the string to be transformed
+ */
+ protected function transformString(string $string): string
+ {
+ return $string;
+ }
+
+ /**
+ * Provides access to $this->constraint for subclasses.
+ */
+ final protected function constraint(): Constraint
+ {
+ return $this->constraint;
+ }
+
+ /**
+ * Returns true if the $constraint needs to be wrapped with parentheses.
+ */
+ protected function constraintNeedsParentheses(Constraint $constraint): bool
+ {
+ $constraint = $constraint->reduce();
+
+ return $constraint instanceof self || parent::constraintNeedsParentheses($constraint);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/String/IsJson.php b/vendor/phpunit/phpunit/src/Framework/Constraint/String/IsJson.php
new file mode 100644
index 000000000..97b294617
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/String/IsJson.php
@@ -0,0 +1,77 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function json_decode;
+use function json_last_error;
+use function sprintf;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class IsJson extends Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'is valid JSON';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ if ($other === '') {
+ return false;
+ }
+
+ json_decode($other);
+
+ if (json_last_error()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function failureDescription($other): string
+ {
+ if ($other === '') {
+ return 'an empty string is valid JSON';
+ }
+
+ json_decode($other);
+ $error = (string) JsonMatchesErrorMessageProvider::determineJsonError(
+ (string) json_last_error()
+ );
+
+ return sprintf(
+ '%s is valid JSON (%s)',
+ $this->exporter()->shortenedExport($other),
+ $error
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/String/RegularExpression.php b/vendor/phpunit/phpunit/src/Framework/Constraint/String/RegularExpression.php
new file mode 100644
index 000000000..8e609e795
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/String/RegularExpression.php
@@ -0,0 +1,51 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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
+ */
+class RegularExpression extends Constraint
+{
+ /**
+ * @var string
+ */
+ private $pattern;
+
+ public function __construct(string $pattern)
+ {
+ $this->pattern = $pattern;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return sprintf(
+ 'matches PCRE pattern "%s"',
+ $this->pattern
+ );
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return preg_match($this->pattern, $other) > 0;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringContains.php b/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringContains.php
new file mode 100644
index 000000000..6279f37ba
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringContains.php
@@ -0,0 +1,85 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function mb_stripos;
+use function mb_strtolower;
+use function sprintf;
+use function strpos;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class StringContains extends Constraint
+{
+ /**
+ * @var string
+ */
+ private $string;
+
+ /**
+ * @var bool
+ */
+ private $ignoreCase;
+
+ public function __construct(string $string, bool $ignoreCase = false)
+ {
+ $this->string = $string;
+ $this->ignoreCase = $ignoreCase;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ if ($this->ignoreCase) {
+ $string = mb_strtolower($this->string, 'UTF-8');
+ } else {
+ $string = $this->string;
+ }
+
+ return sprintf(
+ 'contains "%s"',
+ $string
+ );
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ if ('' === $this->string) {
+ return true;
+ }
+
+ if ($this->ignoreCase) {
+ /*
+ * We must use the multi byte safe version so we can accurately compare non latin upper characters with
+ * their lowercase equivalents.
+ */
+ return mb_stripos($other, $this->string, 0, 'UTF-8') !== false;
+ }
+
+ /*
+ * Use the non multi byte 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 strpos($other, $this->string) !== false;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringEndsWith.php b/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringEndsWith.php
new file mode 100644
index 000000000..bb4ce23be
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringEndsWith.php
@@ -0,0 +1,48 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function strlen;
+use function substr;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class StringEndsWith extends Constraint
+{
+ /**
+ * @var string
+ */
+ private $suffix;
+
+ public function __construct(string $suffix)
+ {
+ $this->suffix = $suffix;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'ends with "' . $this->suffix . '"';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return substr($other, 0 - strlen($this->suffix)) === $this->suffix;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringMatchesFormatDescription.php b/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringMatchesFormatDescription.php
new file mode 100644
index 000000000..c4f7324ec
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringMatchesFormatDescription.php
@@ -0,0 +1,109 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use const DIRECTORY_SEPARATOR;
+use function explode;
+use function implode;
+use function preg_match;
+use function preg_quote;
+use function preg_replace;
+use function strtr;
+use SebastianBergmann\Diff\Differ;
+use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class StringMatchesFormatDescription extends RegularExpression
+{
+ /**
+ * @var string
+ */
+ private $string;
+
+ public function __construct(string $string)
+ {
+ parent::__construct(
+ $this->createPatternFromFormat(
+ $this->convertNewlines($string)
+ )
+ );
+
+ $this->string = $string;
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return parent::matches(
+ $this->convertNewlines($other)
+ );
+ }
+
+ protected function failureDescription($other): string
+ {
+ return 'string matches format description';
+ }
+
+ protected function additionalFailureDescription($other): string
+ {
+ $from = explode("\n", $this->string);
+ $to = explode("\n", $this->convertNewlines($other));
+
+ foreach ($from as $index => $line) {
+ if (isset($to[$index]) && $line !== $to[$index]) {
+ $line = $this->createPatternFromFormat($line);
+
+ if (preg_match($line, $to[$index]) > 0) {
+ $from[$index] = $to[$index];
+ }
+ }
+ }
+
+ $this->string = implode("\n", $from);
+ $other = implode("\n", $to);
+
+ return (new Differ(new UnifiedDiffOutputBuilder("--- Expected\n+++ Actual\n")))->diff($this->string, $other);
+ }
+
+ private function createPatternFromFormat(string $string): string
+ {
+ $string = strtr(
+ preg_quote($string, '/'),
+ [
+ '%%' => '%',
+ '%e' => '\\' . DIRECTORY_SEPARATOR,
+ '%s' => '[^\r\n]+',
+ '%S' => '[^\r\n]*',
+ '%a' => '.+',
+ '%A' => '.*',
+ '%w' => '\s*',
+ '%i' => '[+-]?\d+',
+ '%d' => '\d+',
+ '%x' => '[0-9a-fA-F]+',
+ '%f' => '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?',
+ '%c' => '.',
+ ]
+ );
+
+ return '/^' . $string . '$/s';
+ }
+
+ private function convertNewlines(string $text): string
+ {
+ return preg_replace('/\r\n/', "\n", $text);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringStartsWith.php b/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringStartsWith.php
new file mode 100644
index 000000000..089545c12
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/String/StringStartsWith.php
@@ -0,0 +1,53 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function strlen;
+use function strpos;
+use PHPUnit\Framework\InvalidArgumentException;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class StringStartsWith extends Constraint
+{
+ /**
+ * @var string
+ */
+ private $prefix;
+
+ public function __construct(string $prefix)
+ {
+ if (strlen($prefix) === 0) {
+ throw InvalidArgumentException::create(1, 'non-empty string');
+ }
+
+ $this->prefix = $prefix;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'starts with "' . $this->prefix . '"';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return strpos((string) $other, $this->prefix) === 0;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/ArrayHasKey.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/ArrayHasKey.php
new file mode 100644
index 000000000..44cada3a7
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/ArrayHasKey.php
@@ -0,0 +1,77 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class ArrayHasKey extends Constraint
+{
+ /**
+ * @var int|string
+ */
+ private $key;
+
+ /**
+ * @param int|string $key
+ */
+ public function __construct($key)
+ {
+ $this->key = $key;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ return 'has the key ' . $this->exporter()->export($this->key);
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ if (is_array($other)) {
+ return array_key_exists($this->key, $other);
+ }
+
+ if ($other instanceof ArrayAccess) {
+ return $other->offsetExists($this->key);
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function failureDescription($other): string
+ {
+ return 'an array ' . $this->toString();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContains.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContains.php
new file mode 100644
index 000000000..39660a985
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContains.php
@@ -0,0 +1,63 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+abstract class TraversableContains extends Constraint
+{
+ /**
+ * @var mixed
+ */
+ private $value;
+
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ return 'contains ' . $this->exporter()->export($this->value);
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function failureDescription($other): string
+ {
+ return sprintf(
+ '%s %s',
+ is_array($other) ? 'an array' : 'a traversable',
+ $this->toString()
+ );
+ }
+
+ protected function value()
+ {
+ return $this->value;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsEqual.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsEqual.php
new file mode 100644
index 000000000..c315e709a
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsEqual.php
@@ -0,0 +1,40 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 TraversableContains
+{
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ if ($other instanceof SplObjectStorage) {
+ return $other->contains($this->value());
+ }
+
+ foreach ($other as $element) {
+ /* @noinspection TypeUnsafeComparisonInspection */
+ if ($this->value() == $element) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsIdentical.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsIdentical.php
new file mode 100644
index 000000000..a3437dbc9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsIdentical.php
@@ -0,0 +1,39 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 TraversableContains
+{
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ if ($other instanceof SplObjectStorage) {
+ return $other->contains($this->value());
+ }
+
+ foreach ($other as $element) {
+ if ($this->value() === $element) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsOnly.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsOnly.php
new file mode 100644
index 000000000..cf4a46b42
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsOnly.php
@@ -0,0 +1,91 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Traversable;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class TraversableContainsOnly extends Constraint
+{
+ /**
+ * @var Constraint
+ */
+ private $constraint;
+
+ /**
+ * @var string
+ */
+ private $type;
+
+ /**
+ * @throws \PHPUnit\Framework\Exception
+ */
+ public function __construct(string $type, bool $isNativeType = true)
+ {
+ if ($isNativeType) {
+ $this->constraint = new IsType($type);
+ } else {
+ $this->constraint = new IsInstanceOf(
+ $type
+ );
+ }
+
+ $this->type = $type;
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other.
+ *
+ * If $returnResult is set to false (the default), an exception is thrown
+ * in case of a failure. null is returned otherwise.
+ *
+ * If $returnResult is true, the result of the evaluation is returned as
+ * a boolean value instead: true in case of success, false in case of a
+ * failure.
+ *
+ * @param mixed|Traversable $other
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
+ {
+ $success = true;
+
+ foreach ($other as $item) {
+ if (!$this->constraint->evaluate($item, '', true)) {
+ $success = false;
+
+ break;
+ }
+ }
+
+ if ($returnResult) {
+ return $success;
+ }
+
+ if (!$success) {
+ $this->fail($other, $description);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'contains only values of type "' . $this->type . '"';
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsInstanceOf.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsInstanceOf.php
new file mode 100644
index 000000000..f0fa02b99
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsInstanceOf.php
@@ -0,0 +1,87 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Constraint;
+
+use function sprintf;
+use ReflectionClass;
+use ReflectionException;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class IsInstanceOf extends Constraint
+{
+ /**
+ * @var string
+ */
+ private $className;
+
+ public function __construct(string $className)
+ {
+ $this->className = $className;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return sprintf(
+ 'is instance of %s "%s"',
+ $this->getType(),
+ $this->className
+ );
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return $other instanceof $this->className;
+ }
+
+ /**
+ * Returns the description of the failure.
+ *
+ * The beginning of failure messages is "Failed asserting that" in most
+ * cases. This method should return the second part of that sentence.
+ *
+ * @param mixed $other evaluated value or object
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function failureDescription($other): string
+ {
+ return sprintf(
+ '%s is an instance of %s "%s"',
+ $this->exporter()->shortenedExport($other),
+ $this->getType(),
+ $this->className
+ );
+ }
+
+ private function getType(): string
+ {
+ try {
+ $reflection = new ReflectionClass($this->className);
+
+ if ($reflection->isInterface()) {
+ return 'interface';
+ }
+ } catch (ReflectionException $e) {
+ }
+
+ return 'class';
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsNull.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsNull.php
new file mode 100644
index 000000000..b9fcdd7a7
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsNull.php
@@ -0,0 +1,35 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Constraint
+{
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return 'is null';
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ return $other === null;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsType.php b/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsType.php
new file mode 100644
index 000000000..5bc691d74
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsType.php
@@ -0,0 +1,210 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class IsType extends Constraint
+{
+ /**
+ * @var string
+ */
+ public const TYPE_ARRAY = 'array';
+
+ /**
+ * @var string
+ */
+ public const TYPE_BOOL = 'bool';
+
+ /**
+ * @var string
+ */
+ public const TYPE_FLOAT = 'float';
+
+ /**
+ * @var string
+ */
+ public const TYPE_INT = 'int';
+
+ /**
+ * @var string
+ */
+ public const TYPE_NULL = 'null';
+
+ /**
+ * @var string
+ */
+ public const TYPE_NUMERIC = 'numeric';
+
+ /**
+ * @var string
+ */
+ public const TYPE_OBJECT = 'object';
+
+ /**
+ * @var string
+ */
+ public const TYPE_RESOURCE = 'resource';
+
+ /**
+ * @var string
+ */
+ public const TYPE_CLOSED_RESOURCE = 'resource (closed)';
+
+ /**
+ * @var string
+ */
+ public const TYPE_STRING = 'string';
+
+ /**
+ * @var string
+ */
+ public const TYPE_SCALAR = 'scalar';
+
+ /**
+ * @var string
+ */
+ public const TYPE_CALLABLE = 'callable';
+
+ /**
+ * @var string
+ */
+ public const TYPE_ITERABLE = 'iterable';
+
+ /**
+ * @var array<string,bool>
+ */
+ private const KNOWN_TYPES = [
+ 'array' => true,
+ 'boolean' => true,
+ 'bool' => true,
+ 'double' => true,
+ 'float' => true,
+ 'integer' => true,
+ 'int' => true,
+ 'null' => true,
+ 'numeric' => true,
+ 'object' => true,
+ 'real' => true,
+ 'resource' => true,
+ 'resource (closed)' => true,
+ 'string' => true,
+ 'scalar' => true,
+ 'callable' => true,
+ 'iterable' => true,
+ ];
+
+ /**
+ * @var string
+ */
+ private $type;
+
+ /**
+ * @throws \PHPUnit\Framework\Exception
+ */
+ public function __construct(string $type)
+ {
+ if (!isset(self::KNOWN_TYPES[$type])) {
+ throw new \PHPUnit\Framework\Exception(
+ sprintf(
+ 'Type specified for PHPUnit\Framework\Constraint\IsType <%s> ' .
+ 'is not a valid type.',
+ $type
+ )
+ );
+ }
+
+ $this->type = $type;
+ }
+
+ /**
+ * Returns a string representation of the constraint.
+ */
+ public function toString(): string
+ {
+ return sprintf(
+ 'is of type "%s"',
+ $this->type
+ );
+ }
+
+ /**
+ * Evaluates the constraint for parameter $other. Returns true if the
+ * constraint is met, false otherwise.
+ *
+ * @param mixed $other value or object to evaluate
+ */
+ protected function matches($other): bool
+ {
+ switch ($this->type) {
+ case 'numeric':
+ return is_numeric($other);
+
+ case 'integer':
+ case 'int':
+ return is_int($other);
+
+ case 'double':
+ case 'float':
+ case 'real':
+ return is_float($other);
+
+ case 'string':
+ return is_string($other);
+
+ case 'boolean':
+ case 'bool':
+ return is_bool($other);
+
+ case 'null':
+ return null === $other;
+
+ case 'array':
+ return is_array($other);
+
+ case 'object':
+ return is_object($other);
+
+ case 'resource':
+ $type = gettype($other);
+
+ return $type === 'resource' || $type === 'resource (closed)';
+
+ case 'resource (closed)':
+ return gettype($other) === 'resource (closed)';
+
+ case 'scalar':
+ return is_scalar($other);
+
+ case 'callable':
+ return is_callable($other);
+
+ case 'iterable':
+ return is_iterable($other);
+
+ default:
+ return false;
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/DataProviderTestSuite.php b/vendor/phpunit/phpunit/src/Framework/DataProviderTestSuite.php
new file mode 100644
index 000000000..18b549996
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/DataProviderTestSuite.php
@@ -0,0 +1,75 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use function explode;
+use PHPUnit\Util\Test as TestUtil;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class DataProviderTestSuite extends TestSuite
+{
+ /**
+ * @var list<ExecutionOrderDependency>
+ */
+ private $dependencies = [];
+
+ /**
+ * @param list<ExecutionOrderDependency> $dependencies
+ */
+ public function setDependencies(array $dependencies): void
+ {
+ $this->dependencies = $dependencies;
+
+ foreach ($this->tests as $test) {
+ if (!$test instanceof TestCase) {
+ // @codeCoverageIgnoreStart
+ continue;
+ // @codeCoverageIgnoreStart
+ }
+ $test->setDependencies($dependencies);
+ }
+ }
+
+ /**
+ * @return list<ExecutionOrderDependency>
+ */
+ public function provides(): array
+ {
+ if ($this->providedTests === null) {
+ $this->providedTests = [new ExecutionOrderDependency($this->getName())];
+ }
+
+ return $this->providedTests;
+ }
+
+ /**
+ * @return list<ExecutionOrderDependency>
+ */
+ 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 the each test created using the data provider(s).
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function getSize(): int
+ {
+ [$className, $methodName] = explode('::', $this->getName());
+
+ return TestUtil::getSize($className, $methodName);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Error/Deprecated.php b/vendor/phpunit/phpunit/src/Framework/Error/Deprecated.php
new file mode 100644
index 000000000..db62195f8
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Error/Deprecated.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Error;
+
+/**
+ * @internal
+ */
+final class Deprecated extends Error
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Error/Error.php b/vendor/phpunit/phpunit/src/Framework/Error/Error.php
new file mode 100644
index 000000000..2990b360e
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Error/Error.php
@@ -0,0 +1,26 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Error;
+
+use PHPUnit\Framework\Exception;
+
+/**
+ * @internal
+ */
+class Error extends Exception
+{
+ public function __construct(string $message, int $code, string $file, int $line, \Exception $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+
+ $this->file = $file;
+ $this->line = $line;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Error/Notice.php b/vendor/phpunit/phpunit/src/Framework/Error/Notice.php
new file mode 100644
index 000000000..54e5e31ea
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Error/Notice.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Error;
+
+/**
+ * @internal
+ */
+final class Notice extends Error
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Error/Warning.php b/vendor/phpunit/phpunit/src/Framework/Error/Warning.php
new file mode 100644
index 000000000..0c0c0064f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Error/Warning.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\Error;
+
+/**
+ * @internal
+ */
+final class Warning extends Error
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/ErrorTestCase.php b/vendor/phpunit/phpunit/src/Framework/ErrorTestCase.php
new file mode 100644
index 000000000..841247d72
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/ErrorTestCase.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ErrorTestCase extends TestCase
+{
+ /**
+ * @var bool
+ */
+ protected $backupGlobals = false;
+
+ /**
+ * @var bool
+ */
+ protected $backupStaticAttributes = false;
+
+ /**
+ * @var bool
+ */
+ protected $runTestInSeparateProcess = false;
+
+ /**
+ * @var string
+ */
+ private $message;
+
+ public function __construct(string $message = '')
+ {
+ $this->message = $message;
+
+ parent::__construct('Error');
+ }
+
+ public function getMessage(): string
+ {
+ return $this->message;
+ }
+
+ /**
+ * Returns a string representation of the test case.
+ */
+ public function toString(): string
+ {
+ return 'Error';
+ }
+
+ /**
+ * @throws Exception
+ *
+ * @psalm-return never-return
+ */
+ protected function runTest(): void
+ {
+ throw new Error($this->message);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/ActualValueIsNotAnObjectException.php b/vendor/phpunit/phpunit/src/Framework/Exception/ActualValueIsNotAnObjectException.php
new file mode 100644
index 000000000..adae28294
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/ActualValueIsNotAnObjectException.php
@@ -0,0 +1,32 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ActualValueIsNotAnObjectException extends Exception
+{
+ public function __construct()
+ {
+ parent::__construct(
+ 'Actual value is not an object',
+ 0,
+ null
+ );
+ }
+
+ public function __toString(): string
+ {
+ return $this->getMessage() . PHP_EOL;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/AssertionFailedError.php b/vendor/phpunit/phpunit/src/Framework/Exception/AssertionFailedError.php
new file mode 100644
index 000000000..0ba25286f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/AssertionFailedError.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class AssertionFailedError extends Exception implements SelfDescribing
+{
+ /**
+ * Wrapper for getMessage() which is declared as final.
+ */
+ public function toString(): string
+ {
+ return $this->getMessage();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/CodeCoverageException.php b/vendor/phpunit/phpunit/src/Framework/Exception/CodeCoverageException.php
new file mode 100644
index 000000000..36b072313
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/CodeCoverageException.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class CodeCoverageException extends Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotAcceptParameterTypeException.php b/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotAcceptParameterTypeException.php
new file mode 100644
index 000000000..ebd68f34c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotAcceptParameterTypeException.php
@@ -0,0 +1,38 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 sprintf;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ComparisonMethodDoesNotAcceptParameterTypeException extends 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
+ ),
+ 0,
+ null
+ );
+ }
+
+ public function __toString(): string
+ {
+ return $this->getMessage() . PHP_EOL;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php b/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php
new file mode 100644
index 000000000..20189cde4
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php
@@ -0,0 +1,37 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 sprintf;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ComparisonMethodDoesNotDeclareBoolReturnTypeException extends Exception
+{
+ public function __construct(string $className, string $methodName)
+ {
+ parent::__construct(
+ sprintf(
+ 'Comparison method %s::%s() does not declare bool return type.',
+ $className,
+ $methodName
+ ),
+ 0,
+ null
+ );
+ }
+
+ public function __toString(): string
+ {
+ return $this->getMessage() . PHP_EOL;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php b/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php
new file mode 100644
index 000000000..bd09d87cc
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php
@@ -0,0 +1,37 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 sprintf;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ComparisonMethodDoesNotDeclareExactlyOneParameterException extends Exception
+{
+ public function __construct(string $className, string $methodName)
+ {
+ parent::__construct(
+ sprintf(
+ 'Comparison method %s::%s() does not declare exactly one parameter.',
+ $className,
+ $methodName
+ ),
+ 0,
+ null
+ );
+ }
+
+ public function __toString(): string
+ {
+ return $this->getMessage() . PHP_EOL;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareParameterTypeException.php b/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareParameterTypeException.php
new file mode 100644
index 000000000..9bbb112ea
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotDeclareParameterTypeException.php
@@ -0,0 +1,37 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 sprintf;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ComparisonMethodDoesNotDeclareParameterTypeException extends 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
+ ),
+ 0,
+ null
+ );
+ }
+
+ public function __toString(): string
+ {
+ return $this->getMessage() . PHP_EOL;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotExistException.php b/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotExistException.php
new file mode 100644
index 000000000..ad0e2d088
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/ComparisonMethodDoesNotExistException.php
@@ -0,0 +1,37 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 sprintf;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ComparisonMethodDoesNotExistException extends Exception
+{
+ public function __construct(string $className, string $methodName)
+ {
+ parent::__construct(
+ sprintf(
+ 'Comparison method %s::%s() does not exist.',
+ $className,
+ $methodName
+ ),
+ 0,
+ null
+ );
+ }
+
+ public function __toString(): string
+ {
+ return $this->getMessage() . PHP_EOL;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/CoveredCodeNotExecutedException.php b/vendor/phpunit/phpunit/src/Framework/Exception/CoveredCodeNotExecutedException.php
new file mode 100644
index 000000000..78f89bc39
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/CoveredCodeNotExecutedException.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class CoveredCodeNotExecutedException extends RiskyTestError
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/Error.php b/vendor/phpunit/phpunit/src/Framework/Exception/Error.php
new file mode 100644
index 000000000..d43e42186
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/Error.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Error extends Exception implements SelfDescribing
+{
+ /**
+ * Wrapper for getMessage() which is declared as final.
+ */
+ public function toString(): string
+ {
+ return $this->getMessage();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/Exception.php b/vendor/phpunit/phpunit/src/Framework/Exception/Exception.php
new file mode 100644
index 000000000..0b21e6de3
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/Exception.php
@@ -0,0 +1,81 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use function array_keys;
+use function get_object_vars;
+use PHPUnit\Util\Filter;
+use RuntimeException;
+use Throwable;
+
+/**
+ * Base class for all PHPUnit Framework exceptions.
+ *
+ * Ensures that exceptions thrown during a test run do not leave stray
+ * references behind.
+ *
+ * Every Exception contains a stack trace. Each stack frame contains the 'args'
+ * of the called function. The function arguments can contain references to
+ * instantiated objects. The references prevent the objects from being
+ * destructed (until test results are eventually printed), so memory cannot be
+ * freed up.
+ *
+ * With enabled process isolation, test results are serialized in the child
+ * process and unserialized in the parent process. The stack trace of Exceptions
+ * may contain objects that cannot be serialized or unserialized (e.g., PDO
+ * connections). Unserializing user-space objects from the child process into
+ * the parent would break the intended encapsulation of process isolation.
+ *
+ * @see http://fabien.potencier.org/article/9/php-serialization-stack-traces-and-exceptions
+ *
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class Exception extends RuntimeException implements \PHPUnit\Exception
+{
+ /**
+ * @var array
+ */
+ protected $serializableTrace;
+
+ public function __construct($message = '', $code = 0, Throwable $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+
+ $this->serializableTrace = $this->getTrace();
+
+ foreach (array_keys($this->serializableTrace) as $key) {
+ unset($this->serializableTrace[$key]['args']);
+ }
+ }
+
+ public function __toString(): string
+ {
+ $string = TestFailure::exceptionToString($this);
+
+ if ($trace = Filter::getFilteredStacktrace($this)) {
+ $string .= "\n" . $trace;
+ }
+
+ return $string;
+ }
+
+ public function __sleep(): array
+ {
+ return array_keys(get_object_vars($this));
+ }
+
+ /**
+ * Returns the serializable trace (without 'args').
+ */
+ public function getSerializableTrace(): array
+ {
+ return $this->serializableTrace;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/ExpectationFailedException.php b/vendor/phpunit/phpunit/src/Framework/Exception/ExpectationFailedException.php
new file mode 100644
index 000000000..b9a595a88
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/ExpectationFailedException.php
@@ -0,0 +1,42 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use Exception;
+use SebastianBergmann\Comparator\ComparisonFailure;
+
+/**
+ * Exception for expectations which failed their check.
+ *
+ * The exception contains the error message and optionally a
+ * SebastianBergmann\Comparator\ComparisonFailure which is used to
+ * generate diff output of the failed expectations.
+ *
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ExpectationFailedException extends AssertionFailedError
+{
+ /**
+ * @var ComparisonFailure
+ */
+ protected $comparisonFailure;
+
+ public function __construct(string $message, ComparisonFailure $comparisonFailure = null, Exception $previous = null)
+ {
+ $this->comparisonFailure = $comparisonFailure;
+
+ parent::__construct($message, 0, $previous);
+ }
+
+ public function getComparisonFailure(): ?ComparisonFailure
+ {
+ return $this->comparisonFailure;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/IncompleteTestError.php b/vendor/phpunit/phpunit/src/Framework/Exception/IncompleteTestError.php
new file mode 100644
index 000000000..65f9c8bc3
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/IncompleteTestError.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class IncompleteTestError extends AssertionFailedError implements IncompleteTest
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/InvalidArgumentException.php b/vendor/phpunit/phpunit/src/Framework/Exception/InvalidArgumentException.php
new file mode 100644
index 000000000..77f580799
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/InvalidArgumentException.php
@@ -0,0 +1,46 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use function debug_backtrace;
+use function in_array;
+use function lcfirst;
+use function sprintf;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class InvalidArgumentException extends Exception
+{
+ public static function create(int $argument, string $type): self
+ {
+ $stack = debug_backtrace();
+ $function = $stack[1]['function'];
+
+ if (isset($stack[1]['class'])) {
+ $function = sprintf('%s::%s', $stack[1]['class'], $stack[1]['function']);
+ }
+
+ return new self(
+ sprintf(
+ 'Argument #%d of %s() must be %s %s',
+ $argument,
+ $function,
+ in_array(lcfirst($type)[0], ['a', 'e', 'i', 'o', 'u'], true) ? 'an' : 'a',
+ $type
+ )
+ );
+ }
+
+ private function __construct(string $message = '', int $code = 0, \Exception $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/InvalidCoversTargetException.php b/vendor/phpunit/phpunit/src/Framework/Exception/InvalidCoversTargetException.php
new file mode 100644
index 000000000..ebf2994a9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/InvalidCoversTargetException.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class InvalidCoversTargetException extends CodeCoverageException
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/InvalidDataProviderException.php b/vendor/phpunit/phpunit/src/Framework/Exception/InvalidDataProviderException.php
new file mode 100644
index 000000000..7e2ef24c6
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/InvalidDataProviderException.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class InvalidDataProviderException extends Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/MissingCoversAnnotationException.php b/vendor/phpunit/phpunit/src/Framework/Exception/MissingCoversAnnotationException.php
new file mode 100644
index 000000000..567a6c4c5
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/MissingCoversAnnotationException.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MissingCoversAnnotationException extends RiskyTestError
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/NoChildTestSuiteException.php b/vendor/phpunit/phpunit/src/Framework/Exception/NoChildTestSuiteException.php
new file mode 100644
index 000000000..7ef4153b0
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/NoChildTestSuiteException.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class NoChildTestSuiteException extends Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/OutputError.php b/vendor/phpunit/phpunit/src/Framework/Exception/OutputError.php
new file mode 100644
index 000000000..1c8b37e56
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/OutputError.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class OutputError extends AssertionFailedError
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/PHPTAssertionFailedError.php b/vendor/phpunit/phpunit/src/Framework/Exception/PHPTAssertionFailedError.php
new file mode 100644
index 000000000..17126139f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/PHPTAssertionFailedError.php
@@ -0,0 +1,32 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class PHPTAssertionFailedError extends SyntheticError
+{
+ /**
+ * @var string
+ */
+ private $diff;
+
+ public function __construct(string $message, int $code, string $file, int $line, array $trace, string $diff)
+ {
+ parent::__construct($message, $code, $file, $line, $trace);
+ $this->diff = $diff;
+ }
+
+ public function getDiff(): string
+ {
+ return $this->diff;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/RiskyTestError.php b/vendor/phpunit/phpunit/src/Framework/Exception/RiskyTestError.php
new file mode 100644
index 000000000..a66552c0d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/RiskyTestError.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class RiskyTestError extends AssertionFailedError
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/SkippedTestError.php b/vendor/phpunit/phpunit/src/Framework/Exception/SkippedTestError.php
new file mode 100644
index 000000000..7d553dcf3
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/SkippedTestError.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class SkippedTestError extends AssertionFailedError implements SkippedTest
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/SkippedTestSuiteError.php b/vendor/phpunit/phpunit/src/Framework/Exception/SkippedTestSuiteError.php
new file mode 100644
index 000000000..5448508a1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/SkippedTestSuiteError.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class SkippedTestSuiteError extends AssertionFailedError implements SkippedTest
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/SyntheticError.php b/vendor/phpunit/phpunit/src/Framework/Exception/SyntheticError.php
new file mode 100644
index 000000000..c3124ba0c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/SyntheticError.php
@@ -0,0 +1,61 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class SyntheticError extends AssertionFailedError
+{
+ /**
+ * The synthetic file.
+ *
+ * @var string
+ */
+ protected $syntheticFile = '';
+
+ /**
+ * The synthetic line number.
+ *
+ * @var int
+ */
+ protected $syntheticLine = 0;
+
+ /**
+ * The synthetic trace.
+ *
+ * @var array
+ */
+ protected $syntheticTrace = [];
+
+ public function __construct(string $message, int $code, string $file, int $line, array $trace)
+ {
+ parent::__construct($message, $code);
+
+ $this->syntheticFile = $file;
+ $this->syntheticLine = $line;
+ $this->syntheticTrace = $trace;
+ }
+
+ public function getSyntheticFile(): string
+ {
+ return $this->syntheticFile;
+ }
+
+ public function getSyntheticLine(): int
+ {
+ return $this->syntheticLine;
+ }
+
+ public function getSyntheticTrace(): array
+ {
+ return $this->syntheticTrace;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/SyntheticSkippedError.php b/vendor/phpunit/phpunit/src/Framework/Exception/SyntheticSkippedError.php
new file mode 100644
index 000000000..f6e155d7b
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/SyntheticSkippedError.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class SyntheticSkippedError extends SyntheticError implements SkippedTest
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/UnintentionallyCoveredCodeError.php b/vendor/phpunit/phpunit/src/Framework/Exception/UnintentionallyCoveredCodeError.php
new file mode 100644
index 000000000..fcd1d8249
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/UnintentionallyCoveredCodeError.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class UnintentionallyCoveredCodeError extends RiskyTestError
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Exception/Warning.php b/vendor/phpunit/phpunit/src/Framework/Exception/Warning.php
new file mode 100644
index 000000000..35e94493c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Exception/Warning.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Warning extends Exception implements SelfDescribing
+{
+ /**
+ * Wrapper for getMessage() which is declared as final.
+ */
+ public function toString(): string
+ {
+ return $this->getMessage();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/ExceptionWrapper.php b/vendor/phpunit/phpunit/src/Framework/ExceptionWrapper.php
new file mode 100644
index 000000000..d1ff4abc6
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/ExceptionWrapper.php
@@ -0,0 +1,122 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use function array_keys;
+use function get_class;
+use function spl_object_hash;
+use PHPUnit\Util\Filter;
+use Throwable;
+
+/**
+ * Wraps Exceptions thrown by code under test.
+ *
+ * Re-instantiates Exceptions thrown by user-space code to retain their original
+ * class names, properties, and stack traces (but without arguments).
+ *
+ * Unlike PHPUnit\Framework\Exception, the complete stack of previous Exceptions
+ * is processed.
+ *
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ExceptionWrapper extends Exception
+{
+ /**
+ * @var string
+ */
+ protected $className;
+
+ /**
+ * @var null|ExceptionWrapper
+ */
+ protected $previous;
+
+ public function __construct(Throwable $t)
+ {
+ // PDOException::getCode() is a string.
+ // @see https://php.net/manual/en/class.pdoexception.php#95812
+ parent::__construct($t->getMessage(), (int) $t->getCode());
+
+ $this->setOriginalException($t);
+ }
+
+ public function __toString(): string
+ {
+ $string = TestFailure::exceptionToString($this);
+
+ if ($trace = Filter::getFilteredStacktrace($this)) {
+ $string .= "\n" . $trace;
+ }
+
+ if ($this->previous) {
+ $string .= "\nCaused by\n" . $this->previous;
+ }
+
+ return $string;
+ }
+
+ public function getClassName(): string
+ {
+ return $this->className;
+ }
+
+ public function getPreviousWrapped(): ?self
+ {
+ return $this->previous;
+ }
+
+ public function setClassName(string $className): void
+ {
+ $this->className = $className;
+ }
+
+ public function setOriginalException(Throwable $t): void
+ {
+ $this->originalException($t);
+
+ $this->className = get_class($t);
+ $this->file = $t->getFile();
+ $this->line = $t->getLine();
+
+ $this->serializableTrace = $t->getTrace();
+
+ foreach (array_keys($this->serializableTrace) as $key) {
+ unset($this->serializableTrace[$key]['args']);
+ }
+
+ if ($t->getPrevious()) {
+ $this->previous = new self($t->getPrevious());
+ }
+ }
+
+ public function getOriginalException(): ?Throwable
+ {
+ return $this->originalException();
+ }
+
+ /**
+ * Method to contain static originalException to exclude it from stacktrace to prevent the stacktrace contents,
+ * which can be quite big, from being garbage-collected, thus blocking memory until shutdown.
+ *
+ * Approach works both for var_dump() and var_export() and print_r().
+ */
+ private function originalException(Throwable $exceptionToStore = null): ?Throwable
+ {
+ static $originalExceptions;
+
+ $instanceId = spl_object_hash($this);
+
+ if ($exceptionToStore) {
+ $originalExceptions[$instanceId] = $exceptionToStore;
+ }
+
+ return $originalExceptions[$instanceId] ?? null;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/ExecutionOrderDependency.php b/vendor/phpunit/phpunit/src/Framework/ExecutionOrderDependency.php
new file mode 100644
index 000000000..09c343c16
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/ExecutionOrderDependency.php
@@ -0,0 +1,206 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 count;
+use function explode;
+use function in_array;
+use function strpos;
+use function trim;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ExecutionOrderDependency
+{
+ /**
+ * @var string
+ */
+ private $className = '';
+
+ /**
+ * @var string
+ */
+ private $methodName = '';
+
+ /**
+ * @var bool
+ */
+ private $useShallowClone = false;
+
+ /**
+ * @var bool
+ */
+ private $useDeepClone = false;
+
+ public static function createFromDependsAnnotation(string $className, string $annotation): self
+ {
+ // Split clone option and target
+ $parts = explode(' ', trim($annotation), 2);
+
+ if (count($parts) === 1) {
+ $cloneOption = '';
+ $target = $parts[0];
+ } else {
+ $cloneOption = $parts[0];
+ $target = $parts[1];
+ }
+
+ // Prefix provided class for targets assumed to be in scope
+ if ($target !== '' && strpos($target, '::') === false) {
+ $target = $className . '::' . $target;
+ }
+
+ return new self($target, null, $cloneOption);
+ }
+
+ /**
+ * @psalm-param list<ExecutionOrderDependency> $dependencies
+ *
+ * @psalm-return list<ExecutionOrderDependency>
+ */
+ public static function filterInvalid(array $dependencies): array
+ {
+ return array_values(
+ array_filter(
+ $dependencies,
+ static function (self $d)
+ {
+ return $d->isValid();
+ }
+ )
+ );
+ }
+
+ /**
+ * @psalm-param list<ExecutionOrderDependency> $existing
+ * @psalm-param list<ExecutionOrderDependency> $additional
+ *
+ * @psalm-return list<ExecutionOrderDependency>
+ */
+ public static function mergeUnique(array $existing, array $additional): array
+ {
+ $existingTargets = array_map(
+ static function ($dependency)
+ {
+ return $dependency->getTarget();
+ },
+ $existing
+ );
+
+ foreach ($additional as $dependency) {
+ if (in_array($dependency->getTarget(), $existingTargets, true)) {
+ continue;
+ }
+
+ $existingTargets[] = $dependency->getTarget();
+ $existing[] = $dependency;
+ }
+
+ return $existing;
+ }
+
+ /**
+ * @psalm-param list<ExecutionOrderDependency> $left
+ * @psalm-param list<ExecutionOrderDependency> $right
+ *
+ * @psalm-return list<ExecutionOrderDependency>
+ */
+ public static function diff(array $left, array $right): array
+ {
+ if ($right === []) {
+ return $left;
+ }
+
+ if ($left === []) {
+ return [];
+ }
+
+ $diff = [];
+ $rightTargets = array_map(
+ static function ($dependency)
+ {
+ return $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, ?string $option = null)
+ {
+ if ($classOrCallableName === '') {
+ return;
+ }
+
+ if (strpos($classOrCallableName, '::') !== false) {
+ [$this->className, $this->methodName] = explode('::', $classOrCallableName);
+ } else {
+ $this->className = $classOrCallableName;
+ $this->methodName = !empty($methodName) ? $methodName : 'class';
+ }
+
+ if ($option === 'clone') {
+ $this->useDeepClone = true;
+ } elseif ($option === 'shallowClone') {
+ $this->useShallowClone = true;
+ }
+ }
+
+ public function __toString(): string
+ {
+ return $this->getTarget();
+ }
+
+ public function isValid(): bool
+ {
+ // Invalid dependencies can be declared and are skipped by the runner
+ return $this->className !== '' && $this->methodName !== '';
+ }
+
+ public function useShallowClone(): bool
+ {
+ return $this->useShallowClone;
+ }
+
+ public function useDeepClone(): bool
+ {
+ return $this->useDeepClone;
+ }
+
+ 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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/IncompleteTest.php b/vendor/phpunit/phpunit/src/Framework/IncompleteTest.php
new file mode 100644
index 000000000..b77b1afff
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/IncompleteTest.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface IncompleteTest extends Throwable
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/IncompleteTestCase.php b/vendor/phpunit/phpunit/src/Framework/IncompleteTestCase.php
new file mode 100644
index 000000000..ee1e3e9fe
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/IncompleteTestCase.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class IncompleteTestCase extends TestCase
+{
+ /**
+ * @var bool
+ */
+ protected $backupGlobals = false;
+
+ /**
+ * @var bool
+ */
+ protected $backupStaticAttributes = false;
+
+ /**
+ * @var bool
+ */
+ protected $runTestInSeparateProcess = false;
+
+ /**
+ * @var string
+ */
+ private $message;
+
+ public function __construct(string $className, string $methodName, string $message = '')
+ {
+ parent::__construct($className . '::' . $methodName);
+
+ $this->message = $message;
+ }
+
+ public function getMessage(): string
+ {
+ return $this->message;
+ }
+
+ /**
+ * Returns a string representation of the test case.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ return $this->getName();
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected function runTest(): void
+ {
+ $this->markTestIncomplete($this->message);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/InvalidParameterGroupException.php b/vendor/phpunit/phpunit/src/Framework/InvalidParameterGroupException.php
new file mode 100644
index 000000000..feb9cc989
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/InvalidParameterGroupException.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class InvalidParameterGroupException extends Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Api/Api.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Api/Api.php
new file mode 100644
index 000000000..e2f0a2802
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Api/Api.php
@@ -0,0 +1,97 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+use PHPUnit\Framework\MockObject\Builder\InvocationMocker as InvocationMockerBuilder;
+use PHPUnit\Framework\MockObject\Rule\InvocationOrder;
+
+/**
+ * @internal This trait is not covered by the backward compatibility promise for PHPUnit
+ */
+trait Api
+{
+ /**
+ * @var ConfigurableMethod[]
+ */
+ private static $__phpunit_configurableMethods;
+
+ /**
+ * @var object
+ */
+ private $__phpunit_originalObject;
+
+ /**
+ * @var bool
+ */
+ private $__phpunit_returnValueGeneration = true;
+
+ /**
+ * @var InvocationHandler
+ */
+ private $__phpunit_invocationMocker;
+
+ /** @noinspection MagicMethodsValidityInspection */
+ public static function __phpunit_initConfigurableMethods(ConfigurableMethod ...$configurableMethods): void
+ {
+ if (isset(static::$__phpunit_configurableMethods)) {
+ throw new ConfigurableMethodsAlreadyInitializedException(
+ 'Configurable methods is already initialized and can not be reinitialized'
+ );
+ }
+
+ static::$__phpunit_configurableMethods = $configurableMethods;
+ }
+
+ /** @noinspection MagicMethodsValidityInspection */
+ public function __phpunit_setOriginalObject($originalObject): void
+ {
+ $this->__phpunit_originalObject = $originalObject;
+ }
+
+ /** @noinspection MagicMethodsValidityInspection */
+ public function __phpunit_setReturnValueGeneration(bool $returnValueGeneration): void
+ {
+ $this->__phpunit_returnValueGeneration = $returnValueGeneration;
+ }
+
+ /** @noinspection MagicMethodsValidityInspection */
+ public function __phpunit_getInvocationHandler(): InvocationHandler
+ {
+ if ($this->__phpunit_invocationMocker === null) {
+ $this->__phpunit_invocationMocker = new InvocationHandler(
+ static::$__phpunit_configurableMethods,
+ $this->__phpunit_returnValueGeneration
+ );
+ }
+
+ return $this->__phpunit_invocationMocker;
+ }
+
+ /** @noinspection MagicMethodsValidityInspection */
+ public function __phpunit_hasMatchers(): bool
+ {
+ return $this->__phpunit_getInvocationHandler()->hasMatchers();
+ }
+
+ /** @noinspection MagicMethodsValidityInspection */
+ public function __phpunit_verify(bool $unsetInvocationMocker = true): void
+ {
+ $this->__phpunit_getInvocationHandler()->verify();
+
+ if ($unsetInvocationMocker) {
+ $this->__phpunit_invocationMocker = null;
+ }
+ }
+
+ public function expects(InvocationOrder $matcher): InvocationMockerBuilder
+ {
+ return $this->__phpunit_getInvocationHandler()->expects($matcher);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Api/Method.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Api/Method.php
new file mode 100644
index 000000000..f6df7533c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Api/Method.php
@@ -0,0 +1,30 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+use function call_user_func_array;
+use function func_get_args;
+use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount;
+
+/**
+ * @internal This trait is not covered by the backward compatibility promise for PHPUnit
+ */
+trait Method
+{
+ public function method()
+ {
+ $expects = $this->expects(new AnyInvokedCount);
+
+ return call_user_func_array(
+ [$expects, 'method'],
+ func_get_args()
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Api/MockedCloneMethod.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Api/MockedCloneMethod.php
new file mode 100644
index 000000000..91e35f937
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Api/MockedCloneMethod.php
@@ -0,0 +1,21 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This trait is not covered by the backward compatibility promise for PHPUnit
+ */
+trait MockedCloneMethod
+{
+ public function __clone()
+ {
+ $this->__phpunit_invocationMocker = clone $this->__phpunit_getInvocationHandler();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Api/UnmockedCloneMethod.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Api/UnmockedCloneMethod.php
new file mode 100644
index 000000000..3f493d203
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Api/UnmockedCloneMethod.php
@@ -0,0 +1,23 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This trait is not covered by the backward compatibility promise for PHPUnit
+ */
+trait UnmockedCloneMethod
+{
+ public function __clone()
+ {
+ $this->__phpunit_invocationMocker = clone $this->__phpunit_getInvocationHandler();
+
+ parent::__clone();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/Identity.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/Identity.php
new file mode 100644
index 000000000..a68bfadf9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/Identity.php
@@ -0,0 +1,25 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject\Builder;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface Identity
+{
+ /**
+ * Sets the identification of the expectation to $id.
+ *
+ * @note The identifier is unique per mock object.
+ *
+ * @param string $id unique identification of expectation
+ */
+ public function id($id);
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationMocker.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationMocker.php
new file mode 100644
index 000000000..89b1e31ab
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationMocker.php
@@ -0,0 +1,306 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject\Builder;
+
+use function array_map;
+use function array_merge;
+use function count;
+use function in_array;
+use function is_string;
+use function strtolower;
+use PHPUnit\Framework\Constraint\Constraint;
+use PHPUnit\Framework\MockObject\ConfigurableMethod;
+use PHPUnit\Framework\MockObject\IncompatibleReturnValueException;
+use PHPUnit\Framework\MockObject\InvocationHandler;
+use PHPUnit\Framework\MockObject\Matcher;
+use PHPUnit\Framework\MockObject\MatcherAlreadyRegisteredException;
+use PHPUnit\Framework\MockObject\MethodCannotBeConfiguredException;
+use PHPUnit\Framework\MockObject\MethodNameAlreadyConfiguredException;
+use PHPUnit\Framework\MockObject\MethodNameNotConfiguredException;
+use PHPUnit\Framework\MockObject\MethodParametersAlreadyConfiguredException;
+use PHPUnit\Framework\MockObject\Rule;
+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
+ */
+final class InvocationMocker implements InvocationStubber, MethodNameMatch
+{
+ /**
+ * @var InvocationHandler
+ */
+ private $invocationHandler;
+
+ /**
+ * @var Matcher
+ */
+ private $matcher;
+
+ /**
+ * @var ConfigurableMethod[]
+ */
+ private $configurableMethods;
+
+ public function __construct(InvocationHandler $handler, Matcher $matcher, ConfigurableMethod ...$configurableMethods)
+ {
+ $this->invocationHandler = $handler;
+ $this->matcher = $matcher;
+ $this->configurableMethods = $configurableMethods;
+ }
+
+ /**
+ * @throws MatcherAlreadyRegisteredException
+ *
+ * @return $this
+ */
+ public function id($id): self
+ {
+ $this->invocationHandler->registerMatcher($id, $this->matcher);
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function will(Stub $stub): Identity
+ {
+ $this->matcher->setStub($stub);
+
+ return $this;
+ }
+
+ /**
+ * @param mixed $value
+ * @param mixed[] $nextValues
+ *
+ * @throws IncompatibleReturnValueException
+ */
+ public function willReturn($value, ...$nextValues): self
+ {
+ if (count($nextValues) === 0) {
+ $this->ensureTypeOfReturnValues([$value]);
+
+ $stub = $value instanceof Stub ? $value : new ReturnStub($value);
+ } else {
+ $values = array_merge([$value], $nextValues);
+
+ $this->ensureTypeOfReturnValues($values);
+
+ $stub = new ConsecutiveCalls($values);
+ }
+
+ return $this->will($stub);
+ }
+
+ public function willReturnReference(&$reference): self
+ {
+ $stub = new ReturnReference($reference);
+
+ return $this->will($stub);
+ }
+
+ public function willReturnMap(array $valueMap): self
+ {
+ $stub = new ReturnValueMap($valueMap);
+
+ return $this->will($stub);
+ }
+
+ public function willReturnArgument($argumentIndex): self
+ {
+ $stub = new ReturnArgument($argumentIndex);
+
+ return $this->will($stub);
+ }
+
+ public function willReturnCallback($callback): self
+ {
+ $stub = new ReturnCallback($callback);
+
+ return $this->will($stub);
+ }
+
+ public function willReturnSelf(): self
+ {
+ $stub = new ReturnSelf;
+
+ return $this->will($stub);
+ }
+
+ public function willReturnOnConsecutiveCalls(...$values): self
+ {
+ $stub = new ConsecutiveCalls($values);
+
+ return $this->will($stub);
+ }
+
+ public function willThrowException(Throwable $exception): self
+ {
+ $stub = new Exception($exception);
+
+ return $this->will($stub);
+ }
+
+ /**
+ * @return $this
+ */
+ public function after($id): self
+ {
+ $this->matcher->setAfterMatchBuilderId($id);
+
+ return $this;
+ }
+
+ /**
+ * @param mixed[] $arguments
+ *
+ * @throws \PHPUnit\Framework\Exception
+ * @throws MethodNameNotConfiguredException
+ * @throws MethodParametersAlreadyConfiguredException
+ *
+ * @return $this
+ */
+ public function with(...$arguments): self
+ {
+ $this->ensureParametersCanBeConfigured();
+
+ $this->matcher->setParametersRule(new Rule\Parameters($arguments));
+
+ return $this;
+ }
+
+ /**
+ * @param array ...$arguments
+ *
+ * @throws \PHPUnit\Framework\Exception
+ * @throws MethodNameNotConfiguredException
+ * @throws MethodParametersAlreadyConfiguredException
+ *
+ * @return $this
+ */
+ public function withConsecutive(...$arguments): self
+ {
+ $this->ensureParametersCanBeConfigured();
+
+ $this->matcher->setParametersRule(new Rule\ConsecutiveParameters($arguments));
+
+ return $this;
+ }
+
+ /**
+ * @throws MethodNameNotConfiguredException
+ * @throws MethodParametersAlreadyConfiguredException
+ *
+ * @return $this
+ */
+ public function withAnyParameters(): self
+ {
+ $this->ensureParametersCanBeConfigured();
+
+ $this->matcher->setParametersRule(new Rule\AnyParameters);
+
+ return $this;
+ }
+
+ /**
+ * @param Constraint|string $constraint
+ *
+ * @throws \PHPUnit\Framework\InvalidArgumentException
+ * @throws MethodCannotBeConfiguredException
+ * @throws MethodNameAlreadyConfiguredException
+ *
+ * @return $this
+ */
+ public function method($constraint): self
+ {
+ if ($this->matcher->hasMethodNameRule()) {
+ throw new MethodNameAlreadyConfiguredException;
+ }
+
+ $configurableMethodNames = array_map(
+ static function (ConfigurableMethod $configurable)
+ {
+ return strtolower($configurable->getName());
+ },
+ $this->configurableMethods
+ );
+
+ if (is_string($constraint) && !in_array(strtolower($constraint), $configurableMethodNames, true)) {
+ throw new MethodCannotBeConfiguredException($constraint);
+ }
+
+ $this->matcher->setMethodNameRule(new Rule\MethodName($constraint));
+
+ return $this;
+ }
+
+ /**
+ * @throws MethodNameNotConfiguredException
+ * @throws MethodParametersAlreadyConfiguredException
+ */
+ private function ensureParametersCanBeConfigured(): void
+ {
+ if (!$this->matcher->hasMethodNameRule()) {
+ throw new MethodNameNotConfiguredException;
+ }
+
+ if ($this->matcher->hasParametersRule()) {
+ throw new MethodParametersAlreadyConfiguredException;
+ }
+ }
+
+ private function getConfiguredMethod(): ?ConfigurableMethod
+ {
+ $configuredMethod = null;
+
+ foreach ($this->configurableMethods as $configurableMethod) {
+ if ($this->matcher->getMethodNameRule()->matchesName($configurableMethod->getName())) {
+ if ($configuredMethod !== null) {
+ return null;
+ }
+
+ $configuredMethod = $configurableMethod;
+ }
+ }
+
+ return $configuredMethod;
+ }
+
+ /**
+ * @throws IncompatibleReturnValueException
+ */
+ private function ensureTypeOfReturnValues(array $values): void
+ {
+ $configuredMethod = $this->getConfiguredMethod();
+
+ if ($configuredMethod === null) {
+ return;
+ }
+
+ foreach ($values as $value) {
+ if (!$configuredMethod->mayReturn($value)) {
+ throw new IncompatibleReturnValueException(
+ $configuredMethod,
+ $value
+ );
+ }
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationStubber.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationStubber.php
new file mode 100644
index 000000000..f32ff0e7c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationStubber.php
@@ -0,0 +1,65 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject\Builder;
+
+use PHPUnit\Framework\MockObject\Stub\Stub;
+use Throwable;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+interface InvocationStubber
+{
+ public function will(Stub $stub): Identity;
+
+ /** @return self */
+ public function willReturn($value, ...$nextValues)/*: self */;
+
+ /**
+ * @param mixed $reference
+ *
+ * @return self
+ */
+ public function willReturnReference(&$reference)/*: self */;
+
+ /**
+ * @param array<int, array<int, mixed>> $valueMap
+ *
+ * @return self
+ */
+ public function willReturnMap(array $valueMap)/*: self */;
+
+ /**
+ * @param int $argumentIndex
+ *
+ * @return self
+ */
+ public function willReturnArgument($argumentIndex)/*: self */;
+
+ /**
+ * @param callable $callback
+ *
+ * @return self
+ */
+ public function willReturnCallback($callback)/*: self */;
+
+ /** @return self */
+ public function willReturnSelf()/*: self */;
+
+ /**
+ * @param mixed $values
+ *
+ * @return self
+ */
+ public function willReturnOnConsecutiveCalls(...$values)/*: self */;
+
+ /** @return self */
+ public function willThrowException(Throwable $exception)/*: self */;
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/MethodNameMatch.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/MethodNameMatch.php
new file mode 100644
index 000000000..543d596cc
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/MethodNameMatch.php
@@ -0,0 +1,26 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject\Builder;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface MethodNameMatch extends ParametersMatch
+{
+ /**
+ * Adds a new method name match and returns the parameter match object for
+ * further matching possibilities.
+ *
+ * @param \PHPUnit\Framework\Constraint\Constraint $constraint Constraint for matching method, if a string is passed it will use the PHPUnit_Framework_Constraint_IsEqual
+ *
+ * @return ParametersMatch
+ */
+ public function method($constraint);
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/ParametersMatch.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/ParametersMatch.php
new file mode 100644
index 000000000..707d82551
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/ParametersMatch.php
@@ -0,0 +1,58 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject\Builder;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface ParametersMatch extends Stub
+{
+ /**
+ * Defines the expectation which must occur before the current is valid.
+ *
+ * @param string $id the identification of the expectation that should
+ * occur before this one
+ *
+ * @return Stub
+ */
+ public function after($id);
+
+ /**
+ * Sets the parameters to match for, each parameter to this function will
+ * be part of match. To perform specific matches or constraints create a
+ * new PHPUnit\Framework\Constraint\Constraint and use it for the parameter.
+ * If the parameter value is not a constraint it will use the
+ * PHPUnit\Framework\Constraint\IsEqual for the value.
+ *
+ * Some examples:
+ * <code>
+ * // match first parameter with value 2
+ * $b->with(2);
+ * // match first parameter with value 'smock' and second identical to 42
+ * $b->with('smock', new PHPUnit\Framework\Constraint\IsEqual(42));
+ * </code>
+ *
+ * @return ParametersMatch
+ */
+ public function with(...$arguments);
+
+ /**
+ * Sets a rule which allows any kind of parameters.
+ *
+ * Some examples:
+ * <code>
+ * // match any number of parameters
+ * $b->withAnyParameters();
+ * </code>
+ *
+ * @return ParametersMatch
+ */
+ public function withAnyParameters();
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/Stub.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/Stub.php
new file mode 100644
index 000000000..d7cb78fc4
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/Stub.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject\Builder;
+
+use PHPUnit\Framework\MockObject\Stub\Stub as BaseStub;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface Stub extends Identity
+{
+ /**
+ * Stubs the matching method with the stub object $stub. Any invocations of
+ * the matched method will now be handled by the stub instead.
+ */
+ public function will(BaseStub $stub): Identity;
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/ConfigurableMethod.php b/vendor/phpunit/phpunit/src/Framework/MockObject/ConfigurableMethod.php
new file mode 100644
index 000000000..4757dc637
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/ConfigurableMethod.php
@@ -0,0 +1,53 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+use SebastianBergmann\Type\Type;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ConfigurableMethod
+{
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var Type
+ */
+ private $returnType;
+
+ public function __construct(string $name, Type $returnType)
+ {
+ $this->name = $name;
+ $this->returnType = $returnType;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ public function mayReturn($value): bool
+ {
+ if ($value === null && $this->returnType->allowsNull()) {
+ return true;
+ }
+
+ return $this->returnType->isAssignable(Type::fromValue($value, false));
+ }
+
+ public function getReturnTypeDeclaration(): string
+ {
+ return $this->returnType->asString();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/BadMethodCallException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/BadMethodCallException.php
new file mode 100644
index 000000000..7e655e235
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/BadMethodCallException.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class BadMethodCallException extends \BadMethodCallException implements Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/CannotUseAddMethodsException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/CannotUseAddMethodsException.php
new file mode 100644
index 000000000..0698870bc
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/CannotUseAddMethodsException.php
@@ -0,0 +1,29 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class CannotUseAddMethodsException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct(string $type, string $methodName)
+ {
+ parent::__construct(
+ sprintf(
+ 'Trying to configure method "%s" with addMethods(), but it exists in class "%s". Use onlyMethods() for methods that exist in the class',
+ $methodName,
+ $type
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/CannotUseOnlyMethodsException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/CannotUseOnlyMethodsException.php
new file mode 100644
index 000000000..35a29b731
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/CannotUseOnlyMethodsException.php
@@ -0,0 +1,29 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class CannotUseOnlyMethodsException extends \PHPUnit\Framework\Exception implements 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". Use addMethods() for methods that do not exist in the class',
+ $methodName,
+ $type
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ClassAlreadyExistsException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ClassAlreadyExistsException.php
new file mode 100644
index 000000000..0ba9a187d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ClassAlreadyExistsException.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ClassAlreadyExistsException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct(string $className)
+ {
+ parent::__construct(
+ sprintf(
+ 'Class "%s" already exists',
+ $className
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ClassIsFinalException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ClassIsFinalException.php
new file mode 100644
index 000000000..e648f0263
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ClassIsFinalException.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ClassIsFinalException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct(string $className)
+ {
+ parent::__construct(
+ sprintf(
+ 'Class "%s" is declared "final" and cannot be doubled',
+ $className
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ConfigurableMethodsAlreadyInitializedException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ConfigurableMethodsAlreadyInitializedException.php
new file mode 100644
index 000000000..d12ac9973
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ConfigurableMethodsAlreadyInitializedException.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ConfigurableMethodsAlreadyInitializedException extends \PHPUnit\Framework\Exception implements Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/DuplicateMethodException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/DuplicateMethodException.php
new file mode 100644
index 000000000..864523acb
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/DuplicateMethodException.php
@@ -0,0 +1,32 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class DuplicateMethodException extends \PHPUnit\Framework\Exception implements Exception
+{
+ /**
+ * @psalm-param list<string> $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))))
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/Exception.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/Exception.php
new file mode 100644
index 000000000..5880bc033
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/Exception.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface Exception extends Throwable
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/IncompatibleReturnValueException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/IncompatibleReturnValueException.php
new file mode 100644
index 000000000..00febaf56
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/IncompatibleReturnValueException.php
@@ -0,0 +1,33 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class IncompatibleReturnValueException extends \PHPUnit\Framework\Exception implements Exception
+{
+ /**
+ * @param mixed $value
+ */
+ public function __construct(ConfigurableMethod $method, $value)
+ {
+ parent::__construct(
+ sprintf(
+ 'Method %s may not return value of type %s, its declared return type is "%s"',
+ $method->getName(),
+ is_object($value) ? get_class($value) : gettype($value),
+ $method->getReturnTypeDeclaration()
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/InvalidMethodNameException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/InvalidMethodNameException.php
new file mode 100644
index 000000000..d2444cf12
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/InvalidMethodNameException.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class InvalidMethodNameException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct(string $method)
+ {
+ parent::__construct(
+ sprintf(
+ 'Cannot double method with invalid name "%s"',
+ $method
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MatchBuilderNotFoundException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MatchBuilderNotFoundException.php
new file mode 100644
index 000000000..c05b2bce6
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MatchBuilderNotFoundException.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MatchBuilderNotFoundException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct(string $id)
+ {
+ parent::__construct(
+ sprintf(
+ 'No builder found for match builder identification <%s>',
+ $id
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MatcherAlreadyRegisteredException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MatcherAlreadyRegisteredException.php
new file mode 100644
index 000000000..efcc13ed9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MatcherAlreadyRegisteredException.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MatcherAlreadyRegisteredException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct(string $id)
+ {
+ parent::__construct(
+ sprintf(
+ 'Matcher with id <%s> is already registered',
+ $id
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodCannotBeConfiguredException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodCannotBeConfiguredException.php
new file mode 100644
index 000000000..707290439
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodCannotBeConfiguredException.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MethodCannotBeConfiguredException extends \PHPUnit\Framework\Exception implements 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
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodNameAlreadyConfiguredException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodNameAlreadyConfiguredException.php
new file mode 100644
index 000000000..1e9f2c04c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodNameAlreadyConfiguredException.php
@@ -0,0 +1,21 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MethodNameAlreadyConfiguredException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct()
+ {
+ parent::__construct('Method name is already configured');
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodNameNotConfiguredException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodNameNotConfiguredException.php
new file mode 100644
index 000000000..89565b77e
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodNameNotConfiguredException.php
@@ -0,0 +1,21 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MethodNameNotConfiguredException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct()
+ {
+ parent::__construct('Method name is not configured');
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodParametersAlreadyConfiguredException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodParametersAlreadyConfiguredException.php
new file mode 100644
index 000000000..1609c6ffb
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/MethodParametersAlreadyConfiguredException.php
@@ -0,0 +1,21 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MethodParametersAlreadyConfiguredException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct()
+ {
+ parent::__construct('Method parameters already configured');
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/OriginalConstructorInvocationRequiredException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/OriginalConstructorInvocationRequiredException.php
new file mode 100644
index 000000000..ecb9b63cf
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/OriginalConstructorInvocationRequiredException.php
@@ -0,0 +1,21 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class OriginalConstructorInvocationRequiredException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct()
+ {
+ parent::__construct('Proxying to original methods requires invoking the original constructor');
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ReflectionException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ReflectionException.php
new file mode 100644
index 000000000..d6319c694
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ReflectionException.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+use RuntimeException;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ReflectionException extends RuntimeException implements Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ReturnValueNotConfiguredException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ReturnValueNotConfiguredException.php
new file mode 100644
index 000000000..8121e369b
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/ReturnValueNotConfiguredException.php
@@ -0,0 +1,27 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ReturnValueNotConfiguredException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct(Invocation $invocation)
+ {
+ parent::__construct(
+ sprintf(
+ 'Return value inference disabled and no expectation set up for %s::%s()',
+ $invocation->getClassName(),
+ $invocation->getMethodName()
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/RuntimeException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/RuntimeException.php
new file mode 100644
index 000000000..33b6a5be3
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/RuntimeException.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class RuntimeException extends \RuntimeException implements Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/SoapExtensionNotAvailableException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/SoapExtensionNotAvailableException.php
new file mode 100644
index 000000000..98837c954
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/SoapExtensionNotAvailableException.php
@@ -0,0 +1,23 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class SoapExtensionNotAvailableException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct()
+ {
+ parent::__construct(
+ 'The SOAP extension is required to generate a test double from WSDL'
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownClassException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownClassException.php
new file mode 100644
index 000000000..e124f9b18
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownClassException.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class UnknownClassException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct(string $className)
+ {
+ parent::__construct(
+ sprintf(
+ 'Class "%s" does not exist',
+ $className
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownTraitException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownTraitException.php
new file mode 100644
index 000000000..90fc8d848
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownTraitException.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class UnknownTraitException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct(string $traitName)
+ {
+ parent::__construct(
+ sprintf(
+ 'Trait "%s" does not exist',
+ $traitName
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownTypeException.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownTypeException.php
new file mode 100644
index 000000000..b1a70edd6
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Exception/UnknownTypeException.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class UnknownTypeException extends \PHPUnit\Framework\Exception implements Exception
+{
+ public function __construct(string $type)
+ {
+ parent::__construct(
+ sprintf(
+ 'Class or interface "%s" does not exist',
+ $type
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php
new file mode 100644
index 000000000..cb8531cd3
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php
@@ -0,0 +1,1004 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+use const DIRECTORY_SEPARATOR;
+use const PHP_EOL;
+use const PHP_MAJOR_VERSION;
+use const PREG_OFFSET_CAPTURE;
+use const WSDL_CACHE_NONE;
+use function array_merge;
+use function array_pop;
+use function array_unique;
+use function class_exists;
+use function count;
+use function explode;
+use function extension_loaded;
+use function implode;
+use function in_array;
+use function interface_exists;
+use function is_array;
+use function is_object;
+use function md5;
+use function mt_rand;
+use function preg_match;
+use function preg_match_all;
+use function range;
+use function serialize;
+use function sort;
+use function sprintf;
+use function str_replace;
+use function strlen;
+use function strpos;
+use function strtolower;
+use function substr;
+use function trait_exists;
+use Doctrine\Instantiator\Exception\ExceptionInterface as InstantiatorException;
+use Doctrine\Instantiator\Instantiator;
+use Exception;
+use Iterator;
+use IteratorAggregate;
+use PHPUnit\Framework\InvalidArgumentException;
+use ReflectionClass;
+use ReflectionMethod;
+use SebastianBergmann\Template\Exception as TemplateException;
+use SebastianBergmann\Template\Template;
+use SoapClient;
+use SoapFault;
+use Throwable;
+use Traversable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Generator
+{
+ /**
+ * @var array
+ */
+ private const EXCLUDED_METHOD_NAMES = [
+ '__CLASS__' => true,
+ '__DIR__' => true,
+ '__FILE__' => true,
+ '__FUNCTION__' => true,
+ '__LINE__' => true,
+ '__METHOD__' => true,
+ '__NAMESPACE__' => true,
+ '__TRAIT__' => true,
+ '__clone' => true,
+ '__halt_compiler' => true,
+ ];
+
+ /**
+ * @var array
+ */
+ private static $cache = [];
+
+ /**
+ * @var Template[]
+ */
+ private static $templates = [];
+
+ /**
+ * Returns a mock object for the specified class.
+ *
+ * @param null|array $methods
+ *
+ * @throws \PHPUnit\Framework\InvalidArgumentException
+ * @throws ClassAlreadyExistsException
+ * @throws ClassIsFinalException
+ * @throws DuplicateMethodException
+ * @throws InvalidMethodNameException
+ * @throws OriginalConstructorInvocationRequiredException
+ * @throws ReflectionException
+ * @throws RuntimeException
+ * @throws UnknownTypeException
+ */
+ public function getMock(string $type, $methods = [], array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, bool $cloneArguments = true, bool $callOriginalMethods = false, object $proxyTarget = null, bool $allowMockingUnknownTypes = true, bool $returnValueGeneration = true): MockObject
+ {
+ if (!is_array($methods) && null !== $methods) {
+ throw InvalidArgumentException::create(2, 'array');
+ }
+
+ if ($type === 'Traversable' || $type === '\\Traversable') {
+ $type = 'Iterator';
+ }
+
+ if (!$allowMockingUnknownTypes && !class_exists($type, $callAutoload) && !interface_exists($type, $callAutoload)) {
+ throw new UnknownTypeException($type);
+ }
+
+ if (null !== $methods) {
+ foreach ($methods as $method) {
+ if (!preg_match('~[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*~', (string) $method)) {
+ throw new InvalidMethodNameException((string) $method);
+ }
+ }
+
+ if ($methods !== array_unique($methods)) {
+ throw new DuplicateMethodException($methods);
+ }
+ }
+
+ if ($mockClassName !== '' && class_exists($mockClassName, false)) {
+ try {
+ $reflector = new ReflectionClass($mockClassName);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if (!$reflector->implementsInterface(MockObject::class)) {
+ throw new ClassAlreadyExistsException($mockClassName);
+ }
+ }
+
+ if (!$callOriginalConstructor && $callOriginalMethods) {
+ throw new OriginalConstructorInvocationRequiredException;
+ }
+
+ $mock = $this->generate(
+ $type,
+ $methods,
+ $mockClassName,
+ $callOriginalClone,
+ $callAutoload,
+ $cloneArguments,
+ $callOriginalMethods
+ );
+
+ return $this->getObject(
+ $mock,
+ $type,
+ $callOriginalConstructor,
+ $callAutoload,
+ $arguments,
+ $callOriginalMethods,
+ $proxyTarget,
+ $returnValueGeneration
+ );
+ }
+
+ /**
+ * Returns a mock object for the specified abstract class with all abstract
+ * methods of the class mocked.
+ *
+ * Concrete methods to mock can be specified with the $mockedMethods parameter.
+ *
+ * @psalm-template RealInstanceType of object
+ * @psalm-param class-string<RealInstanceType> $originalClassName
+ * @psalm-return MockObject&RealInstanceType
+ *
+ * @throws \PHPUnit\Framework\InvalidArgumentException
+ * @throws ClassAlreadyExistsException
+ * @throws ClassIsFinalException
+ * @throws DuplicateMethodException
+ * @throws InvalidMethodNameException
+ * @throws OriginalConstructorInvocationRequiredException
+ * @throws ReflectionException
+ * @throws RuntimeException
+ * @throws UnknownClassException
+ * @throws UnknownTypeException
+ */
+ public function getMockForAbstractClass(string $originalClassName, array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, array $mockedMethods = null, bool $cloneArguments = true): MockObject
+ {
+ if (class_exists($originalClassName, $callAutoload) ||
+ interface_exists($originalClassName, $callAutoload)) {
+ try {
+ $reflector = new ReflectionClass($originalClassName);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $methods = $mockedMethods;
+
+ foreach ($reflector->getMethods() as $method) {
+ if ($method->isAbstract() && !in_array($method->getName(), $methods ?? [], true)) {
+ $methods[] = $method->getName();
+ }
+ }
+
+ if (empty($methods)) {
+ $methods = null;
+ }
+
+ return $this->getMock(
+ $originalClassName,
+ $methods,
+ $arguments,
+ $mockClassName,
+ $callOriginalConstructor,
+ $callOriginalClone,
+ $callAutoload,
+ $cloneArguments
+ );
+ }
+
+ throw new UnknownClassException($originalClassName);
+ }
+
+ /**
+ * Returns a mock object for the specified trait with all abstract methods
+ * of the trait mocked. Concrete methods to mock can be specified with the
+ * `$mockedMethods` parameter.
+ *
+ * @psalm-param trait-string $traitName
+ *
+ * @throws \PHPUnit\Framework\InvalidArgumentException
+ * @throws ClassAlreadyExistsException
+ * @throws ClassIsFinalException
+ * @throws DuplicateMethodException
+ * @throws InvalidMethodNameException
+ * @throws OriginalConstructorInvocationRequiredException
+ * @throws ReflectionException
+ * @throws RuntimeException
+ * @throws UnknownClassException
+ * @throws UnknownTraitException
+ * @throws UnknownTypeException
+ */
+ public function getMockForTrait(string $traitName, array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, array $mockedMethods = null, bool $cloneArguments = true): MockObject
+ {
+ if (!trait_exists($traitName, $callAutoload)) {
+ throw new UnknownTraitException($traitName);
+ }
+
+ $className = $this->generateClassName(
+ $traitName,
+ '',
+ 'Trait_'
+ );
+
+ $classTemplate = $this->getTemplate('trait_class.tpl');
+
+ $classTemplate->setVar(
+ [
+ 'prologue' => 'abstract ',
+ 'class_name' => $className['className'],
+ 'trait_name' => $traitName,
+ ]
+ );
+
+ $mockTrait = new MockTrait($classTemplate->render(), $className['className']);
+ $mockTrait->generate();
+
+ return $this->getMockForAbstractClass($className['className'], $arguments, $mockClassName, $callOriginalConstructor, $callOriginalClone, $callAutoload, $mockedMethods, $cloneArguments);
+ }
+
+ /**
+ * Returns an object for the specified trait.
+ *
+ * @psalm-param trait-string $traitName
+ *
+ * @throws ReflectionException
+ * @throws RuntimeException
+ * @throws UnknownTraitException
+ */
+ public function getObjectForTrait(string $traitName, string $traitClassName = '', bool $callAutoload = true, bool $callOriginalConstructor = false, array $arguments = []): object
+ {
+ if (!trait_exists($traitName, $callAutoload)) {
+ throw new UnknownTraitException($traitName);
+ }
+
+ $className = $this->generateClassName(
+ $traitName,
+ $traitClassName,
+ 'Trait_'
+ );
+
+ $classTemplate = $this->getTemplate('trait_class.tpl');
+
+ $classTemplate->setVar(
+ [
+ 'prologue' => '',
+ 'class_name' => $className['className'],
+ 'trait_name' => $traitName,
+ ]
+ );
+
+ return $this->getObject(
+ new MockTrait(
+ $classTemplate->render(),
+ $className['className']
+ ),
+ '',
+ $callOriginalConstructor,
+ $callAutoload,
+ $arguments
+ );
+ }
+
+ /**
+ * @throws ClassIsFinalException
+ * @throws ReflectionException
+ * @throws RuntimeException
+ */
+ public function generate(string $type, array $methods = null, string $mockClassName = '', bool $callOriginalClone = true, bool $callAutoload = true, bool $cloneArguments = true, bool $callOriginalMethods = false): MockClass
+ {
+ if ($mockClassName !== '') {
+ return $this->generateMock(
+ $type,
+ $methods,
+ $mockClassName,
+ $callOriginalClone,
+ $callAutoload,
+ $cloneArguments,
+ $callOriginalMethods
+ );
+ }
+
+ $key = md5(
+ $type .
+ serialize($methods) .
+ serialize($callOriginalClone) .
+ serialize($cloneArguments) .
+ serialize($callOriginalMethods)
+ );
+
+ if (!isset(self::$cache[$key])) {
+ self::$cache[$key] = $this->generateMock(
+ $type,
+ $methods,
+ $mockClassName,
+ $callOriginalClone,
+ $callAutoload,
+ $cloneArguments,
+ $callOriginalMethods
+ );
+ }
+
+ return self::$cache[$key];
+ }
+
+ /**
+ * @throws RuntimeException
+ * @throws SoapExtensionNotAvailableException
+ */
+ public function generateClassFromWsdl(string $wsdlFile, string $className, array $methods = [], array $options = []): string
+ {
+ if (!extension_loaded('soap')) {
+ throw new SoapExtensionNotAvailableException;
+ }
+
+ $options = array_merge($options, ['cache_wsdl' => WSDL_CACHE_NONE]);
+
+ try {
+ $client = new SoapClient($wsdlFile, $options);
+ $_methods = array_unique($client->__getFunctions());
+ unset($client);
+ } catch (SoapFault $e) {
+ throw new RuntimeException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+
+ sort($_methods);
+
+ $methodTemplate = $this->getTemplate('wsdl_method.tpl');
+ $methodsBuffer = '';
+
+ foreach ($_methods as $method) {
+ preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\(/', $method, $matches, PREG_OFFSET_CAPTURE);
+ $lastFunction = array_pop($matches[0]);
+ $nameStart = $lastFunction[1];
+ $nameEnd = $nameStart + strlen($lastFunction[0]) - 1;
+ $name = str_replace('(', '', $lastFunction[0]);
+
+ if (empty($methods) || in_array($name, $methods, true)) {
+ $args = explode(
+ ',',
+ str_replace(')', '', substr($method, $nameEnd + 1))
+ );
+
+ foreach (range(0, count($args) - 1) as $i) {
+ $parameterStart = strpos($args[$i], '$');
+
+ if (!$parameterStart) {
+ continue;
+ }
+
+ $args[$i] = substr($args[$i], $parameterStart);
+ }
+
+ $methodTemplate->setVar(
+ [
+ 'method_name' => $name,
+ 'arguments' => implode(', ', $args),
+ ]
+ );
+
+ $methodsBuffer .= $methodTemplate->render();
+ }
+ }
+
+ $optionsBuffer = '[';
+
+ foreach ($options as $key => $value) {
+ $optionsBuffer .= $key . ' => ' . $value;
+ }
+
+ $optionsBuffer .= ']';
+
+ $classTemplate = $this->getTemplate('wsdl_class.tpl');
+ $namespace = '';
+
+ if (strpos($className, '\\') !== false) {
+ $parts = explode('\\', $className);
+ $className = array_pop($parts);
+ $namespace = 'namespace ' . implode('\\', $parts) . ';' . "\n\n";
+ }
+
+ $classTemplate->setVar(
+ [
+ 'namespace' => $namespace,
+ 'class_name' => $className,
+ 'wsdl' => $wsdlFile,
+ 'options' => $optionsBuffer,
+ 'methods' => $methodsBuffer,
+ ]
+ );
+
+ return $classTemplate->render();
+ }
+
+ /**
+ * @throws ReflectionException
+ *
+ * @return string[]
+ */
+ public function getClassMethods(string $className): array
+ {
+ try {
+ $class = new ReflectionClass($className);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $methods = [];
+
+ foreach ($class->getMethods() as $method) {
+ if ($method->isPublic() || $method->isAbstract()) {
+ $methods[] = $method->getName();
+ }
+ }
+
+ return $methods;
+ }
+
+ /**
+ * @throws ReflectionException
+ *
+ * @return MockMethod[]
+ */
+ public function mockClassMethods(string $className, bool $callOriginalMethods, bool $cloneArguments): array
+ {
+ try {
+ $class = new ReflectionClass($className);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $methods = [];
+
+ foreach ($class->getMethods() as $method) {
+ if (($method->isPublic() || $method->isAbstract()) && $this->canMockMethod($method)) {
+ $methods[] = MockMethod::fromReflection($method, $callOriginalMethods, $cloneArguments);
+ }
+ }
+
+ return $methods;
+ }
+
+ /**
+ * @throws ReflectionException
+ *
+ * @return MockMethod[]
+ */
+ public function mockInterfaceMethods(string $interfaceName, bool $cloneArguments): array
+ {
+ try {
+ $class = new ReflectionClass($interfaceName);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $methods = [];
+
+ foreach ($class->getMethods() as $method) {
+ $methods[] = MockMethod::fromReflection($method, false, $cloneArguments);
+ }
+
+ return $methods;
+ }
+
+ /**
+ * @psalm-param class-string $interfaceName
+ *
+ * @throws ReflectionException
+ *
+ * @return ReflectionMethod[]
+ */
+ private function userDefinedInterfaceMethods(string $interfaceName): array
+ {
+ try {
+ // @codeCoverageIgnoreStart
+ $interface = new ReflectionClass($interfaceName);
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $methods = [];
+
+ foreach ($interface->getMethods() as $method) {
+ if (!$method->isUserDefined()) {
+ continue;
+ }
+
+ $methods[] = $method;
+ }
+
+ return $methods;
+ }
+
+ /**
+ * @throws ReflectionException
+ * @throws RuntimeException
+ */
+ private function getObject(MockType $mockClass, $type = '', bool $callOriginalConstructor = false, bool $callAutoload = false, array $arguments = [], bool $callOriginalMethods = false, object $proxyTarget = null, bool $returnValueGeneration = true)
+ {
+ $className = $mockClass->generate();
+
+ if ($callOriginalConstructor) {
+ if (count($arguments) === 0) {
+ $object = new $className;
+ } else {
+ try {
+ $class = new ReflectionClass($className);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $object = $class->newInstanceArgs($arguments);
+ }
+ } else {
+ try {
+ $object = (new Instantiator)->instantiate($className);
+ } catch (InstantiatorException $e) {
+ throw new RuntimeException($e->getMessage());
+ }
+ }
+
+ if ($callOriginalMethods) {
+ if (!is_object($proxyTarget)) {
+ if (count($arguments) === 0) {
+ $proxyTarget = new $type;
+ } else {
+ try {
+ $class = new ReflectionClass($type);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $proxyTarget = $class->newInstanceArgs($arguments);
+ }
+ }
+
+ $object->__phpunit_setOriginalObject($proxyTarget);
+ }
+
+ if ($object instanceof MockObject) {
+ $object->__phpunit_setReturnValueGeneration($returnValueGeneration);
+ }
+
+ return $object;
+ }
+
+ /**
+ * @throws ClassIsFinalException
+ * @throws ReflectionException
+ * @throws RuntimeException
+ */
+ private function generateMock(string $type, ?array $explicitMethods, string $mockClassName, bool $callOriginalClone, bool $callAutoload, bool $cloneArguments, bool $callOriginalMethods): MockClass
+ {
+ $classTemplate = $this->getTemplate('mocked_class.tpl');
+ $additionalInterfaces = [];
+ $mockedCloneMethod = false;
+ $unmockedCloneMethod = false;
+ $isClass = false;
+ $isInterface = false;
+ $class = null;
+ $mockMethods = new MockMethodSet;
+
+ $_mockClassName = $this->generateClassName(
+ $type,
+ $mockClassName,
+ 'Mock_'
+ );
+
+ if (class_exists($_mockClassName['fullClassName'], $callAutoload)) {
+ $isClass = true;
+ } elseif (interface_exists($_mockClassName['fullClassName'], $callAutoload)) {
+ $isInterface = true;
+ }
+
+ if (!$isClass && !$isInterface) {
+ $prologue = 'class ' . $_mockClassName['originalClassName'] . "\n{\n}\n\n";
+
+ if (!empty($_mockClassName['namespaceName'])) {
+ $prologue = 'namespace ' . $_mockClassName['namespaceName'] .
+ " {\n\n" . $prologue . "}\n\n" .
+ "namespace {\n\n";
+
+ $epilogue = "\n\n}";
+ }
+
+ $mockedCloneMethod = true;
+ } else {
+ try {
+ $class = new ReflectionClass($_mockClassName['fullClassName']);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if ($class->isFinal()) {
+ throw new ClassIsFinalException($_mockClassName['fullClassName']);
+ }
+
+ // @see https://github.com/sebastianbergmann/phpunit/issues/2995
+ if ($isInterface && $class->implementsInterface(Throwable::class)) {
+ $actualClassName = Exception::class;
+ $additionalInterfaces[] = $class->getName();
+ $isInterface = false;
+
+ try {
+ $class = new ReflectionClass($actualClassName);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ foreach ($this->userDefinedInterfaceMethods($_mockClassName['fullClassName']) as $method) {
+ $methodName = $method->getName();
+
+ if ($class->hasMethod($methodName)) {
+ try {
+ $classMethod = $class->getMethod($methodName);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if (!$this->canMockMethod($classMethod)) {
+ continue;
+ }
+ }
+
+ $mockMethods->addMethods(
+ MockMethod::fromReflection($method, $callOriginalMethods, $cloneArguments)
+ );
+ }
+
+ $_mockClassName = $this->generateClassName(
+ $actualClassName,
+ $_mockClassName['className'],
+ 'Mock_'
+ );
+ }
+
+ // @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, $callOriginalMethods, $cloneArguments)
+ );
+ }
+
+ if ($class->hasMethod('__clone')) {
+ try {
+ $cloneMethod = $class->getMethod('__clone');
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if (!$cloneMethod->isFinal()) {
+ if ($callOriginalClone && !$isInterface) {
+ $unmockedCloneMethod = true;
+ } else {
+ $mockedCloneMethod = true;
+ }
+ }
+ } else {
+ $mockedCloneMethod = true;
+ }
+ }
+
+ if ($isClass && $explicitMethods === []) {
+ $mockMethods->addMethods(
+ ...$this->mockClassMethods($_mockClassName['fullClassName'], $callOriginalMethods, $cloneArguments)
+ );
+ }
+
+ if ($isInterface && ($explicitMethods === [] || $explicitMethods === null)) {
+ $mockMethods->addMethods(
+ ...$this->mockInterfaceMethods($_mockClassName['fullClassName'], $cloneArguments)
+ );
+ }
+
+ if (is_array($explicitMethods)) {
+ foreach ($explicitMethods as $methodName) {
+ if ($class !== null && $class->hasMethod($methodName)) {
+ try {
+ $method = $class->getMethod($methodName);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if ($this->canMockMethod($method)) {
+ $mockMethods->addMethods(
+ MockMethod::fromReflection($method, $callOriginalMethods, $cloneArguments)
+ );
+ }
+ } else {
+ $mockMethods->addMethods(
+ MockMethod::fromName(
+ $_mockClassName['fullClassName'],
+ $methodName,
+ $cloneArguments
+ )
+ );
+ }
+ }
+ }
+
+ $mockedMethods = '';
+ $configurable = [];
+
+ foreach ($mockMethods->asArray() as $mockMethod) {
+ $mockedMethods .= $mockMethod->generateCode();
+ $configurable[] = new ConfigurableMethod($mockMethod->getName(), $mockMethod->getReturnType());
+ }
+
+ $method = '';
+
+ if (!$mockMethods->hasMethod('method') && (!isset($class) || !$class->hasMethod('method'))) {
+ $method = PHP_EOL . ' use \PHPUnit\Framework\MockObject\Method;';
+ }
+
+ $cloneTrait = '';
+
+ if ($mockedCloneMethod) {
+ $cloneTrait = PHP_EOL . ' use \PHPUnit\Framework\MockObject\MockedCloneMethod;';
+ }
+
+ if ($unmockedCloneMethod) {
+ $cloneTrait = PHP_EOL . ' use \PHPUnit\Framework\MockObject\UnmockedCloneMethod;';
+ }
+
+ $classTemplate->setVar(
+ [
+ 'prologue' => $prologue ?? '',
+ 'epilogue' => $epilogue ?? '',
+ 'class_declaration' => $this->generateMockClassDeclaration(
+ $_mockClassName,
+ $isInterface,
+ $additionalInterfaces
+ ),
+ 'clone' => $cloneTrait,
+ 'mock_class_name' => $_mockClassName['className'],
+ 'mocked_methods' => $mockedMethods,
+ 'method' => $method,
+ ]
+ );
+
+ return new MockClass(
+ $classTemplate->render(),
+ $_mockClassName['className'],
+ $configurable
+ );
+ }
+
+ 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,
+ ];
+ }
+
+ private function generateMockClassDeclaration(array $mockClassName, bool $isInterface, array $additionalInterfaces = []): string
+ {
+ $buffer = 'class ';
+
+ $additionalInterfaces[] = MockObject::class;
+ $interfaces = implode(', ', $additionalInterfaces);
+
+ if ($isInterface) {
+ $buffer .= sprintf(
+ '%s implements %s',
+ $mockClassName['className'],
+ $interfaces
+ );
+
+ if (!in_array($mockClassName['originalClassName'], $additionalInterfaces, true)) {
+ $buffer .= ', ';
+
+ if (!empty($mockClassName['namespaceName'])) {
+ $buffer .= $mockClassName['namespaceName'] . '\\';
+ }
+
+ $buffer .= $mockClassName['originalClassName'];
+ }
+ } else {
+ $buffer .= sprintf(
+ '%s extends %s%s implements %s',
+ $mockClassName['className'],
+ !empty($mockClassName['namespaceName']) ? $mockClassName['namespaceName'] . '\\' : '',
+ $mockClassName['originalClassName'],
+ $interfaces
+ );
+ }
+
+ return $buffer;
+ }
+
+ private function canMockMethod(ReflectionMethod $method): bool
+ {
+ return !($this->isConstructor($method) || $method->isFinal() || $method->isPrivate() || $this->isMethodNameExcluded($method->getName()));
+ }
+
+ private function isMethodNameExcluded(string $name): bool
+ {
+ return isset(self::EXCLUDED_METHOD_NAMES[$name]);
+ }
+
+ /**
+ * @throws RuntimeException
+ */
+ private function getTemplate(string $template): Template
+ {
+ $filename = __DIR__ . DIRECTORY_SEPARATOR . 'Generator' . DIRECTORY_SEPARATOR . $template;
+
+ if (!isset(self::$templates[$filename])) {
+ try {
+ self::$templates[$filename] = new Template($filename);
+ } catch (TemplateException $e) {
+ throw new RuntimeException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ }
+
+ return self::$templates[$filename];
+ }
+
+ /**
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4139#issuecomment-605409765
+ */
+ private function isConstructor(ReflectionMethod $method): bool
+ {
+ $methodName = strtolower($method->getName());
+
+ if ($methodName === '__construct') {
+ return true;
+ }
+
+ if (PHP_MAJOR_VERSION >= 8) {
+ return false;
+ }
+
+ $className = strtolower($method->getDeclaringClass()->getName());
+
+ return $methodName === $className;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/deprecation.tpl b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/deprecation.tpl
new file mode 100644
index 000000000..5bf06f52d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/deprecation.tpl
@@ -0,0 +1,2 @@
+
+ @trigger_error({deprecation}, E_USER_DEPRECATED);
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_class.tpl b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_class.tpl
new file mode 100644
index 000000000..593119fb2
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_class.tpl
@@ -0,0 +1,6 @@
+declare(strict_types=1);
+
+{prologue}{class_declaration}
+{
+ use \PHPUnit\Framework\MockObject\Api;{method}{clone}
+{mocked_methods}}{epilogue}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_method.tpl b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_method.tpl
new file mode 100644
index 000000000..114ff8d0d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_method.tpl
@@ -0,0 +1,22 @@
+
+ {modifier} function {reference}{method_name}({arguments_decl}){return_declaration}
+ {{deprecation}
+ $__phpunit_arguments = [{arguments_call}];
+ $__phpunit_count = func_num_args();
+
+ if ($__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_result = $this->__phpunit_getInvocationHandler()->invoke(
+ new \PHPUnit\Framework\MockObject\Invocation(
+ '{class_name}', '{method_name}', $__phpunit_arguments, '{return_type}', $this, {clone_arguments}
+ )
+ );
+
+ return $__phpunit_result;
+ }
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_method_void.tpl b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_method_void.tpl
new file mode 100644
index 000000000..390202201
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_method_void.tpl
@@ -0,0 +1,20 @@
+
+ {modifier} function {reference}{method_name}({arguments_decl}){return_declaration}
+ {{deprecation}
+ $__phpunit_arguments = [{arguments_call}];
+ $__phpunit_count = func_num_args();
+
+ if ($__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];
+ }
+ }
+
+ $this->__phpunit_getInvocationHandler()->invoke(
+ new \PHPUnit\Framework\MockObject\Invocation(
+ '{class_name}', '{method_name}', $__phpunit_arguments, '{return_type}', $this, {clone_arguments}
+ )
+ );
+ }
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_static_method.tpl b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_static_method.tpl
new file mode 100644
index 000000000..5e5cf23cd
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/mocked_static_method.tpl
@@ -0,0 +1,5 @@
+
+ {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');
+ }
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/proxied_method.tpl b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/proxied_method.tpl
new file mode 100644
index 000000000..91bef463d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/proxied_method.tpl
@@ -0,0 +1,22 @@
+
+ {modifier} function {reference}{method_name}({arguments_decl}){return_declaration}
+ {
+ $__phpunit_arguments = [{arguments_call}];
+ $__phpunit_count = func_num_args();
+
+ if ($__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];
+ }
+ }
+
+ $this->__phpunit_getInvocationHandler()->invoke(
+ new \PHPUnit\Framework\MockObject\Invocation(
+ '{class_name}', '{method_name}', $__phpunit_arguments, '{return_type}', $this, {clone_arguments}, true
+ )
+ );
+
+ return call_user_func_array(array($this->__phpunit_originalObject, "{method_name}"), $__phpunit_arguments);
+ }
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/proxied_method_void.tpl b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/proxied_method_void.tpl
new file mode 100644
index 000000000..cce198826
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/proxied_method_void.tpl
@@ -0,0 +1,22 @@
+
+ {modifier} function {reference}{method_name}({arguments_decl}){return_declaration}
+ {
+ $__phpunit_arguments = [{arguments_call}];
+ $__phpunit_count = func_num_args();
+
+ if ($__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];
+ }
+ }
+
+ $this->__phpunit_getInvocationHandler()->invoke(
+ new \PHPUnit\Framework\MockObject\Invocation(
+ '{class_name}', '{method_name}', $__phpunit_arguments, '{return_type}', $this, {clone_arguments}, true
+ )
+ );
+
+ call_user_func_array(array($this->__phpunit_originalObject, "{method_name}"), $__phpunit_arguments);
+ }
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/trait_class.tpl b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/trait_class.tpl
new file mode 100644
index 000000000..a8fe470fd
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/trait_class.tpl
@@ -0,0 +1,6 @@
+declare(strict_types=1);
+
+{prologue}class {class_name}
+{
+ use {trait_name};
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/wsdl_class.tpl b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/wsdl_class.tpl
new file mode 100644
index 000000000..b3100b414
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/wsdl_class.tpl
@@ -0,0 +1,9 @@
+declare(strict_types=1);
+
+{namespace}class {class_name} extends \SoapClient
+{
+ public function __construct($wsdl, array $options)
+ {
+ parent::__construct('{wsdl}', $options);
+ }
+{methods}}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/wsdl_method.tpl b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/wsdl_method.tpl
new file mode 100644
index 000000000..bb16e763e
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Generator/wsdl_method.tpl
@@ -0,0 +1,4 @@
+
+ public function {method_name}({arguments})
+ {
+ }
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Invocation.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Invocation.php
new file mode 100644
index 000000000..392938347
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Invocation.php
@@ -0,0 +1,254 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 explode;
+use function get_class;
+use function implode;
+use function is_object;
+use function sprintf;
+use function strpos;
+use function strtolower;
+use function substr;
+use Doctrine\Instantiator\Instantiator;
+use PHPUnit\Framework\SelfDescribing;
+use PHPUnit\Util\Type;
+use SebastianBergmann\Exporter\Exporter;
+use stdClass;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Invocation implements SelfDescribing
+{
+ /**
+ * @var string
+ */
+ private $className;
+
+ /**
+ * @var string
+ */
+ private $methodName;
+
+ /**
+ * @var array
+ */
+ private $parameters;
+
+ /**
+ * @var string
+ */
+ private $returnType;
+
+ /**
+ * @var bool
+ */
+ private $isReturnTypeNullable = false;
+
+ /**
+ * @var bool
+ */
+ private $proxiedCall;
+
+ /**
+ * @var object
+ */
+ private $object;
+
+ public function __construct(string $className, string $methodName, array $parameters, string $returnType, object $object, bool $cloneObjects = false, bool $proxiedCall = false)
+ {
+ $this->className = $className;
+ $this->methodName = $methodName;
+ $this->parameters = $parameters;
+ $this->object = $object;
+ $this->proxiedCall = $proxiedCall;
+
+ if (strtolower($methodName) === '__tostring') {
+ $returnType = 'string';
+ }
+
+ if (strpos($returnType, '?') === 0) {
+ $returnType = substr($returnType, 1);
+ $this->isReturnTypeNullable = true;
+ }
+
+ $this->returnType = $returnType;
+
+ if (!$cloneObjects) {
+ return;
+ }
+
+ foreach ($this->parameters as $key => $value) {
+ if (is_object($value)) {
+ $this->parameters[$key] = $this->cloneObject($value);
+ }
+ }
+ }
+
+ public function getClassName(): string
+ {
+ return $this->className;
+ }
+
+ public function getMethodName(): string
+ {
+ return $this->methodName;
+ }
+
+ public function getParameters(): array
+ {
+ return $this->parameters;
+ }
+
+ /**
+ * @throws RuntimeException
+ *
+ * @return mixed Mocked return value
+ */
+ public function generateReturnValue()
+ {
+ if ($this->isReturnTypeNullable || $this->proxiedCall) {
+ return null;
+ }
+
+ $union = false;
+
+ if (strpos($this->returnType, '|') !== false) {
+ $types = explode('|', $this->returnType);
+ $union = true;
+ } else {
+ $types = [$this->returnType];
+ }
+
+ $types = array_map('strtolower', $types);
+
+ if (in_array('', $types, true) ||
+ in_array('null', $types, true) ||
+ in_array('mixed', $types, true) ||
+ in_array('void', $types, true)) {
+ return null;
+ }
+
+ if (in_array('false', $types, true) ||
+ in_array('bool', $types, true)) {
+ return false;
+ }
+
+ if (in_array('float', $types, true)) {
+ return 0.0;
+ }
+
+ if (in_array('int', $types, true)) {
+ return 0;
+ }
+
+ if (in_array('string', $types, true)) {
+ return '';
+ }
+
+ if (in_array('array', $types, true)) {
+ return [];
+ }
+
+ if (in_array('static', $types, true)) {
+ try {
+ return (new Instantiator)->instantiate(get_class($this->object));
+ } catch (Throwable $t) {
+ throw new RuntimeException(
+ $t->getMessage(),
+ (int) $t->getCode(),
+ $t
+ );
+ }
+ }
+
+ if (in_array('object', $types, true)) {
+ return new stdClass;
+ }
+
+ if (in_array('callable', $types, true) ||
+ in_array('closure', $types, true)) {
+ return static function (): void
+ {
+ };
+ }
+
+ if (in_array('traversable', $types, true) ||
+ in_array('generator', $types, true) ||
+ in_array('iterable', $types, true)) {
+ $generator = static function (): \Generator
+ {
+ yield from [];
+ };
+
+ return $generator();
+ }
+
+ if (!$union) {
+ try {
+ return (new Generator)->getMock($this->returnType, [], [], '', false);
+ } catch (Throwable $t) {
+ throw new RuntimeException(
+ sprintf(
+ 'Return value for %s::%s() cannot be generated: %s',
+ $this->className,
+ $this->methodName,
+ $t->getMessage(),
+ ),
+ (int) $t->getCode(),
+ );
+ }
+ }
+
+ throw new RuntimeException(
+ sprintf(
+ 'Return value for %s::%s() cannot be generated because the declared return type is a union, please configure a return value for this method',
+ $this->className,
+ $this->methodName
+ )
+ );
+ }
+
+ public function toString(): string
+ {
+ $exporter = new Exporter;
+
+ 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 getObject(): object
+ {
+ return $this->object;
+ }
+
+ private function cloneObject(object $original): object
+ {
+ if (Type::isCloneable($original)) {
+ return clone $original;
+ }
+
+ return $original;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/InvocationHandler.php b/vendor/phpunit/phpunit/src/Framework/MockObject/InvocationHandler.php
new file mode 100644
index 000000000..b9d62610a
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/InvocationHandler.php
@@ -0,0 +1,186 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 strtolower;
+use Exception;
+use PHPUnit\Framework\MockObject\Builder\InvocationMocker;
+use PHPUnit\Framework\MockObject\Rule\InvocationOrder;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class InvocationHandler
+{
+ /**
+ * @var Matcher[]
+ */
+ private $matchers = [];
+
+ /**
+ * @var Matcher[]
+ */
+ private $matcherMap = [];
+
+ /**
+ * @var ConfigurableMethod[]
+ */
+ private $configurableMethods;
+
+ /**
+ * @var bool
+ */
+ private $returnValueGeneration;
+
+ /**
+ * @var Throwable
+ */
+ private $deferredError;
+
+ public function __construct(array $configurableMethods, bool $returnValueGeneration)
+ {
+ $this->configurableMethods = $configurableMethods;
+ $this->returnValueGeneration = $returnValueGeneration;
+ }
+
+ public function hasMatchers(): bool
+ {
+ foreach ($this->matchers as $matcher) {
+ if ($matcher->hasMatchers()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Looks up the match builder with identification $id and returns it.
+ *
+ * @param string $id The identification of the match builder
+ */
+ public function lookupMatcher(string $id): ?Matcher
+ {
+ if (isset($this->matcherMap[$id])) {
+ return $this->matcherMap[$id];
+ }
+
+ return 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 string $id The identification of the matcher
+ * @param Matcher $matcher The builder which is being registered
+ *
+ * @throws MatcherAlreadyRegisteredException
+ */
+ public function registerMatcher(string $id, Matcher $matcher): void
+ {
+ if (isset($this->matcherMap[$id])) {
+ throw new MatcherAlreadyRegisteredException($id);
+ }
+
+ $this->matcherMap[$id] = $matcher;
+ }
+
+ public function expects(InvocationOrder $rule): InvocationMocker
+ {
+ $matcher = new Matcher($rule);
+ $this->addMatcher($matcher);
+
+ return new InvocationMocker(
+ $this,
+ $matcher,
+ ...$this->configurableMethods
+ );
+ }
+
+ /**
+ * @throws Exception
+ * @throws RuntimeException
+ */
+ public function invoke(Invocation $invocation)
+ {
+ $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) {
+ $exception = new ReturnValueNotConfiguredException($invocation);
+
+ if (strtolower($invocation->getMethodName()) === '__tostring') {
+ $this->deferredError = $exception;
+
+ return '';
+ }
+
+ throw $exception;
+ }
+
+ return $invocation->generateReturnValue();
+ }
+
+ public function matches(Invocation $invocation): bool
+ {
+ foreach ($this->matchers as $matcher) {
+ if (!$matcher->matches($invocation)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @throws Throwable
+ */
+ public function verify(): void
+ {
+ foreach ($this->matchers as $matcher) {
+ $matcher->verify();
+ }
+
+ if ($this->deferredError) {
+ throw $this->deferredError;
+ }
+ }
+
+ private function addMatcher(Matcher $matcher): void
+ {
+ $this->matchers[] = $matcher;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Matcher.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Matcher.php
new file mode 100644
index 000000000..a0f8817bd
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Matcher.php
@@ -0,0 +1,272 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function implode;
+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\InvokedCount;
+use PHPUnit\Framework\MockObject\Rule\MethodName;
+use PHPUnit\Framework\MockObject\Rule\ParametersRule;
+use PHPUnit\Framework\MockObject\Stub\Stub;
+use PHPUnit\Framework\TestFailure;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Matcher
+{
+ /**
+ * @var InvocationOrder
+ */
+ private $invocationRule;
+
+ /**
+ * @var mixed
+ */
+ private $afterMatchBuilderId;
+
+ /**
+ * @var bool
+ */
+ private $afterMatchBuilderIsInvoked = false;
+
+ /**
+ * @var MethodName
+ */
+ private $methodNameRule;
+
+ /**
+ * @var ParametersRule
+ */
+ private $parametersRule;
+
+ /**
+ * @var Stub
+ */
+ private $stub;
+
+ public function __construct(InvocationOrder $rule)
+ {
+ $this->invocationRule = $rule;
+ }
+
+ public function hasMatchers(): bool
+ {
+ return !$this->invocationRule instanceof AnyInvokedCount;
+ }
+
+ public function hasMethodNameRule(): bool
+ {
+ return $this->methodNameRule !== null;
+ }
+
+ public function getMethodNameRule(): MethodName
+ {
+ return $this->methodNameRule;
+ }
+
+ public function setMethodNameRule(MethodName $rule): void
+ {
+ $this->methodNameRule = $rule;
+ }
+
+ 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;
+ }
+
+ public function setAfterMatchBuilderId(string $id): void
+ {
+ $this->afterMatchBuilderId = $id;
+ }
+
+ /**
+ * @throws ExpectationFailedException
+ * @throws MatchBuilderNotFoundException
+ * @throws MethodNameNotConfiguredException
+ * @throws RuntimeException
+ */
+ public function invoked(Invocation $invocation)
+ {
+ if ($this->methodNameRule === null) {
+ throw new MethodNameNotConfiguredException;
+ }
+
+ if ($this->afterMatchBuilderId !== null) {
+ $matcher = $invocation->getObject()
+ ->__phpunit_getInvocationHandler()
+ ->lookupMatcher($this->afterMatchBuilderId);
+
+ if (!$matcher) {
+ throw new MatchBuilderNotFoundException($this->afterMatchBuilderId);
+ }
+
+ assert($matcher instanceof self);
+
+ if ($matcher->invocationRule->hasBeenInvoked()) {
+ $this->afterMatchBuilderIsInvoked = true;
+ }
+ }
+
+ $this->invocationRule->invoked($invocation);
+
+ try {
+ if ($this->parametersRule !== null) {
+ $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) {
+ return $this->stub->invoke($invocation);
+ }
+
+ return $invocation->generateReturnValue();
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ * @throws MatchBuilderNotFoundException
+ * @throws MethodNameNotConfiguredException
+ * @throws RuntimeException
+ */
+ public function matches(Invocation $invocation): bool
+ {
+ if ($this->afterMatchBuilderId !== null) {
+ $matcher = $invocation->getObject()
+ ->__phpunit_getInvocationHandler()
+ ->lookupMatcher($this->afterMatchBuilderId);
+
+ if (!$matcher) {
+ throw new MatchBuilderNotFoundException($this->afterMatchBuilderId);
+ }
+
+ assert($matcher instanceof self);
+
+ if (!$matcher->invocationRule->hasBeenInvoked()) {
+ return false;
+ }
+ }
+
+ if ($this->methodNameRule === null) {
+ throw new 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 \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ * @throws MethodNameNotConfiguredException
+ */
+ public function verify(): void
+ {
+ if ($this->methodNameRule === null) {
+ throw new 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();
+
+ if (!$invocationIsAny && !$invocationIsNever) {
+ $this->parametersRule->verify();
+ }
+ } catch (ExpectationFailedException $e) {
+ throw new ExpectationFailedException(
+ sprintf(
+ "Expectation failed for %s when %s.\n%s",
+ $this->methodNameRule->toString(),
+ $this->invocationRule->toString(),
+ TestFailure::exceptionToString($e)
+ )
+ );
+ }
+ }
+
+ public function toString(): string
+ {
+ $list = [];
+
+ if ($this->invocationRule !== null) {
+ $list[] = $this->invocationRule->toString();
+ }
+
+ if ($this->methodNameRule !== null) {
+ $list[] = 'where ' . $this->methodNameRule->toString();
+ }
+
+ if ($this->parametersRule !== null) {
+ $list[] = 'and ' . $this->parametersRule->toString();
+ }
+
+ if ($this->afterMatchBuilderId !== null) {
+ $list[] = 'after ' . $this->afterMatchBuilderId;
+ }
+
+ if ($this->stub !== null) {
+ $list[] = 'will ' . $this->stub->toString();
+ }
+
+ return implode(' ', $list);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/MethodNameConstraint.php b/vendor/phpunit/phpunit/src/Framework/MockObject/MethodNameConstraint.php
new file mode 100644
index 000000000..3082ab384
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/MethodNameConstraint.php
@@ -0,0 +1,48 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 is_string;
+use function sprintf;
+use function strtolower;
+use PHPUnit\Framework\Constraint\Constraint;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MethodNameConstraint extends Constraint
+{
+ /**
+ * @var string
+ */
+ private $methodName;
+
+ public function __construct(string $methodName)
+ {
+ $this->methodName = $methodName;
+ }
+
+ public function toString(): string
+ {
+ return sprintf(
+ 'is "%s"',
+ $this->methodName
+ );
+ }
+
+ protected function matches($other): bool
+ {
+ if (!is_string($other)) {
+ return false;
+ }
+
+ return strtolower($this->methodName) === strtolower($other);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/MockBuilder.php b/vendor/phpunit/phpunit/src/Framework/MockObject/MockBuilder.php
new file mode 100644
index 000000000..aec32a2d4
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/MockBuilder.php
@@ -0,0 +1,516 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_diff;
+use function array_merge;
+use PHPUnit\Framework\TestCase;
+use ReflectionClass;
+
+/**
+ * @psalm-template MockedType
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class MockBuilder
+{
+ /**
+ * @var TestCase
+ */
+ private $testCase;
+
+ /**
+ * @var string
+ */
+ private $type;
+
+ /**
+ * @var null|string[]
+ */
+ private $methods = [];
+
+ /**
+ * @var bool
+ */
+ private $emptyMethodsArray = false;
+
+ /**
+ * @var string
+ */
+ private $mockClassName = '';
+
+ /**
+ * @var array
+ */
+ private $constructorArgs = [];
+
+ /**
+ * @var bool
+ */
+ private $originalConstructor = true;
+
+ /**
+ * @var bool
+ */
+ private $originalClone = true;
+
+ /**
+ * @var bool
+ */
+ private $autoload = true;
+
+ /**
+ * @var bool
+ */
+ private $cloneArguments = false;
+
+ /**
+ * @var bool
+ */
+ private $callOriginalMethods = false;
+
+ /**
+ * @var ?object
+ */
+ private $proxyTarget;
+
+ /**
+ * @var bool
+ */
+ private $allowMockingUnknownTypes = true;
+
+ /**
+ * @var bool
+ */
+ private $returnValueGeneration = true;
+
+ /**
+ * @var Generator
+ */
+ private $generator;
+
+ /**
+ * @param string|string[] $type
+ *
+ * @psalm-param class-string<MockedType>|string|string[] $type
+ */
+ public function __construct(TestCase $testCase, $type)
+ {
+ $this->testCase = $testCase;
+ $this->type = $type;
+ $this->generator = new Generator;
+ }
+
+ /**
+ * Creates a mock object using a fluent interface.
+ *
+ * @throws \PHPUnit\Framework\InvalidArgumentException
+ * @throws ClassAlreadyExistsException
+ * @throws ClassIsFinalException
+ * @throws DuplicateMethodException
+ * @throws InvalidMethodNameException
+ * @throws OriginalConstructorInvocationRequiredException
+ * @throws ReflectionException
+ * @throws RuntimeException
+ * @throws UnknownTypeException
+ *
+ * @psalm-return MockObject&MockedType
+ */
+ public function getMock(): MockObject
+ {
+ $object = $this->generator->getMock(
+ $this->type,
+ !$this->emptyMethodsArray ? $this->methods : null,
+ $this->constructorArgs,
+ $this->mockClassName,
+ $this->originalConstructor,
+ $this->originalClone,
+ $this->autoload,
+ $this->cloneArguments,
+ $this->callOriginalMethods,
+ $this->proxyTarget,
+ $this->allowMockingUnknownTypes,
+ $this->returnValueGeneration
+ );
+
+ $this->testCase->registerMockObject($object);
+
+ return $object;
+ }
+
+ /**
+ * Creates a mock object for an abstract class using a fluent interface.
+ *
+ * @psalm-return MockObject&MockedType
+ *
+ * @throws \PHPUnit\Framework\Exception
+ * @throws ReflectionException
+ * @throws RuntimeException
+ */
+ public function getMockForAbstractClass(): MockObject
+ {
+ $object = $this->generator->getMockForAbstractClass(
+ $this->type,
+ $this->constructorArgs,
+ $this->mockClassName,
+ $this->originalConstructor,
+ $this->originalClone,
+ $this->autoload,
+ $this->methods,
+ $this->cloneArguments
+ );
+
+ $this->testCase->registerMockObject($object);
+
+ return $object;
+ }
+
+ /**
+ * Creates a mock object for a trait using a fluent interface.
+ *
+ * @psalm-return MockObject&MockedType
+ *
+ * @throws \PHPUnit\Framework\Exception
+ * @throws ReflectionException
+ * @throws RuntimeException
+ */
+ public function getMockForTrait(): MockObject
+ {
+ $object = $this->generator->getMockForTrait(
+ $this->type,
+ $this->constructorArgs,
+ $this->mockClassName,
+ $this->originalConstructor,
+ $this->originalClone,
+ $this->autoload,
+ $this->methods,
+ $this->cloneArguments
+ );
+
+ $this->testCase->registerMockObject($object);
+
+ return $object;
+ }
+
+ /**
+ * Specifies the subset of methods to mock. Default is to mock none of them.
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/pull/3687
+ *
+ * @return $this
+ */
+ public function setMethods(?array $methods = null): self
+ {
+ if ($methods === null) {
+ $this->methods = $methods;
+ } else {
+ $this->methods = array_merge($this->methods ?? [], $methods);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Specifies the subset of methods to mock, requiring each to exist in the class.
+ *
+ * @param string[] $methods
+ *
+ * @throws CannotUseOnlyMethodsException
+ * @throws ReflectionException
+ *
+ * @return $this
+ */
+ public function onlyMethods(array $methods): self
+ {
+ if (empty($methods)) {
+ $this->emptyMethodsArray = true;
+
+ return $this;
+ }
+
+ try {
+ $reflector = new ReflectionClass($this->type);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ foreach ($methods as $method) {
+ if (!$reflector->hasMethod($method)) {
+ throw new CannotUseOnlyMethodsException($this->type, $method);
+ }
+ }
+
+ $this->methods = array_merge($this->methods ?? [], $methods);
+
+ return $this;
+ }
+
+ /**
+ * Specifies methods that don't exist in the class which you want to mock.
+ *
+ * @param string[] $methods
+ *
+ * @throws CannotUseAddMethodsException
+ * @throws ReflectionException
+ * @throws RuntimeException
+ *
+ * @return $this
+ */
+ public function addMethods(array $methods): self
+ {
+ if (empty($methods)) {
+ $this->emptyMethodsArray = true;
+
+ return $this;
+ }
+
+ try {
+ $reflector = new ReflectionClass($this->type);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ foreach ($methods as $method) {
+ if ($reflector->hasMethod($method)) {
+ throw new CannotUseAddMethodsException($this->type, $method);
+ }
+ }
+
+ $this->methods = array_merge($this->methods ?? [], $methods);
+
+ return $this;
+ }
+
+ /**
+ * Specifies the subset of methods to not mock. Default is to mock all of them.
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/pull/3687
+ *
+ * @throws ReflectionException
+ */
+ public function setMethodsExcept(array $methods = []): self
+ {
+ return $this->setMethods(
+ array_diff(
+ $this->generator->getClassMethods($this->type),
+ $methods
+ )
+ );
+ }
+
+ /**
+ * Specifies the arguments for the constructor.
+ *
+ * @return $this
+ */
+ public function setConstructorArgs(array $args): self
+ {
+ $this->constructorArgs = $args;
+
+ return $this;
+ }
+
+ /**
+ * Specifies the name for the mock class.
+ *
+ * @return $this
+ */
+ public function setMockClassName(string $name): self
+ {
+ $this->mockClassName = $name;
+
+ 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;
+ }
+
+ /**
+ * Disables the use of class autoloading while creating the mock object.
+ *
+ * @return $this
+ */
+ public function disableAutoload(): self
+ {
+ $this->autoload = false;
+
+ return $this;
+ }
+
+ /**
+ * Enables the use of class autoloading while creating the mock object.
+ *
+ * @return $this
+ */
+ public function enableAutoload(): self
+ {
+ $this->autoload = true;
+
+ return $this;
+ }
+
+ /**
+ * Disables the cloning of arguments passed to mocked methods.
+ *
+ * @return $this
+ */
+ public function disableArgumentCloning(): self
+ {
+ $this->cloneArguments = false;
+
+ return $this;
+ }
+
+ /**
+ * Enables the cloning of arguments passed to mocked methods.
+ *
+ * @return $this
+ */
+ public function enableArgumentCloning(): self
+ {
+ $this->cloneArguments = true;
+
+ return $this;
+ }
+
+ /**
+ * Enables the invocation of the original methods.
+ *
+ * @return $this
+ */
+ public function enableProxyingToOriginalMethods(): self
+ {
+ $this->callOriginalMethods = true;
+
+ return $this;
+ }
+
+ /**
+ * Disables the invocation of the original methods.
+ *
+ * @return $this
+ */
+ public function disableProxyingToOriginalMethods(): self
+ {
+ $this->callOriginalMethods = false;
+ $this->proxyTarget = null;
+
+ return $this;
+ }
+
+ /**
+ * Sets the proxy target.
+ *
+ * @return $this
+ */
+ public function setProxyTarget(object $object): self
+ {
+ $this->proxyTarget = $object;
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function allowMockingUnknownTypes(): self
+ {
+ $this->allowMockingUnknownTypes = true;
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function disallowMockingUnknownTypes(): self
+ {
+ $this->allowMockingUnknownTypes = false;
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function enableAutoReturnValueGeneration(): self
+ {
+ $this->returnValueGeneration = true;
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function disableAutoReturnValueGeneration(): self
+ {
+ $this->returnValueGeneration = false;
+
+ return $this;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/MockClass.php b/vendor/phpunit/phpunit/src/Framework/MockObject/MockClass.php
new file mode 100644
index 000000000..253d78460
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/MockClass.php
@@ -0,0 +1,69 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+use function call_user_func;
+use function class_exists;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MockClass implements MockType
+{
+ /**
+ * @var string
+ */
+ private $classCode;
+
+ /**
+ * @var class-string
+ */
+ private $mockName;
+
+ /**
+ * @var ConfigurableMethod[]
+ */
+ private $configurableMethods;
+
+ /**
+ * @psalm-param class-string $mockName
+ */
+ public function __construct(string $classCode, string $mockName, array $configurableMethods)
+ {
+ $this->classCode = $classCode;
+ $this->mockName = $mockName;
+ $this->configurableMethods = $configurableMethods;
+ }
+
+ /**
+ * @psalm-return class-string
+ */
+ public function generate(): string
+ {
+ if (!class_exists($this->mockName, false)) {
+ eval($this->classCode);
+
+ call_user_func(
+ [
+ $this->mockName,
+ '__phpunit_initConfigurableMethods',
+ ],
+ ...$this->configurableMethods
+ );
+ }
+
+ return $this->mockName;
+ }
+
+ public function getClassCode(): string
+ {
+ return $this->classCode;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/MockMethod.php b/vendor/phpunit/phpunit/src/Framework/MockObject/MockMethod.php
new file mode 100644
index 000000000..5e02cae5f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/MockMethod.php
@@ -0,0 +1,398 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+use const DIRECTORY_SEPARATOR;
+use function implode;
+use function is_string;
+use function preg_match;
+use function preg_replace;
+use function sprintf;
+use function substr_count;
+use function trim;
+use function var_export;
+use ReflectionMethod;
+use ReflectionNamedType;
+use ReflectionParameter;
+use ReflectionUnionType;
+use SebastianBergmann\Template\Exception as TemplateException;
+use SebastianBergmann\Template\Template;
+use SebastianBergmann\Type\ReflectionMapper;
+use SebastianBergmann\Type\Type;
+use SebastianBergmann\Type\UnknownType;
+use SebastianBergmann\Type\VoidType;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MockMethod
+{
+ /**
+ * @var Template[]
+ */
+ private static $templates = [];
+
+ /**
+ * @var string
+ */
+ private $className;
+
+ /**
+ * @var string
+ */
+ private $methodName;
+
+ /**
+ * @var bool
+ */
+ private $cloneArguments;
+
+ /**
+ * @var string string
+ */
+ private $modifier;
+
+ /**
+ * @var string
+ */
+ private $argumentsForDeclaration;
+
+ /**
+ * @var string
+ */
+ private $argumentsForCall;
+
+ /**
+ * @var Type
+ */
+ private $returnType;
+
+ /**
+ * @var string
+ */
+ private $reference;
+
+ /**
+ * @var bool
+ */
+ private $callOriginalMethod;
+
+ /**
+ * @var bool
+ */
+ private $static;
+
+ /**
+ * @var ?string
+ */
+ private $deprecation;
+
+ /**
+ * @throws ReflectionException
+ * @throws RuntimeException
+ */
+ public static function fromReflection(ReflectionMethod $method, bool $callOriginalMethod, bool $cloneArguments): 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)) {
+ $deprecation = trim(preg_replace('#[ \t]*\r?\n[ \t]*+\*[ \t]*+#', ' ', $deprecation[1]));
+ } else {
+ $deprecation = null;
+ }
+
+ return new self(
+ $method->getDeclaringClass()->getName(),
+ $method->getName(),
+ $cloneArguments,
+ $modifier,
+ self::getMethodParametersForDeclaration($method),
+ self::getMethodParametersForCall($method),
+ (new ReflectionMapper)->fromMethodReturnType($method),
+ $reference,
+ $callOriginalMethod,
+ $method->isStatic(),
+ $deprecation
+ );
+ }
+
+ public static function fromName(string $fullClassName, string $methodName, bool $cloneArguments): self
+ {
+ return new self(
+ $fullClassName,
+ $methodName,
+ $cloneArguments,
+ 'public',
+ '',
+ '',
+ new UnknownType,
+ '',
+ false,
+ false,
+ null
+ );
+ }
+
+ public function __construct(string $className, string $methodName, bool $cloneArguments, string $modifier, string $argumentsForDeclaration, string $argumentsForCall, Type $returnType, string $reference, bool $callOriginalMethod, bool $static, ?string $deprecation)
+ {
+ $this->className = $className;
+ $this->methodName = $methodName;
+ $this->cloneArguments = $cloneArguments;
+ $this->modifier = $modifier;
+ $this->argumentsForDeclaration = $argumentsForDeclaration;
+ $this->argumentsForCall = $argumentsForCall;
+ $this->returnType = $returnType;
+ $this->reference = $reference;
+ $this->callOriginalMethod = $callOriginalMethod;
+ $this->static = $static;
+ $this->deprecation = $deprecation;
+ }
+
+ public function getName(): string
+ {
+ return $this->methodName;
+ }
+
+ /**
+ * @throws RuntimeException
+ */
+ public function generateCode(): string
+ {
+ if ($this->static) {
+ $templateFile = 'mocked_static_method.tpl';
+ } elseif ($this->returnType instanceof VoidType) {
+ $templateFile = sprintf(
+ '%s_method_void.tpl',
+ $this->callOriginalMethod ? 'proxied' : 'mocked'
+ );
+ } else {
+ $templateFile = sprintf(
+ '%s_method.tpl',
+ $this->callOriginalMethod ? 'proxied' : 'mocked'
+ );
+ }
+
+ $deprecation = $this->deprecation;
+
+ if (null !== $this->deprecation) {
+ $deprecation = "The {$this->className}::{$this->methodName} method is deprecated ({$this->deprecation}).";
+ $deprecationTemplate = $this->getTemplate('deprecation.tpl');
+
+ $deprecationTemplate->setVar(
+ [
+ 'deprecation' => var_export($deprecation, true),
+ ]
+ );
+
+ $deprecation = $deprecationTemplate->render();
+ }
+
+ $template = $this->getTemplate($templateFile);
+
+ $template->setVar(
+ [
+ 'arguments_decl' => $this->argumentsForDeclaration,
+ 'arguments_call' => $this->argumentsForCall,
+ 'return_declaration' => !empty($this->returnType->asString()) ? (': ' . $this->returnType->asString()) : '',
+ 'return_type' => $this->returnType->asString(),
+ 'arguments_count' => !empty($this->argumentsForCall) ? substr_count($this->argumentsForCall, ',') + 1 : 0,
+ 'class_name' => $this->className,
+ 'method_name' => $this->methodName,
+ 'modifier' => $this->modifier,
+ 'reference' => $this->reference,
+ 'clone_arguments' => $this->cloneArguments ? 'true' : 'false',
+ 'deprecation' => $deprecation,
+ ]
+ );
+
+ return $template->render();
+ }
+
+ public function getReturnType(): Type
+ {
+ return $this->returnType;
+ }
+
+ /**
+ * @throws RuntimeException
+ */
+ private function getTemplate(string $template): Template
+ {
+ $filename = __DIR__ . DIRECTORY_SEPARATOR . 'Generator' . DIRECTORY_SEPARATOR . $template;
+
+ if (!isset(self::$templates[$filename])) {
+ try {
+ self::$templates[$filename] = new Template($filename);
+ } catch (TemplateException $e) {
+ throw new RuntimeException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ }
+
+ return self::$templates[$filename];
+ }
+
+ /**
+ * Returns the parameters of a function or method.
+ *
+ * @throws RuntimeException
+ */
+ private static function getMethodParametersForDeclaration(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;
+ }
+
+ $nullable = '';
+ $default = '';
+ $reference = '';
+ $typeDeclaration = '';
+ $type = null;
+ $typeName = null;
+
+ if ($parameter->hasType()) {
+ $type = $parameter->getType();
+
+ if ($type instanceof ReflectionNamedType) {
+ $typeName = $type->getName();
+ }
+ }
+
+ if ($parameter->isVariadic()) {
+ $name = '...' . $name;
+ } elseif ($parameter->isDefaultValueAvailable()) {
+ $default = ' = ' . self::exportDefaultValue($parameter);
+ } elseif ($parameter->isOptional()) {
+ $default = ' = null';
+ }
+
+ if ($type !== null) {
+ if ($typeName !== 'mixed' && $parameter->allowsNull() && !$type instanceof ReflectionUnionType) {
+ $nullable = '?';
+ }
+
+ if ($typeName === 'self') {
+ $typeDeclaration = $method->getDeclaringClass()->getName() . ' ';
+ } elseif ($typeName !== null) {
+ $typeDeclaration = $typeName . ' ';
+ } elseif ($type instanceof ReflectionUnionType) {
+ $typeDeclaration = self::unionTypeAsString(
+ $type,
+ $method->getDeclaringClass()->getName()
+ );
+ }
+ }
+
+ if ($parameter->isPassedByReference()) {
+ $reference = '&';
+ }
+
+ $parameters[] = $nullable . $typeDeclaration . $reference . $name . $default;
+ }
+
+ return implode(', ', $parameters);
+ }
+
+ /**
+ * Returns the parameters of a function or method.
+ *
+ * @throws ReflectionException
+ */
+ private static function getMethodParametersForCall(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 {
+ return (string) var_export($parameter->getDefaultValue(), true);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ private static function unionTypeAsString(ReflectionUnionType $union, string $self): string
+ {
+ $types = [];
+
+ foreach ($union->getTypes() as $type) {
+ if ((string) $type === 'self') {
+ $types[] = $self;
+ } else {
+ $types[] = $type;
+ }
+ }
+
+ return implode('|', $types) . ' ';
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/MockMethodSet.php b/vendor/phpunit/phpunit/src/Framework/MockObject/MockMethodSet.php
new file mode 100644
index 000000000..1c78963c0
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/MockMethodSet.php
@@ -0,0 +1,45 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_key_exists;
+use function array_values;
+use function strtolower;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MockMethodSet
+{
+ /**
+ * @var MockMethod[]
+ */
+ private $methods = [];
+
+ public function addMethods(MockMethod ...$methods): void
+ {
+ foreach ($methods as $method) {
+ $this->methods[strtolower($method->getName())] = $method;
+ }
+ }
+
+ /**
+ * @return MockMethod[]
+ */
+ public function asArray(): array
+ {
+ return array_values($this->methods);
+ }
+
+ public function hasMethod(string $methodName): bool
+ {
+ return array_key_exists(strtolower($methodName), $this->methods);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/MockObject.php b/vendor/phpunit/phpunit/src/Framework/MockObject/MockObject.php
new file mode 100644
index 000000000..094decf43
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/MockObject.php
@@ -0,0 +1,27 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+use PHPUnit\Framework\MockObject\Builder\InvocationMocker as BuilderInvocationMocker;
+use PHPUnit\Framework\MockObject\Rule\InvocationOrder;
+
+/**
+ * @method BuilderInvocationMocker method($constraint)
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+interface MockObject extends Stub
+{
+ public function __phpunit_setOriginalObject($originalObject): void;
+
+ public function __phpunit_verify(bool $unsetInvocationMocker = true): void;
+
+ public function expects(InvocationOrder $invocationRule): BuilderInvocationMocker;
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/MockTrait.php b/vendor/phpunit/phpunit/src/Framework/MockObject/MockTrait.php
new file mode 100644
index 000000000..7c326988f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/MockTrait.php
@@ -0,0 +1,54 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 class_exists;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MockTrait implements MockType
+{
+ /**
+ * @var string
+ */
+ private $classCode;
+
+ /**
+ * @var class-string
+ */
+ private $mockName;
+
+ /**
+ * @psalm-param class-string $mockName
+ */
+ public function __construct(string $classCode, string $mockName)
+ {
+ $this->classCode = $classCode;
+ $this->mockName = $mockName;
+ }
+
+ /**
+ * @psalm-return class-string
+ */
+ public function generate(): string
+ {
+ if (!class_exists($this->mockName, false)) {
+ eval($this->classCode);
+ }
+
+ return $this->mockName;
+ }
+
+ public function getClassCode(): string
+ {
+ return $this->classCode;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/MockType.php b/vendor/phpunit/phpunit/src/Framework/MockObject/MockType.php
new file mode 100644
index 000000000..6a03fb51a
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/MockType.php
@@ -0,0 +1,21 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface MockType
+{
+ /**
+ * @psalm-return class-string
+ */
+ public function generate(): string;
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/AnyInvokedCount.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/AnyInvokedCount.php
new file mode 100644
index 000000000..f93e5686b
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/AnyInvokedCount.php
@@ -0,0 +1,36 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class AnyInvokedCount extends InvocationOrder
+{
+ public function toString(): string
+ {
+ return 'invoked zero or more times';
+ }
+
+ public function verify(): void
+ {
+ }
+
+ public function matches(BaseInvocation $invocation): bool
+ {
+ return true;
+ }
+
+ protected function invokedDo(BaseInvocation $invocation): void
+ {
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/AnyParameters.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/AnyParameters.php
new file mode 100644
index 000000000..61de78878
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/AnyParameters.php
@@ -0,0 +1,31 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class AnyParameters implements ParametersRule
+{
+ public function toString(): string
+ {
+ return 'with any parameters';
+ }
+
+ public function apply(BaseInvocation $invocation): void
+ {
+ }
+
+ public function verify(): void
+ {
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ConsecutiveParameters.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ConsecutiveParameters.php
new file mode 100644
index 000000000..6025c0a16
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ConsecutiveParameters.php
@@ -0,0 +1,130 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 gettype;
+use function is_iterable;
+use function sprintf;
+use PHPUnit\Framework\Constraint\Constraint;
+use PHPUnit\Framework\Constraint\IsEqual;
+use PHPUnit\Framework\ExpectationFailedException;
+use PHPUnit\Framework\InvalidParameterGroupException;
+use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ConsecutiveParameters implements ParametersRule
+{
+ /**
+ * @var array
+ */
+ private $parameterGroups = [];
+
+ /**
+ * @var array
+ */
+ private $invocations = [];
+
+ /**
+ * @throws \PHPUnit\Framework\Exception
+ */
+ public function __construct(array $parameterGroups)
+ {
+ foreach ($parameterGroups as $index => $parameters) {
+ if (!is_iterable($parameters)) {
+ throw new InvalidParameterGroupException(
+ sprintf(
+ 'Parameter group #%d must be an array or Traversable, got %s',
+ $index,
+ gettype($parameters)
+ )
+ );
+ }
+
+ foreach ($parameters as $parameter) {
+ if (!$parameter instanceof Constraint) {
+ $parameter = new IsEqual($parameter);
+ }
+
+ $this->parameterGroups[$index][] = $parameter;
+ }
+ }
+ }
+
+ public function toString(): string
+ {
+ return 'with consecutive parameters';
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public function apply(BaseInvocation $invocation): void
+ {
+ $this->invocations[] = $invocation;
+ $callIndex = count($this->invocations) - 1;
+
+ $this->verifyInvocation($invocation, $callIndex);
+ }
+
+ /**
+ * @throws \PHPUnit\Framework\ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function verify(): void
+ {
+ foreach ($this->invocations as $callIndex => $invocation) {
+ $this->verifyInvocation($invocation, $callIndex);
+ }
+ }
+
+ /**
+ * Verify a single invocation.
+ *
+ * @param int $callIndex
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ private function verifyInvocation(BaseInvocation $invocation, $callIndex): void
+ {
+ if (!isset($this->parameterGroups[$callIndex])) {
+ // no parameter assertion for this call index
+ return;
+ }
+
+ $parameters = $this->parameterGroups[$callIndex];
+
+ if (count($invocation->getParameters()) < count($parameters)) {
+ throw new ExpectationFailedException(
+ sprintf(
+ 'Parameter count for invocation %s is too low.',
+ $invocation->toString()
+ )
+ );
+ }
+
+ foreach ($parameters as $i => $parameter) {
+ $parameter->evaluate(
+ $invocation->getParameters()[$i],
+ sprintf(
+ 'Parameter %s for invocation #%d %s does not match expected ' .
+ 'value.',
+ $i,
+ $callIndex,
+ $invocation->toString()
+ )
+ );
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvocationOrder.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvocationOrder.php
new file mode 100644
index 000000000..90aa49350
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvocationOrder.php
@@ -0,0 +1,47 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\MockObject\Verifiable;
+use PHPUnit\Framework\SelfDescribing;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+abstract class InvocationOrder implements SelfDescribing, Verifiable
+{
+ /**
+ * @var BaseInvocation[]
+ */
+ private $invocations = [];
+
+ public function getInvocationCount(): int
+ {
+ return count($this->invocations);
+ }
+
+ public function hasBeenInvoked(): bool
+ {
+ return count($this->invocations) > 0;
+ }
+
+ final public function invoked(BaseInvocation $invocation)
+ {
+ $this->invocations[] = $invocation;
+
+ return $this->invokedDo($invocation);
+ }
+
+ abstract public function matches(BaseInvocation $invocation): bool;
+
+ abstract protected function invokedDo(BaseInvocation $invocation);
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtIndex.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtIndex.php
new file mode 100644
index 000000000..2a6625e2f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtIndex.php
@@ -0,0 +1,75 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4297
+ * @codeCoverageIgnore
+ */
+final class InvokedAtIndex extends InvocationOrder
+{
+ /**
+ * @var int
+ */
+ private $sequenceIndex;
+
+ /**
+ * @var int
+ */
+ private $currentIndex = -1;
+
+ /**
+ * @param int $sequenceIndex
+ */
+ public function __construct($sequenceIndex)
+ {
+ $this->sequenceIndex = $sequenceIndex;
+ }
+
+ public function toString(): string
+ {
+ return 'invoked at sequence index ' . $this->sequenceIndex;
+ }
+
+ public function matches(BaseInvocation $invocation): bool
+ {
+ $this->currentIndex++;
+
+ return $this->currentIndex == $this->sequenceIndex;
+ }
+
+ /**
+ * 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
+ {
+ if ($this->currentIndex < $this->sequenceIndex) {
+ throw new ExpectationFailedException(
+ sprintf(
+ 'The expected invocation at index %s was never reached.',
+ $this->sequenceIndex
+ )
+ );
+ }
+ }
+
+ protected function invokedDo(BaseInvocation $invocation): void
+ {
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastCount.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastCount.php
new file mode 100644
index 000000000..a84aa6559
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastCount.php
@@ -0,0 +1,64 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class InvokedAtLeastCount extends InvocationOrder
+{
+ /**
+ * @var int
+ */
+ private $requiredInvocations;
+
+ /**
+ * @param int $requiredInvocations
+ */
+ public function __construct($requiredInvocations)
+ {
+ $this->requiredInvocations = $requiredInvocations;
+ }
+
+ public function toString(): string
+ {
+ return 'invoked at least ' . $this->requiredInvocations . ' times';
+ }
+
+ /**
+ * 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->getInvocationCount();
+
+ if ($count < $this->requiredInvocations) {
+ throw new ExpectationFailedException(
+ 'Expected invocation at least ' . $this->requiredInvocations .
+ ' times but it occurred ' . $count . ' time(s).'
+ );
+ }
+ }
+
+ public function matches(BaseInvocation $invocation): bool
+ {
+ return true;
+ }
+
+ protected function invokedDo(BaseInvocation $invocation): void
+ {
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastOnce.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastOnce.php
new file mode 100644
index 000000000..d0ad1f801
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtLeastOnce.php
@@ -0,0 +1,50 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class InvokedAtLeastOnce extends 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->getInvocationCount();
+
+ if ($count < 1) {
+ throw new ExpectationFailedException(
+ 'Expected invocation at least once but it never occurred.'
+ );
+ }
+ }
+
+ public function matches(BaseInvocation $invocation): bool
+ {
+ return true;
+ }
+
+ protected function invokedDo(BaseInvocation $invocation): void
+ {
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtMostCount.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtMostCount.php
new file mode 100644
index 000000000..c3b815aa4
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedAtMostCount.php
@@ -0,0 +1,64 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class InvokedAtMostCount extends InvocationOrder
+{
+ /**
+ * @var int
+ */
+ private $allowedInvocations;
+
+ /**
+ * @param int $allowedInvocations
+ */
+ public function __construct($allowedInvocations)
+ {
+ $this->allowedInvocations = $allowedInvocations;
+ }
+
+ public function toString(): string
+ {
+ return 'invoked at most ' . $this->allowedInvocations . ' times';
+ }
+
+ /**
+ * 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->getInvocationCount();
+
+ if ($count > $this->allowedInvocations) {
+ throw new ExpectationFailedException(
+ 'Expected invocation at most ' . $this->allowedInvocations .
+ ' times but it occurred ' . $count . ' time(s).'
+ );
+ }
+ }
+
+ public function matches(BaseInvocation $invocation): bool
+ {
+ return true;
+ }
+
+ protected function invokedDo(BaseInvocation $invocation): void
+ {
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedCount.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedCount.php
new file mode 100644
index 000000000..188326c91
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/InvokedCount.php
@@ -0,0 +1,102 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class InvokedCount extends InvocationOrder
+{
+ /**
+ * @var int
+ */
+ private $expectedCount;
+
+ /**
+ * @param int $expectedCount
+ */
+ public function __construct($expectedCount)
+ {
+ $this->expectedCount = $expectedCount;
+ }
+
+ public function isNever(): bool
+ {
+ return $this->expectedCount === 0;
+ }
+
+ public function toString(): string
+ {
+ return 'invoked ' . $this->expectedCount . ' time(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
+ {
+ $count = $this->getInvocationCount();
+
+ if ($count !== $this->expectedCount) {
+ throw new ExpectationFailedException(
+ sprintf(
+ 'Method was expected to be called %d times, ' .
+ 'actually called %d times.',
+ $this->expectedCount,
+ $count
+ )
+ );
+ }
+ }
+
+ /**
+ * @throws ExpectationFailedException
+ */
+ protected function invokedDo(BaseInvocation $invocation): void
+ {
+ $count = $this->getInvocationCount();
+
+ if ($count > $this->expectedCount) {
+ $message = $invocation->toString() . ' ';
+
+ switch ($this->expectedCount) {
+ case 0:
+ $message .= 'was not expected to be called.';
+
+ break;
+
+ case 1:
+ $message .= 'was not expected to be called more than once.';
+
+ break;
+
+ default:
+ $message .= sprintf(
+ 'was not expected to be called more than %d times.',
+ $this->expectedCount
+ );
+ }
+
+ throw new ExpectationFailedException($message);
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/MethodName.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/MethodName.php
new file mode 100644
index 000000000..83ba3b8da
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/MethodName.php
@@ -0,0 +1,68 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\InvalidArgumentException;
+use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
+use PHPUnit\Framework\MockObject\MethodNameConstraint;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MethodName
+{
+ /**
+ * @var Constraint
+ */
+ private $constraint;
+
+ /**
+ * @param Constraint|string $constraint
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct($constraint)
+ {
+ if (is_string($constraint)) {
+ $constraint = new MethodNameConstraint($constraint);
+ }
+
+ if (!$constraint instanceof Constraint) {
+ throw InvalidArgumentException::create(1, 'PHPUnit\Framework\Constraint\Constraint object or string');
+ }
+
+ $this->constraint = $constraint;
+ }
+
+ public function toString(): string
+ {
+ return 'method name ' . $this->constraint->toString();
+ }
+
+ /**
+ * @throws \PHPUnit\Framework\ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function matches(BaseInvocation $invocation): bool
+ {
+ return $this->matchesName($invocation->getMethodName());
+ }
+
+ /**
+ * @throws \PHPUnit\Framework\ExpectationFailedException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function matchesName(string $methodName): bool
+ {
+ return (bool) $this->constraint->evaluate($methodName, '', true);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/Parameters.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/Parameters.php
new file mode 100644
index 000000000..3f1cc53ae
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/Parameters.php
@@ -0,0 +1,160 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 get_class;
+use function sprintf;
+use Exception;
+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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Parameters implements ParametersRule
+{
+ /**
+ * @var Constraint[]
+ */
+ private $parameters = [];
+
+ /**
+ * @var BaseInvocation
+ */
+ private $invocation;
+
+ /**
+ * @var bool|ExpectationFailedException
+ */
+ private $parameterVerificationResult;
+
+ /**
+ * @throws \PHPUnit\Framework\Exception
+ */
+ public function __construct(array $parameters)
+ {
+ foreach ($parameters as $parameter) {
+ if (!($parameter instanceof Constraint)) {
+ $parameter = new IsEqual(
+ $parameter
+ );
+ }
+
+ $this->parameters[] = $parameter;
+ }
+ }
+
+ public function toString(): string
+ {
+ $text = 'with parameter';
+
+ foreach ($this->parameters as $index => $parameter) {
+ if ($index > 0) {
+ $text .= ' and';
+ }
+
+ $text .= ' ' . $index . ' ' . $parameter->toString();
+ }
+
+ return $text;
+ }
+
+ /**
+ * @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 \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ public function verify(): void
+ {
+ $this->doVerify();
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws ExpectationFailedException
+ */
+ private function doVerify(): bool
+ {
+ if (isset($this->parameterVerificationResult)) {
+ return $this->guardAgainstDuplicateEvaluationOfParameterConstraints();
+ }
+
+ if ($this->invocation === null) {
+ throw new ExpectationFailedException('Mocked method does not exist.');
+ }
+
+ if (count($this->invocation->getParameters()) < 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 &&
+ get_class($this->parameters[0]) === IsAnything::class) {
+ $message .= "\nTo allow 0 or more parameters with any value, omit ->with() or use ->withAnyParameters() instead.";
+ }
+
+ throw new ExpectationFailedException(
+ sprintf($message, $this->invocation->toString())
+ );
+ }
+
+ foreach ($this->parameters as $i => $parameter) {
+ $parameter->evaluate(
+ $this->invocation->getParameters()[$i],
+ 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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ParametersRule.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ParametersRule.php
new file mode 100644
index 000000000..70c47fe32
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ParametersRule.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+use PHPUnit\Framework\MockObject\Verifiable;
+use PHPUnit\Framework\SelfDescribing;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+interface ParametersRule extends SelfDescribing, Verifiable
+{
+ /**
+ * @throws ExpectationFailedException if the invocation violates the rule
+ */
+ public function apply(BaseInvocation $invocation): void;
+
+ public function verify(): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Stub.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub.php
new file mode 100644
index 000000000..2b032e2dc
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub.php
@@ -0,0 +1,26 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework\MockObject;
+
+use PHPUnit\Framework\MockObject\Builder\InvocationStubber;
+
+/**
+ * @method InvocationStubber method($constraint)
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+interface Stub
+{
+ public function __phpunit_getInvocationHandler(): InvocationHandler;
+
+ public function __phpunit_hasMatchers(): bool;
+
+ public function __phpunit_setReturnValueGeneration(bool $returnValueGeneration): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ConsecutiveCalls.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ConsecutiveCalls.php
new file mode 100644
index 000000000..0dcf386b3
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ConsecutiveCalls.php
@@ -0,0 +1,57 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 sprintf;
+use PHPUnit\Framework\MockObject\Invocation;
+use SebastianBergmann\Exporter\Exporter;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ConsecutiveCalls implements Stub
+{
+ /**
+ * @var array
+ */
+ private $stack;
+
+ /**
+ * @var mixed
+ */
+ private $value;
+
+ public function __construct(array $stack)
+ {
+ $this->stack = $stack;
+ }
+
+ public function invoke(Invocation $invocation)
+ {
+ $this->value = array_shift($this->stack);
+
+ if ($this->value instanceof Stub) {
+ $this->value = $this->value->invoke($invocation);
+ }
+
+ return $this->value;
+ }
+
+ public function toString(): string
+ {
+ $exporter = new Exporter;
+
+ return sprintf(
+ 'return user-specified value %s',
+ $exporter->export($this->value)
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/Exception.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/Exception.php
new file mode 100644
index 000000000..5d64c96a5
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/Exception.php
@@ -0,0 +1,46 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 sprintf;
+use PHPUnit\Framework\MockObject\Invocation;
+use SebastianBergmann\Exporter\Exporter;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Exception implements Stub
+{
+ private $exception;
+
+ public function __construct(Throwable $exception)
+ {
+ $this->exception = $exception;
+ }
+
+ /**
+ * @throws Throwable
+ */
+ public function invoke(Invocation $invocation): void
+ {
+ throw $this->exception;
+ }
+
+ public function toString(): string
+ {
+ $exporter = new Exporter;
+
+ return sprintf(
+ 'raise user-specified exception %s',
+ $exporter->export($this->exception)
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnArgument.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnArgument.php
new file mode 100644
index 000000000..c7b3f8f41
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnArgument.php
@@ -0,0 +1,41 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 sprintf;
+use PHPUnit\Framework\MockObject\Invocation;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ReturnArgument implements Stub
+{
+ /**
+ * @var int
+ */
+ private $argumentIndex;
+
+ public function __construct($argumentIndex)
+ {
+ $this->argumentIndex = $argumentIndex;
+ }
+
+ public function invoke(Invocation $invocation)
+ {
+ if (isset($invocation->getParameters()[$this->argumentIndex])) {
+ return $invocation->getParameters()[$this->argumentIndex];
+ }
+ }
+
+ public function toString(): string
+ {
+ return sprintf('return argument #%d', $this->argumentIndex);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnCallback.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnCallback.php
new file mode 100644
index 000000000..e02181e90
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnCallback.php
@@ -0,0 +1,59 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function get_class;
+use function is_array;
+use function is_object;
+use function sprintf;
+use PHPUnit\Framework\MockObject\Invocation;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ReturnCallback implements Stub
+{
+ private $callback;
+
+ public function __construct($callback)
+ {
+ $this->callback = $callback;
+ }
+
+ public function invoke(Invocation $invocation)
+ {
+ return call_user_func_array($this->callback, $invocation->getParameters());
+ }
+
+ public function toString(): string
+ {
+ if (is_array($this->callback)) {
+ if (is_object($this->callback[0])) {
+ $class = get_class($this->callback[0]);
+ $type = '->';
+ } else {
+ $class = $this->callback[0];
+ $type = '::';
+ }
+
+ return sprintf(
+ 'return result of user defined callback %s%s%s() with the ' .
+ 'passed arguments',
+ $class,
+ $type,
+ $this->callback[1]
+ );
+ }
+
+ return 'return result of user defined callback ' . $this->callback .
+ ' with the passed arguments';
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnReference.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnReference.php
new file mode 100644
index 000000000..0d288cebe
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnReference.php
@@ -0,0 +1,45 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 sprintf;
+use PHPUnit\Framework\MockObject\Invocation;
+use SebastianBergmann\Exporter\Exporter;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ReturnReference implements Stub
+{
+ /**
+ * @var mixed
+ */
+ private $reference;
+
+ public function __construct(&$reference)
+ {
+ $this->reference = &$reference;
+ }
+
+ public function invoke(Invocation $invocation)
+ {
+ return $this->reference;
+ }
+
+ public function toString(): string
+ {
+ $exporter = new Exporter;
+
+ return sprintf(
+ 'return user-specified reference %s',
+ $exporter->export($this->reference)
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnSelf.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnSelf.php
new file mode 100644
index 000000000..6d2137bfb
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnSelf.php
@@ -0,0 +1,32 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ReturnSelf implements Stub
+{
+ /**
+ * @throws RuntimeException
+ */
+ public function invoke(Invocation $invocation)
+ {
+ return $invocation->getObject();
+ }
+
+ public function toString(): string
+ {
+ return 'return the current object';
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnStub.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnStub.php
new file mode 100644
index 000000000..fbcd0a07a
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnStub.php
@@ -0,0 +1,45 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 sprintf;
+use PHPUnit\Framework\MockObject\Invocation;
+use SebastianBergmann\Exporter\Exporter;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ReturnStub implements Stub
+{
+ /**
+ * @var mixed
+ */
+ private $value;
+
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ public function invoke(Invocation $invocation)
+ {
+ return $this->value;
+ }
+
+ public function toString(): string
+ {
+ $exporter = new Exporter;
+
+ return sprintf(
+ 'return user-specified value %s',
+ $exporter->export($this->value)
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnValueMap.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnValueMap.php
new file mode 100644
index 000000000..5fcd3a09a
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/ReturnValueMap.php
@@ -0,0 +1,53 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ReturnValueMap implements Stub
+{
+ /**
+ * @var array
+ */
+ private $valueMap;
+
+ public function __construct(array $valueMap)
+ {
+ $this->valueMap = $valueMap;
+ }
+
+ public function invoke(Invocation $invocation)
+ {
+ $parameterCount = count($invocation->getParameters());
+
+ foreach ($this->valueMap as $map) {
+ if (!is_array($map) || $parameterCount !== (count($map) - 1)) {
+ continue;
+ }
+
+ $return = array_pop($map);
+
+ if ($invocation->getParameters() === $map) {
+ return $return;
+ }
+ }
+ }
+
+ public function toString(): string
+ {
+ return 'return value from a map';
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/Stub.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/Stub.php
new file mode 100644
index 000000000..15cfce5c3
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Stub/Stub.php
@@ -0,0 +1,27 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\SelfDescribing;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface Stub extends SelfDescribing
+{
+ /**
+ * Fakes the processing of the invocation $invocation by returning a
+ * specific value.
+ *
+ * @param Invocation $invocation The invocation which was mocked and matched by the current method and argument matchers
+ */
+ public function invoke(Invocation $invocation);
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/MockObject/Verifiable.php b/vendor/phpunit/phpunit/src/Framework/MockObject/Verifiable.php
new file mode 100644
index 000000000..8c9a82c5a
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/MockObject/Verifiable.php
@@ -0,0 +1,26 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\ExpectationFailedException;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface Verifiable
+{
+ /**
+ * 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;
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Reorderable.php b/vendor/phpunit/phpunit/src/Framework/Reorderable.php
new file mode 100644
index 000000000..34951f8dc
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Reorderable.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface Reorderable
+{
+ public function sortId(): string;
+
+ /**
+ * @return list<ExecutionOrderDependency>
+ */
+ public function provides(): array;
+
+ /**
+ * @return list<ExecutionOrderDependency>
+ */
+ public function requires(): array;
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/SelfDescribing.php b/vendor/phpunit/phpunit/src/Framework/SelfDescribing.php
new file mode 100644
index 000000000..73034f650
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/SelfDescribing.php
@@ -0,0 +1,21 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface SelfDescribing
+{
+ /**
+ * Returns a string representation of the object.
+ */
+ public function toString(): string;
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/SkippedTest.php b/vendor/phpunit/phpunit/src/Framework/SkippedTest.php
new file mode 100644
index 000000000..a12aa402d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/SkippedTest.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface SkippedTest extends Throwable
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/SkippedTestCase.php b/vendor/phpunit/phpunit/src/Framework/SkippedTestCase.php
new file mode 100644
index 000000000..51c00619c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/SkippedTestCase.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class SkippedTestCase extends TestCase
+{
+ /**
+ * @var bool
+ */
+ protected $backupGlobals = false;
+
+ /**
+ * @var bool
+ */
+ protected $backupStaticAttributes = false;
+
+ /**
+ * @var bool
+ */
+ protected $runTestInSeparateProcess = false;
+
+ /**
+ * @var string
+ */
+ private $message;
+
+ public function __construct(string $className, string $methodName, string $message = '')
+ {
+ parent::__construct($className . '::' . $methodName);
+
+ $this->message = $message;
+ }
+
+ public function getMessage(): string
+ {
+ return $this->message;
+ }
+
+ /**
+ * Returns a string representation of the test case.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function toString(): string
+ {
+ return $this->getName();
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected function runTest(): void
+ {
+ $this->markTestSkipped($this->message);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/Test.php b/vendor/phpunit/phpunit/src/Framework/Test.php
new file mode 100644
index 000000000..be0dcd0ef
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/Test.php
@@ -0,0 +1,23 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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
+{
+ /**
+ * Runs a test and collects its result in a TestResult instance.
+ */
+ public function run(TestResult $result = null): TestResult;
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/TestBuilder.php b/vendor/phpunit/phpunit/src/Framework/TestBuilder.php
new file mode 100644
index 000000000..5dd91e219
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/TestBuilder.php
@@ -0,0 +1,239 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 count;
+use function get_class;
+use function sprintf;
+use function trim;
+use PHPUnit\Util\Filter;
+use PHPUnit\Util\InvalidDataSetException;
+use PHPUnit\Util\Test as TestUtil;
+use ReflectionClass;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestBuilder
+{
+ public function build(ReflectionClass $theClass, string $methodName): Test
+ {
+ $className = $theClass->getName();
+
+ if (!$theClass->isInstantiable()) {
+ return new ErrorTestCase(
+ sprintf('Cannot instantiate class "%s".', $className)
+ );
+ }
+
+ $backupSettings = TestUtil::getBackupSettings(
+ $className,
+ $methodName
+ );
+
+ $preserveGlobalState = TestUtil::getPreserveGlobalStateSettings(
+ $className,
+ $methodName
+ );
+
+ $runTestInSeparateProcess = TestUtil::getProcessIsolationSettings(
+ $className,
+ $methodName
+ );
+
+ $runClassInSeparateProcess = TestUtil::getClassProcessIsolationSettings(
+ $className,
+ $methodName
+ );
+
+ $constructor = $theClass->getConstructor();
+
+ if ($constructor === null) {
+ throw new Exception('No valid test provided.');
+ }
+
+ $parameters = $constructor->getParameters();
+
+ // TestCase() or TestCase($name)
+ if (count($parameters) < 2) {
+ $test = $this->buildTestWithoutData($className);
+ } // TestCase($name, $data)
+ else {
+ try {
+ $data = TestUtil::getProvidedData(
+ $className,
+ $methodName
+ );
+ } catch (IncompleteTestError $e) {
+ $message = sprintf(
+ "Test for %s::%s marked incomplete by data provider\n%s",
+ $className,
+ $methodName,
+ $this->throwableToString($e)
+ );
+
+ $data = new IncompleteTestCase($className, $methodName, $message);
+ } catch (SkippedTestError $e) {
+ $message = sprintf(
+ "Test for %s::%s skipped by data provider\n%s",
+ $className,
+ $methodName,
+ $this->throwableToString($e)
+ );
+
+ $data = new SkippedTestCase($className, $methodName, $message);
+ } catch (Throwable $t) {
+ $message = sprintf(
+ "The data provider specified for %s::%s is invalid.\n%s",
+ $className,
+ $methodName,
+ $this->throwableToString($t)
+ );
+
+ $data = new ErrorTestCase($message);
+ }
+
+ // Test method with @dataProvider.
+ if (isset($data)) {
+ $test = $this->buildDataProviderTestSuite(
+ $methodName,
+ $className,
+ $data,
+ $runTestInSeparateProcess,
+ $preserveGlobalState,
+ $runClassInSeparateProcess,
+ $backupSettings
+ );
+ } else {
+ $test = $this->buildTestWithoutData($className);
+ }
+ }
+
+ if ($test instanceof TestCase) {
+ $test->setName($methodName);
+ $this->configureTestCase(
+ $test,
+ $runTestInSeparateProcess,
+ $preserveGlobalState,
+ $runClassInSeparateProcess,
+ $backupSettings
+ );
+ }
+
+ return $test;
+ }
+
+ /** @psalm-param class-string $className */
+ private function buildTestWithoutData(string $className)
+ {
+ return new $className;
+ }
+
+ /** @psalm-param class-string $className */
+ private function buildDataProviderTestSuite(
+ string $methodName,
+ string $className,
+ $data,
+ bool $runTestInSeparateProcess,
+ ?bool $preserveGlobalState,
+ bool $runClassInSeparateProcess,
+ array $backupSettings
+ ): DataProviderTestSuite {
+ $dataProviderTestSuite = new DataProviderTestSuite(
+ $className . '::' . $methodName
+ );
+
+ $groups = TestUtil::getGroups($className, $methodName);
+
+ if ($data instanceof ErrorTestCase ||
+ $data instanceof SkippedTestCase ||
+ $data instanceof IncompleteTestCase) {
+ $dataProviderTestSuite->addTest($data, $groups);
+ } else {
+ foreach ($data as $_dataName => $_data) {
+ $_test = new $className($methodName, $_data, $_dataName);
+
+ assert($_test instanceof TestCase);
+
+ $this->configureTestCase(
+ $_test,
+ $runTestInSeparateProcess,
+ $preserveGlobalState,
+ $runClassInSeparateProcess,
+ $backupSettings
+ );
+
+ $dataProviderTestSuite->addTest($_test, $groups);
+ }
+ }
+
+ return $dataProviderTestSuite;
+ }
+
+ private function configureTestCase(
+ TestCase $test,
+ bool $runTestInSeparateProcess,
+ ?bool $preserveGlobalState,
+ bool $runClassInSeparateProcess,
+ array $backupSettings
+ ): void {
+ if ($runTestInSeparateProcess) {
+ $test->setRunTestInSeparateProcess(true);
+
+ if ($preserveGlobalState !== null) {
+ $test->setPreserveGlobalState($preserveGlobalState);
+ }
+ }
+
+ if ($runClassInSeparateProcess) {
+ $test->setRunClassInSeparateProcess(true);
+
+ if ($preserveGlobalState !== null) {
+ $test->setPreserveGlobalState($preserveGlobalState);
+ }
+ }
+
+ if ($backupSettings['backupGlobals'] !== null) {
+ $test->setBackupGlobals($backupSettings['backupGlobals']);
+ }
+
+ if ($backupSettings['backupStaticAttributes'] !== null) {
+ $test->setBackupStaticAttributes(
+ $backupSettings['backupStaticAttributes']
+ );
+ }
+ }
+
+ private function throwableToString(Throwable $t): string
+ {
+ $message = $t->getMessage();
+
+ if (empty(trim($message))) {
+ $message = '<no message>';
+ }
+
+ if ($t instanceof InvalidDataSetException) {
+ return sprintf(
+ "%s\n%s",
+ $message,
+ Filter::getFilteredStacktrace($t)
+ );
+ }
+
+ return sprintf(
+ "%s: %s\n%s",
+ get_class($t),
+ $message,
+ Filter::getFilteredStacktrace($t)
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/TestCase.php b/vendor/phpunit/phpunit/src/Framework/TestCase.php
new file mode 100644
index 000000000..f90245bd1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/TestCase.php
@@ -0,0 +1,2581 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use const LC_ALL;
+use const LC_COLLATE;
+use const LC_CTYPE;
+use const LC_MONETARY;
+use const LC_NUMERIC;
+use const LC_TIME;
+use const PATHINFO_FILENAME;
+use const PHP_EOL;
+use const PHP_URL_PATH;
+use function array_filter;
+use function array_flip;
+use function array_keys;
+use function array_merge;
+use function array_pop;
+use function array_search;
+use function array_unique;
+use function array_values;
+use function basename;
+use function call_user_func;
+use function chdir;
+use function class_exists;
+use function clearstatcache;
+use function count;
+use function debug_backtrace;
+use function defined;
+use function explode;
+use function get_class;
+use function get_include_path;
+use function getcwd;
+use function implode;
+use function in_array;
+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 libxml_clear_errors;
+use function method_exists;
+use function ob_end_clean;
+use function ob_get_contents;
+use function ob_get_level;
+use function ob_start;
+use function parse_url;
+use function pathinfo;
+use function preg_replace;
+use function serialize;
+use function setlocale;
+use function sprintf;
+use function strpos;
+use function substr;
+use function trim;
+use function var_export;
+use DeepCopy\DeepCopy;
+use PHPUnit\Framework\Constraint\Exception as ExceptionConstraint;
+use PHPUnit\Framework\Constraint\ExceptionCode;
+use PHPUnit\Framework\Constraint\ExceptionMessage;
+use PHPUnit\Framework\Constraint\ExceptionMessageRegularExpression;
+use PHPUnit\Framework\Constraint\LogicalOr;
+use PHPUnit\Framework\Error\Deprecated;
+use PHPUnit\Framework\Error\Error;
+use PHPUnit\Framework\Error\Notice;
+use PHPUnit\Framework\Error\Warning as WarningError;
+use PHPUnit\Framework\MockObject\Generator as MockGenerator;
+use PHPUnit\Framework\MockObject\MockBuilder;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount as AnyInvokedCountMatcher;
+use PHPUnit\Framework\MockObject\Rule\InvokedAtIndex as InvokedAtIndexMatcher;
+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;
+use PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls as ConsecutiveCallsStub;
+use PHPUnit\Framework\MockObject\Stub\Exception as ExceptionStub;
+use PHPUnit\Framework\MockObject\Stub\ReturnArgument as ReturnArgumentStub;
+use PHPUnit\Framework\MockObject\Stub\ReturnCallback as ReturnCallbackStub;
+use PHPUnit\Framework\MockObject\Stub\ReturnSelf as ReturnSelfStub;
+use PHPUnit\Framework\MockObject\Stub\ReturnStub;
+use PHPUnit\Framework\MockObject\Stub\ReturnValueMap as ReturnValueMapStub;
+use PHPUnit\Runner\BaseTestRunner;
+use PHPUnit\Runner\PhptTestCase;
+use PHPUnit\Util\Exception as UtilException;
+use PHPUnit\Util\GlobalState;
+use PHPUnit\Util\PHP\AbstractPhpProcess;
+use PHPUnit\Util\Test as TestUtil;
+use PHPUnit\Util\Type;
+use Prophecy\Exception\Prediction\PredictionException;
+use Prophecy\Prophecy\MethodProphecy;
+use Prophecy\Prophecy\ObjectProphecy;
+use Prophecy\Prophet;
+use ReflectionClass;
+use ReflectionException;
+use SebastianBergmann\Comparator\Comparator;
+use SebastianBergmann\Comparator\Factory as ComparatorFactory;
+use SebastianBergmann\Diff\Differ;
+use SebastianBergmann\Exporter\Exporter;
+use SebastianBergmann\GlobalState\ExcludeList;
+use SebastianBergmann\GlobalState\Restorer;
+use SebastianBergmann\GlobalState\Snapshot;
+use SebastianBergmann\ObjectEnumerator\Enumerator;
+use SebastianBergmann\Template\Template;
+use SoapClient;
+use Throwable;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+abstract class TestCase extends Assert implements Reorderable, SelfDescribing, Test
+{
+ private const LOCALE_CATEGORIES = [LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME];
+
+ /**
+ * @var ?bool
+ */
+ protected $backupGlobals;
+
+ /**
+ * @var string[]
+ */
+ protected $backupGlobalsExcludeList = [];
+
+ /**
+ * @var string[]
+ *
+ * @deprecated Use $backupGlobalsExcludeList instead
+ */
+ protected $backupGlobalsBlacklist = [];
+
+ /**
+ * @var bool
+ */
+ protected $backupStaticAttributes;
+
+ /**
+ * @var array<string,array<int,string>>
+ */
+ protected $backupStaticAttributesExcludeList = [];
+
+ /**
+ * @var array<string,array<int,string>>
+ *
+ * @deprecated Use $backupStaticAttributesExcludeList instead
+ */
+ protected $backupStaticAttributesBlacklist = [];
+
+ /**
+ * @var bool
+ */
+ protected $runTestInSeparateProcess;
+
+ /**
+ * @var bool
+ */
+ protected $preserveGlobalState = true;
+
+ /**
+ * @var list<ExecutionOrderDependency>
+ */
+ protected $providedTests = [];
+
+ /**
+ * @var bool
+ */
+ private $runClassInSeparateProcess;
+
+ /**
+ * @var bool
+ */
+ private $inIsolation = false;
+
+ /**
+ * @var array
+ */
+ private $data;
+
+ /**
+ * @var int|string
+ */
+ private $dataName;
+
+ /**
+ * @var null|string
+ */
+ private $expectedException;
+
+ /**
+ * @var null|string
+ */
+ private $expectedExceptionMessage;
+
+ /**
+ * @var null|string
+ */
+ private $expectedExceptionMessageRegExp;
+
+ /**
+ * @var null|int|string
+ */
+ private $expectedExceptionCode;
+
+ /**
+ * @var string
+ */
+ private $name = '';
+
+ /**
+ * @var list<ExecutionOrderDependency>
+ */
+ private $dependencies = [];
+
+ /**
+ * @var array
+ */
+ private $dependencyInput = [];
+
+ /**
+ * @var array<string,string>
+ */
+ private $iniSettings = [];
+
+ /**
+ * @var array
+ */
+ private $locale = [];
+
+ /**
+ * @var MockObject[]
+ */
+ private $mockObjects = [];
+
+ /**
+ * @var MockGenerator
+ */
+ private $mockObjectGenerator;
+
+ /**
+ * @var int
+ */
+ private $status = BaseTestRunner::STATUS_UNKNOWN;
+
+ /**
+ * @var string
+ */
+ private $statusMessage = '';
+
+ /**
+ * @var int
+ */
+ private $numAssertions = 0;
+
+ /**
+ * @var TestResult
+ */
+ private $result;
+
+ /**
+ * @var mixed
+ */
+ private $testResult;
+
+ /**
+ * @var string
+ */
+ private $output = '';
+
+ /**
+ * @var ?string
+ */
+ private $outputExpectedRegex;
+
+ /**
+ * @var ?string
+ */
+ private $outputExpectedString;
+
+ /**
+ * @var mixed
+ */
+ private $outputCallback = false;
+
+ /**
+ * @var bool
+ */
+ private $outputBufferingActive = false;
+
+ /**
+ * @var int
+ */
+ private $outputBufferingLevel;
+
+ /**
+ * @var bool
+ */
+ private $outputRetrievedForAssertion = false;
+
+ /**
+ * @var ?Snapshot
+ */
+ private $snapshot;
+
+ /**
+ * @var \Prophecy\Prophet
+ */
+ private $prophet;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutChangesToGlobalState = false;
+
+ /**
+ * @var bool
+ */
+ private $registerMockObjectsFromTestArgumentsRecursively = false;
+
+ /**
+ * @var string[]
+ */
+ private $warnings = [];
+
+ /**
+ * @var string[]
+ */
+ private $groups = [];
+
+ /**
+ * @var bool
+ */
+ private $doesNotPerformAssertions = false;
+
+ /**
+ * @var Comparator[]
+ */
+ private $customComparators = [];
+
+ /**
+ * @var string[]
+ */
+ private $doubledTypes = [];
+
+ /**
+ * Returns a matcher that matches when the method is executed
+ * zero or more times.
+ */
+ public static function any(): AnyInvokedCountMatcher
+ {
+ return new AnyInvokedCountMatcher;
+ }
+
+ /**
+ * Returns a matcher that matches when the method is never executed.
+ */
+ public static function never(): InvokedCountMatcher
+ {
+ return new InvokedCountMatcher(0);
+ }
+
+ /**
+ * Returns a matcher that matches when the method is executed
+ * at least N times.
+ */
+ public static function atLeast(int $requiredInvocations): InvokedAtLeastCountMatcher
+ {
+ return new InvokedAtLeastCountMatcher(
+ $requiredInvocations
+ );
+ }
+
+ /**
+ * Returns a matcher that matches when the method is executed at least once.
+ */
+ public static function atLeastOnce(): InvokedAtLeastOnceMatcher
+ {
+ return new InvokedAtLeastOnceMatcher;
+ }
+
+ /**
+ * Returns a matcher that matches when the method is executed exactly once.
+ */
+ public static function once(): InvokedCountMatcher
+ {
+ return new InvokedCountMatcher(1);
+ }
+
+ /**
+ * Returns a matcher that matches when the method is executed
+ * exactly $count times.
+ */
+ public static function exactly(int $count): InvokedCountMatcher
+ {
+ return new InvokedCountMatcher($count);
+ }
+
+ /**
+ * Returns a matcher that matches when the method is executed
+ * at most N times.
+ */
+ public static function atMost(int $allowedInvocations): InvokedAtMostCountMatcher
+ {
+ return new InvokedAtMostCountMatcher($allowedInvocations);
+ }
+
+ /**
+ * Returns a matcher that matches when the method is executed
+ * at the given index.
+ *
+ * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4297
+ * @codeCoverageIgnore
+ */
+ public static function at(int $index): InvokedAtIndexMatcher
+ {
+ $stack = debug_backtrace();
+
+ while (!empty($stack)) {
+ $frame = array_pop($stack);
+
+ if (isset($frame['object']) && $frame['object'] instanceof self) {
+ $frame['object']->addWarning(
+ 'The at() matcher has been deprecated. It will be removed in PHPUnit 10. Please refactor your test to not rely on the order in which methods are invoked.'
+ );
+
+ break;
+ }
+ }
+
+ return new InvokedAtIndexMatcher($index);
+ }
+
+ public static function returnValue($value): ReturnStub
+ {
+ return new ReturnStub($value);
+ }
+
+ public static function returnValueMap(array $valueMap): ReturnValueMapStub
+ {
+ return new ReturnValueMapStub($valueMap);
+ }
+
+ public static function returnArgument(int $argumentIndex): ReturnArgumentStub
+ {
+ return new ReturnArgumentStub($argumentIndex);
+ }
+
+ public static function returnCallback($callback): ReturnCallbackStub
+ {
+ return new ReturnCallbackStub($callback);
+ }
+
+ /**
+ * Returns the current object.
+ *
+ * This method is useful when mocking a fluent interface.
+ */
+ public static function returnSelf(): ReturnSelfStub
+ {
+ return new ReturnSelfStub;
+ }
+
+ public static function throwException(Throwable $exception): ExceptionStub
+ {
+ return new ExceptionStub($exception);
+ }
+
+ public static function onConsecutiveCalls(...$args): ConsecutiveCallsStub
+ {
+ return new ConsecutiveCallsStub($args);
+ }
+
+ /**
+ * @param int|string $dataName
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function __construct(?string $name = null, array $data = [], $dataName = '')
+ {
+ if ($name !== null) {
+ $this->setName($name);
+ }
+
+ $this->data = $data;
+ $this->dataName = $dataName;
+ }
+
+ /**
+ * This method is called before the first test of this test class is run.
+ */
+ public static function setUpBeforeClass(): void
+ {
+ }
+
+ /**
+ * This method is called after the last test of this test class is run.
+ */
+ public static function tearDownAfterClass(): void
+ {
+ }
+
+ /**
+ * This method is called before each test.
+ */
+ protected function setUp(): void
+ {
+ }
+
+ /**
+ * Performs assertions shared by all tests of a test case.
+ *
+ * This method is called between setUp() and test.
+ */
+ protected function assertPreConditions(): void
+ {
+ }
+
+ /**
+ * Performs assertions shared by all tests of a test case.
+ *
+ * This method is called between test and tearDown().
+ */
+ protected function assertPostConditions(): void
+ {
+ }
+
+ /**
+ * This method is called after each test.
+ */
+ protected function tearDown(): void
+ {
+ }
+
+ /**
+ * Returns a string representation of the test case.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ */
+ public function toString(): string
+ {
+ try {
+ $class = new ReflectionClass($this);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $buffer = sprintf(
+ '%s::%s',
+ $class->name,
+ $this->getName(false)
+ );
+
+ return $buffer . $this->getDataSetAsString();
+ }
+
+ public function count(): int
+ {
+ return 1;
+ }
+
+ public function getActualOutputForAssertion(): string
+ {
+ $this->outputRetrievedForAssertion = true;
+
+ return $this->getActualOutput();
+ }
+
+ public function expectOutputRegex(string $expectedRegex): void
+ {
+ $this->outputExpectedRegex = $expectedRegex;
+ }
+
+ public function expectOutputString(string $expectedString): void
+ {
+ $this->outputExpectedString = $expectedString;
+ }
+
+ /**
+ * @psalm-param class-string<\Throwable> $exception
+ */
+ public function expectException(string $exception): void
+ {
+ // @codeCoverageIgnoreStart
+ switch ($exception) {
+ case Deprecated::class:
+ $this->addWarning('Support for using expectException() with PHPUnit\Framework\Error\Deprecated is deprecated and will be removed in PHPUnit 10. Use expectDeprecation() instead.');
+
+ break;
+
+ case Error::class:
+ $this->addWarning('Support for using expectException() with PHPUnit\Framework\Error\Error is deprecated and will be removed in PHPUnit 10. Use expectError() instead.');
+
+ break;
+
+ case Notice::class:
+ $this->addWarning('Support for using expectException() with PHPUnit\Framework\Error\Notice is deprecated and will be removed in PHPUnit 10. Use expectNotice() instead.');
+
+ break;
+
+ case WarningError::class:
+ $this->addWarning('Support for using expectException() with PHPUnit\Framework\Error\Warning is deprecated and will be removed in PHPUnit 10. Use expectWarning() instead.');
+
+ break;
+ }
+ // @codeCoverageIgnoreEnd
+
+ $this->expectedException = $exception;
+ }
+
+ /**
+ * @param int|string $code
+ */
+ public function expectExceptionCode($code): void
+ {
+ $this->expectedExceptionCode = $code;
+ }
+
+ public function expectExceptionMessage(string $message): void
+ {
+ $this->expectedExceptionMessage = $message;
+ }
+
+ public 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.
+ */
+ public function expectExceptionObject(\Exception $exception): void
+ {
+ $this->expectException(get_class($exception));
+ $this->expectExceptionMessage($exception->getMessage());
+ $this->expectExceptionCode($exception->getCode());
+ }
+
+ public function expectNotToPerformAssertions(): void
+ {
+ $this->doesNotPerformAssertions = true;
+ }
+
+ public function expectDeprecation(): void
+ {
+ $this->expectedException = Deprecated::class;
+ }
+
+ public function expectDeprecationMessage(string $message): void
+ {
+ $this->expectExceptionMessage($message);
+ }
+
+ public function expectDeprecationMessageMatches(string $regularExpression): void
+ {
+ $this->expectExceptionMessageMatches($regularExpression);
+ }
+
+ public function expectNotice(): void
+ {
+ $this->expectedException = Notice::class;
+ }
+
+ public function expectNoticeMessage(string $message): void
+ {
+ $this->expectExceptionMessage($message);
+ }
+
+ public function expectNoticeMessageMatches(string $regularExpression): void
+ {
+ $this->expectExceptionMessageMatches($regularExpression);
+ }
+
+ public function expectWarning(): void
+ {
+ $this->expectedException = WarningError::class;
+ }
+
+ public function expectWarningMessage(string $message): void
+ {
+ $this->expectExceptionMessage($message);
+ }
+
+ public function expectWarningMessageMatches(string $regularExpression): void
+ {
+ $this->expectExceptionMessageMatches($regularExpression);
+ }
+
+ public function expectError(): void
+ {
+ $this->expectedException = Error::class;
+ }
+
+ public function expectErrorMessage(string $message): void
+ {
+ $this->expectExceptionMessage($message);
+ }
+
+ public function expectErrorMessageMatches(string $regularExpression): void
+ {
+ $this->expectExceptionMessageMatches($regularExpression);
+ }
+
+ public function getStatus(): int
+ {
+ return $this->status;
+ }
+
+ public function markAsRisky(): void
+ {
+ $this->status = BaseTestRunner::STATUS_RISKY;
+ }
+
+ public function getStatusMessage(): string
+ {
+ return $this->statusMessage;
+ }
+
+ public function hasFailed(): bool
+ {
+ $status = $this->getStatus();
+
+ return $status === BaseTestRunner::STATUS_FAILURE || $status === BaseTestRunner::STATUS_ERROR;
+ }
+
+ /**
+ * Runs the test case and collects the results in a TestResult object.
+ * If no TestResult object is passed a new one will be created.
+ *
+ * @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
+ * @throws \SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws CodeCoverageException
+ * @throws UtilException
+ */
+ public function run(TestResult $result = null): TestResult
+ {
+ if ($result === null) {
+ $result = $this->createResult();
+ }
+
+ if (!$this instanceof ErrorTestCase && !$this instanceof WarningTestCase) {
+ $this->setTestResultObject($result);
+ }
+
+ if (!$this instanceof ErrorTestCase &&
+ !$this instanceof WarningTestCase &&
+ !$this instanceof SkippedTestCase &&
+ !$this->handleDependencies()) {
+ return $result;
+ }
+
+ if ($this->runInSeparateProcess()) {
+ $runEntireClass = $this->runClassInSeparateProcess && !$this->runTestInSeparateProcess;
+
+ try {
+ $class = new ReflectionClass($this);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if ($runEntireClass) {
+ $template = new Template(
+ __DIR__ . '/../Util/PHP/Template/TestCaseClass.tpl'
+ );
+ } else {
+ $template = new Template(
+ __DIR__ . '/../Util/PHP/Template/TestCaseMethod.tpl'
+ );
+ }
+
+ if ($this->preserveGlobalState) {
+ $constants = GlobalState::getConstantsAsString();
+ $globals = GlobalState::getGlobalsAsString();
+ $includedFiles = GlobalState::getIncludedFilesAsString();
+ $iniSettings = GlobalState::getIniSettingsAsString();
+ } else {
+ $constants = '';
+
+ if (!empty($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
+ $globals = '$GLOBALS[\'__PHPUNIT_BOOTSTRAP\'] = ' . var_export($GLOBALS['__PHPUNIT_BOOTSTRAP'], true) . ";\n";
+ } else {
+ $globals = '';
+ }
+
+ $includedFiles = '';
+ $iniSettings = '';
+ }
+
+ $coverage = $result->getCollectCodeCoverageInformation() ? 'true' : 'false';
+ $isStrictAboutTestsThatDoNotTestAnything = $result->isStrictAboutTestsThatDoNotTestAnything() ? 'true' : 'false';
+ $isStrictAboutOutputDuringTests = $result->isStrictAboutOutputDuringTests() ? 'true' : 'false';
+ $enforcesTimeLimit = $result->enforcesTimeLimit() ? 'true' : 'false';
+ $isStrictAboutTodoAnnotatedTests = $result->isStrictAboutTodoAnnotatedTests() ? 'true' : 'false';
+ $isStrictAboutResourceUsageDuringSmallTests = $result->isStrictAboutResourceUsageDuringSmallTests() ? '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 = '\'\'';
+ }
+
+ $codeCoverage = $result->getCodeCoverage();
+ $codeCoverageFilter = null;
+ $cachesStaticAnalysis = 'false';
+ $codeCoverageCacheDirectory = null;
+ $driverMethod = 'forLineCoverage';
+
+ if ($codeCoverage) {
+ $codeCoverageFilter = $codeCoverage->filter();
+
+ if ($codeCoverage->collectsBranchAndPathCoverage()) {
+ $driverMethod = 'forLineAndPathCoverage';
+ }
+
+ if ($codeCoverage->cachesStaticAnalysis()) {
+ $cachesStaticAnalysis = 'true';
+ $codeCoverageCacheDirectory = $codeCoverage->cacheDirectory();
+ }
+ }
+
+ $data = var_export(serialize($this->data), true);
+ $dataName = var_export($this->dataName, true);
+ $dependencyInput = var_export(serialize($this->dependencyInput), true);
+ $includePath = var_export(get_include_path(), true);
+ $codeCoverageFilter = var_export(serialize($codeCoverageFilter), true);
+ $codeCoverageCacheDirectory = var_export(serialize($codeCoverageCacheDirectory), 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 . ".'";
+ $codeCoverageFilter = "'." . $codeCoverageFilter . ".'";
+ $codeCoverageCacheDirectory = "'." . $codeCoverageCacheDirectory . ".'";
+
+ $configurationFilePath = $GLOBALS['__PHPUNIT_CONFIGURATION_FILE'] ?? '';
+
+ $var = [
+ 'composerAutoload' => $composerAutoload,
+ 'phar' => $phar,
+ 'filename' => $class->getFileName(),
+ 'className' => $class->getName(),
+ 'collectCodeCoverageInformation' => $coverage,
+ 'cachesStaticAnalysis' => $cachesStaticAnalysis,
+ 'codeCoverageCacheDirectory' => $codeCoverageCacheDirectory,
+ 'driverMethod' => $driverMethod,
+ 'data' => $data,
+ 'dataName' => $dataName,
+ 'dependencyInput' => $dependencyInput,
+ 'constants' => $constants,
+ 'globals' => $globals,
+ 'include_path' => $includePath,
+ 'included_files' => $includedFiles,
+ 'iniSettings' => $iniSettings,
+ 'isStrictAboutTestsThatDoNotTestAnything' => $isStrictAboutTestsThatDoNotTestAnything,
+ 'isStrictAboutOutputDuringTests' => $isStrictAboutOutputDuringTests,
+ 'enforcesTimeLimit' => $enforcesTimeLimit,
+ 'isStrictAboutTodoAnnotatedTests' => $isStrictAboutTodoAnnotatedTests,
+ 'isStrictAboutResourceUsageDuringSmallTests' => $isStrictAboutResourceUsageDuringSmallTests,
+ 'codeCoverageFilter' => $codeCoverageFilter,
+ 'configurationFilePath' => $configurationFilePath,
+ 'name' => $this->getName(false),
+ ];
+
+ if (!$runEntireClass) {
+ $var['methodName'] = $this->name;
+ }
+
+ $template->setVar($var);
+
+ $php = AbstractPhpProcess::factory();
+ $php->runTestJob($template->render(), $this, $result);
+ } else {
+ $result->run($this);
+ }
+
+ $this->result = null;
+
+ return $result;
+ }
+
+ /**
+ * Returns a builder object to create mock objects using a fluent interface.
+ *
+ * @psalm-template RealInstanceType of object
+ * @psalm-param class-string<RealInstanceType> $className
+ * @psalm-return MockBuilder<RealInstanceType>
+ */
+ public function getMockBuilder(string $className): MockBuilder
+ {
+ $this->recordDoubledType($className);
+
+ return new MockBuilder($this, $className);
+ }
+
+ public function registerComparator(Comparator $comparator): void
+ {
+ ComparatorFactory::getInstance()->register($comparator);
+
+ $this->customComparators[] = $comparator;
+ }
+
+ /**
+ * @return string[]
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function doubledTypes(): array
+ {
+ return array_unique($this->doubledTypes);
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getGroups(): array
+ {
+ return $this->groups;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setGroups(array $groups): void
+ {
+ $this->groups = $groups;
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getName(bool $withDataSet = true): string
+ {
+ if ($withDataSet) {
+ return $this->name . $this->getDataSetAsString(false);
+ }
+
+ return $this->name;
+ }
+
+ /**
+ * Returns the size of the test.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getSize(): int
+ {
+ return TestUtil::getSize(
+ static::class,
+ $this->getName(false)
+ );
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function hasSize(): bool
+ {
+ return $this->getSize() !== TestUtil::UNKNOWN;
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function isSmall(): bool
+ {
+ return $this->getSize() === TestUtil::SMALL;
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function isMedium(): bool
+ {
+ return $this->getSize() === TestUtil::MEDIUM;
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function isLarge(): bool
+ {
+ return $this->getSize() === TestUtil::LARGE;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getActualOutput(): 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
+ */
+ public function hasOutput(): bool
+ {
+ if ($this->output === '') {
+ return false;
+ }
+
+ if ($this->hasExpectationOnOutput()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function doesNotPerformAssertions(): bool
+ {
+ return $this->doesNotPerformAssertions;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function hasExpectationOnOutput(): bool
+ {
+ return is_string($this->outputExpectedString) || is_string($this->outputExpectedRegex) || $this->outputRetrievedForAssertion;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getExpectedException(): ?string
+ {
+ return $this->expectedException;
+ }
+
+ /**
+ * @return null|int|string
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getExpectedExceptionCode()
+ {
+ return $this->expectedExceptionCode;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getExpectedExceptionMessage(): ?string
+ {
+ return $this->expectedExceptionMessage;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getExpectedExceptionMessageRegExp(): ?string
+ {
+ return $this->expectedExceptionMessageRegExp;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setRegisterMockObjectsFromTestArgumentsRecursively(bool $flag): void
+ {
+ $this->registerMockObjectsFromTestArgumentsRecursively = $flag;
+ }
+
+ /**
+ * @throws Throwable
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function runBare(): void
+ {
+ $this->numAssertions = 0;
+
+ $this->snapshotGlobalState();
+ $this->startOutputBuffering();
+ clearstatcache();
+ $currentWorkingDirectory = getcwd();
+
+ $hookMethods = TestUtil::getHookMethods(static::class);
+
+ $hasMetRequirements = false;
+
+ try {
+ $this->checkRequirements();
+ $hasMetRequirements = true;
+
+ if ($this->inIsolation) {
+ foreach ($hookMethods['beforeClass'] as $method) {
+ $this->{$method}();
+ }
+ }
+
+ $this->setDoesNotPerformAssertionsFromAnnotation();
+
+ foreach ($hookMethods['before'] as $method) {
+ $this->{$method}();
+ }
+
+ foreach ($hookMethods['preCondition'] as $method) {
+ $this->{$method}();
+ }
+
+ $this->testResult = $this->runTest();
+ $this->verifyMockObjects();
+
+ foreach ($hookMethods['postCondition'] as $method) {
+ $this->{$method}();
+ }
+
+ if (!empty($this->warnings)) {
+ throw new Warning(
+ implode(
+ "\n",
+ array_unique($this->warnings)
+ )
+ );
+ }
+
+ $this->status = BaseTestRunner::STATUS_PASSED;
+ } catch (IncompleteTest $e) {
+ $this->status = BaseTestRunner::STATUS_INCOMPLETE;
+ $this->statusMessage = $e->getMessage();
+ } catch (SkippedTest $e) {
+ $this->status = BaseTestRunner::STATUS_SKIPPED;
+ $this->statusMessage = $e->getMessage();
+ } catch (Warning $e) {
+ $this->status = BaseTestRunner::STATUS_WARNING;
+ $this->statusMessage = $e->getMessage();
+ } catch (AssertionFailedError $e) {
+ $this->status = BaseTestRunner::STATUS_FAILURE;
+ $this->statusMessage = $e->getMessage();
+ } catch (PredictionException $e) {
+ $this->status = BaseTestRunner::STATUS_FAILURE;
+ $this->statusMessage = $e->getMessage();
+ } catch (Throwable $_e) {
+ $e = $_e;
+ $this->status = BaseTestRunner::STATUS_ERROR;
+ $this->statusMessage = $_e->getMessage();
+ }
+
+ $this->mockObjects = [];
+ $this->prophet = null;
+
+ // Tear down the fixture. An exception raised in tearDown() will be
+ // caught and passed on when no exception was raised before.
+ try {
+ if ($hasMetRequirements) {
+ foreach ($hookMethods['after'] as $method) {
+ $this->{$method}();
+ }
+
+ if ($this->inIsolation) {
+ foreach ($hookMethods['afterClass'] as $method) {
+ $this->{$method}();
+ }
+ }
+ }
+ } catch (Throwable $_e) {
+ $e = $e ?? $_e;
+ }
+
+ try {
+ $this->stopOutputBuffering();
+ } catch (RiskyTestError $_e) {
+ $e = $e ?? $_e;
+ }
+
+ if (isset($_e)) {
+ $this->status = BaseTestRunner::STATUS_ERROR;
+ $this->statusMessage = $_e->getMessage();
+ }
+
+ clearstatcache();
+
+ if ($currentWorkingDirectory !== getcwd()) {
+ chdir($currentWorkingDirectory);
+ }
+
+ $this->restoreGlobalState();
+ $this->unregisterCustomComparators();
+ $this->cleanupIniSettings();
+ $this->cleanupLocaleSettings();
+ libxml_clear_errors();
+
+ // Perform assertion on output.
+ if (!isset($e)) {
+ try {
+ if ($this->outputExpectedRegex !== null) {
+ $this->assertMatchesRegularExpression($this->outputExpectedRegex, $this->output);
+ } elseif ($this->outputExpectedString !== null) {
+ $this->assertEquals($this->outputExpectedString, $this->output);
+ }
+ } catch (Throwable $_e) {
+ $e = $_e;
+ }
+ }
+
+ // Workaround for missing "finally".
+ if (isset($e)) {
+ if ($e instanceof PredictionException) {
+ $e = new AssertionFailedError($e->getMessage());
+ }
+
+ $this->onNotSuccessfulTest($e);
+ }
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setName(string $name): void
+ {
+ $this->name = $name;
+
+ if (is_callable($this->sortId(), true)) {
+ $this->providedTests = [new ExecutionOrderDependency($this->sortId())];
+ }
+ }
+
+ /**
+ * @param list<ExecutionOrderDependency> $dependencies
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setDependencies(array $dependencies): void
+ {
+ $this->dependencies = $dependencies;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setDependencyInput(array $dependencyInput): void
+ {
+ $this->dependencyInput = $dependencyInput;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setBeStrictAboutChangesToGlobalState(?bool $beStrictAboutChangesToGlobalState): void
+ {
+ $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setBackupGlobals(?bool $backupGlobals): void
+ {
+ if ($this->backupGlobals === null && $backupGlobals !== null) {
+ $this->backupGlobals = $backupGlobals;
+ }
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setBackupStaticAttributes(?bool $backupStaticAttributes): void
+ {
+ if ($this->backupStaticAttributes === null && $backupStaticAttributes !== null) {
+ $this->backupStaticAttributes = $backupStaticAttributes;
+ }
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ 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
+ */
+ public function setRunClassInSeparateProcess(bool $runClassInSeparateProcess): void
+ {
+ if ($this->runClassInSeparateProcess === null) {
+ $this->runClassInSeparateProcess = $runClassInSeparateProcess;
+ }
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setPreserveGlobalState(bool $preserveGlobalState): void
+ {
+ $this->preserveGlobalState = $preserveGlobalState;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setInIsolation(bool $inIsolation): void
+ {
+ $this->inIsolation = $inIsolation;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function isInIsolation(): bool
+ {
+ return $this->inIsolation;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getResult()
+ {
+ return $this->testResult;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setResult($result): void
+ {
+ $this->testResult = $result;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setOutputCallback(callable $callback): void
+ {
+ $this->outputCallback = $callback;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getTestResultObject(): ?TestResult
+ {
+ return $this->result;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function setTestResultObject(TestResult $result): void
+ {
+ $this->result = $result;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function registerMockObject(MockObject $mockObject): void
+ {
+ $this->mockObjects[] = $mockObject;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function addToAssertionCount(int $count): void
+ {
+ $this->numAssertions += $count;
+ }
+
+ /**
+ * Returns the number of assertions performed by this test.
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getNumAssertions(): int
+ {
+ return $this->numAssertions;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function usesDataProvider(): bool
+ {
+ return !empty($this->data);
+ }
+
+ /**
+ * @return int|string
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function dataName()
+ {
+ return $this->dataName;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getDataSetAsString(bool $includeData = true): string
+ {
+ $buffer = '';
+
+ if (!empty($this->data)) {
+ if (is_int($this->dataName)) {
+ $buffer .= sprintf(' with data set #%d', $this->dataName);
+ } else {
+ $buffer .= sprintf(' with data set "%s"', $this->dataName);
+ }
+
+ if ($includeData) {
+ $exporter = new Exporter;
+
+ $buffer .= sprintf(' (%s)', $exporter->shortenedRecursiveExport($this->data));
+ }
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Gets the data set of a TestCase.
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function getProvidedData(): array
+ {
+ return $this->data;
+ }
+
+ /**
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ public function addWarning(string $warning): void
+ {
+ $this->warnings[] = $warning;
+ }
+
+ public function sortId(): string
+ {
+ $id = $this->name;
+
+ if (strpos($id, '::') === false) {
+ $id = static::class . '::' . $id;
+ }
+
+ if ($this->usesDataProvider()) {
+ $id .= $this->getDataSetAsString(false);
+ }
+
+ return $id;
+ }
+
+ /**
+ * Returns the normalized test name as class::method.
+ *
+ * @return list<ExecutionOrderDependency>
+ */
+ public function provides(): array
+ {
+ return $this->providedTests;
+ }
+
+ /**
+ * Returns a list of normalized dependency names, class::method.
+ *
+ * This list can differ from the raw dependencies as the resolver has
+ * no need for the [!][shallow]clone prefix that is filtered out
+ * during normalization.
+ *
+ * @return list<ExecutionOrderDependency>
+ */
+ public function requires(): array
+ {
+ return $this->dependencies;
+ }
+
+ /**
+ * Override to run the test and assert its state.
+ *
+ * @throws \SebastianBergmann\ObjectEnumerator\InvalidArgumentException
+ * @throws AssertionFailedError
+ * @throws Exception
+ * @throws ExpectationFailedException
+ * @throws Throwable
+ */
+ protected function runTest()
+ {
+ if (trim($this->name) === '') {
+ throw new Exception(
+ 'PHPUnit\Framework\TestCase::$name must be a non-blank string.'
+ );
+ }
+
+ $testArguments = array_merge($this->data, $this->dependencyInput);
+
+ $this->registerMockObjectsFromTestArguments($testArguments);
+
+ try {
+ $testResult = $this->{$this->name}(...array_values($testArguments));
+ } catch (Throwable $exception) {
+ if (!$this->checkExceptionExpectations($exception)) {
+ throw $exception;
+ }
+
+ if ($this->expectedException !== null) {
+ if ($this->expectedException === Error::class) {
+ $this->assertThat(
+ $exception,
+ LogicalOr::fromConstraints(
+ new ExceptionConstraint(Error::class),
+ new ExceptionConstraint(\Error::class)
+ )
+ );
+ } else {
+ $this->assertThat(
+ $exception,
+ new ExceptionConstraint(
+ $this->expectedException
+ )
+ );
+ }
+ }
+
+ if ($this->expectedExceptionMessage !== null) {
+ $this->assertThat(
+ $exception,
+ new ExceptionMessage(
+ $this->expectedExceptionMessage
+ )
+ );
+ }
+
+ if ($this->expectedExceptionMessageRegExp !== null) {
+ $this->assertThat(
+ $exception,
+ new ExceptionMessageRegularExpression(
+ $this->expectedExceptionMessageRegExp
+ )
+ );
+ }
+
+ if ($this->expectedExceptionCode !== null) {
+ $this->assertThat(
+ $exception,
+ new ExceptionCode(
+ $this->expectedExceptionCode
+ )
+ );
+ }
+
+ return;
+ }
+
+ if ($this->expectedException !== null) {
+ $this->assertThat(
+ null,
+ new ExceptionConstraint(
+ $this->expectedException
+ )
+ );
+ } elseif ($this->expectedExceptionMessage !== null) {
+ $this->numAssertions++;
+
+ throw new AssertionFailedError(
+ sprintf(
+ 'Failed asserting that exception with message "%s" is thrown',
+ $this->expectedExceptionMessage
+ )
+ );
+ } elseif ($this->expectedExceptionMessageRegExp !== null) {
+ $this->numAssertions++;
+
+ throw new AssertionFailedError(
+ sprintf(
+ 'Failed asserting that exception with message matching "%s" is thrown',
+ $this->expectedExceptionMessageRegExp
+ )
+ );
+ } elseif ($this->expectedExceptionCode !== null) {
+ $this->numAssertions++;
+
+ throw new AssertionFailedError(
+ sprintf(
+ 'Failed asserting that exception with code "%s" is thrown',
+ $this->expectedExceptionCode
+ )
+ );
+ }
+
+ return $testResult;
+ }
+
+ /**
+ * This method is a wrapper for the ini_set() function that automatically
+ * resets the modified php.ini setting to its original value after the
+ * test is run.
+ *
+ * @throws Exception
+ */
+ protected function iniSet(string $varName, string $newValue): void
+ {
+ $currentValue = ini_set($varName, $newValue);
+
+ if ($currentValue !== false) {
+ $this->iniSettings[$varName] = $currentValue;
+ } else {
+ throw new Exception(
+ sprintf(
+ 'INI setting "%s" could not be set to "%s".',
+ $varName,
+ $newValue
+ )
+ );
+ }
+ }
+
+ /**
+ * This method is a wrapper for the setlocale() function that automatically
+ * resets the locale to its original value after the test is run.
+ *
+ * @throws Exception
+ */
+ protected function setLocale(...$args): void
+ {
+ if (count($args) < 2) {
+ throw new Exception;
+ }
+
+ [$category, $locale] = $args;
+
+ if (!in_array($category, self::LOCALE_CATEGORIES, true)) {
+ throw new Exception;
+ }
+
+ if (!is_array($locale) && !is_string($locale)) {
+ throw new Exception;
+ }
+
+ $this->locale[$category] = setlocale($category, 0);
+
+ $result = setlocale(...$args);
+
+ if ($result === false) {
+ throw new Exception(
+ 'The locale functionality is not implemented on your platform, ' .
+ 'the specified locale does not exist or the category name is ' .
+ 'invalid.'
+ );
+ }
+ }
+
+ /**
+ * Makes configurable stub for the specified class.
+ *
+ * @psalm-template RealInstanceType of object
+ * @psalm-param class-string<RealInstanceType> $originalClassName
+ * @psalm-return Stub&RealInstanceType
+ */
+ protected function createStub(string $originalClassName): Stub
+ {
+ return $this->createMockObject($originalClassName);
+ }
+
+ /**
+ * Returns a mock object for the specified class.
+ *
+ * @psalm-template RealInstanceType of object
+ * @psalm-param class-string<RealInstanceType> $originalClassName
+ * @psalm-return MockObject&RealInstanceType
+ */
+ protected function createMock(string $originalClassName): MockObject
+ {
+ return $this->createMockObject($originalClassName);
+ }
+
+ /**
+ * Returns a configured mock object for the specified class.
+ *
+ * @psalm-template RealInstanceType of object
+ * @psalm-param class-string<RealInstanceType> $originalClassName
+ * @psalm-return MockObject&RealInstanceType
+ */
+ protected function createConfiguredMock(string $originalClassName, array $configuration): MockObject
+ {
+ $o = $this->createMockObject($originalClassName);
+
+ foreach ($configuration as $method => $return) {
+ $o->method($method)->willReturn($return);
+ }
+
+ return $o;
+ }
+
+ /**
+ * Returns a partial mock object for the specified class.
+ *
+ * @param string[] $methods
+ *
+ * @psalm-template RealInstanceType of object
+ * @psalm-param class-string<RealInstanceType> $originalClassName
+ * @psalm-return MockObject&RealInstanceType
+ */
+ protected function createPartialMock(string $originalClassName, array $methods): MockObject
+ {
+ try {
+ $reflector = new ReflectionClass($originalClassName);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $mockedMethodsThatDontExist = array_filter(
+ $methods,
+ static function (string $method) use ($reflector)
+ {
+ return !$reflector->hasMethod($method);
+ }
+ );
+
+ if ($mockedMethodsThatDontExist) {
+ $this->addWarning(
+ sprintf(
+ 'createPartialMock() called with method(s) %s that do not exist in %s. This will not be allowed in future versions of PHPUnit.',
+ implode(', ', $mockedMethodsThatDontExist),
+ $originalClassName
+ )
+ );
+ }
+
+ return $this->getMockBuilder($originalClassName)
+ ->disableOriginalConstructor()
+ ->disableOriginalClone()
+ ->disableArgumentCloning()
+ ->disallowMockingUnknownTypes()
+ ->setMethods(empty($methods) ? null : $methods)
+ ->getMock();
+ }
+
+ /**
+ * Returns a test proxy for the specified class.
+ *
+ * @psalm-template RealInstanceType of object
+ * @psalm-param class-string<RealInstanceType> $originalClassName
+ * @psalm-return MockObject&RealInstanceType
+ */
+ protected function createTestProxy(string $originalClassName, array $constructorArguments = []): MockObject
+ {
+ return $this->getMockBuilder($originalClassName)
+ ->setConstructorArgs($constructorArguments)
+ ->enableProxyingToOriginalMethods()
+ ->getMock();
+ }
+
+ /**
+ * Mocks the specified class and returns the name of the mocked class.
+ *
+ * @param null|array $methods $methods
+ *
+ * @psalm-template RealInstanceType of object
+ * @psalm-param class-string<RealInstanceType>|string $originalClassName
+ * @psalm-return class-string<MockObject&RealInstanceType>
+ */
+ protected function getMockClass(string $originalClassName, $methods = [], array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = false, bool $callOriginalClone = true, bool $callAutoload = true, bool $cloneArguments = false): string
+ {
+ $this->recordDoubledType($originalClassName);
+
+ $mock = $this->getMockObjectGenerator()->getMock(
+ $originalClassName,
+ $methods,
+ $arguments,
+ $mockClassName,
+ $callOriginalConstructor,
+ $callOriginalClone,
+ $callAutoload,
+ $cloneArguments
+ );
+
+ return get_class($mock);
+ }
+
+ /**
+ * Returns a mock object for the specified abstract class with all abstract
+ * methods of the class mocked. Concrete methods are not mocked by default.
+ * To mock concrete methods, use the 7th parameter ($mockedMethods).
+ *
+ * @psalm-template RealInstanceType of object
+ * @psalm-param class-string<RealInstanceType> $originalClassName
+ * @psalm-return MockObject&RealInstanceType
+ */
+ protected function getMockForAbstractClass(string $originalClassName, array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, array $mockedMethods = [], bool $cloneArguments = false): MockObject
+ {
+ $this->recordDoubledType($originalClassName);
+
+ $mockObject = $this->getMockObjectGenerator()->getMockForAbstractClass(
+ $originalClassName,
+ $arguments,
+ $mockClassName,
+ $callOriginalConstructor,
+ $callOriginalClone,
+ $callAutoload,
+ $mockedMethods,
+ $cloneArguments
+ );
+
+ $this->registerMockObject($mockObject);
+
+ return $mockObject;
+ }
+
+ /**
+ * Returns a mock object based on the given WSDL file.
+ *
+ * @psalm-template RealInstanceType of object
+ * @psalm-param class-string<RealInstanceType>|string $originalClassName
+ * @psalm-return MockObject&RealInstanceType
+ */
+ protected function getMockFromWsdl(string $wsdlFile, string $originalClassName = '', string $mockClassName = '', array $methods = [], bool $callOriginalConstructor = true, array $options = []): MockObject
+ {
+ $this->recordDoubledType(SoapClient::class);
+
+ if ($originalClassName === '') {
+ $fileName = pathinfo(basename(parse_url($wsdlFile, PHP_URL_PATH)), PATHINFO_FILENAME);
+ $originalClassName = preg_replace('/\W/', '', $fileName);
+ }
+
+ if (!class_exists($originalClassName)) {
+ eval(
+ $this->getMockObjectGenerator()->generateClassFromWsdl(
+ $wsdlFile,
+ $originalClassName,
+ $methods,
+ $options
+ )
+ );
+ }
+
+ $mockObject = $this->getMockObjectGenerator()->getMock(
+ $originalClassName,
+ $methods,
+ ['', $options],
+ $mockClassName,
+ $callOriginalConstructor,
+ false,
+ false
+ );
+
+ $this->registerMockObject($mockObject);
+
+ return $mockObject;
+ }
+
+ /**
+ * Returns a mock object for the specified trait with all abstract methods
+ * of the trait mocked. Concrete methods to mock can be specified with the
+ * `$mockedMethods` parameter.
+ *
+ * @psalm-param trait-string $traitName
+ */
+ protected function getMockForTrait(string $traitName, array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, array $mockedMethods = [], bool $cloneArguments = false): MockObject
+ {
+ $this->recordDoubledType($traitName);
+
+ $mockObject = $this->getMockObjectGenerator()->getMockForTrait(
+ $traitName,
+ $arguments,
+ $mockClassName,
+ $callOriginalConstructor,
+ $callOriginalClone,
+ $callAutoload,
+ $mockedMethods,
+ $cloneArguments
+ );
+
+ $this->registerMockObject($mockObject);
+
+ return $mockObject;
+ }
+
+ /**
+ * Returns an object for the specified trait.
+ *
+ * @psalm-param trait-string $traitName
+ */
+ protected function getObjectForTrait(string $traitName, array $arguments = [], string $traitClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true): object
+ {
+ $this->recordDoubledType($traitName);
+
+ return $this->getMockObjectGenerator()->getObjectForTrait(
+ $traitName,
+ $traitClassName,
+ $callAutoload,
+ $callOriginalConstructor,
+ $arguments
+ );
+ }
+
+ /**
+ * @throws \Prophecy\Exception\Doubler\ClassNotFoundException
+ * @throws \Prophecy\Exception\Doubler\DoubleException
+ * @throws \Prophecy\Exception\Doubler\InterfaceNotFoundException
+ *
+ * @psalm-param class-string|null $classOrInterface
+ */
+ protected function prophesize(?string $classOrInterface = null): ObjectProphecy
+ {
+ $this->addWarning('PHPUnit\Framework\TestCase::prophesize() is deprecated and will be removed in PHPUnit 10. Please use the trait provided by phpspec/prophecy-phpunit.');
+
+ if (is_string($classOrInterface)) {
+ $this->recordDoubledType($classOrInterface);
+ }
+
+ return $this->getProphet()->prophesize($classOrInterface);
+ }
+
+ /**
+ * Creates a default TestResult object.
+ *
+ * @internal This method is not covered by the backward compatibility promise for PHPUnit
+ */
+ protected function createResult(): TestResult
+ {
+ return new TestResult;
+ }
+
+ /**
+ * This method is called when a test method did not execute successfully.
+ *
+ * @throws Throwable
+ */
+ protected function onNotSuccessfulTest(Throwable $t): void
+ {
+ throw $t;
+ }
+
+ protected function recordDoubledType(string $originalClassName): void
+ {
+ $this->doubledTypes[] = $originalClassName;
+ }
+
+ /**
+ * @throws Throwable
+ */
+ private function verifyMockObjects(): void
+ {
+ foreach ($this->mockObjects as $mockObject) {
+ if ($mockObject->__phpunit_hasMatchers()) {
+ $this->numAssertions++;
+ }
+
+ $mockObject->__phpunit_verify(
+ $this->shouldInvocationMockerBeReset($mockObject)
+ );
+ }
+
+ if ($this->prophet !== null) {
+ try {
+ $this->prophet->checkPredictions();
+ } finally {
+ foreach ($this->prophet->getProphecies() as $objectProphecy) {
+ foreach ($objectProphecy->getMethodProphecies() as $methodProphecies) {
+ foreach ($methodProphecies as $methodProphecy) {
+ /* @var MethodProphecy $methodProphecy */
+ $this->numAssertions += count($methodProphecy->getCheckedPredictions());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws SkippedTestError
+ * @throws SyntheticSkippedError
+ * @throws Warning
+ */
+ private function checkRequirements(): void
+ {
+ if (!$this->name || !method_exists($this, $this->name)) {
+ return;
+ }
+
+ $missingRequirements = TestUtil::getMissingRequirements(
+ static::class,
+ $this->name
+ );
+
+ if (!empty($missingRequirements)) {
+ $this->markTestSkipped(implode(PHP_EOL, $missingRequirements));
+ }
+ }
+
+ private function handleDependencies(): bool
+ {
+ if ([] === $this->dependencies || $this->inIsolation) {
+ return true;
+ }
+
+ $passed = $this->result->passed();
+ $passedKeys = array_keys($passed);
+ $numKeys = count($passedKeys);
+
+ for ($i = 0; $i < $numKeys; $i++) {
+ $pos = strpos($passedKeys[$i], ' with data set');
+
+ if ($pos !== false) {
+ $passedKeys[$i] = substr($passedKeys[$i], 0, $pos);
+ }
+ }
+
+ $passedKeys = array_flip(array_unique($passedKeys));
+
+ foreach ($this->dependencies as $dependency) {
+ if (!$dependency->isValid()) {
+ $this->markSkippedForNotSpecifyingDependency();
+
+ return false;
+ }
+
+ if ($dependency->targetIsClass()) {
+ $dependencyClassName = $dependency->getTargetClassName();
+
+ if (array_search($dependencyClassName, $this->result->passedClasses(), true) === false) {
+ $this->markSkippedForMissingDependency($dependency);
+
+ return false;
+ }
+
+ continue;
+ }
+
+ $dependencyTarget = $dependency->getTarget();
+
+ if (!isset($passedKeys[$dependencyTarget])) {
+ if (!$this->isCallableTestMethod($dependencyTarget)) {
+ $this->markWarningForUncallableDependency($dependency);
+ } else {
+ $this->markSkippedForMissingDependency($dependency);
+ }
+
+ return false;
+ }
+
+ if (isset($passed[$dependencyTarget])) {
+ if ($passed[$dependencyTarget]['size'] != \PHPUnit\Util\Test::UNKNOWN &&
+ $this->getSize() != \PHPUnit\Util\Test::UNKNOWN &&
+ $passed[$dependencyTarget]['size'] > $this->getSize()) {
+ $this->result->addError(
+ $this,
+ new SkippedTestError(
+ 'This test depends on a test that is larger than itself.'
+ ),
+ 0
+ );
+
+ return false;
+ }
+
+ if ($dependency->useDeepClone()) {
+ $deepCopy = new DeepCopy;
+ $deepCopy->skipUncloneable(false);
+
+ $this->dependencyInput[$dependencyTarget] = $deepCopy->copy($passed[$dependencyTarget]['result']);
+ } elseif ($dependency->useShallowClone()) {
+ $this->dependencyInput[$dependencyTarget] = clone $passed[$dependencyTarget]['result'];
+ } else {
+ $this->dependencyInput[$dependencyTarget] = $passed[$dependencyTarget]['result'];
+ }
+ } else {
+ $this->dependencyInput[$dependencyTarget] = null;
+ }
+ }
+
+ return true;
+ }
+
+ private function markSkippedForNotSpecifyingDependency(): void
+ {
+ $this->status = BaseTestRunner::STATUS_SKIPPED;
+
+ $this->result->startTest($this);
+
+ $this->result->addError(
+ $this,
+ new SkippedTestError(
+ 'This method has an invalid @depends annotation.'
+ ),
+ 0
+ );
+
+ $this->result->endTest($this, 0);
+ }
+
+ private function markSkippedForMissingDependency(ExecutionOrderDependency $dependency): void
+ {
+ $this->status = BaseTestRunner::STATUS_SKIPPED;
+
+ $this->result->startTest($this);
+
+ $this->result->addError(
+ $this,
+ new SkippedTestError(
+ sprintf(
+ 'This test depends on "%s" to pass.',
+ $dependency->getTarget()
+ )
+ ),
+ 0
+ );
+
+ $this->result->endTest($this, 0);
+ }
+
+ private function markWarningForUncallableDependency(ExecutionOrderDependency $dependency): void
+ {
+ $this->status = BaseTestRunner::STATUS_WARNING;
+
+ $this->result->startTest($this);
+
+ $this->result->addWarning(
+ $this,
+ new Warning(
+ sprintf(
+ 'This test depends on "%s" which does not exist.',
+ $dependency->getTarget()
+ )
+ ),
+ 0
+ );
+
+ $this->result->endTest($this, 0);
+ }
+
+ /**
+ * Get the mock object generator, creating it if it doesn't exist.
+ */
+ private function getMockObjectGenerator(): MockGenerator
+ {
+ if ($this->mockObjectGenerator === null) {
+ $this->mockObjectGenerator = new MockGenerator;
+ }
+
+ return $this->mockObjectGenerator;
+ }
+
+ private function startOutputBuffering(): void
+ {
+ ob_start();
+
+ $this->outputBufferingActive = true;
+ $this->outputBufferingLevel = ob_get_level();
+ }
+
+ /**
+ * @throws RiskyTestError
+ */
+ private function stopOutputBuffering(): void
+ {
+ if (ob_get_level() !== $this->outputBufferingLevel) {
+ while (ob_get_level() >= $this->outputBufferingLevel) {
+ ob_end_clean();
+ }
+
+ throw new RiskyTestError(
+ 'Test code or tested code did not (only) close its own output buffers'
+ );
+ }
+
+ $this->output = ob_get_contents();
+
+ if ($this->outputCallback !== false) {
+ $this->output = (string) call_user_func($this->outputCallback, $this->output);
+ }
+
+ ob_end_clean();
+
+ $this->outputBufferingActive = false;
+ $this->outputBufferingLevel = ob_get_level();
+ }
+
+ private function snapshotGlobalState(): void
+ {
+ if ($this->runTestInSeparateProcess || $this->inIsolation ||
+ (!$this->backupGlobals && !$this->backupStaticAttributes)) {
+ return;
+ }
+
+ $this->snapshot = $this->createGlobalStateSnapshot($this->backupGlobals === true);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws RiskyTestError
+ */
+ private function restoreGlobalState(): void
+ {
+ if (!$this->snapshot instanceof Snapshot) {
+ return;
+ }
+
+ if ($this->beStrictAboutChangesToGlobalState) {
+ try {
+ $this->compareGlobalStateSnapshots(
+ $this->snapshot,
+ $this->createGlobalStateSnapshot($this->backupGlobals === true)
+ );
+ } catch (RiskyTestError $rte) {
+ // Intentionally left empty
+ }
+ }
+
+ $restorer = new Restorer;
+
+ if ($this->backupGlobals) {
+ $restorer->restoreGlobalVariables($this->snapshot);
+ }
+
+ if ($this->backupStaticAttributes) {
+ $restorer->restoreStaticAttributes($this->snapshot);
+ }
+
+ $this->snapshot = null;
+
+ if (isset($rte)) {
+ throw $rte;
+ }
+ }
+
+ private function createGlobalStateSnapshot(bool $backupGlobals): Snapshot
+ {
+ $excludeList = new ExcludeList;
+
+ foreach ($this->backupGlobalsExcludeList as $globalVariable) {
+ $excludeList->addGlobalVariable($globalVariable);
+ }
+
+ if (!empty($this->backupGlobalsBlacklist)) {
+ $this->addWarning('PHPUnit\Framework\TestCase::$backupGlobalsBlacklist is deprecated and will be removed in PHPUnit 10. Please use PHPUnit\Framework\TestCase::$backupGlobalsExcludeList instead.');
+
+ foreach ($this->backupGlobalsBlacklist as $globalVariable) {
+ $excludeList->addGlobalVariable($globalVariable);
+ }
+ }
+
+ if (!defined('PHPUNIT_TESTSUITE')) {
+ $excludeList->addClassNamePrefix('PHPUnit');
+ $excludeList->addClassNamePrefix('SebastianBergmann\CodeCoverage');
+ $excludeList->addClassNamePrefix('SebastianBergmann\FileIterator');
+ $excludeList->addClassNamePrefix('SebastianBergmann\Invoker');
+ $excludeList->addClassNamePrefix('SebastianBergmann\Template');
+ $excludeList->addClassNamePrefix('SebastianBergmann\Timer');
+ $excludeList->addClassNamePrefix('Symfony');
+ $excludeList->addClassNamePrefix('Doctrine\Instantiator');
+ $excludeList->addClassNamePrefix('Prophecy');
+ $excludeList->addStaticAttribute(ComparatorFactory::class, 'instance');
+
+ foreach ($this->backupStaticAttributesExcludeList as $class => $attributes) {
+ foreach ($attributes as $attribute) {
+ $excludeList->addStaticAttribute($class, $attribute);
+ }
+ }
+
+ if (!empty($this->backupStaticAttributesBlacklist)) {
+ $this->addWarning('PHPUnit\Framework\TestCase::$backupStaticAttributesBlacklist is deprecated and will be removed in PHPUnit 10. Please use PHPUnit\Framework\TestCase::$backupStaticAttributesExcludeList instead.');
+
+ foreach ($this->backupStaticAttributesBlacklist as $class => $attributes) {
+ foreach ($attributes as $attribute) {
+ $excludeList->addStaticAttribute($class, $attribute);
+ }
+ }
+ }
+ }
+
+ return new Snapshot(
+ $excludeList,
+ $backupGlobals,
+ (bool) $this->backupStaticAttributes,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false
+ );
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws RiskyTestError
+ */
+ 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->backupStaticAttributes) {
+ $this->compareGlobalStateSnapshotPart(
+ $before->staticAttributes(),
+ $after->staticAttributes(),
+ "--- Static attributes before the test\n+++ Static attributes after the test\n"
+ );
+ }
+ }
+
+ /**
+ * @throws RiskyTestError
+ */
+ private function compareGlobalStateSnapshotPart(array $before, array $after, string $header): void
+ {
+ if ($before != $after) {
+ $differ = new Differ($header);
+ $exporter = new Exporter;
+
+ $diff = $differ->diff(
+ $exporter->export($before),
+ $exporter->export($after)
+ );
+
+ throw new RiskyTestError(
+ $diff
+ );
+ }
+ }
+
+ private function getProphet(): Prophet
+ {
+ if ($this->prophet === null) {
+ $this->prophet = new Prophet;
+ }
+
+ return $this->prophet;
+ }
+
+ /**
+ * @throws \SebastianBergmann\ObjectEnumerator\InvalidArgumentException
+ */
+ private function shouldInvocationMockerBeReset(MockObject $mock): bool
+ {
+ $enumerator = new Enumerator;
+
+ foreach ($enumerator->enumerate($this->dependencyInput) as $object) {
+ if ($mock === $object) {
+ return false;
+ }
+ }
+
+ if (!is_array($this->testResult) && !is_object($this->testResult)) {
+ return true;
+ }
+
+ return !in_array($mock, $enumerator->enumerate($this->testResult), true);
+ }
+
+ /**
+ * @throws \SebastianBergmann\ObjectEnumerator\InvalidArgumentException
+ * @throws \SebastianBergmann\ObjectReflector\InvalidArgumentException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ private function registerMockObjectsFromTestArguments(array $testArguments, array &$visited = []): void
+ {
+ if ($this->registerMockObjectsFromTestArgumentsRecursively) {
+ foreach ((new Enumerator)->enumerate($testArguments) as $object) {
+ if ($object instanceof MockObject) {
+ $this->registerMockObject($object);
+ }
+ }
+ } else {
+ foreach ($testArguments as $testArgument) {
+ if ($testArgument instanceof MockObject) {
+ if (Type::isCloneable($testArgument)) {
+ $testArgument = clone $testArgument;
+ }
+
+ $this->registerMockObject($testArgument);
+ } elseif (is_array($testArgument) && !in_array($testArgument, $visited, true)) {
+ $visited[] = $testArgument;
+
+ $this->registerMockObjectsFromTestArguments(
+ $testArgument,
+ $visited
+ );
+ }
+ }
+ }
+ }
+
+ private function setDoesNotPerformAssertionsFromAnnotation(): void
+ {
+ $annotations = TestUtil::parseTestMethodAnnotations(
+ static::class,
+ $this->name
+ );
+
+ if (isset($annotations['method']['doesNotPerformAssertions'])) {
+ $this->doesNotPerformAssertions = true;
+ }
+ }
+
+ private function unregisterCustomComparators(): void
+ {
+ $factory = ComparatorFactory::getInstance();
+
+ foreach ($this->customComparators as $comparator) {
+ $factory->unregister($comparator);
+ }
+
+ $this->customComparators = [];
+ }
+
+ private function cleanupIniSettings(): void
+ {
+ foreach ($this->iniSettings as $varName => $oldValue) {
+ ini_set($varName, $oldValue);
+ }
+
+ $this->iniSettings = [];
+ }
+
+ private function cleanupLocaleSettings(): void
+ {
+ foreach ($this->locale as $category => $locale) {
+ setlocale($category, $locale);
+ }
+
+ $this->locale = [];
+ }
+
+ /**
+ * @throws Exception
+ */
+ private function checkExceptionExpectations(Throwable $throwable): bool
+ {
+ $result = false;
+
+ if ($this->expectedException !== null || $this->expectedExceptionCode !== null || $this->expectedExceptionMessage !== null || $this->expectedExceptionMessageRegExp !== null) {
+ $result = true;
+ }
+
+ if ($throwable instanceof Exception) {
+ $result = false;
+ }
+
+ if (is_string($this->expectedException)) {
+ try {
+ $reflector = new ReflectionClass($this->expectedException);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if ($this->expectedException === 'PHPUnit\Framework\Exception' ||
+ $this->expectedException === '\PHPUnit\Framework\Exception' ||
+ $reflector->isSubclassOf(Exception::class)) {
+ $result = true;
+ }
+ }
+
+ return $result;
+ }
+
+ private function runInSeparateProcess(): bool
+ {
+ return ($this->runTestInSeparateProcess || $this->runClassInSeparateProcess) &&
+ !$this->inIsolation && !$this instanceof PhptTestCase;
+ }
+
+ private function isCallableTestMethod(string $dependency): bool
+ {
+ [$className, $methodName] = explode('::', $dependency);
+
+ if (!class_exists($className)) {
+ return false;
+ }
+
+ try {
+ $class = new ReflectionClass($className);
+ } catch (ReflectionException $e) {
+ return false;
+ }
+
+ if (!$class->isSubclassOf(__CLASS__)) {
+ return false;
+ }
+
+ if (!$class->hasMethod($methodName)) {
+ return false;
+ }
+
+ try {
+ $method = $class->getMethod($methodName);
+ } catch (ReflectionException $e) {
+ return false;
+ }
+
+ return TestUtil::isTestMethod($method);
+ }
+
+ /**
+ * @psalm-template RealInstanceType of object
+ * @psalm-param class-string<RealInstanceType> $originalClassName
+ * @psalm-return MockObject&RealInstanceType
+ */
+ private function createMockObject(string $originalClassName): MockObject
+ {
+ return $this->getMockBuilder($originalClassName)
+ ->disableOriginalConstructor()
+ ->disableOriginalClone()
+ ->disableArgumentCloning()
+ ->disallowMockingUnknownTypes()
+ ->getMock();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/TestFailure.php b/vendor/phpunit/phpunit/src/Framework/TestFailure.php
new file mode 100644
index 000000000..0764bc789
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/TestFailure.php
@@ -0,0 +1,155 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use function get_class;
+use function sprintf;
+use function trim;
+use PHPUnit\Framework\Error\Error;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestFailure
+{
+ /**
+ * @var null|Test
+ */
+ private $failedTest;
+
+ /**
+ * @var Throwable
+ */
+ private $thrownException;
+
+ /**
+ * @var string
+ */
+ private $testName;
+
+ /**
+ * Returns a description for an exception.
+ */
+ public static function exceptionToString(Throwable $e): string
+ {
+ if ($e instanceof SelfDescribing) {
+ $buffer = $e->toString();
+
+ if ($e instanceof ExpectationFailedException && $e->getComparisonFailure()) {
+ $buffer .= $e->getComparisonFailure()->getDiff();
+ }
+
+ if ($e instanceof PHPTAssertionFailedError) {
+ $buffer .= $e->getDiff();
+ }
+
+ if (!empty($buffer)) {
+ $buffer = trim($buffer) . "\n";
+ }
+
+ return $buffer;
+ }
+
+ if ($e instanceof Error) {
+ return $e->getMessage() . "\n";
+ }
+
+ if ($e instanceof ExceptionWrapper) {
+ return $e->getClassName() . ': ' . $e->getMessage() . "\n";
+ }
+
+ return get_class($e) . ': ' . $e->getMessage() . "\n";
+ }
+
+ /**
+ * Constructs a TestFailure with the given test and exception.
+ */
+ public function __construct(Test $failedTest, Throwable $t)
+ {
+ if ($failedTest instanceof SelfDescribing) {
+ $this->testName = $failedTest->toString();
+ } else {
+ $this->testName = get_class($failedTest);
+ }
+
+ if (!$failedTest instanceof TestCase || !$failedTest->isInIsolation()) {
+ $this->failedTest = $failedTest;
+ }
+
+ $this->thrownException = $t;
+ }
+
+ /**
+ * Returns a short description of the failure.
+ */
+ public function toString(): string
+ {
+ return sprintf(
+ '%s: %s',
+ $this->testName,
+ $this->thrownException->getMessage()
+ );
+ }
+
+ /**
+ * Returns a description for the thrown exception.
+ */
+ public function getExceptionAsString(): string
+ {
+ return self::exceptionToString($this->thrownException);
+ }
+
+ /**
+ * Returns the name of the failing test (including data set, if any).
+ */
+ public function getTestName(): string
+ {
+ return $this->testName;
+ }
+
+ /**
+ * Returns the failing test.
+ *
+ * Note: The test object is not set when the test is executed in process
+ * isolation.
+ *
+ * @see Exception
+ */
+ public function failedTest(): ?Test
+ {
+ return $this->failedTest;
+ }
+
+ /**
+ * Gets the thrown exception.
+ */
+ public function thrownException(): Throwable
+ {
+ return $this->thrownException;
+ }
+
+ /**
+ * Returns the exception's message.
+ */
+ public function exceptionMessage(): string
+ {
+ return $this->thrownException()->getMessage();
+ }
+
+ /**
+ * Returns true if the thrown exception
+ * is of type AssertionFailedError.
+ */
+ public function isFailure(): bool
+ {
+ return $this->thrownException() instanceof AssertionFailedError;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/TestListener.php b/vendor/phpunit/phpunit/src/Framework/TestListener.php
new file mode 100644
index 000000000..eade600f2
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/TestListener.php
@@ -0,0 +1,45 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use Throwable;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @deprecated
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface TestListener
+{
+ public function addError(Test $test, Throwable $t, float $time): void;
+
+ public function addWarning(Test $test, Warning $e, float $time): void;
+
+ public function addFailure(Test $test, AssertionFailedError $e, float $time): void;
+
+ public function addIncompleteTest(Test $test, Throwable $t, float $time): void;
+
+ public function addRiskyTest(Test $test, Throwable $t, float $time): void;
+
+ public function addSkippedTest(Test $test, Throwable $t, float $time): void;
+
+ public function startTestSuite(TestSuite $suite): void;
+
+ public function endTestSuite(TestSuite $suite): void;
+
+ public function startTest(Test $test): void;
+
+ public function endTest(Test $test, float $time): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/TestListenerDefaultImplementation.php b/vendor/phpunit/phpunit/src/Framework/TestListenerDefaultImplementation.php
new file mode 100644
index 000000000..3e56708b6
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/TestListenerDefaultImplementation.php
@@ -0,0 +1,59 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+use Throwable;
+
+/**
+ * @deprecated The `TestListener` interface is deprecated
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+trait TestListenerDefaultImplementation
+{
+ public function addError(Test $test, Throwable $t, float $time): void
+ {
+ }
+
+ public function addWarning(Test $test, Warning $e, float $time): void
+ {
+ }
+
+ public function addFailure(Test $test, AssertionFailedError $e, float $time): void
+ {
+ }
+
+ public function addIncompleteTest(Test $test, Throwable $t, float $time): void
+ {
+ }
+
+ public function addRiskyTest(Test $test, Throwable $t, float $time): void
+ {
+ }
+
+ public function addSkippedTest(Test $test, Throwable $t, float $time): void
+ {
+ }
+
+ public function startTestSuite(TestSuite $suite): void
+ {
+ }
+
+ public function endTestSuite(TestSuite $suite): void
+ {
+ }
+
+ public function startTest(Test $test): void
+ {
+ }
+
+ public function endTest(Test $test, float $time): void
+ {
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/TestResult.php b/vendor/phpunit/phpunit/src/Framework/TestResult.php
new file mode 100644
index 000000000..99b4246cb
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/TestResult.php
@@ -0,0 +1,1318 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 count;
+use function function_exists;
+use function get_class;
+use function sprintf;
+use function xdebug_get_monitored_functions;
+use function xdebug_is_debugger_active;
+use function xdebug_start_function_monitor;
+use function xdebug_stop_function_monitor;
+use AssertionError;
+use Countable;
+use Error;
+use PHPUnit\Util\ErrorHandler;
+use PHPUnit\Util\ExcludeList;
+use PHPUnit\Util\Printer;
+use PHPUnit\Util\Test as TestUtil;
+use ReflectionClass;
+use ReflectionException;
+use SebastianBergmann\CodeCoverage\CodeCoverage;
+use SebastianBergmann\CodeCoverage\Exception as OriginalCodeCoverageException;
+use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException;
+use SebastianBergmann\Invoker\Invoker;
+use SebastianBergmann\Invoker\TimeoutException;
+use SebastianBergmann\ResourceOperations\ResourceOperations;
+use SebastianBergmann\Timer\Timer;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestResult implements Countable
+{
+ /**
+ * @var array
+ */
+ private $passed = [];
+
+ /**
+ * @var array<string>
+ */
+ private $passedTestClasses = [];
+
+ /**
+ * @var bool
+ */
+ private $currentTestSuiteFailed = false;
+
+ /**
+ * @var TestFailure[]
+ */
+ private $errors = [];
+
+ /**
+ * @var TestFailure[]
+ */
+ private $failures = [];
+
+ /**
+ * @var TestFailure[]
+ */
+ private $warnings = [];
+
+ /**
+ * @var TestFailure[]
+ */
+ private $notImplemented = [];
+
+ /**
+ * @var TestFailure[]
+ */
+ private $risky = [];
+
+ /**
+ * @var TestFailure[]
+ */
+ private $skipped = [];
+
+ /**
+ * @deprecated Use the `TestHook` interfaces instead
+ *
+ * @var TestListener[]
+ */
+ private $listeners = [];
+
+ /**
+ * @var int
+ */
+ private $runTests = 0;
+
+ /**
+ * @var float
+ */
+ private $time = 0;
+
+ /**
+ * Code Coverage information.
+ *
+ * @var CodeCoverage
+ */
+ private $codeCoverage;
+
+ /**
+ * @var bool
+ */
+ private $convertDeprecationsToExceptions = false;
+
+ /**
+ * @var bool
+ */
+ private $convertErrorsToExceptions = true;
+
+ /**
+ * @var bool
+ */
+ private $convertNoticesToExceptions = true;
+
+ /**
+ * @var bool
+ */
+ private $convertWarningsToExceptions = true;
+
+ /**
+ * @var bool
+ */
+ private $stop = false;
+
+ /**
+ * @var bool
+ */
+ private $stopOnError = false;
+
+ /**
+ * @var bool
+ */
+ private $stopOnFailure = false;
+
+ /**
+ * @var bool
+ */
+ private $stopOnWarning = false;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutTestsThatDoNotTestAnything = true;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutOutputDuringTests = false;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutTodoAnnotatedTests = false;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutResourceUsageDuringSmallTests = false;
+
+ /**
+ * @var bool
+ */
+ private $enforceTimeLimit = false;
+
+ /**
+ * @var bool
+ */
+ private $forceCoversAnnotation = false;
+
+ /**
+ * @var int
+ */
+ private $timeoutForSmallTests = 1;
+
+ /**
+ * @var int
+ */
+ private $timeoutForMediumTests = 10;
+
+ /**
+ * @var int
+ */
+ private $timeoutForLargeTests = 60;
+
+ /**
+ * @var bool
+ */
+ private $stopOnRisky = false;
+
+ /**
+ * @var bool
+ */
+ private $stopOnIncomplete = false;
+
+ /**
+ * @var bool
+ */
+ private $stopOnSkipped = false;
+
+ /**
+ * @var bool
+ */
+ private $lastTestFailed = false;
+
+ /**
+ * @var int
+ */
+ private $defaultTimeLimit = 0;
+
+ /**
+ * @var bool
+ */
+ private $stopOnDefect = false;
+
+ /**
+ * @var bool
+ */
+ private $registerMockObjectsFromTestArgumentsRecursively = false;
+
+ /**
+ * @deprecated Use the `TestHook` interfaces instead
+ *
+ * @codeCoverageIgnore
+ *
+ * Registers a TestListener.
+ */
+ public function addListener(TestListener $listener): void
+ {
+ $this->listeners[] = $listener;
+ }
+
+ /**
+ * @deprecated Use the `TestHook` interfaces instead
+ *
+ * @codeCoverageIgnore
+ *
+ * Unregisters a TestListener.
+ */
+ public function removeListener(TestListener $listener): void
+ {
+ foreach ($this->listeners as $key => $_listener) {
+ if ($listener === $_listener) {
+ unset($this->listeners[$key]);
+ }
+ }
+ }
+
+ /**
+ * @deprecated Use the `TestHook` interfaces instead
+ *
+ * @codeCoverageIgnore
+ *
+ * Flushes all flushable TestListeners.
+ */
+ public function flushListeners(): void
+ {
+ foreach ($this->listeners as $listener) {
+ if ($listener instanceof Printer) {
+ $listener->flush();
+ }
+ }
+ }
+
+ /**
+ * Adds an error to the list of errors.
+ */
+ public function addError(Test $test, Throwable $t, float $time): void
+ {
+ if ($t instanceof RiskyTestError) {
+ $this->recordRisky($test, $t);
+
+ $notifyMethod = 'addRiskyTest';
+
+ if ($test instanceof TestCase) {
+ $test->markAsRisky();
+ }
+
+ if ($this->stopOnRisky || $this->stopOnDefect) {
+ $this->stop();
+ }
+ } elseif ($t instanceof IncompleteTest) {
+ $this->recordNotImplemented($test, $t);
+
+ $notifyMethod = 'addIncompleteTest';
+
+ if ($this->stopOnIncomplete) {
+ $this->stop();
+ }
+ } elseif ($t instanceof SkippedTest) {
+ $this->recordSkipped($test, $t);
+
+ $notifyMethod = 'addSkippedTest';
+
+ if ($this->stopOnSkipped) {
+ $this->stop();
+ }
+ } else {
+ $this->recordError($test, $t);
+
+ $notifyMethod = 'addError';
+
+ if ($this->stopOnError || $this->stopOnFailure) {
+ $this->stop();
+ }
+ }
+
+ // @see https://github.com/sebastianbergmann/phpunit/issues/1953
+ if ($t instanceof Error) {
+ $t = new ExceptionWrapper($t);
+ }
+
+ foreach ($this->listeners as $listener) {
+ $listener->{$notifyMethod}($test, $t, $time);
+ }
+
+ $this->lastTestFailed = true;
+ $this->time += $time;
+ }
+
+ /**
+ * Adds a warning to the list of warnings.
+ * The passed in exception caused the warning.
+ */
+ public function addWarning(Test $test, Warning $e, float $time): void
+ {
+ if ($this->stopOnWarning || $this->stopOnDefect) {
+ $this->stop();
+ }
+
+ $this->recordWarning($test, $e);
+
+ foreach ($this->listeners as $listener) {
+ $listener->addWarning($test, $e, $time);
+ }
+
+ $this->time += $time;
+ }
+
+ /**
+ * Adds a failure to the list of failures.
+ * The passed in exception caused the failure.
+ */
+ public function addFailure(Test $test, AssertionFailedError $e, float $time): void
+ {
+ if ($e instanceof RiskyTestError || $e instanceof OutputError) {
+ $this->recordRisky($test, $e);
+
+ $notifyMethod = 'addRiskyTest';
+
+ if ($test instanceof TestCase) {
+ $test->markAsRisky();
+ }
+
+ if ($this->stopOnRisky || $this->stopOnDefect) {
+ $this->stop();
+ }
+ } elseif ($e instanceof IncompleteTest) {
+ $this->recordNotImplemented($test, $e);
+
+ $notifyMethod = 'addIncompleteTest';
+
+ if ($this->stopOnIncomplete) {
+ $this->stop();
+ }
+ } elseif ($e instanceof SkippedTest) {
+ $this->recordSkipped($test, $e);
+
+ $notifyMethod = 'addSkippedTest';
+
+ if ($this->stopOnSkipped) {
+ $this->stop();
+ }
+ } else {
+ $this->failures[] = new TestFailure($test, $e);
+ $notifyMethod = 'addFailure';
+
+ if ($this->stopOnFailure || $this->stopOnDefect) {
+ $this->stop();
+ }
+ }
+
+ foreach ($this->listeners as $listener) {
+ $listener->{$notifyMethod}($test, $e, $time);
+ }
+
+ $this->lastTestFailed = true;
+ $this->time += $time;
+ }
+
+ /**
+ * Informs the result that a test suite will be started.
+ */
+ public function startTestSuite(TestSuite $suite): void
+ {
+ $this->currentTestSuiteFailed = false;
+
+ foreach ($this->listeners as $listener) {
+ $listener->startTestSuite($suite);
+ }
+ }
+
+ /**
+ * Informs the result that a test suite was completed.
+ */
+ public function endTestSuite(TestSuite $suite): void
+ {
+ if (!$this->currentTestSuiteFailed) {
+ $this->passedTestClasses[] = $suite->getName();
+ }
+
+ foreach ($this->listeners as $listener) {
+ $listener->endTestSuite($suite);
+ }
+ }
+
+ /**
+ * Informs the result that a test will be started.
+ */
+ public function startTest(Test $test): void
+ {
+ $this->lastTestFailed = false;
+ $this->runTests += count($test);
+
+ foreach ($this->listeners as $listener) {
+ $listener->startTest($test);
+ }
+ }
+
+ /**
+ * Informs the result that a test was completed.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function endTest(Test $test, float $time): void
+ {
+ foreach ($this->listeners as $listener) {
+ $listener->endTest($test, $time);
+ }
+
+ if (!$this->lastTestFailed && $test instanceof TestCase) {
+ $class = get_class($test);
+ $key = $class . '::' . $test->getName();
+
+ $this->passed[$key] = [
+ 'result' => $test->getResult(),
+ 'size' => TestUtil::getSize(
+ $class,
+ $test->getName(false)
+ ),
+ ];
+
+ $this->time += $time;
+ }
+
+ if ($this->lastTestFailed && $test instanceof TestCase) {
+ $this->currentTestSuiteFailed = true;
+ }
+ }
+
+ /**
+ * Returns true if no risky test occurred.
+ */
+ public function allHarmless(): bool
+ {
+ return $this->riskyCount() === 0;
+ }
+
+ /**
+ * Gets the number of risky tests.
+ */
+ public function riskyCount(): int
+ {
+ return count($this->risky);
+ }
+
+ /**
+ * Returns true if no incomplete test occurred.
+ */
+ public function allCompletelyImplemented(): bool
+ {
+ return $this->notImplementedCount() === 0;
+ }
+
+ /**
+ * Gets the number of incomplete tests.
+ */
+ public function notImplementedCount(): int
+ {
+ return count($this->notImplemented);
+ }
+
+ /**
+ * Returns an array of TestFailure objects for the risky tests.
+ *
+ * @return TestFailure[]
+ */
+ public function risky(): array
+ {
+ return $this->risky;
+ }
+
+ /**
+ * Returns an array of TestFailure objects for the incomplete tests.
+ *
+ * @return TestFailure[]
+ */
+ public function notImplemented(): array
+ {
+ return $this->notImplemented;
+ }
+
+ /**
+ * Returns true if no test has been skipped.
+ */
+ public function noneSkipped(): bool
+ {
+ return $this->skippedCount() === 0;
+ }
+
+ /**
+ * Gets the number of skipped tests.
+ */
+ public function skippedCount(): int
+ {
+ return count($this->skipped);
+ }
+
+ /**
+ * Returns an array of TestFailure objects for the skipped tests.
+ *
+ * @return TestFailure[]
+ */
+ public function skipped(): array
+ {
+ return $this->skipped;
+ }
+
+ /**
+ * Gets the number of detected errors.
+ */
+ public function errorCount(): int
+ {
+ return count($this->errors);
+ }
+
+ /**
+ * Returns an array of TestFailure objects for the errors.
+ *
+ * @return TestFailure[]
+ */
+ public function errors(): array
+ {
+ return $this->errors;
+ }
+
+ /**
+ * Gets the number of detected failures.
+ */
+ public function failureCount(): int
+ {
+ return count($this->failures);
+ }
+
+ /**
+ * Returns an array of TestFailure objects for the failures.
+ *
+ * @return TestFailure[]
+ */
+ public function failures(): array
+ {
+ return $this->failures;
+ }
+
+ /**
+ * Gets the number of detected warnings.
+ */
+ public function warningCount(): int
+ {
+ return count($this->warnings);
+ }
+
+ /**
+ * Returns an array of TestFailure objects for the warnings.
+ *
+ * @return TestFailure[]
+ */
+ public function warnings(): array
+ {
+ return $this->warnings;
+ }
+
+ /**
+ * Returns the names of the tests that have passed.
+ */
+ public function passed(): array
+ {
+ return $this->passed;
+ }
+
+ /**
+ * Returns the names of the TestSuites that have passed.
+ *
+ * This enables @depends-annotations for TestClassName::class
+ */
+ public function passedClasses(): array
+ {
+ return $this->passedTestClasses;
+ }
+
+ /**
+ * Returns whether code coverage information should be collected.
+ */
+ public function getCollectCodeCoverageInformation(): bool
+ {
+ return $this->codeCoverage !== null;
+ }
+
+ /**
+ * Runs a TestCase.
+ *
+ * @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws CodeCoverageException
+ * @throws UnintentionallyCoveredCodeException
+ */
+ public function run(Test $test): void
+ {
+ Assert::resetCount();
+
+ $size = TestUtil::UNKNOWN;
+
+ if ($test instanceof TestCase) {
+ $test->setRegisterMockObjectsFromTestArgumentsRecursively(
+ $this->registerMockObjectsFromTestArgumentsRecursively
+ );
+
+ $isAnyCoverageRequired = TestUtil::requiresCodeCoverageDataCollection($test);
+ $size = $test->getSize();
+ }
+
+ $error = false;
+ $failure = false;
+ $warning = false;
+ $incomplete = false;
+ $risky = false;
+ $skipped = false;
+
+ $this->startTest($test);
+
+ if ($this->convertDeprecationsToExceptions || $this->convertErrorsToExceptions || $this->convertNoticesToExceptions || $this->convertWarningsToExceptions) {
+ $errorHandler = new ErrorHandler(
+ $this->convertDeprecationsToExceptions,
+ $this->convertErrorsToExceptions,
+ $this->convertNoticesToExceptions,
+ $this->convertWarningsToExceptions
+ );
+
+ $errorHandler->register();
+ }
+
+ $collectCodeCoverage = $this->codeCoverage !== null &&
+ !$test instanceof ErrorTestCase &&
+ !$test instanceof WarningTestCase &&
+ $isAnyCoverageRequired;
+
+ if ($collectCodeCoverage) {
+ $this->codeCoverage->start($test);
+ }
+
+ $monitorFunctions = $this->beStrictAboutResourceUsageDuringSmallTests &&
+ !$test instanceof ErrorTestCase &&
+ !$test instanceof WarningTestCase &&
+ $size === TestUtil::SMALL &&
+ function_exists('xdebug_start_function_monitor');
+
+ if ($monitorFunctions) {
+ /* @noinspection ForgottenDebugOutputInspection */
+ xdebug_start_function_monitor(ResourceOperations::getFunctions());
+ }
+
+ $timer = new Timer;
+ $timer->start();
+
+ try {
+ $invoker = new Invoker;
+
+ if (!$test instanceof ErrorTestCase &&
+ !$test instanceof WarningTestCase &&
+ $this->shouldTimeLimitBeEnforced($size) &&
+ $invoker->canInvokeWithTimeout()) {
+ switch ($size) {
+ case TestUtil::SMALL:
+ $_timeout = $this->timeoutForSmallTests;
+
+ break;
+
+ case TestUtil::MEDIUM:
+ $_timeout = $this->timeoutForMediumTests;
+
+ break;
+
+ case TestUtil::LARGE:
+ $_timeout = $this->timeoutForLargeTests;
+
+ break;
+
+ default:
+ $_timeout = $this->defaultTimeLimit;
+ }
+
+ $invoker->invoke([$test, 'runBare'], [], $_timeout);
+ } else {
+ $test->runBare();
+ }
+ } catch (TimeoutException $e) {
+ $this->addFailure(
+ $test,
+ new RiskyTestError(
+ $e->getMessage()
+ ),
+ $_timeout
+ );
+
+ $risky = true;
+ } catch (AssertionFailedError $e) {
+ $failure = true;
+
+ if ($e instanceof RiskyTestError) {
+ $risky = true;
+ } elseif ($e instanceof IncompleteTestError) {
+ $incomplete = true;
+ } elseif ($e instanceof SkippedTestError) {
+ $skipped = true;
+ }
+ } catch (AssertionError $e) {
+ $test->addToAssertionCount(1);
+
+ $failure = true;
+ $frame = $e->getTrace()[0];
+
+ $e = new AssertionFailedError(
+ sprintf(
+ '%s in %s:%s',
+ $e->getMessage(),
+ $frame['file'] ?? $e->getFile(),
+ $frame['line'] ?? $e->getLine()
+ )
+ );
+ } catch (Warning $e) {
+ $warning = true;
+ } catch (Exception $e) {
+ $error = true;
+ } catch (Throwable $e) {
+ $e = new ExceptionWrapper($e);
+ $error = true;
+ }
+
+ $time = $timer->stop()->asSeconds();
+
+ $test->addToAssertionCount(Assert::getCount());
+
+ if ($monitorFunctions) {
+ $excludeList = new ExcludeList;
+
+ /** @noinspection ForgottenDebugOutputInspection */
+ $functions = xdebug_get_monitored_functions();
+
+ /* @noinspection ForgottenDebugOutputInspection */
+ xdebug_stop_function_monitor();
+
+ foreach ($functions as $function) {
+ if (!$excludeList->isExcluded($function['filename'])) {
+ $this->addFailure(
+ $test,
+ new RiskyTestError(
+ sprintf(
+ '%s() used in %s:%s',
+ $function['function'],
+ $function['filename'],
+ $function['lineno']
+ )
+ ),
+ $time
+ );
+ }
+ }
+ }
+
+ if ($this->beStrictAboutTestsThatDoNotTestAnything &&
+ $test->getNumAssertions() === 0) {
+ $risky = true;
+ }
+
+ if ($this->forceCoversAnnotation && !$error && !$failure && !$warning && !$incomplete && !$skipped && !$risky) {
+ $annotations = TestUtil::parseTestMethodAnnotations(
+ get_class($test),
+ $test->getName(false)
+ );
+
+ if (!isset($annotations['class']['covers']) &&
+ !isset($annotations['method']['covers']) &&
+ !isset($annotations['class']['coversNothing']) &&
+ !isset($annotations['method']['coversNothing'])) {
+ $this->addFailure(
+ $test,
+ new MissingCoversAnnotationException(
+ 'This test does not have a @covers annotation but is expected to have one'
+ ),
+ $time
+ );
+
+ $risky = true;
+ }
+ }
+
+ if ($collectCodeCoverage) {
+ $append = !$risky && !$incomplete && !$skipped;
+ $linesToBeCovered = [];
+ $linesToBeUsed = [];
+
+ if ($append && $test instanceof TestCase) {
+ try {
+ $linesToBeCovered = TestUtil::getLinesToBeCovered(
+ get_class($test),
+ $test->getName(false)
+ );
+
+ $linesToBeUsed = TestUtil::getLinesToBeUsed(
+ get_class($test),
+ $test->getName(false)
+ );
+ } catch (InvalidCoversTargetException $cce) {
+ $this->addWarning(
+ $test,
+ new Warning(
+ $cce->getMessage()
+ ),
+ $time
+ );
+ }
+ }
+
+ try {
+ $this->codeCoverage->stop(
+ $append,
+ $linesToBeCovered,
+ $linesToBeUsed
+ );
+ } catch (UnintentionallyCoveredCodeException $cce) {
+ $unintentionallyCoveredCodeError = new UnintentionallyCoveredCodeError(
+ 'This test executed code that is not listed as code to be covered or used:' .
+ PHP_EOL . $cce->getMessage()
+ );
+ } catch (OriginalCodeCoverageException $cce) {
+ $error = true;
+
+ $e = $e ?? $cce;
+ }
+ }
+
+ if (isset($errorHandler)) {
+ $errorHandler->unregister();
+
+ unset($errorHandler);
+ }
+
+ if ($error) {
+ $this->addError($test, $e, $time);
+ } elseif ($failure) {
+ $this->addFailure($test, $e, $time);
+ } elseif ($warning) {
+ $this->addWarning($test, $e, $time);
+ } elseif (isset($unintentionallyCoveredCodeError)) {
+ $this->addFailure(
+ $test,
+ $unintentionallyCoveredCodeError,
+ $time
+ );
+ } elseif ($this->beStrictAboutTestsThatDoNotTestAnything &&
+ !$test->doesNotPerformAssertions() &&
+ $test->getNumAssertions() === 0) {
+ try {
+ $reflected = new ReflectionClass($test);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $name = $test->getName(false);
+
+ if ($name && $reflected->hasMethod($name)) {
+ try {
+ $reflected = $reflected->getMethod($name);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ $this->addFailure(
+ $test,
+ new RiskyTestError(
+ sprintf(
+ "This test did not perform any assertions\n\n%s:%d",
+ $reflected->getFileName(),
+ $reflected->getStartLine()
+ )
+ ),
+ $time
+ );
+ } elseif ($this->beStrictAboutTestsThatDoNotTestAnything &&
+ $test->doesNotPerformAssertions() &&
+ $test->getNumAssertions() > 0) {
+ $this->addFailure(
+ $test,
+ new RiskyTestError(
+ sprintf(
+ 'This test is annotated with "@doesNotPerformAssertions" but performed %d assertions',
+ $test->getNumAssertions()
+ )
+ ),
+ $time
+ );
+ } elseif ($this->beStrictAboutOutputDuringTests && $test->hasOutput()) {
+ $this->addFailure(
+ $test,
+ new OutputError(
+ sprintf(
+ 'This test printed output: %s',
+ $test->getActualOutput()
+ )
+ ),
+ $time
+ );
+ } elseif ($this->beStrictAboutTodoAnnotatedTests && $test instanceof TestCase) {
+ $annotations = TestUtil::parseTestMethodAnnotations(
+ get_class($test),
+ $test->getName(false)
+ );
+
+ if (isset($annotations['method']['todo'])) {
+ $this->addFailure(
+ $test,
+ new RiskyTestError(
+ 'Test method is annotated with @todo'
+ ),
+ $time
+ );
+ }
+ }
+
+ $this->endTest($test, $time);
+ }
+
+ /**
+ * Gets the number of run tests.
+ */
+ public function count(): int
+ {
+ return $this->runTests;
+ }
+
+ /**
+ * Checks whether the test run should stop.
+ */
+ public function shouldStop(): bool
+ {
+ return $this->stop;
+ }
+
+ /**
+ * Marks that the test run should stop.
+ */
+ public function stop(): void
+ {
+ $this->stop = true;
+ }
+
+ /**
+ * Returns the code coverage object.
+ */
+ public function getCodeCoverage(): ?CodeCoverage
+ {
+ return $this->codeCoverage;
+ }
+
+ /**
+ * Sets the code coverage object.
+ */
+ public function setCodeCoverage(CodeCoverage $codeCoverage): void
+ {
+ $this->codeCoverage = $codeCoverage;
+ }
+
+ /**
+ * Enables or disables the deprecation-to-exception conversion.
+ */
+ public function convertDeprecationsToExceptions(bool $flag): void
+ {
+ $this->convertDeprecationsToExceptions = $flag;
+ }
+
+ /**
+ * Returns the deprecation-to-exception conversion setting.
+ */
+ public function getConvertDeprecationsToExceptions(): bool
+ {
+ return $this->convertDeprecationsToExceptions;
+ }
+
+ /**
+ * Enables or disables the error-to-exception conversion.
+ */
+ public function convertErrorsToExceptions(bool $flag): void
+ {
+ $this->convertErrorsToExceptions = $flag;
+ }
+
+ /**
+ * Returns the error-to-exception conversion setting.
+ */
+ public function getConvertErrorsToExceptions(): bool
+ {
+ return $this->convertErrorsToExceptions;
+ }
+
+ /**
+ * Enables or disables the notice-to-exception conversion.
+ */
+ public function convertNoticesToExceptions(bool $flag): void
+ {
+ $this->convertNoticesToExceptions = $flag;
+ }
+
+ /**
+ * Returns the notice-to-exception conversion setting.
+ */
+ public function getConvertNoticesToExceptions(): bool
+ {
+ return $this->convertNoticesToExceptions;
+ }
+
+ /**
+ * Enables or disables the warning-to-exception conversion.
+ */
+ public function convertWarningsToExceptions(bool $flag): void
+ {
+ $this->convertWarningsToExceptions = $flag;
+ }
+
+ /**
+ * Returns the warning-to-exception conversion setting.
+ */
+ public function getConvertWarningsToExceptions(): bool
+ {
+ return $this->convertWarningsToExceptions;
+ }
+
+ /**
+ * Enables or disables the stopping when an error occurs.
+ */
+ public function stopOnError(bool $flag): void
+ {
+ $this->stopOnError = $flag;
+ }
+
+ /**
+ * Enables or disables the stopping when a failure occurs.
+ */
+ public function stopOnFailure(bool $flag): void
+ {
+ $this->stopOnFailure = $flag;
+ }
+
+ /**
+ * Enables or disables the stopping when a warning occurs.
+ */
+ public function stopOnWarning(bool $flag): void
+ {
+ $this->stopOnWarning = $flag;
+ }
+
+ public function beStrictAboutTestsThatDoNotTestAnything(bool $flag): void
+ {
+ $this->beStrictAboutTestsThatDoNotTestAnything = $flag;
+ }
+
+ public function isStrictAboutTestsThatDoNotTestAnything(): bool
+ {
+ return $this->beStrictAboutTestsThatDoNotTestAnything;
+ }
+
+ public function beStrictAboutOutputDuringTests(bool $flag): void
+ {
+ $this->beStrictAboutOutputDuringTests = $flag;
+ }
+
+ public function isStrictAboutOutputDuringTests(): bool
+ {
+ return $this->beStrictAboutOutputDuringTests;
+ }
+
+ public function beStrictAboutResourceUsageDuringSmallTests(bool $flag): void
+ {
+ $this->beStrictAboutResourceUsageDuringSmallTests = $flag;
+ }
+
+ public function isStrictAboutResourceUsageDuringSmallTests(): bool
+ {
+ return $this->beStrictAboutResourceUsageDuringSmallTests;
+ }
+
+ public function enforceTimeLimit(bool $flag): void
+ {
+ $this->enforceTimeLimit = $flag;
+ }
+
+ public function enforcesTimeLimit(): bool
+ {
+ return $this->enforceTimeLimit;
+ }
+
+ public function beStrictAboutTodoAnnotatedTests(bool $flag): void
+ {
+ $this->beStrictAboutTodoAnnotatedTests = $flag;
+ }
+
+ public function isStrictAboutTodoAnnotatedTests(): bool
+ {
+ return $this->beStrictAboutTodoAnnotatedTests;
+ }
+
+ public function forceCoversAnnotation(): void
+ {
+ $this->forceCoversAnnotation = true;
+ }
+
+ public function forcesCoversAnnotation(): bool
+ {
+ return $this->forceCoversAnnotation;
+ }
+
+ /**
+ * Enables or disables the stopping for risky tests.
+ */
+ public function stopOnRisky(bool $flag): void
+ {
+ $this->stopOnRisky = $flag;
+ }
+
+ /**
+ * Enables or disables the stopping for incomplete tests.
+ */
+ public function stopOnIncomplete(bool $flag): void
+ {
+ $this->stopOnIncomplete = $flag;
+ }
+
+ /**
+ * Enables or disables the stopping for skipped tests.
+ */
+ public function stopOnSkipped(bool $flag): void
+ {
+ $this->stopOnSkipped = $flag;
+ }
+
+ /**
+ * Enables or disables the stopping for defects: error, failure, warning.
+ */
+ public function stopOnDefect(bool $flag): void
+ {
+ $this->stopOnDefect = $flag;
+ }
+
+ /**
+ * Returns the time spent running the tests.
+ */
+ public function time(): float
+ {
+ return $this->time;
+ }
+
+ /**
+ * Returns whether the entire test was successful or not.
+ */
+ public function wasSuccessful(): bool
+ {
+ return $this->wasSuccessfulIgnoringWarnings() && empty($this->warnings);
+ }
+
+ public function wasSuccessfulIgnoringWarnings(): bool
+ {
+ return empty($this->errors) && empty($this->failures);
+ }
+
+ public function wasSuccessfulAndNoTestIsRiskyOrSkippedOrIncomplete(): bool
+ {
+ return $this->wasSuccessful() && $this->allHarmless() && $this->allCompletelyImplemented() && $this->noneSkipped();
+ }
+
+ /**
+ * Sets the default timeout for tests.
+ */
+ public function setDefaultTimeLimit(int $timeout): void
+ {
+ $this->defaultTimeLimit = $timeout;
+ }
+
+ /**
+ * Sets the timeout for small tests.
+ */
+ public function setTimeoutForSmallTests(int $timeout): void
+ {
+ $this->timeoutForSmallTests = $timeout;
+ }
+
+ /**
+ * Sets the timeout for medium tests.
+ */
+ public function setTimeoutForMediumTests(int $timeout): void
+ {
+ $this->timeoutForMediumTests = $timeout;
+ }
+
+ /**
+ * Sets the timeout for large tests.
+ */
+ public function setTimeoutForLargeTests(int $timeout): void
+ {
+ $this->timeoutForLargeTests = $timeout;
+ }
+
+ /**
+ * Returns the set timeout for large tests.
+ */
+ public function getTimeoutForLargeTests(): int
+ {
+ return $this->timeoutForLargeTests;
+ }
+
+ public function setRegisterMockObjectsFromTestArgumentsRecursively(bool $flag): void
+ {
+ $this->registerMockObjectsFromTestArgumentsRecursively = $flag;
+ }
+
+ private function recordError(Test $test, Throwable $t): void
+ {
+ $this->errors[] = new TestFailure($test, $t);
+ }
+
+ private function recordNotImplemented(Test $test, Throwable $t): void
+ {
+ $this->notImplemented[] = new TestFailure($test, $t);
+ }
+
+ private function recordRisky(Test $test, Throwable $t): void
+ {
+ $this->risky[] = new TestFailure($test, $t);
+ }
+
+ private function recordSkipped(Test $test, Throwable $t): void
+ {
+ $this->skipped[] = new TestFailure($test, $t);
+ }
+
+ private function recordWarning(Test $test, Throwable $t): void
+ {
+ $this->warnings[] = new TestFailure($test, $t);
+ }
+
+ private function shouldTimeLimitBeEnforced(int $size): bool
+ {
+ if (!$this->enforceTimeLimit) {
+ return false;
+ }
+
+ if (!(($this->defaultTimeLimit || $size !== TestUtil::UNKNOWN))) {
+ return false;
+ }
+
+ if (!extension_loaded('pcntl')) {
+ return false;
+ }
+
+ if (!class_exists(Invoker::class)) {
+ return false;
+ }
+
+ if (extension_loaded('xdebug') && xdebug_is_debugger_active()) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/TestSuite.php b/vendor/phpunit/phpunit/src/Framework/TestSuite.php
new file mode 100644
index 000000000..0bb81844b
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/TestSuite.php
@@ -0,0 +1,914 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_keys;
+use function array_map;
+use function array_merge;
+use function array_unique;
+use function basename;
+use function call_user_func;
+use function class_exists;
+use function count;
+use function dirname;
+use function get_declared_classes;
+use function implode;
+use function is_bool;
+use function is_callable;
+use function is_file;
+use function is_object;
+use function is_string;
+use function method_exists;
+use function preg_match;
+use function preg_quote;
+use function sprintf;
+use function strpos;
+use function substr;
+use Iterator;
+use IteratorAggregate;
+use PHPUnit\Runner\BaseTestRunner;
+use PHPUnit\Runner\Filter\Factory;
+use PHPUnit\Runner\PhptTestCase;
+use PHPUnit\Util\FileLoader;
+use PHPUnit\Util\Test as TestUtil;
+use ReflectionClass;
+use ReflectionException;
+use ReflectionMethod;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class TestSuite implements IteratorAggregate, Reorderable, SelfDescribing, Test
+{
+ /**
+ * Enable or disable the backup and restoration of the $GLOBALS array.
+ *
+ * @var bool
+ */
+ protected $backupGlobals;
+
+ /**
+ * Enable or disable the backup and restoration of static attributes.
+ *
+ * @var bool
+ */
+ protected $backupStaticAttributes;
+
+ /**
+ * @var bool
+ */
+ protected $runTestInSeparateProcess = false;
+
+ /**
+ * The name of the test suite.
+ *
+ * @var string
+ */
+ protected $name = '';
+
+ /**
+ * The test groups of the test suite.
+ *
+ * @psalm-var array<string,list<Test>>
+ */
+ protected $groups = [];
+
+ /**
+ * The tests in the test suite.
+ *
+ * @var Test[]
+ */
+ protected $tests = [];
+
+ /**
+ * The number of tests in the test suite.
+ *
+ * @var int
+ */
+ protected $numTests = -1;
+
+ /**
+ * @var bool
+ */
+ protected $testCase = false;
+
+ /**
+ * @var string[]
+ */
+ protected $foundClasses = [];
+
+ /**
+ * @var null|list<ExecutionOrderDependency>
+ */
+ protected $providedTests;
+
+ /**
+ * @var null|list<ExecutionOrderDependency>
+ */
+ protected $requiredTests;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutChangesToGlobalState;
+
+ /**
+ * @var Factory
+ */
+ private $iteratorFilter;
+
+ /**
+ * @var int
+ */
+ private $declaredClassesPointer;
+
+ /**
+ * @psalm-var array<int,string>
+ */
+ private $warnings = [];
+
+ /**
+ * Constructs a new TestSuite.
+ *
+ * - PHPUnit\Framework\TestSuite() constructs an empty TestSuite.
+ *
+ * - PHPUnit\Framework\TestSuite(ReflectionClass) constructs a
+ * TestSuite from the given class.
+ *
+ * - PHPUnit\Framework\TestSuite(ReflectionClass, String)
+ * constructs a TestSuite from the given class with the given
+ * name.
+ *
+ * - PHPUnit\Framework\TestSuite(String) either constructs a
+ * TestSuite from the given class (if the passed string is the
+ * name of an existing class) or constructs an empty TestSuite
+ * with the given name.
+ *
+ * @param ReflectionClass|string $theClass
+ *
+ * @throws Exception
+ */
+ public function __construct($theClass = '', string $name = '')
+ {
+ if (!is_string($theClass) && !$theClass instanceof ReflectionClass) {
+ throw InvalidArgumentException::create(
+ 1,
+ 'ReflectionClass object or string'
+ );
+ }
+
+ $this->declaredClassesPointer = count(get_declared_classes());
+
+ if (!$theClass instanceof ReflectionClass) {
+ if (class_exists($theClass, true)) {
+ if ($name === '') {
+ $name = $theClass;
+ }
+
+ try {
+ $theClass = new ReflectionClass($theClass);
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ } else {
+ $this->setName($theClass);
+
+ return;
+ }
+ }
+
+ if (!$theClass->isSubclassOf(TestCase::class)) {
+ $this->setName((string) $theClass);
+
+ return;
+ }
+
+ if ($name !== '') {
+ $this->setName($name);
+ } else {
+ $this->setName($theClass->getName());
+ }
+
+ $constructor = $theClass->getConstructor();
+
+ if ($constructor !== null &&
+ !$constructor->isPublic()) {
+ $this->addTest(
+ new WarningTestCase(
+ sprintf(
+ 'Class "%s" has no public constructor.',
+ $theClass->getName()
+ )
+ )
+ );
+
+ return;
+ }
+
+ foreach ($theClass->getMethods() as $method) {
+ if ($method->getDeclaringClass()->getName() === Assert::class) {
+ continue;
+ }
+
+ if ($method->getDeclaringClass()->getName() === TestCase::class) {
+ continue;
+ }
+
+ if (!TestUtil::isTestMethod($method)) {
+ continue;
+ }
+
+ $this->addTestMethod($theClass, $method);
+ }
+
+ if (empty($this->tests)) {
+ $this->addTest(
+ new WarningTestCase(
+ sprintf(
+ 'No tests found in class "%s".',
+ $theClass->getName()
+ )
+ )
+ );
+ }
+
+ $this->testCase = true;
+ }
+
+ /**
+ * Returns a string representation of the test suite.
+ */
+ public function toString(): string
+ {
+ return $this->getName();
+ }
+
+ /**
+ * Adds a test to the suite.
+ *
+ * @param array $groups
+ */
+ public function addTest(Test $test, $groups = []): void
+ {
+ try {
+ $class = new ReflectionClass($test);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if (!$class->isAbstract()) {
+ $this->tests[] = $test;
+ $this->clearCaches();
+
+ if ($test instanceof self && empty($groups)) {
+ $groups = $test->getGroups();
+ }
+
+ if ($this->containsOnlyVirtualGroups($groups)) {
+ $groups[] = 'default';
+ }
+
+ foreach ($groups as $group) {
+ if (!isset($this->groups[$group])) {
+ $this->groups[$group] = [$test];
+ } else {
+ $this->groups[$group][] = $test;
+ }
+ }
+
+ if ($test instanceof TestCase) {
+ $test->setGroups($groups);
+ }
+ }
+ }
+
+ /**
+ * Adds the tests from the given class to the suite.
+ *
+ * @psalm-param object|class-string $testClass
+ *
+ * @throws Exception
+ */
+ public function addTestSuite($testClass): void
+ {
+ if (!(is_object($testClass) || (is_string($testClass) && class_exists($testClass)))) {
+ throw InvalidArgumentException::create(
+ 1,
+ 'class name or object'
+ );
+ }
+
+ if (!is_object($testClass)) {
+ try {
+ $testClass = new ReflectionClass($testClass);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ if ($testClass instanceof self) {
+ $this->addTest($testClass);
+ } elseif ($testClass instanceof ReflectionClass) {
+ $suiteMethod = false;
+
+ if (!$testClass->isAbstract() && $testClass->hasMethod(BaseTestRunner::SUITE_METHODNAME)) {
+ try {
+ $method = $testClass->getMethod(
+ BaseTestRunner::SUITE_METHODNAME
+ );
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if ($method->isStatic()) {
+ $this->addTest(
+ $method->invoke(null, $testClass->getName())
+ );
+
+ $suiteMethod = true;
+ }
+ }
+
+ if (!$suiteMethod && !$testClass->isAbstract() && $testClass->isSubclassOf(TestCase::class)) {
+ $this->addTest(new self($testClass));
+ }
+ } else {
+ throw new Exception;
+ }
+ }
+
+ public function addWarning(string $warning): void
+ {
+ $this->warnings[] = $warning;
+ }
+
+ /**
+ * Wraps both <code>addTest()</code> and <code>addTestSuite</code>
+ * 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 <code>PHPUnit\Framework\WarningTestCase</code> will be created instead,
+ * leaving the current test run untouched.
+ *
+ * @throws Exception
+ */
+ public function addTestFile(string $filename): void
+ {
+ if (is_file($filename) && substr($filename, -5) === '.phpt') {
+ $this->addTest(new PhptTestCase($filename));
+
+ $this->declaredClassesPointer = count(get_declared_classes());
+
+ return;
+ }
+
+ $numTests = count($this->tests);
+
+ // The given file may contain further stub classes in addition to the
+ // test class itself. Figure out the actual test class.
+ $filename = FileLoader::checkAndLoad($filename);
+ $newClasses = array_slice(get_declared_classes(), $this->declaredClassesPointer);
+
+ // The diff is empty in case a parent class (with test methods) is added
+ // AFTER a child class that inherited from it. To account for that case,
+ // accumulate all discovered classes, so the parent class may be found in
+ // a later invocation.
+ if (!empty($newClasses)) {
+ // On the assumption that test classes are defined first in files,
+ // process discovered classes in approximate LIFO order, so as to
+ // avoid unnecessary reflection.
+ $this->foundClasses = array_merge($newClasses, $this->foundClasses);
+ $this->declaredClassesPointer = count(get_declared_classes());
+ }
+
+ // The test class's name must match the filename, either in full, or as
+ // a PEAR/PSR-0 prefixed short name ('NameSpace_ShortName'), or as a
+ // PSR-1 local short name ('NameSpace\ShortName'). The comparison must be
+ // anchored to prevent false-positive matches (e.g., 'OtherShortName').
+ $shortName = basename($filename, '.php');
+ $shortNameRegEx = '/(?:^|_|\\\\)' . preg_quote($shortName, '/') . '$/';
+
+ foreach ($this->foundClasses as $i => $className) {
+ if (preg_match($shortNameRegEx, $className)) {
+ try {
+ $class = new ReflectionClass($className);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if ($class->getFileName() == $filename) {
+ $newClasses = [$className];
+ unset($this->foundClasses[$i]);
+
+ break;
+ }
+ }
+ }
+
+ foreach ($newClasses as $className) {
+ try {
+ $class = new ReflectionClass($className);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if (dirname($class->getFileName()) === __DIR__) {
+ continue;
+ }
+
+ if (!$class->isAbstract()) {
+ if ($class->hasMethod(BaseTestRunner::SUITE_METHODNAME)) {
+ try {
+ $method = $class->getMethod(
+ BaseTestRunner::SUITE_METHODNAME
+ );
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if ($method->isStatic()) {
+ $this->addTest($method->invoke(null, $className));
+ }
+ } elseif ($class->implementsInterface(Test::class)) {
+ $expectedClassName = $shortName;
+
+ if (($pos = strpos($expectedClassName, '.')) !== false) {
+ $expectedClassName = substr(
+ $expectedClassName,
+ 0,
+ $pos
+ );
+ }
+
+ if ($class->getShortName() !== $expectedClassName) {
+ $this->addWarning(
+ sprintf(
+ "Test case class not matching filename is deprecated\n in %s\n Class name was '%s', expected '%s'",
+ $filename,
+ $class->getShortName(),
+ $expectedClassName
+ )
+ );
+ }
+
+ $this->addTestSuite($class);
+ }
+ }
+ }
+
+ if (count($this->tests) > ++$numTests) {
+ $this->addWarning(
+ sprintf(
+ "Multiple test case classes per file is deprecated\n in %s",
+ $filename
+ )
+ );
+ }
+
+ $this->numTests = -1;
+ }
+
+ /**
+ * Wrapper for addTestFile() that adds multiple test files.
+ *
+ * @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.
+ *
+ * @todo refactor usage of numTests in DefaultResultPrinter
+ */
+ public function count(): int
+ {
+ $this->numTests = 0;
+
+ foreach ($this as $test) {
+ $this->numTests += count($test);
+ }
+
+ return $this->numTests;
+ }
+
+ /**
+ * Returns the name of the suite.
+ */
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ /**
+ * Returns the test groups of the suite.
+ *
+ * @psalm-return list<string>
+ */
+ public function getGroups(): array
+ {
+ return array_map(
+ static function ($key): string
+ {
+ return (string) $key;
+ },
+ array_keys($this->groups)
+ );
+ }
+
+ public function getGroupDetails(): array
+ {
+ return $this->groups;
+ }
+
+ /**
+ * Set tests groups of the test case.
+ */
+ public function setGroupDetails(array $groups): void
+ {
+ $this->groups = $groups;
+ }
+
+ /**
+ * Runs the tests and collects their result in a TestResult.
+ *
+ * @throws \PHPUnit\Framework\CodeCoverageException
+ * @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
+ * @throws \SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Warning
+ */
+ public function run(TestResult $result = null): TestResult
+ {
+ if ($result === null) {
+ $result = $this->createResult();
+ }
+
+ if (count($this) === 0) {
+ return $result;
+ }
+
+ /** @psalm-var class-string $className */
+ $className = $this->name;
+ $hookMethods = TestUtil::getHookMethods($className);
+
+ $result->startTestSuite($this);
+
+ $test = null;
+
+ if ($this->testCase && class_exists($this->name, false)) {
+ try {
+ foreach ($hookMethods['beforeClass'] as $beforeClassMethod) {
+ if (method_exists($this->name, $beforeClassMethod)) {
+ if ($missingRequirements = TestUtil::getMissingRequirements($this->name, $beforeClassMethod)) {
+ $this->markTestSuiteSkipped(implode(PHP_EOL, $missingRequirements));
+ }
+
+ call_user_func([$this->name, $beforeClassMethod]);
+ }
+ }
+ } catch (SkippedTestSuiteError $error) {
+ foreach ($this->tests() as $test) {
+ $result->startTest($test);
+ $result->addFailure($test, $error, 0);
+ $result->endTest($test, 0);
+ }
+
+ $result->endTestSuite($this);
+
+ return $result;
+ } catch (Throwable $t) {
+ $errorAdded = false;
+
+ foreach ($this->tests() as $test) {
+ if ($result->shouldStop()) {
+ break;
+ }
+
+ $result->startTest($test);
+
+ if (!$errorAdded) {
+ $result->addError($test, $t, 0);
+
+ $errorAdded = true;
+ } else {
+ $result->addFailure(
+ $test,
+ new SkippedTestError('Test skipped because of an error in hook method'),
+ 0
+ );
+ }
+
+ $result->endTest($test, 0);
+ }
+
+ $result->endTestSuite($this);
+
+ return $result;
+ }
+ }
+
+ foreach ($this as $test) {
+ if ($result->shouldStop()) {
+ break;
+ }
+
+ if ($test instanceof TestCase || $test instanceof self) {
+ $test->setBeStrictAboutChangesToGlobalState($this->beStrictAboutChangesToGlobalState);
+ $test->setBackupGlobals($this->backupGlobals);
+ $test->setBackupStaticAttributes($this->backupStaticAttributes);
+ $test->setRunTestInSeparateProcess($this->runTestInSeparateProcess);
+ }
+
+ $test->run($result);
+ }
+
+ if ($this->testCase && class_exists($this->name, false)) {
+ foreach ($hookMethods['afterClass'] as $afterClassMethod) {
+ if (method_exists($this->name, $afterClassMethod)) {
+ try {
+ call_user_func([$this->name, $afterClassMethod]);
+ } catch (Throwable $t) {
+ $message = "Exception in {$this->name}::{$afterClassMethod}" . PHP_EOL . $t->getMessage();
+ $error = new SyntheticError($message, 0, $t->getFile(), $t->getLine(), $t->getTrace());
+
+ $placeholderTest = clone $test;
+ $placeholderTest->setName($afterClassMethod);
+
+ $result->startTest($placeholderTest);
+ $result->addFailure($placeholderTest, $error, 0);
+ $result->endTest($placeholderTest, 0);
+ }
+ }
+ }
+ }
+
+ $result->endTestSuite($this);
+
+ return $result;
+ }
+
+ public function setRunTestInSeparateProcess(bool $runTestInSeparateProcess): void
+ {
+ $this->runTestInSeparateProcess = $runTestInSeparateProcess;
+ }
+
+ public function setName(string $name): void
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * Returns the tests as an enumeration.
+ *
+ * @return Test[]
+ */
+ public function tests(): array
+ {
+ return $this->tests;
+ }
+
+ /**
+ * Set tests of the test suite.
+ *
+ * @param Test[] $tests
+ */
+ public function setTests(array $tests): void
+ {
+ $this->tests = $tests;
+ }
+
+ /**
+ * Mark the test suite as skipped.
+ *
+ * @param string $message
+ *
+ * @throws SkippedTestSuiteError
+ *
+ * @psalm-return never-return
+ */
+ public function markTestSuiteSkipped($message = ''): void
+ {
+ throw new SkippedTestSuiteError($message);
+ }
+
+ /**
+ * @param bool $beStrictAboutChangesToGlobalState
+ */
+ public function setBeStrictAboutChangesToGlobalState($beStrictAboutChangesToGlobalState): void
+ {
+ if (null === $this->beStrictAboutChangesToGlobalState && is_bool($beStrictAboutChangesToGlobalState)) {
+ $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState;
+ }
+ }
+
+ /**
+ * @param bool $backupGlobals
+ */
+ public function setBackupGlobals($backupGlobals): void
+ {
+ if (null === $this->backupGlobals && is_bool($backupGlobals)) {
+ $this->backupGlobals = $backupGlobals;
+ }
+ }
+
+ /**
+ * @param bool $backupStaticAttributes
+ */
+ public function setBackupStaticAttributes($backupStaticAttributes): void
+ {
+ if (null === $this->backupStaticAttributes && is_bool($backupStaticAttributes)) {
+ $this->backupStaticAttributes = $backupStaticAttributes;
+ }
+ }
+
+ /**
+ * Returns an iterator for this test suite.
+ */
+ public function getIterator(): Iterator
+ {
+ $iterator = new 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);
+ }
+ }
+ }
+
+ /**
+ * @psalm-return array<int,string>
+ */
+ public function warnings(): array
+ {
+ return array_unique($this->warnings);
+ }
+
+ /**
+ * @return list<ExecutionOrderDependency>
+ */
+ public function provides(): array
+ {
+ if ($this->providedTests === null) {
+ $this->providedTests = [];
+
+ if (is_callable($this->sortId(), true)) {
+ $this->providedTests[] = new ExecutionOrderDependency($this->sortId());
+ }
+
+ foreach ($this->tests as $test) {
+ if (!($test instanceof Reorderable)) {
+ // @codeCoverageIgnoreStart
+ continue;
+ // @codeCoverageIgnoreEnd
+ }
+ $this->providedTests = ExecutionOrderDependency::mergeUnique($this->providedTests, $test->provides());
+ }
+ }
+
+ return $this->providedTests;
+ }
+
+ /**
+ * @return list<ExecutionOrderDependency>
+ */
+ public function requires(): array
+ {
+ if ($this->requiredTests === null) {
+ $this->requiredTests = [];
+
+ foreach ($this->tests as $test) {
+ if (!($test instanceof Reorderable)) {
+ // @codeCoverageIgnoreStart
+ continue;
+ // @codeCoverageIgnoreEnd
+ }
+ $this->requiredTests = ExecutionOrderDependency::mergeUnique(
+ ExecutionOrderDependency::filterInvalid($this->requiredTests),
+ $test->requires()
+ );
+ }
+
+ $this->requiredTests = ExecutionOrderDependency::diff($this->requiredTests, $this->provides());
+ }
+
+ return $this->requiredTests;
+ }
+
+ public function sortId(): string
+ {
+ return $this->getName() . '::class';
+ }
+
+ /**
+ * Creates a default TestResult object.
+ */
+ protected function createResult(): TestResult
+ {
+ return new TestResult;
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected function addTestMethod(ReflectionClass $class, ReflectionMethod $method): void
+ {
+ $methodName = $method->getName();
+
+ $test = (new TestBuilder)->build($class, $methodName);
+
+ if ($test instanceof TestCase || $test instanceof DataProviderTestSuite) {
+ $test->setDependencies(
+ TestUtil::getDependencies($class->getName(), $methodName)
+ );
+ }
+
+ $this->addTest(
+ $test,
+ TestUtil::getGroups($class->getName(), $methodName)
+ );
+ }
+
+ private function clearCaches(): void
+ {
+ $this->numTests = -1;
+ $this->providedTests = null;
+ $this->requiredTests = null;
+ }
+
+ private function containsOnlyVirtualGroups(array $groups): bool
+ {
+ foreach ($groups as $group) {
+ if (strpos($group, '__phpunit_') !== 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/TestSuiteIterator.php b/vendor/phpunit/phpunit/src/Framework/TestSuiteIterator.php
new file mode 100644
index 000000000..e351622f3
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/TestSuiteIterator.php
@@ -0,0 +1,83 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 count;
+use RecursiveIterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestSuiteIterator implements RecursiveIterator
+{
+ /**
+ * @var int
+ */
+ private $position = 0;
+
+ /**
+ * @var Test[]
+ */
+ private $tests;
+
+ public function __construct(TestSuite $testSuite)
+ {
+ $this->tests = $testSuite->tests();
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->tests);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): Test
+ {
+ return $this->tests[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+
+ /**
+ * @throws NoChildTestSuiteException
+ */
+ public function getChildren(): self
+ {
+ if (!$this->hasChildren()) {
+ throw new NoChildTestSuiteException(
+ 'The current item is not a TestSuite instance and therefore does not have any children.'
+ );
+ }
+
+ $current = $this->current();
+
+ assert($current instanceof TestSuite);
+
+ return new self($current);
+ }
+
+ public function hasChildren(): bool
+ {
+ return $this->valid() && $this->current() instanceof TestSuite;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Framework/WarningTestCase.php b/vendor/phpunit/phpunit/src/Framework/WarningTestCase.php
new file mode 100644
index 000000000..e1e41bc44
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Framework/WarningTestCase.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Framework;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class WarningTestCase extends TestCase
+{
+ /**
+ * @var bool
+ */
+ protected $backupGlobals = false;
+
+ /**
+ * @var bool
+ */
+ protected $backupStaticAttributes = false;
+
+ /**
+ * @var bool
+ */
+ protected $runTestInSeparateProcess = false;
+
+ /**
+ * @var string
+ */
+ private $message;
+
+ public function __construct(string $message = '')
+ {
+ $this->message = $message;
+
+ parent::__construct('Warning');
+ }
+
+ public function getMessage(): string
+ {
+ return $this->message;
+ }
+
+ /**
+ * Returns a string representation of the test case.
+ */
+ public function toString(): string
+ {
+ return 'Warning';
+ }
+
+ /**
+ * @throws Exception
+ *
+ * @psalm-return never-return
+ */
+ protected function runTest(): void
+ {
+ throw new Warning($this->message);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php b/vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php
new file mode 100644
index 000000000..75a70ca5f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php
@@ -0,0 +1,161 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+use function is_dir;
+use function is_file;
+use function substr;
+use PHPUnit\Framework\Exception;
+use PHPUnit\Framework\TestSuite;
+use ReflectionClass;
+use ReflectionException;
+use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+abstract class BaseTestRunner
+{
+ /**
+ * @var int
+ */
+ public const STATUS_UNKNOWN = -1;
+
+ /**
+ * @var int
+ */
+ public const STATUS_PASSED = 0;
+
+ /**
+ * @var int
+ */
+ public const STATUS_SKIPPED = 1;
+
+ /**
+ * @var int
+ */
+ public const STATUS_INCOMPLETE = 2;
+
+ /**
+ * @var int
+ */
+ public const STATUS_FAILURE = 3;
+
+ /**
+ * @var int
+ */
+ public const STATUS_ERROR = 4;
+
+ /**
+ * @var int
+ */
+ public const STATUS_RISKY = 5;
+
+ /**
+ * @var int
+ */
+ public const STATUS_WARNING = 6;
+
+ /**
+ * @var string
+ */
+ public const SUITE_METHODNAME = 'suite';
+
+ /**
+ * Returns the loader to be used.
+ */
+ public function getLoader(): TestSuiteLoader
+ {
+ return new StandardTestSuiteLoader;
+ }
+
+ /**
+ * Returns the Test corresponding to the given suite.
+ * This is a template method, subclasses override
+ * the runFailed() and clearStatus() methods.
+ *
+ * @param string|string[] $suffixes
+ *
+ * @throws Exception
+ */
+ public function getTest(string $suiteClassFile, $suffixes = ''): ?TestSuite
+ {
+ if (is_dir($suiteClassFile)) {
+ /** @var string[] $files */
+ $files = (new FileIteratorFacade)->getFilesAsArray(
+ $suiteClassFile,
+ $suffixes
+ );
+
+ $suite = new TestSuite($suiteClassFile);
+ $suite->addTestFiles($files);
+
+ return $suite;
+ }
+
+ if (is_file($suiteClassFile) && substr($suiteClassFile, -5, 5) === '.phpt') {
+ $suite = new TestSuite;
+ $suite->addTestFile($suiteClassFile);
+
+ return $suite;
+ }
+
+ try {
+ $testClass = $this->loadSuiteClass(
+ $suiteClassFile
+ );
+ } catch (\PHPUnit\Exception $e) {
+ $this->runFailed($e->getMessage());
+
+ return null;
+ }
+
+ try {
+ $suiteMethod = $testClass->getMethod(self::SUITE_METHODNAME);
+
+ if (!$suiteMethod->isStatic()) {
+ $this->runFailed(
+ 'suite() method must be static.'
+ );
+
+ return null;
+ }
+
+ $test = $suiteMethod->invoke(null, $testClass->getName());
+ } catch (ReflectionException $e) {
+ $test = new TestSuite($testClass);
+ }
+
+ $this->clearStatus();
+
+ return $test;
+ }
+
+ /**
+ * Returns the loaded ReflectionClass for a suite name.
+ */
+ protected function loadSuiteClass(string $suiteClassFile): ReflectionClass
+ {
+ return $this->getLoader()->load($suiteClassFile);
+ }
+
+ /**
+ * Clears the status message.
+ */
+ protected function clearStatus(): void
+ {
+ }
+
+ /**
+ * Override to define how to handle a failed loading of
+ * a test suite.
+ */
+ abstract protected function runFailed(string $message): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/DefaultTestResultCache.php b/vendor/phpunit/phpunit/src/Runner/DefaultTestResultCache.php
new file mode 100644
index 000000000..19278cc06
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/DefaultTestResultCache.php
@@ -0,0 +1,157 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+use const DIRECTORY_SEPARATOR;
+use const LOCK_EX;
+use function assert;
+use function dirname;
+use function file_get_contents;
+use function file_put_contents;
+use function in_array;
+use function is_array;
+use function is_dir;
+use function is_file;
+use function json_decode;
+use function json_encode;
+use PHPUnit\Util\Filesystem;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class DefaultTestResultCache implements TestResultCache
+{
+ /**
+ * @var int
+ */
+ private const VERSION = 1;
+
+ /**
+ * @psalm-var list<int>
+ */
+ private const ALLOWED_TEST_STATUSES = [
+ BaseTestRunner::STATUS_SKIPPED,
+ BaseTestRunner::STATUS_INCOMPLETE,
+ BaseTestRunner::STATUS_FAILURE,
+ BaseTestRunner::STATUS_ERROR,
+ BaseTestRunner::STATUS_RISKY,
+ BaseTestRunner::STATUS_WARNING,
+ ];
+
+ /**
+ * @var string
+ */
+ private const DEFAULT_RESULT_CACHE_FILENAME = '.phpunit.result.cache';
+
+ /**
+ * @var string
+ */
+ private $cacheFilename;
+
+ /**
+ * @psalm-var array<string, int>
+ */
+ private $defects = [];
+
+ /**
+ * @psalm-var array<string, float>
+ */
+ private $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 setState(string $testName, int $state): void
+ {
+ if (!in_array($state, self::ALLOWED_TEST_STATUSES, true)) {
+ return;
+ }
+
+ $this->defects[$testName] = $state;
+ }
+
+ public function getState(string $testName): int
+ {
+ return $this->defects[$testName] ?? BaseTestRunner::STATUS_UNKNOWN;
+ }
+
+ public function setTime(string $testName, float $time): void
+ {
+ $this->times[$testName] = $time;
+ }
+
+ public function getTime(string $testName): float
+ {
+ return $this->times[$testName] ?? 0.0;
+ }
+
+ public function load(): void
+ {
+ if (!is_file($this->cacheFilename)) {
+ return;
+ }
+
+ $data = json_decode(
+ file_get_contents($this->cacheFilename),
+ 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']));
+
+ $this->defects = $data['defects'];
+ $this->times = $data['times'];
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function persist(): void
+ {
+ if (!Filesystem::createDirectory(dirname($this->cacheFilename))) {
+ throw new Exception(
+ sprintf(
+ 'Cannot create directory "%s" for result cache file',
+ $this->cacheFilename
+ )
+ );
+ }
+
+ file_put_contents(
+ $this->cacheFilename,
+ json_encode(
+ [
+ 'version' => self::VERSION,
+ 'defects' => $this->defects,
+ 'times' => $this->times,
+ ]
+ ),
+ LOCK_EX
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Exception.php b/vendor/phpunit/phpunit/src/Runner/Exception.php
new file mode 100644
index 000000000..adcd11558
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Exception.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+use RuntimeException;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Exception extends RuntimeException implements \PHPUnit\Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Extension/ExtensionHandler.php b/vendor/phpunit/phpunit/src/Runner/Extension/ExtensionHandler.php
new file mode 100644
index 000000000..286f717ee
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Extension/ExtensionHandler.php
@@ -0,0 +1,117 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 class_exists;
+use function sprintf;
+use PHPUnit\Framework\TestListener;
+use PHPUnit\Runner\Exception;
+use PHPUnit\Runner\Hook;
+use PHPUnit\TextUI\TestRunner;
+use PHPUnit\TextUI\XmlConfiguration\Extension;
+use ReflectionClass;
+use ReflectionException;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ExtensionHandler
+{
+ /**
+ * @throws Exception
+ */
+ public function registerExtension(Extension $extensionConfiguration, TestRunner $runner): void
+ {
+ $extension = $this->createInstance($extensionConfiguration);
+
+ if (!$extension instanceof Hook) {
+ throw new Exception(
+ sprintf(
+ 'Class "%s" does not implement a PHPUnit\Runner\Hook interface',
+ $extensionConfiguration->className()
+ )
+ );
+ }
+
+ $runner->addExtension($extension);
+ }
+
+ /**
+ * @throws Exception
+ *
+ * @deprecated
+ */
+ public function createTestListenerInstance(Extension $listenerConfiguration): TestListener
+ {
+ $listener = $this->createInstance($listenerConfiguration);
+
+ if (!$listener instanceof TestListener) {
+ throw new Exception(
+ sprintf(
+ 'Class "%s" does not implement the PHPUnit\Framework\TestListener interface',
+ $listenerConfiguration->className()
+ )
+ );
+ }
+
+ return $listener;
+ }
+
+ /**
+ * @throws Exception
+ */
+ private function createInstance(Extension $extensionConfiguration): object
+ {
+ $this->ensureClassExists($extensionConfiguration);
+
+ try {
+ $reflector = new ReflectionClass($extensionConfiguration->className());
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+
+ if (!$extensionConfiguration->hasArguments()) {
+ return $reflector->newInstance();
+ }
+
+ return $reflector->newInstanceArgs($extensionConfiguration->arguments());
+ }
+
+ /**
+ * @throws Exception
+ */
+ private function ensureClassExists(Extension $extensionConfiguration): void
+ {
+ if (class_exists($extensionConfiguration->className(), false)) {
+ return;
+ }
+
+ if ($extensionConfiguration->hasSourceFile()) {
+ /**
+ * @noinspection PhpIncludeInspection
+ * @psalm-suppress UnresolvableInclude
+ */
+ require_once $extensionConfiguration->sourceFile();
+ }
+
+ if (!class_exists($extensionConfiguration->className())) {
+ throw new Exception(
+ sprintf(
+ 'Class "%s" does not exist',
+ $extensionConfiguration->className()
+ )
+ );
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Extension/PharLoader.php b/vendor/phpunit/phpunit/src/Runner/Extension/PharLoader.php
new file mode 100644
index 000000000..adc4cd77c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Extension/PharLoader.php
@@ -0,0 +1,75 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner\Extension;
+
+use PharIo\Manifest\ApplicationName;
+use PharIo\Manifest\Exception as ManifestException;
+use PharIo\Manifest\ManifestLoader;
+use PharIo\Version\Version as PharIoVersion;
+use PHPUnit\Runner\Version;
+use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class PharLoader
+{
+ /**
+ * @psalm-return array{loadedExtensions: list<string>, notLoadedExtensions: list<string>}
+ */
+ public function loadPharExtensionsInDirectory(string $directory): array
+ {
+ $loadedExtensions = [];
+ $notLoadedExtensions = [];
+
+ foreach ((new FileIteratorFacade)->getFilesAsArray($directory, '.phar') as $file) {
+ if (!is_file('phar://' . $file . '/manifest.xml')) {
+ $notLoadedExtensions[] = $file . ' is not an extension for PHPUnit';
+
+ continue;
+ }
+
+ try {
+ $applicationName = new ApplicationName('phpunit/phpunit');
+ $version = new PharIoVersion(Version::series());
+ $manifest = ManifestLoader::fromFile('phar://' . $file . '/manifest.xml');
+
+ if (!$manifest->isExtensionFor($applicationName)) {
+ $notLoadedExtensions[] = $file . ' is not an extension for PHPUnit';
+
+ continue;
+ }
+
+ if (!$manifest->isExtensionFor($applicationName, $version)) {
+ $notLoadedExtensions[] = $file . ' is not compatible with this version of PHPUnit';
+
+ continue;
+ }
+ } catch (ManifestException $e) {
+ $notLoadedExtensions[] = $file . ': ' . $e->getMessage();
+
+ continue;
+ }
+
+ /**
+ * @noinspection PhpIncludeInspection
+ * @psalm-suppress UnresolvableInclude
+ */
+ require $file;
+
+ $loadedExtensions[] = $manifest->getName()->asString() . ' ' . $manifest->getVersion()->getVersionString();
+ }
+
+ return [
+ 'loadedExtensions' => $loadedExtensions,
+ 'notLoadedExtensions' => $notLoadedExtensions,
+ ];
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Filter/ExcludeGroupFilterIterator.php b/vendor/phpunit/phpunit/src/Runner/Filter/ExcludeGroupFilterIterator.php
new file mode 100644
index 000000000..4b26e5716
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Filter/ExcludeGroupFilterIterator.php
@@ -0,0 +1,23 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ExcludeGroupFilterIterator extends GroupFilterIterator
+{
+ protected function doAccept(string $hash): bool
+ {
+ return !in_array($hash, $this->groupTests, true);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Filter/Factory.php b/vendor/phpunit/phpunit/src/Runner/Filter/Factory.php
new file mode 100644
index 000000000..3f79da541
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Filter/Factory.php
@@ -0,0 +1,61 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function sprintf;
+use FilterIterator;
+use Iterator;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Runner\Exception;
+use RecursiveFilterIterator;
+use ReflectionClass;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Factory
+{
+ /**
+ * @psalm-var array<int,array{0: \ReflectionClass, 1: array|string}>
+ */
+ private $filters = [];
+
+ /**
+ * @param array|string $args
+ *
+ * @throws Exception
+ */
+ public function addFilter(ReflectionClass $filter, $args): void
+ {
+ if (!$filter->isSubclassOf(RecursiveFilterIterator::class)) {
+ throw new Exception(
+ sprintf(
+ 'Class "%s" does not extend RecursiveFilterIterator',
+ $filter->name
+ )
+ );
+ }
+
+ $this->filters[] = [$filter, $args];
+ }
+
+ public function factory(Iterator $iterator, TestSuite $suite): FilterIterator
+ {
+ foreach ($this->filters as $filter) {
+ [$class, $args] = $filter;
+ $iterator = $class->newInstance($iterator, $args, $suite);
+ }
+
+ assert($iterator instanceof FilterIterator);
+
+ return $iterator;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Filter/GroupFilterIterator.php b/vendor/phpunit/phpunit/src/Runner/Filter/GroupFilterIterator.php
new file mode 100644
index 000000000..42ca77a38
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Filter/GroupFilterIterator.php
@@ -0,0 +1,58 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_map;
+use function array_merge;
+use function in_array;
+use function spl_object_hash;
+use PHPUnit\Framework\TestSuite;
+use RecursiveFilterIterator;
+use RecursiveIterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+abstract class GroupFilterIterator extends RecursiveFilterIterator
+{
+ /**
+ * @var string[]
+ */
+ protected $groupTests = [];
+
+ public function __construct(RecursiveIterator $iterator, array $groups, TestSuite $suite)
+ {
+ parent::__construct($iterator);
+
+ foreach ($suite->getGroupDetails() as $group => $tests) {
+ if (in_array((string) $group, $groups, true)) {
+ $testHashes = array_map(
+ 'spl_object_hash',
+ $tests
+ );
+
+ $this->groupTests = array_merge($this->groupTests, $testHashes);
+ }
+ }
+ }
+
+ public function accept(): bool
+ {
+ $test = $this->getInnerIterator()->current();
+
+ if ($test instanceof TestSuite) {
+ return true;
+ }
+
+ return $this->doAccept(spl_object_hash($test));
+ }
+
+ abstract protected function doAccept(string $hash);
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Filter/IncludeGroupFilterIterator.php b/vendor/phpunit/phpunit/src/Runner/Filter/IncludeGroupFilterIterator.php
new file mode 100644
index 000000000..0346c6013
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Filter/IncludeGroupFilterIterator.php
@@ -0,0 +1,23 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class IncludeGroupFilterIterator extends GroupFilterIterator
+{
+ protected function doAccept(string $hash): bool
+ {
+ return in_array($hash, $this->groupTests, true);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Filter/NameFilterIterator.php b/vendor/phpunit/phpunit/src/Runner/Filter/NameFilterIterator.php
new file mode 100644
index 000000000..7057e1c47
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Filter/NameFilterIterator.php
@@ -0,0 +1,136 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 implode;
+use function preg_match;
+use function sprintf;
+use function str_replace;
+use Exception;
+use PHPUnit\Framework\ErrorTestCase;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Framework\WarningTestCase;
+use PHPUnit\Util\RegularExpression;
+use RecursiveFilterIterator;
+use RecursiveIterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class NameFilterIterator extends RecursiveFilterIterator
+{
+ /**
+ * @var string
+ */
+ private $filter;
+
+ /**
+ * @var int
+ */
+ private $filterMin;
+
+ /**
+ * @var int
+ */
+ private $filterMax;
+
+ /**
+ * @throws Exception
+ */
+ public function __construct(RecursiveIterator $iterator, string $filter)
+ {
+ parent::__construct($iterator);
+
+ $this->setFilter($filter);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function accept(): bool
+ {
+ $test = $this->getInnerIterator()->current();
+
+ if ($test instanceof TestSuite) {
+ return true;
+ }
+
+ $tmp = \PHPUnit\Util\Test::describe($test);
+
+ if ($test instanceof ErrorTestCase || $test instanceof WarningTestCase) {
+ $name = $test->getMessage();
+ } elseif ($tmp[0] !== '') {
+ $name = implode('::', $tmp);
+ } else {
+ $name = $tmp[1];
+ }
+
+ $accepted = @preg_match($this->filter, $name, $matches);
+
+ if ($accepted && isset($this->filterMax)) {
+ $set = end($matches);
+ $accepted = $set >= $this->filterMin && $set <= $this->filterMax;
+ }
+
+ return (bool) $accepted;
+ }
+
+ /**
+ * @throws Exception
+ */
+ private function setFilter(string $filter): void
+ {
+ if (RegularExpression::safeMatch($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]
+ );
+
+ $this->filterMin = (int) $matches[2];
+ $this->filterMax = (int) $matches[3];
+ } else {
+ $filter = sprintf(
+ '%s.*with data set #%s$',
+ $matches[1],
+ $matches[2]
+ );
+ }
+ } // Handles:
+ // * testDetermineJsonError@JSON_ERROR_NONE
+ // * testDetermineJsonError@JSON.*
+ elseif (preg_match('/^(.*?)@(.+)$/', $filter, $matches)) {
+ $filter = sprintf(
+ '%s.*with data set "%s"$',
+ $matches[1],
+ $matches[2]
+ );
+ }
+
+ // Escape delimiters in regular expression. Do NOT use preg_quote,
+ // to keep magic characters.
+ $filter = sprintf(
+ '/%s/i',
+ str_replace(
+ '/',
+ '\\/',
+ $filter
+ )
+ );
+ }
+
+ $this->filter = $filter;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/AfterIncompleteTestHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/AfterIncompleteTestHook.php
new file mode 100644
index 000000000..432be9a93
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/AfterIncompleteTestHook.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface AfterIncompleteTestHook extends TestHook
+{
+ public function executeAfterIncompleteTest(string $test, string $message, float $time): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/AfterLastTestHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/AfterLastTestHook.php
new file mode 100644
index 000000000..eb789f264
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/AfterLastTestHook.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface AfterLastTestHook extends Hook
+{
+ public function executeAfterLastTest(): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/AfterRiskyTestHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/AfterRiskyTestHook.php
new file mode 100644
index 000000000..31cc91abf
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/AfterRiskyTestHook.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface AfterRiskyTestHook extends TestHook
+{
+ public function executeAfterRiskyTest(string $test, string $message, float $time): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/AfterSkippedTestHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/AfterSkippedTestHook.php
new file mode 100644
index 000000000..76980b3fc
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/AfterSkippedTestHook.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface AfterSkippedTestHook extends TestHook
+{
+ public function executeAfterSkippedTest(string $test, string $message, float $time): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/AfterSuccessfulTestHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/AfterSuccessfulTestHook.php
new file mode 100644
index 000000000..d0a10dd15
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/AfterSuccessfulTestHook.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface AfterSuccessfulTestHook extends TestHook
+{
+ public function executeAfterSuccessfulTest(string $test, float $time): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestErrorHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestErrorHook.php
new file mode 100644
index 000000000..12ecebd32
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestErrorHook.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface AfterTestErrorHook extends TestHook
+{
+ public function executeAfterTestError(string $test, string $message, float $time): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestFailureHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestFailureHook.php
new file mode 100644
index 000000000..94b2f3004
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestFailureHook.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface AfterTestFailureHook extends TestHook
+{
+ public function executeAfterTestFailure(string $test, string $message, float $time): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestHook.php
new file mode 100644
index 000000000..3d5bcaa93
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestHook.php
@@ -0,0 +1,30 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface AfterTestHook extends TestHook
+{
+ /**
+ * This hook will fire after any test, regardless of the result.
+ *
+ * For more fine grained control, have a look at the other hooks
+ * that extend PHPUnit\Runner\Hook.
+ */
+ public function executeAfterTest(string $test, float $time): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestWarningHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestWarningHook.php
new file mode 100644
index 000000000..860fcceeb
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/AfterTestWarningHook.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface AfterTestWarningHook extends TestHook
+{
+ public function executeAfterTestWarning(string $test, string $message, float $time): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/BeforeFirstTestHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/BeforeFirstTestHook.php
new file mode 100644
index 000000000..feeb90fba
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/BeforeFirstTestHook.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface BeforeFirstTestHook extends Hook
+{
+ public function executeBeforeFirstTest(): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/BeforeTestHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/BeforeTestHook.php
new file mode 100644
index 000000000..b7e0827d0
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/BeforeTestHook.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface BeforeTestHook extends TestHook
+{
+ public function executeBeforeTest(string $test): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/Hook.php b/vendor/phpunit/phpunit/src/Runner/Hook/Hook.php
new file mode 100644
index 000000000..a08dc72b0
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/Hook.php
@@ -0,0 +1,23 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface Hook
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/TestHook.php b/vendor/phpunit/phpunit/src/Runner/Hook/TestHook.php
new file mode 100644
index 000000000..31e880e2c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/TestHook.php
@@ -0,0 +1,23 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * This interface, as well as the associated mechanism for extending PHPUnit,
+ * will be removed in PHPUnit 10. There is no alternative available in this
+ * version of PHPUnit.
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/4676
+ */
+interface TestHook extends Hook
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Hook/TestListenerAdapter.php b/vendor/phpunit/phpunit/src/Runner/Hook/TestListenerAdapter.php
new file mode 100644
index 000000000..60fbfba31
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Hook/TestListenerAdapter.php
@@ -0,0 +1,141 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\Test;
+use PHPUnit\Framework\TestListener;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Framework\Warning;
+use PHPUnit\Util\Test as TestUtil;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestListenerAdapter implements TestListener
+{
+ /**
+ * @var TestHook[]
+ */
+ private $hooks = [];
+
+ /**
+ * @var bool
+ */
+ private $lastTestWasNotSuccessful;
+
+ public function add(TestHook $hook): void
+ {
+ $this->hooks[] = $hook;
+ }
+
+ public function startTest(Test $test): void
+ {
+ foreach ($this->hooks as $hook) {
+ if ($hook instanceof BeforeTestHook) {
+ $hook->executeBeforeTest(TestUtil::describeAsString($test));
+ }
+ }
+
+ $this->lastTestWasNotSuccessful = false;
+ }
+
+ public function addError(Test $test, Throwable $t, float $time): void
+ {
+ foreach ($this->hooks as $hook) {
+ if ($hook instanceof AfterTestErrorHook) {
+ $hook->executeAfterTestError(TestUtil::describeAsString($test), $t->getMessage(), $time);
+ }
+ }
+
+ $this->lastTestWasNotSuccessful = true;
+ }
+
+ public function addWarning(Test $test, Warning $e, float $time): void
+ {
+ foreach ($this->hooks as $hook) {
+ if ($hook instanceof AfterTestWarningHook) {
+ $hook->executeAfterTestWarning(TestUtil::describeAsString($test), $e->getMessage(), $time);
+ }
+ }
+
+ $this->lastTestWasNotSuccessful = true;
+ }
+
+ public function addFailure(Test $test, AssertionFailedError $e, float $time): void
+ {
+ foreach ($this->hooks as $hook) {
+ if ($hook instanceof AfterTestFailureHook) {
+ $hook->executeAfterTestFailure(TestUtil::describeAsString($test), $e->getMessage(), $time);
+ }
+ }
+
+ $this->lastTestWasNotSuccessful = true;
+ }
+
+ public function addIncompleteTest(Test $test, Throwable $t, float $time): void
+ {
+ foreach ($this->hooks as $hook) {
+ if ($hook instanceof AfterIncompleteTestHook) {
+ $hook->executeAfterIncompleteTest(TestUtil::describeAsString($test), $t->getMessage(), $time);
+ }
+ }
+
+ $this->lastTestWasNotSuccessful = true;
+ }
+
+ public function addRiskyTest(Test $test, Throwable $t, float $time): void
+ {
+ foreach ($this->hooks as $hook) {
+ if ($hook instanceof AfterRiskyTestHook) {
+ $hook->executeAfterRiskyTest(TestUtil::describeAsString($test), $t->getMessage(), $time);
+ }
+ }
+
+ $this->lastTestWasNotSuccessful = true;
+ }
+
+ public function addSkippedTest(Test $test, Throwable $t, float $time): void
+ {
+ foreach ($this->hooks as $hook) {
+ if ($hook instanceof AfterSkippedTestHook) {
+ $hook->executeAfterSkippedTest(TestUtil::describeAsString($test), $t->getMessage(), $time);
+ }
+ }
+
+ $this->lastTestWasNotSuccessful = true;
+ }
+
+ public function endTest(Test $test, float $time): void
+ {
+ if (!$this->lastTestWasNotSuccessful) {
+ foreach ($this->hooks as $hook) {
+ if ($hook instanceof AfterSuccessfulTestHook) {
+ $hook->executeAfterSuccessfulTest(TestUtil::describeAsString($test), $time);
+ }
+ }
+ }
+
+ foreach ($this->hooks as $hook) {
+ if ($hook instanceof AfterTestHook) {
+ $hook->executeAfterTest(TestUtil::describeAsString($test), $time);
+ }
+ }
+ }
+
+ public function startTestSuite(TestSuite $suite): void
+ {
+ }
+
+ public function endTestSuite(TestSuite $suite): void
+ {
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/NullTestResultCache.php b/vendor/phpunit/phpunit/src/Runner/NullTestResultCache.php
new file mode 100644
index 000000000..2aa86534a
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/NullTestResultCache.php
@@ -0,0 +1,42 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class NullTestResultCache implements TestResultCache
+{
+ public function setState(string $testName, int $state): void
+ {
+ }
+
+ public function getState(string $testName): int
+ {
+ return BaseTestRunner::STATUS_UNKNOWN;
+ }
+
+ public function setTime(string $testName, float $time): void
+ {
+ }
+
+ public function getTime(string $testName): float
+ {
+ return 0;
+ }
+
+ public function load(): void
+ {
+ }
+
+ public function persist(): void
+ {
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/PhptTestCase.php b/vendor/phpunit/phpunit/src/Runner/PhptTestCase.php
new file mode 100644
index 000000000..6590102d7
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/PhptTestCase.php
@@ -0,0 +1,864 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 DIRECTORY_SEPARATOR;
+use function array_merge;
+use function basename;
+use function debug_backtrace;
+use function defined;
+use function dirname;
+use function explode;
+use function extension_loaded;
+use function file;
+use function file_get_contents;
+use function file_put_contents;
+use function is_array;
+use function is_file;
+use function is_readable;
+use function is_string;
+use function ltrim;
+use function phpversion;
+use function preg_match;
+use function preg_replace;
+use function preg_split;
+use function realpath;
+use function rtrim;
+use function sprintf;
+use function str_replace;
+use function strncasecmp;
+use function strpos;
+use function substr;
+use function trim;
+use function unlink;
+use function unserialize;
+use function var_export;
+use function version_compare;
+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\SkippedTestError;
+use PHPUnit\Framework\SyntheticSkippedError;
+use PHPUnit\Framework\Test;
+use PHPUnit\Framework\TestResult;
+use PHPUnit\Util\PHP\AbstractPhpProcess;
+use SebastianBergmann\CodeCoverage\RawCodeCoverageData;
+use SebastianBergmann\Template\Template;
+use SebastianBergmann\Timer\Timer;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class PhptTestCase implements Reorderable, SelfDescribing, Test
+{
+ /**
+ * @var string
+ */
+ private $filename;
+
+ /**
+ * @var AbstractPhpProcess
+ */
+ private $phpUtil;
+
+ /**
+ * @var string
+ */
+ private $output = '';
+
+ /**
+ * Constructs a test case with the given filename.
+ *
+ * @throws Exception
+ */
+ public function __construct(string $filename, AbstractPhpProcess $phpUtil = null)
+ {
+ if (!is_file($filename)) {
+ throw new Exception(
+ sprintf(
+ 'File "%s" does not exist.',
+ $filename
+ )
+ );
+ }
+
+ $this->filename = $filename;
+ $this->phpUtil = $phpUtil ?: AbstractPhpProcess::factory();
+ }
+
+ /**
+ * Counts the number of test cases executed by run(TestResult result).
+ */
+ public function count(): int
+ {
+ return 1;
+ }
+
+ /**
+ * Runs a test and collects its result in a TestResult instance.
+ *
+ * @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
+ * @throws \SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ */
+ public function run(TestResult $result = null): TestResult
+ {
+ if ($result === null) {
+ $result = new TestResult;
+ }
+
+ try {
+ $sections = $this->parse();
+ } catch (Exception $e) {
+ $result->startTest($this);
+ $result->addFailure($this, new SkippedTestError($e->getMessage()), 0);
+ $result->endTest($this, 0);
+
+ return $result;
+ }
+
+ $code = $this->render($sections['FILE']);
+ $xfail = false;
+ $settings = $this->parseIniSection($this->settings($result->getCollectCodeCoverageInformation()));
+
+ $result->startTest($this);
+
+ if (isset($sections['INI'])) {
+ $settings = $this->parseIniSection($sections['INI'], $settings);
+ }
+
+ if (isset($sections['ENV'])) {
+ $env = $this->parseEnvSection($sections['ENV']);
+ $this->phpUtil->setEnv($env);
+ }
+
+ $this->phpUtil->setUseStderrRedirection(true);
+
+ if ($result->enforcesTimeLimit()) {
+ $this->phpUtil->setTimeout($result->getTimeoutForLargeTests());
+ }
+
+ $skip = $this->runSkip($sections, $result, $settings);
+
+ if ($skip) {
+ return $result;
+ }
+
+ if (isset($sections['XFAIL'])) {
+ $xfail = trim($sections['XFAIL']);
+ }
+
+ if (isset($sections['STDIN'])) {
+ $this->phpUtil->setStdin($sections['STDIN']);
+ }
+
+ if (isset($sections['ARGS'])) {
+ $this->phpUtil->setArgs($sections['ARGS']);
+ }
+
+ if ($result->getCollectCodeCoverageInformation()) {
+ $codeCoverageCacheDirectory = null;
+ $pathCoverage = false;
+
+ $codeCoverage = $result->getCodeCoverage();
+
+ if ($codeCoverage) {
+ if ($codeCoverage->cachesStaticAnalysis()) {
+ $codeCoverageCacheDirectory = $codeCoverage->cacheDirectory();
+ }
+
+ $pathCoverage = $codeCoverage->collectsBranchAndPathCoverage();
+ }
+
+ $this->renderForCoverage($code, $pathCoverage, $codeCoverageCacheDirectory);
+ }
+
+ $timer = new Timer;
+ $timer->start();
+
+ $jobResult = $this->phpUtil->runJob($code, $this->stringifyIni($settings));
+ $time = $timer->stop()->asSeconds();
+ $this->output = $jobResult['stdout'] ?? '';
+
+ if (isset($codeCoverage) && ($coverage = $this->cleanupForCoverage())) {
+ $codeCoverage->append($coverage, $this, true, [], []);
+ }
+
+ try {
+ $this->assertPhptExpectation($sections, $this->output);
+ } catch (AssertionFailedError $e) {
+ $failure = $e;
+
+ if ($xfail !== false) {
+ $failure = new IncompleteTestError($xfail, 0, $e);
+ } elseif ($e instanceof ExpectationFailedException) {
+ $comparisonFailure = $e->getComparisonFailure();
+
+ if ($comparisonFailure) {
+ $diff = $comparisonFailure->getDiff();
+ } else {
+ $diff = $e->getMessage();
+ }
+
+ $hint = $this->getLocationHintFromDiff($diff, $sections);
+ $trace = array_merge($hint, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
+ $failure = new PHPTAssertionFailedError(
+ $e->getMessage(),
+ 0,
+ $trace[0]['file'],
+ $trace[0]['line'],
+ $trace,
+ $comparisonFailure ? $diff : ''
+ );
+ }
+
+ $result->addFailure($this, $failure, $time);
+ } catch (Throwable $t) {
+ $result->addError($this, $t, $time);
+ }
+
+ if ($xfail !== false && $result->allCompletelyImplemented()) {
+ $result->addFailure($this, new IncompleteTestError('XFAIL section but test passes'), $time);
+ }
+
+ $this->runClean($sections, $result->getCollectCodeCoverageInformation());
+
+ $result->endTest($this, $time);
+
+ return $result;
+ }
+
+ /**
+ * 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 usesDataProvider(): bool
+ {
+ return false;
+ }
+
+ public function getNumAssertions(): int
+ {
+ return 1;
+ }
+
+ public function getActualOutput(): string
+ {
+ return $this->output;
+ }
+
+ public function hasOutput(): bool
+ {
+ return !empty($this->output);
+ }
+
+ public function sortId(): string
+ {
+ return $this->filename;
+ }
+
+ /**
+ * @return list<ExecutionOrderDependency>
+ */
+ public function provides(): array
+ {
+ return [];
+ }
+
+ /**
+ * @return list<ExecutionOrderDependency>
+ */
+ public function requires(): array
+ {
+ return [];
+ }
+
+ /**
+ * Parse --INI-- section key value pairs and return as array.
+ *
+ * @param array|string $content
+ */
+ private function parseIniSection($content, array $ini = []): array
+ {
+ if (is_string($content)) {
+ $content = explode("\n", trim($content));
+ }
+
+ foreach ($content as $setting) {
+ if (strpos($setting, '=') === false) {
+ 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;
+ }
+
+ private function parseEnvSection(string $content): array
+ {
+ $env = [];
+
+ foreach (explode("\n", trim($content)) as $e) {
+ $e = explode('=', trim($e), 2);
+
+ if (!empty($e[0]) && isset($e[1])) {
+ $env[$e[0]] = $e[1];
+ }
+ }
+
+ return $env;
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @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;
+
+ if ($expected === '') {
+ throw new Exception('No PHPT expectation found');
+ }
+
+ Assert::$sectionAssertion($expected, $actual);
+
+ return;
+ }
+ }
+
+ throw new Exception('No PHPT assertion found');
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ private function runSkip(array &$sections, TestResult $result, array $settings): bool
+ {
+ if (!isset($sections['SKIPIF'])) {
+ return false;
+ }
+
+ $skipif = $this->render($sections['SKIPIF']);
+ $jobResult = $this->phpUtil->runJob($skipif, $this->stringifyIni($settings));
+
+ if (!strncasecmp('skip', ltrim($jobResult['stdout']), 4)) {
+ $message = '';
+
+ if (preg_match('/^\s*skip\s*(.+)\s*/i', $jobResult['stdout'], $skipMatch)) {
+ $message = substr($skipMatch[1], 2);
+ }
+
+ $hint = $this->getLocationHint($message, $sections, 'SKIPIF');
+ $trace = array_merge($hint, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
+ $result->addFailure(
+ $this,
+ new SyntheticSkippedError($message, 0, $trace[0]['file'], $trace[0]['line'], $trace),
+ 0
+ );
+ $result->endTest($this, 0);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private function runClean(array &$sections, bool $collectCoverage): void
+ {
+ $this->phpUtil->setStdin('');
+ $this->phpUtil->setArgs('');
+
+ if (isset($sections['CLEAN'])) {
+ $cleanCode = $this->render($sections['CLEAN']);
+
+ $this->phpUtil->runJob($cleanCode, $this->settings($collectCoverage));
+ }
+ }
+
+ /**
+ * @throws Exception
+ */
+ private function parse(): 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($this->filename) as $line) {
+ $lineNr++;
+
+ if (preg_match('/^--([_A-Z]+)--/', $line, $result)) {
+ $section = $result[1];
+ $sections[$section] = '';
+ $sections[$section . '_offset'] = $lineNr;
+
+ continue;
+ }
+
+ if (empty($section)) {
+ throw new Exception('Invalid PHPT file: empty section header');
+ }
+
+ $sections[$section] .= $line;
+ }
+
+ if (isset($sections['FILEEOF'])) {
+ $sections['FILE'] = rtrim($sections['FILEEOF'], "\r\n");
+ unset($sections['FILEEOF']);
+ }
+
+ $this->parseExternal($sections);
+
+ if (!$this->validate($sections)) {
+ throw new Exception('Invalid PHPT file');
+ }
+
+ foreach ($unsupportedSections as $section) {
+ if (isset($sections[$section])) {
+ throw new Exception(
+ "PHPUnit does not support PHPT {$section} sections"
+ );
+ }
+ }
+
+ return $sections;
+ }
+
+ /**
+ * @throws Exception
+ */
+ private function parseExternal(array &$sections): void
+ {
+ $allowSections = [
+ 'FILE',
+ 'EXPECT',
+ 'EXPECTF',
+ 'EXPECTREGEX',
+ ];
+ $testDirectory = dirname($this->filename) . 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 Exception(
+ sprintf(
+ 'Could not load --%s-- %s for PHPT file',
+ $section . '_EXTERNAL',
+ $testDirectory . $externalFilename
+ )
+ );
+ }
+
+ $sections[$section] = file_get_contents($testDirectory . $externalFilename);
+ }
+ }
+ }
+
+ private function validate(array &$sections): bool
+ {
+ $requiredSections = [
+ 'FILE',
+ [
+ 'EXPECT',
+ 'EXPECTF',
+ 'EXPECTREGEX',
+ ],
+ ];
+
+ foreach ($requiredSections as $section) {
+ if (is_array($section)) {
+ $foundSection = false;
+
+ foreach ($section as $anySection) {
+ if (isset($sections[$anySection])) {
+ $foundSection = true;
+
+ break;
+ }
+ }
+
+ if (!$foundSection) {
+ return false;
+ }
+
+ continue;
+ }
+
+ if (!isset($sections[$section])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private function render(string $code): string
+ {
+ return str_replace(
+ [
+ '__DIR__',
+ '__FILE__',
+ ],
+ [
+ "'" . dirname($this->filename) . "'",
+ "'" . $this->filename . "'",
+ ],
+ $code
+ );
+ }
+
+ private function getCoverageFiles(): array
+ {
+ $baseDir = dirname(realpath($this->filename)) . DIRECTORY_SEPARATOR;
+ $basename = basename($this->filename, 'phpt');
+
+ return [
+ 'coverage' => $baseDir . $basename . 'coverage',
+ 'job' => $baseDir . $basename . 'php',
+ ];
+ }
+
+ private function renderForCoverage(string &$job, bool $pathCoverage, ?string $codeCoverageCacheDirectory): void
+ {
+ $files = $this->getCoverageFiles();
+
+ $template = new Template(
+ __DIR__ . '/../Util/PHP/Template/PhptTestCase.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);
+ }
+
+ $globals = '';
+
+ if (!empty($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
+ $globals = '$GLOBALS[\'__PHPUNIT_BOOTSTRAP\'] = ' . var_export(
+ $GLOBALS['__PHPUNIT_BOOTSTRAP'],
+ true
+ ) . ";\n";
+ }
+
+ if ($codeCoverageCacheDirectory === null) {
+ $codeCoverageCacheDirectory = 'null';
+ } else {
+ $codeCoverageCacheDirectory = "'" . $codeCoverageCacheDirectory . "'";
+ }
+
+ $template->setVar(
+ [
+ 'composerAutoload' => $composerAutoload,
+ 'phar' => $phar,
+ 'globals' => $globals,
+ 'job' => $files['job'],
+ 'coverageFile' => $files['coverage'],
+ 'driverMethod' => $pathCoverage ? 'forLineAndPathCoverage' : 'forLineCoverage',
+ 'codeCoverageCacheDirectory' => $codeCoverageCacheDirectory,
+ ]
+ );
+
+ file_put_contents($files['job'], $job);
+
+ $job = $template->render();
+ }
+
+ private function cleanupForCoverage(): RawCodeCoverageData
+ {
+ $coverage = RawCodeCoverageData::fromXdebugWithoutPathCoverage([]);
+ $files = $this->getCoverageFiles();
+
+ if (is_file($files['coverage'])) {
+ $buffer = @file_get_contents($files['coverage']);
+
+ if ($buffer !== false) {
+ $coverage = @unserialize($buffer);
+
+ if ($coverage === false) {
+ $coverage = RawCodeCoverageData::fromXdebugWithoutPathCoverage([]);
+ }
+ }
+ }
+
+ foreach ($files as $file) {
+ @unlink($file);
+ }
+
+ return $coverage;
+ }
+
+ 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;
+ }
+
+ private function getLocationHintFromDiff(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 (strpos($line, '+') === 0) {
+ $needle = $this->getCleanDiffLine($previousLine);
+
+ break;
+ }
+
+ if (strpos($line, '-') === 0) {
+ $needle = $this->getCleanDiffLine($line);
+
+ break;
+ }
+ }
+
+ if (!empty($line)) {
+ $previousLine = $line;
+ }
+ }
+
+ return $this->getLocationHint($needle, $sections);
+ }
+
+ private function getCleanDiffLine(string $line): string
+ {
+ if (preg_match('/^[\-+]([\'\"]?)(.*)\1$/', $line, $matches)) {
+ $line = $matches[2];
+ }
+
+ return $line;
+ }
+
+ private function getLocationHint(string $needle, array $sections, ?string $sectionName = null): array
+ {
+ $needle = trim($needle);
+
+ if (empty($needle)) {
+ return [[
+ 'file' => realpath($this->filename),
+ 'line' => 1,
+ ]];
+ }
+
+ if ($sectionName) {
+ $search = [$sectionName];
+ } else {
+ $search = [
+ // 'FILE',
+ 'EXPECT',
+ 'EXPECTF',
+ 'EXPECTREGEX',
+ ];
+ }
+
+ $sectionOffset = null;
+
+ 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 (strpos($line, $needle) !== false) {
+ return [[
+ 'file' => realpath($this->filename),
+ 'line' => $offset,
+ ]];
+ }
+ $offset++;
+ }
+ }
+
+ if ($sectionName) {
+ // String not found in specified section, show user the start of the named section
+ return [[
+ 'file' => realpath($this->filename),
+ 'line' => $sectionOffset,
+ ]];
+ }
+
+ // No section specified, show user start of code
+ return [[
+ 'file' => realpath($this->filename),
+ 'line' => 1,
+ ]];
+ }
+
+ /**
+ * @psalm-return list<string>
+ */
+ 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_memleaks=0',
+ 'report_zend_debug=0',
+ ];
+
+ if (extension_loaded('pcov')) {
+ if ($collectCoverage) {
+ $settings[] = 'pcov.enabled=1';
+ } else {
+ $settings[] = 'pcov.enabled=0';
+ }
+ }
+
+ if (extension_loaded('xdebug')) {
+ if (version_compare(phpversion('xdebug'), '3', '>=')) {
+ if ($collectCoverage) {
+ $settings[] = 'xdebug.mode=coverage';
+ } else {
+ $settings[] = 'xdebug.mode=off';
+ }
+ } else {
+ $settings[] = 'xdebug.default_enable=0';
+
+ if ($collectCoverage) {
+ $settings[] = 'xdebug.coverage_enable=1';
+ }
+ }
+ }
+
+ return $settings;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/ResultCacheExtension.php b/vendor/phpunit/phpunit/src/Runner/ResultCacheExtension.php
new file mode 100644
index 000000000..31d7610e2
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/ResultCacheExtension.php
@@ -0,0 +1,110 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+use function preg_match;
+use function round;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ResultCacheExtension implements AfterIncompleteTestHook, AfterLastTestHook, AfterRiskyTestHook, AfterSkippedTestHook, AfterSuccessfulTestHook, AfterTestErrorHook, AfterTestFailureHook, AfterTestWarningHook
+{
+ /**
+ * @var TestResultCache
+ */
+ private $cache;
+
+ public function __construct(TestResultCache $cache)
+ {
+ $this->cache = $cache;
+ }
+
+ public function flush(): void
+ {
+ $this->cache->persist();
+ }
+
+ public function executeAfterSuccessfulTest(string $test, float $time): void
+ {
+ $testName = $this->getTestName($test);
+
+ $this->cache->setTime($testName, round($time, 3));
+ }
+
+ public function executeAfterIncompleteTest(string $test, string $message, float $time): void
+ {
+ $testName = $this->getTestName($test);
+
+ $this->cache->setTime($testName, round($time, 3));
+ $this->cache->setState($testName, BaseTestRunner::STATUS_INCOMPLETE);
+ }
+
+ public function executeAfterRiskyTest(string $test, string $message, float $time): void
+ {
+ $testName = $this->getTestName($test);
+
+ $this->cache->setTime($testName, round($time, 3));
+ $this->cache->setState($testName, BaseTestRunner::STATUS_RISKY);
+ }
+
+ public function executeAfterSkippedTest(string $test, string $message, float $time): void
+ {
+ $testName = $this->getTestName($test);
+
+ $this->cache->setTime($testName, round($time, 3));
+ $this->cache->setState($testName, BaseTestRunner::STATUS_SKIPPED);
+ }
+
+ public function executeAfterTestError(string $test, string $message, float $time): void
+ {
+ $testName = $this->getTestName($test);
+
+ $this->cache->setTime($testName, round($time, 3));
+ $this->cache->setState($testName, BaseTestRunner::STATUS_ERROR);
+ }
+
+ public function executeAfterTestFailure(string $test, string $message, float $time): void
+ {
+ $testName = $this->getTestName($test);
+
+ $this->cache->setTime($testName, round($time, 3));
+ $this->cache->setState($testName, BaseTestRunner::STATUS_FAILURE);
+ }
+
+ public function executeAfterTestWarning(string $test, string $message, float $time): void
+ {
+ $testName = $this->getTestName($test);
+
+ $this->cache->setTime($testName, round($time, 3));
+ $this->cache->setState($testName, BaseTestRunner::STATUS_WARNING);
+ }
+
+ public function executeAfterLastTest(): void
+ {
+ $this->flush();
+ }
+
+ /**
+ * @param string $test A long description format of the current test
+ *
+ * @return string The test name without TestSuiteClassName:: and @dataprovider details
+ */
+ private function getTestName(string $test): string
+ {
+ $matches = [];
+
+ if (preg_match('/^(?<name>\S+::\S+)(?:(?<dataname> with data set (?:#\d+|"[^"]+"))\s\()?/', $test, $matches)) {
+ $test = $matches['name'] . ($matches['dataname'] ?? '');
+ }
+
+ return $test;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php b/vendor/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php
new file mode 100644
index 000000000..f6de4e937
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php
@@ -0,0 +1,123 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_values;
+use function basename;
+use function class_exists;
+use function get_declared_classes;
+use function sprintf;
+use function stripos;
+use function strlen;
+use function substr;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Util\FileLoader;
+use ReflectionClass;
+use ReflectionException;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ *
+ * @deprecated see https://github.com/sebastianbergmann/phpunit/issues/4039
+ */
+final class StandardTestSuiteLoader implements TestSuiteLoader
+{
+ /**
+ * @throws Exception
+ */
+ public function load(string $suiteClassFile): ReflectionClass
+ {
+ $suiteClassName = basename($suiteClassFile, '.php');
+ $loadedClasses = get_declared_classes();
+
+ if (!class_exists($suiteClassName, false)) {
+ /* @noinspection UnusedFunctionResultInspection */
+ FileLoader::checkAndLoad($suiteClassFile);
+
+ $loadedClasses = array_values(
+ array_diff(get_declared_classes(), $loadedClasses)
+ );
+
+ if (empty($loadedClasses)) {
+ throw $this->exceptionFor($suiteClassName, $suiteClassFile);
+ }
+ }
+
+ if (!class_exists($suiteClassName, false)) {
+ // this block will handle namespaced classes
+ $offset = 0 - strlen($suiteClassName);
+
+ foreach ($loadedClasses as $loadedClass) {
+ if (stripos(substr($loadedClass, $offset - 1), '\\' . $suiteClassName) === 0) {
+ $suiteClassName = $loadedClass;
+
+ break;
+ }
+ }
+ }
+
+ if (!class_exists($suiteClassName, false)) {
+ throw $this->exceptionFor($suiteClassName, $suiteClassFile);
+ }
+
+ try {
+ $class = new ReflectionClass($suiteClassName);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if ($class->isSubclassOf(TestCase::class) && !$class->isAbstract()) {
+ return $class;
+ }
+
+ if ($class->hasMethod('suite')) {
+ try {
+ $method = $class->getMethod('suite');
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if (!$method->isAbstract() && $method->isPublic() && $method->isStatic()) {
+ return $class;
+ }
+ }
+
+ throw $this->exceptionFor($suiteClassName, $suiteClassFile);
+ }
+
+ public function reload(ReflectionClass $aClass): ReflectionClass
+ {
+ return $aClass;
+ }
+
+ private function exceptionFor(string $className, string $filename): Exception
+ {
+ return new Exception(
+ sprintf(
+ "Class '%s' could not be found in '%s'.",
+ $className,
+ $filename
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/TestResultCache.php b/vendor/phpunit/phpunit/src/Runner/TestResultCache.php
new file mode 100644
index 000000000..69e628289
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/TestResultCache.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface TestResultCache
+{
+ public function setState(string $testName, int $state): void;
+
+ public function getState(string $testName): int;
+
+ public function setTime(string $testName, float $time): void;
+
+ public function getTime(string $testName): float;
+
+ public function load(): void;
+
+ public function persist(): void;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/TestSuiteLoader.php b/vendor/phpunit/phpunit/src/Runner/TestSuiteLoader.php
new file mode 100644
index 000000000..c9d8e01b1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/TestSuiteLoader.php
@@ -0,0 +1,24 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Runner;
+
+use ReflectionClass;
+
+/**
+ * @deprecated see https://github.com/sebastianbergmann/phpunit/issues/4039
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+interface TestSuiteLoader
+{
+ public function load(string $suiteClassFile): ReflectionClass;
+
+ public function reload(ReflectionClass $aClass): ReflectionClass;
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/TestSuiteSorter.php b/vendor/phpunit/phpunit/src/Runner/TestSuiteSorter.php
new file mode 100644
index 000000000..64ad845cf
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/TestSuiteSorter.php
@@ -0,0 +1,394 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 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\Util\Test as TestUtil;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestSuiteSorter
+{
+ /**
+ * @var int
+ */
+ public const ORDER_DEFAULT = 0;
+
+ /**
+ * @var int
+ */
+ public const ORDER_RANDOMIZED = 1;
+
+ /**
+ * @var int
+ */
+ public const ORDER_REVERSED = 2;
+
+ /**
+ * @var int
+ */
+ public const ORDER_DEFECTS_FIRST = 3;
+
+ /**
+ * @var int
+ */
+ public const ORDER_DURATION = 4;
+
+ /**
+ * Order tests by @size annotation 'small', 'medium', 'large'.
+ *
+ * @var int
+ */
+ public const ORDER_SIZE = 5;
+
+ /**
+ * List of sorting weights for all test result codes. A higher number gives higher priority.
+ */
+ private const DEFECT_SORT_WEIGHT = [
+ BaseTestRunner::STATUS_ERROR => 6,
+ BaseTestRunner::STATUS_FAILURE => 5,
+ BaseTestRunner::STATUS_WARNING => 4,
+ BaseTestRunner::STATUS_INCOMPLETE => 3,
+ BaseTestRunner::STATUS_RISKY => 2,
+ BaseTestRunner::STATUS_SKIPPED => 1,
+ BaseTestRunner::STATUS_UNKNOWN => 0,
+ ];
+
+ private const SIZE_SORT_WEIGHT = [
+ TestUtil::SMALL => 1,
+ TestUtil::MEDIUM => 2,
+ TestUtil::LARGE => 3,
+ TestUtil::UNKNOWN => 4,
+ ];
+
+ /**
+ * @var array<string, int> Associative array of (string => DEFECT_SORT_WEIGHT) elements
+ */
+ private $defectSortOrder = [];
+
+ /**
+ * @var TestResultCache
+ */
+ private $cache;
+
+ /**
+ * @var array<string> A list of normalized names of tests before reordering
+ */
+ private $originalExecutionOrder = [];
+
+ /**
+ * @var array<string> A list of normalized names of tests affected by reordering
+ */
+ private $executionOrder = [];
+
+ public function __construct(?TestResultCache $cache = null)
+ {
+ $this->cache = $cache ?? new NullTestResultCache;
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ * @throws Exception
+ */
+ public function reorderTestsInSuite(Test $suite, int $order, bool $resolveDependencies, int $orderDefects, bool $isRootTestSuite = true): void
+ {
+ $allowedOrders = [
+ self::ORDER_DEFAULT,
+ self::ORDER_REVERSED,
+ self::ORDER_RANDOMIZED,
+ self::ORDER_DURATION,
+ self::ORDER_SIZE,
+ ];
+
+ if (!in_array($order, $allowedOrders, true)) {
+ throw new Exception(
+ '$order must be one of TestSuiteSorter::ORDER_[DEFAULT|REVERSED|RANDOMIZED|DURATION|SIZE]'
+ );
+ }
+
+ $allowedOrderDefects = [
+ self::ORDER_DEFAULT,
+ self::ORDER_DEFECTS_FIRST,
+ ];
+
+ if (!in_array($orderDefects, $allowedOrderDefects, true)) {
+ throw new Exception(
+ '$orderDefects must be one of TestSuiteSorter::ORDER_DEFAULT, TestSuiteSorter::ORDER_DEFECTS_FIRST'
+ );
+ }
+
+ if ($isRootTestSuite) {
+ $this->originalExecutionOrder = $this->calculateTestExecutionOrder($suite);
+ }
+
+ if ($suite instanceof TestSuite) {
+ foreach ($suite as $_suite) {
+ $this->reorderTestsInSuite($_suite, $order, $resolveDependencies, $orderDefects, false);
+ }
+
+ if ($orderDefects === self::ORDER_DEFECTS_FIRST) {
+ $this->addSuiteToDefectSortOrder($suite);
+ }
+
+ $this->sort($suite, $order, $resolveDependencies, $orderDefects);
+ }
+
+ if ($isRootTestSuite) {
+ $this->executionOrder = $this->calculateTestExecutionOrder($suite);
+ }
+ }
+
+ public function getOriginalExecutionOrder(): array
+ {
+ return $this->originalExecutionOrder;
+ }
+
+ public function getExecutionOrder(): array
+ {
+ return $this->executionOrder;
+ }
+
+ private function sort(TestSuite $suite, int $order, bool $resolveDependencies, int $orderDefects): void
+ {
+ if (empty($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 && $this->cache !== null) {
+ $suite->setTests($this->sortByDuration($suite->tests()));
+ } elseif ($order === self::ORDER_SIZE) {
+ $suite->setTests($this->sortBySize($suite->tests()));
+ }
+
+ if ($orderDefects === self::ORDER_DEFECTS_FIRST && $this->cache !== null) {
+ $suite->setTests($this->sortDefectsFirst($suite->tests()));
+ }
+
+ if ($resolveDependencies && !($suite instanceof DataProviderTestSuite)) {
+ /** @var TestCase[] $tests */
+ $tests = $suite->tests();
+
+ $suite->setTests($this->resolveDependencies($tests));
+ }
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ private function addSuiteToDefectSortOrder(TestSuite $suite): void
+ {
+ $max = 0;
+
+ foreach ($suite->tests() as $test) {
+ if (!$test instanceof Reorderable) {
+ continue;
+ }
+
+ if (!isset($this->defectSortOrder[$test->sortId()])) {
+ $this->defectSortOrder[$test->sortId()] = self::DEFECT_SORT_WEIGHT[$this->cache->getState($test->sortId())];
+ $max = max($max, $this->defectSortOrder[$test->sortId()]);
+ }
+ }
+
+ $this->defectSortOrder[$suite->sortId()] = $max;
+ }
+
+ private function reverse(array $tests): array
+ {
+ return array_reverse($tests);
+ }
+
+ private function randomize(array $tests): array
+ {
+ shuffle($tests);
+
+ return $tests;
+ }
+
+ private function sortDefectsFirst(array $tests): array
+ {
+ usort(
+ $tests,
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ function ($left, $right)
+ {
+ return $this->cmpDefectPriorityAndTime($left, $right);
+ }
+ );
+
+ return $tests;
+ }
+
+ private function sortByDuration(array $tests): array
+ {
+ usort(
+ $tests,
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ function ($left, $right)
+ {
+ return $this->cmpDuration($left, $right);
+ }
+ );
+
+ return $tests;
+ }
+
+ private function sortBySize(array $tests): array
+ {
+ usort(
+ $tests,
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ function ($left, $right)
+ {
+ return $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
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ private function cmpDefectPriorityAndTime(Test $a, Test $b): int
+ {
+ if (!($a instanceof Reorderable && $b instanceof Reorderable)) {
+ return 0;
+ }
+
+ $priorityA = $this->defectSortOrder[$a->sortId()] ?? 0;
+ $priorityB = $this->defectSortOrder[$b->sortId()] ?? 0;
+
+ if ($priorityB <=> $priorityA) {
+ // Sort defect weight descending
+ return $priorityB <=> $priorityA;
+ }
+
+ if ($priorityA || $priorityB) {
+ return $this->cmpDuration($a, $b);
+ }
+
+ // do not change execution order
+ return 0;
+ }
+
+ /**
+ * Compares test duration for sorting tests by duration ascending.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ private function cmpDuration(Test $a, Test $b): int
+ {
+ if (!($a instanceof Reorderable && $b instanceof Reorderable)) {
+ return 0;
+ }
+
+ return $this->cache->getTime($a->sortId()) <=> $this->cache->getTime($b->sortId());
+ }
+
+ /**
+ * 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->getSize()
+ : TestUtil::UNKNOWN;
+ $sizeB = ($b instanceof TestCase || $b instanceof DataProviderTestSuite)
+ ? $b->getSize()
+ : TestUtil::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<DataProviderTestSuite|TestCase> $tests
+ *
+ * @return array<DataProviderTestSuite|TestCase>
+ */
+ 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 (!empty($tests) && ($i < count($tests)));
+
+ return array_merge($newTestOrder, $tests);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ private function calculateTestExecutionOrder(Test $suite): array
+ {
+ $tests = [];
+
+ if ($suite instanceof TestSuite) {
+ foreach ($suite->tests() as $test) {
+ if (!$test instanceof TestSuite && $test instanceof Reorderable) {
+ $tests[] = $test->sortId();
+ } else {
+ $tests = array_merge($tests, $this->calculateTestExecutionOrder($test));
+ }
+ }
+ }
+
+ return $tests;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Runner/Version.php b/vendor/phpunit/phpunit/src/Runner/Version.php
new file mode 100644
index 000000000..4e9675209
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Runner/Version.php
@@ -0,0 +1,65 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 dirname;
+use function explode;
+use function implode;
+use function strpos;
+use SebastianBergmann\Version as VersionId;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class Version
+{
+ /**
+ * @var string
+ */
+ private static $pharVersion = '';
+
+ /**
+ * @var string
+ */
+ private static $version = '';
+
+ /**
+ * Returns the current version of PHPUnit.
+ */
+ public static function id(): string
+ {
+ if (self::$pharVersion !== '') {
+ return self::$pharVersion;
+ }
+
+ if (self::$version === '') {
+ self::$version = (new VersionId('9.5.16', dirname(__DIR__, 2)))->getVersion();
+ }
+
+ return self::$version;
+ }
+
+ public static function series(): string
+ {
+ if (strpos(self::id(), '-')) {
+ $version = explode('-', self::id())[0];
+ } else {
+ $version = self::id();
+ }
+
+ return implode('.', array_slice(explode('.', $version), 0, 2));
+ }
+
+ public static function getVersionString(): string
+ {
+ return 'PHPUnit ' . self::id() . ' by Sebastian Bergmann and contributors.';
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php b/vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php
new file mode 100644
index 000000000..7d5e1b5b4
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/CliArguments/Builder.php
@@ -0,0 +1,887 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 array_map;
+use function array_merge;
+use function class_exists;
+use function explode;
+use function is_numeric;
+use function str_replace;
+use PHPUnit\Runner\TestSuiteSorter;
+use PHPUnit\TextUI\DefaultResultPrinter;
+use PHPUnit\TextUI\XmlConfiguration\Extension;
+use PHPUnit\Util\Log\TeamCity;
+use PHPUnit\Util\TestDox\CliTestDoxPrinter;
+use SebastianBergmann\CliParser\Exception as CliParserException;
+use SebastianBergmann\CliParser\Parser as CliParser;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Builder
+{
+ private const LONG_OPTIONS = [
+ 'atleast-version=',
+ 'prepend=',
+ 'bootstrap=',
+ 'cache-result',
+ 'do-not-cache-result',
+ 'cache-result-file=',
+ 'check-version',
+ 'colors==',
+ 'columns=',
+ 'configuration=',
+ 'coverage-cache=',
+ 'warm-coverage-cache',
+ 'coverage-filter=',
+ 'coverage-clover=',
+ 'coverage-cobertura=',
+ 'coverage-crap4j=',
+ 'coverage-html=',
+ 'coverage-php=',
+ 'coverage-text==',
+ 'coverage-xml=',
+ 'path-coverage',
+ 'debug',
+ 'disallow-test-output',
+ 'disallow-resource-usage',
+ 'disallow-todo-tests',
+ 'default-time-limit=',
+ 'enforce-time-limit',
+ 'exclude-group=',
+ 'extensions=',
+ 'filter=',
+ 'generate-configuration',
+ 'globals-backup',
+ 'group=',
+ 'covers=',
+ 'uses=',
+ 'help',
+ 'resolve-dependencies',
+ 'ignore-dependencies',
+ 'include-path=',
+ 'list-groups',
+ 'list-suites',
+ 'list-tests',
+ 'list-tests-xml=',
+ 'loader=',
+ 'log-junit=',
+ 'log-teamcity=',
+ 'migrate-configuration',
+ 'no-configuration',
+ 'no-coverage',
+ 'no-logging',
+ 'no-interaction',
+ 'no-extensions',
+ 'order-by=',
+ 'printer=',
+ 'process-isolation',
+ 'repeat=',
+ 'dont-report-useless-tests',
+ 'random-order',
+ 'random-order-seed=',
+ 'reverse-order',
+ 'reverse-list',
+ 'static-backup',
+ 'stderr',
+ 'stop-on-defect',
+ 'stop-on-error',
+ 'stop-on-failure',
+ 'stop-on-warning',
+ 'stop-on-incomplete',
+ 'stop-on-risky',
+ 'stop-on-skipped',
+ 'fail-on-empty-test-suite',
+ 'fail-on-incomplete',
+ 'fail-on-risky',
+ 'fail-on-skipped',
+ 'fail-on-warning',
+ 'strict-coverage',
+ 'disable-coverage-ignore',
+ 'strict-global-state',
+ 'teamcity',
+ 'testdox',
+ 'testdox-group=',
+ 'testdox-exclude-group=',
+ 'testdox-html=',
+ 'testdox-text=',
+ 'testdox-xml=',
+ 'test-suffix=',
+ 'testsuite=',
+ 'verbose',
+ 'version',
+ 'whitelist=',
+ 'dump-xdebug-filter=',
+ ];
+
+ private const SHORT_OPTIONS = 'd:c:hv';
+
+ public function fromParameters(array $parameters, array $additionalLongOptions): Configuration
+ {
+ try {
+ $options = (new CliParser)->parse(
+ $parameters,
+ self::SHORT_OPTIONS,
+ array_merge(self::LONG_OPTIONS, $additionalLongOptions)
+ );
+ } catch (CliParserException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+
+ $argument = null;
+ $atLeastVersion = null;
+ $backupGlobals = null;
+ $backupStaticAttributes = null;
+ $beStrictAboutChangesToGlobalState = null;
+ $beStrictAboutResourceUsageDuringSmallTests = null;
+ $bootstrap = null;
+ $cacheResult = null;
+ $cacheResultFile = null;
+ $checkVersion = null;
+ $colors = null;
+ $columns = null;
+ $configuration = null;
+ $coverageCacheDirectory = null;
+ $warmCoverageCache = null;
+ $coverageFilter = null;
+ $coverageClover = null;
+ $coverageCobertura = null;
+ $coverageCrap4J = null;
+ $coverageHtml = null;
+ $coveragePhp = null;
+ $coverageText = null;
+ $coverageTextShowUncoveredFiles = null;
+ $coverageTextShowOnlySummary = null;
+ $coverageXml = null;
+ $pathCoverage = null;
+ $debug = null;
+ $defaultTimeLimit = null;
+ $disableCodeCoverageIgnore = null;
+ $disallowTestOutput = null;
+ $disallowTodoAnnotatedTests = null;
+ $enforceTimeLimit = null;
+ $excludeGroups = null;
+ $executionOrder = null;
+ $executionOrderDefects = null;
+ $extensions = [];
+ $unavailableExtensions = [];
+ $failOnEmptyTestSuite = null;
+ $failOnIncomplete = null;
+ $failOnRisky = null;
+ $failOnSkipped = null;
+ $failOnWarning = null;
+ $filter = null;
+ $generateConfiguration = null;
+ $migrateConfiguration = null;
+ $groups = null;
+ $testsCovering = null;
+ $testsUsing = null;
+ $help = null;
+ $includePath = null;
+ $iniSettings = [];
+ $junitLogfile = null;
+ $listGroups = null;
+ $listSuites = null;
+ $listTests = null;
+ $listTestsXml = null;
+ $loader = null;
+ $noCoverage = null;
+ $noExtensions = null;
+ $noInteraction = null;
+ $noLogging = null;
+ $printer = null;
+ $processIsolation = null;
+ $randomOrderSeed = null;
+ $repeat = null;
+ $reportUselessTests = null;
+ $resolveDependencies = null;
+ $reverseList = null;
+ $stderr = null;
+ $strictCoverage = null;
+ $stopOnDefect = null;
+ $stopOnError = null;
+ $stopOnFailure = null;
+ $stopOnIncomplete = null;
+ $stopOnRisky = null;
+ $stopOnSkipped = null;
+ $stopOnWarning = null;
+ $teamcityLogfile = null;
+ $testdoxExcludeGroups = null;
+ $testdoxGroups = null;
+ $testdoxHtmlFile = null;
+ $testdoxTextFile = null;
+ $testdoxXmlFile = null;
+ $testSuffixes = null;
+ $testSuite = null;
+ $unrecognizedOptions = [];
+ $unrecognizedOrderBy = null;
+ $useDefaultConfiguration = null;
+ $verbose = null;
+ $version = null;
+ $xdebugFilterFile = null;
+
+ if (isset($options[1][0])) {
+ $argument = $options[1][0];
+ }
+
+ foreach ($options[0] as $option) {
+ switch ($option[0]) {
+ case '--colors':
+ $colors = $option[1] ?: DefaultResultPrinter::COLOR_AUTO;
+
+ break;
+
+ case '--bootstrap':
+ $bootstrap = $option[1];
+
+ break;
+
+ case '--cache-result':
+ $cacheResult = true;
+
+ break;
+
+ case '--do-not-cache-result':
+ $cacheResult = false;
+
+ break;
+
+ case '--cache-result-file':
+ $cacheResultFile = $option[1];
+
+ 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 '--coverage-cache':
+ $coverageCacheDirectory = $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-text':
+ if ($option[1] === null) {
+ $option[1] = 'php://stdout';
+ }
+
+ $coverageText = $option[1];
+ $coverageTextShowUncoveredFiles = false;
+ $coverageTextShowOnlySummary = false;
+
+ break;
+
+ case '--coverage-xml':
+ $coverageXml = $option[1];
+
+ break;
+
+ case '--path-coverage':
+ $pathCoverage = true;
+
+ break;
+
+ case 'd':
+ $tmp = explode('=', $option[1]);
+
+ if (isset($tmp[0])) {
+ if (isset($tmp[1])) {
+ $iniSettings[$tmp[0]] = $tmp[1];
+ } else {
+ $iniSettings[$tmp[0]] = '1';
+ }
+ }
+
+ break;
+
+ case '--debug':
+ $debug = true;
+
+ break;
+
+ case 'h':
+ case '--help':
+ $help = true;
+
+ break;
+
+ case '--filter':
+ $filter = $option[1];
+
+ break;
+
+ case '--testsuite':
+ $testSuite = $option[1];
+
+ break;
+
+ case '--generate-configuration':
+ $generateConfiguration = true;
+
+ break;
+
+ case '--migrate-configuration':
+ $migrateConfiguration = true;
+
+ break;
+
+ case '--group':
+ $groups = explode(',', $option[1]);
+
+ break;
+
+ case '--exclude-group':
+ $excludeGroups = explode(',', $option[1]);
+
+ break;
+
+ case '--covers':
+ $testsCovering = array_map('strtolower', explode(',', $option[1]));
+
+ break;
+
+ case '--uses':
+ $testsUsing = array_map('strtolower', explode(',', $option[1]));
+
+ break;
+
+ case '--test-suffix':
+ $testSuffixes = explode(',', $option[1]);
+
+ break;
+
+ case '--include-path':
+ $includePath = $option[1];
+
+ break;
+
+ case '--list-groups':
+ $listGroups = true;
+
+ break;
+
+ case '--list-suites':
+ $listSuites = true;
+
+ break;
+
+ case '--list-tests':
+ $listTests = true;
+
+ break;
+
+ case '--list-tests-xml':
+ $listTestsXml = $option[1];
+
+ break;
+
+ case '--printer':
+ $printer = $option[1];
+
+ break;
+
+ case '--loader':
+ $loader = $option[1];
+
+ break;
+
+ case '--log-junit':
+ $junitLogfile = $option[1];
+
+ 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:
+ $unrecognizedOrderBy = $order;
+ }
+ }
+
+ break;
+
+ case '--process-isolation':
+ $processIsolation = true;
+
+ break;
+
+ case '--repeat':
+ $repeat = (int) $option[1];
+
+ break;
+
+ case '--stderr':
+ $stderr = true;
+
+ break;
+
+ case '--stop-on-defect':
+ $stopOnDefect = true;
+
+ break;
+
+ case '--stop-on-error':
+ $stopOnError = true;
+
+ break;
+
+ case '--stop-on-failure':
+ $stopOnFailure = true;
+
+ break;
+
+ case '--stop-on-warning':
+ $stopOnWarning = true;
+
+ break;
+
+ case '--stop-on-incomplete':
+ $stopOnIncomplete = true;
+
+ break;
+
+ case '--stop-on-risky':
+ $stopOnRisky = true;
+
+ break;
+
+ case '--stop-on-skipped':
+ $stopOnSkipped = true;
+
+ break;
+
+ case '--fail-on-empty-test-suite':
+ $failOnEmptyTestSuite = true;
+
+ break;
+
+ case '--fail-on-incomplete':
+ $failOnIncomplete = true;
+
+ break;
+
+ case '--fail-on-risky':
+ $failOnRisky = true;
+
+ break;
+
+ case '--fail-on-skipped':
+ $failOnSkipped = true;
+
+ break;
+
+ case '--fail-on-warning':
+ $failOnWarning = true;
+
+ break;
+
+ case '--teamcity':
+ $printer = TeamCity::class;
+
+ break;
+
+ case '--testdox':
+ $printer = CliTestDoxPrinter::class;
+
+ break;
+
+ case '--testdox-group':
+ $testdoxGroups = explode(',', $option[1]);
+
+ break;
+
+ case '--testdox-exclude-group':
+ $testdoxExcludeGroups = explode(',', $option[1]);
+
+ break;
+
+ case '--testdox-html':
+ $testdoxHtmlFile = $option[1];
+
+ break;
+
+ case '--testdox-text':
+ $testdoxTextFile = $option[1];
+
+ break;
+
+ case '--testdox-xml':
+ $testdoxXmlFile = $option[1];
+
+ break;
+
+ case '--no-configuration':
+ $useDefaultConfiguration = false;
+
+ break;
+
+ case '--extensions':
+ foreach (explode(',', $option[1]) as $extensionClass) {
+ if (!class_exists($extensionClass)) {
+ $unavailableExtensions[] = $extensionClass;
+
+ continue;
+ }
+
+ $extensions[] = new Extension($extensionClass, '', []);
+ }
+
+ break;
+
+ case '--no-extensions':
+ $noExtensions = true;
+
+ break;
+
+ case '--no-coverage':
+ $noCoverage = true;
+
+ break;
+
+ case '--no-logging':
+ $noLogging = true;
+
+ break;
+
+ case '--no-interaction':
+ $noInteraction = true;
+
+ break;
+
+ case '--globals-backup':
+ $backupGlobals = true;
+
+ break;
+
+ case '--static-backup':
+ $backupStaticAttributes = true;
+
+ break;
+
+ case 'v':
+ case '--verbose':
+ $verbose = true;
+
+ break;
+
+ case '--atleast-version':
+ $atLeastVersion = $option[1];
+
+ break;
+
+ case '--version':
+ $version = true;
+
+ break;
+
+ case '--dont-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 '--disallow-resource-usage':
+ $beStrictAboutResourceUsageDuringSmallTests = true;
+
+ break;
+
+ case '--default-time-limit':
+ $defaultTimeLimit = (int) $option[1];
+
+ break;
+
+ case '--enforce-time-limit':
+ $enforceTimeLimit = true;
+
+ break;
+
+ case '--disallow-todo-tests':
+ $disallowTodoAnnotatedTests = true;
+
+ break;
+
+ case '--reverse-list':
+ $reverseList = true;
+
+ break;
+
+ case '--check-version':
+ $checkVersion = true;
+
+ break;
+
+ case '--coverage-filter':
+ case '--whitelist':
+ if ($coverageFilter === null) {
+ $coverageFilter = [];
+ }
+
+ $coverageFilter[] = $option[1];
+
+ 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 '--dump-xdebug-filter':
+ $xdebugFilterFile = $option[1];
+
+ break;
+
+ default:
+ $unrecognizedOptions[str_replace('--', '', $option[0])] = $option[1];
+ }
+ }
+
+ if (empty($extensions)) {
+ $extensions = null;
+ }
+
+ if (empty($unavailableExtensions)) {
+ $unavailableExtensions = null;
+ }
+
+ if (empty($iniSettings)) {
+ $iniSettings = null;
+ }
+
+ if (empty($coverageFilter)) {
+ $coverageFilter = null;
+ }
+
+ return new Configuration(
+ $argument,
+ $atLeastVersion,
+ $backupGlobals,
+ $backupStaticAttributes,
+ $beStrictAboutChangesToGlobalState,
+ $beStrictAboutResourceUsageDuringSmallTests,
+ $bootstrap,
+ $cacheResult,
+ $cacheResultFile,
+ $checkVersion,
+ $colors,
+ $columns,
+ $configuration,
+ $coverageClover,
+ $coverageCobertura,
+ $coverageCrap4J,
+ $coverageHtml,
+ $coveragePhp,
+ $coverageText,
+ $coverageTextShowUncoveredFiles,
+ $coverageTextShowOnlySummary,
+ $coverageXml,
+ $pathCoverage,
+ $coverageCacheDirectory,
+ $warmCoverageCache,
+ $debug,
+ $defaultTimeLimit,
+ $disableCodeCoverageIgnore,
+ $disallowTestOutput,
+ $disallowTodoAnnotatedTests,
+ $enforceTimeLimit,
+ $excludeGroups,
+ $executionOrder,
+ $executionOrderDefects,
+ $extensions,
+ $unavailableExtensions,
+ $failOnEmptyTestSuite,
+ $failOnIncomplete,
+ $failOnRisky,
+ $failOnSkipped,
+ $failOnWarning,
+ $filter,
+ $generateConfiguration,
+ $migrateConfiguration,
+ $groups,
+ $testsCovering,
+ $testsUsing,
+ $help,
+ $includePath,
+ $iniSettings,
+ $junitLogfile,
+ $listGroups,
+ $listSuites,
+ $listTests,
+ $listTestsXml,
+ $loader,
+ $noCoverage,
+ $noExtensions,
+ $noInteraction,
+ $noLogging,
+ $printer,
+ $processIsolation,
+ $randomOrderSeed,
+ $repeat,
+ $reportUselessTests,
+ $resolveDependencies,
+ $reverseList,
+ $stderr,
+ $strictCoverage,
+ $stopOnDefect,
+ $stopOnError,
+ $stopOnFailure,
+ $stopOnIncomplete,
+ $stopOnRisky,
+ $stopOnSkipped,
+ $stopOnWarning,
+ $teamcityLogfile,
+ $testdoxExcludeGroups,
+ $testdoxGroups,
+ $testdoxHtmlFile,
+ $testdoxTextFile,
+ $testdoxXmlFile,
+ $testSuffixes,
+ $testSuite,
+ $unrecognizedOptions,
+ $unrecognizedOrderBy,
+ $useDefaultConfiguration,
+ $verbose,
+ $version,
+ $coverageFilter,
+ $xdebugFilterFile
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/CliArguments/Configuration.php b/vendor/phpunit/phpunit/src/TextUI/CliArguments/Configuration.php
new file mode 100644
index 000000000..b220dd7aa
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/CliArguments/Configuration.php
@@ -0,0 +1,2107 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\CliArguments;
+
+use PHPUnit\TextUI\XmlConfiguration\Extension;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Configuration
+{
+ /**
+ * @var ?string
+ */
+ private $argument;
+
+ /**
+ * @var ?string
+ */
+ private $atLeastVersion;
+
+ /**
+ * @var ?bool
+ */
+ private $backupGlobals;
+
+ /**
+ * @var ?bool
+ */
+ private $backupStaticAttributes;
+
+ /**
+ * @var ?bool
+ */
+ private $beStrictAboutChangesToGlobalState;
+
+ /**
+ * @var ?bool
+ */
+ private $beStrictAboutResourceUsageDuringSmallTests;
+
+ /**
+ * @var ?string
+ */
+ private $bootstrap;
+
+ /**
+ * @var ?bool
+ */
+ private $cacheResult;
+
+ /**
+ * @var ?string
+ */
+ private $cacheResultFile;
+
+ /**
+ * @var ?bool
+ */
+ private $checkVersion;
+
+ /**
+ * @var ?string
+ */
+ private $colors;
+
+ /**
+ * @var null|int|string
+ */
+ private $columns;
+
+ /**
+ * @var ?string
+ */
+ private $configuration;
+
+ /**
+ * @var null|string[]
+ */
+ private $coverageFilter;
+
+ /**
+ * @var ?string
+ */
+ private $coverageClover;
+
+ /**
+ * @var ?string
+ */
+ private $coverageCobertura;
+
+ /**
+ * @var ?string
+ */
+ private $coverageCrap4J;
+
+ /**
+ * @var ?string
+ */
+ private $coverageHtml;
+
+ /**
+ * @var ?string
+ */
+ private $coveragePhp;
+
+ /**
+ * @var ?string
+ */
+ private $coverageText;
+
+ /**
+ * @var ?bool
+ */
+ private $coverageTextShowUncoveredFiles;
+
+ /**
+ * @var ?bool
+ */
+ private $coverageTextShowOnlySummary;
+
+ /**
+ * @var ?string
+ */
+ private $coverageXml;
+
+ /**
+ * @var ?bool
+ */
+ private $pathCoverage;
+
+ /**
+ * @var ?string
+ */
+ private $coverageCacheDirectory;
+
+ /**
+ * @var ?bool
+ */
+ private $warmCoverageCache;
+
+ /**
+ * @var ?bool
+ */
+ private $debug;
+
+ /**
+ * @var ?int
+ */
+ private $defaultTimeLimit;
+
+ /**
+ * @var ?bool
+ */
+ private $disableCodeCoverageIgnore;
+
+ /**
+ * @var ?bool
+ */
+ private $disallowTestOutput;
+
+ /**
+ * @var ?bool
+ */
+ private $disallowTodoAnnotatedTests;
+
+ /**
+ * @var ?bool
+ */
+ private $enforceTimeLimit;
+
+ /**
+ * @var null|string[]
+ */
+ private $excludeGroups;
+
+ /**
+ * @var ?int
+ */
+ private $executionOrder;
+
+ /**
+ * @var ?int
+ */
+ private $executionOrderDefects;
+
+ /**
+ * @var null|Extension[]
+ */
+ private $extensions;
+
+ /**
+ * @var null|string[]
+ */
+ private $unavailableExtensions;
+
+ /**
+ * @var ?bool
+ */
+ private $failOnEmptyTestSuite;
+
+ /**
+ * @var ?bool
+ */
+ private $failOnIncomplete;
+
+ /**
+ * @var ?bool
+ */
+ private $failOnRisky;
+
+ /**
+ * @var ?bool
+ */
+ private $failOnSkipped;
+
+ /**
+ * @var ?bool
+ */
+ private $failOnWarning;
+
+ /**
+ * @var ?string
+ */
+ private $filter;
+
+ /**
+ * @var ?bool
+ */
+ private $generateConfiguration;
+
+ /**
+ * @var ?bool
+ */
+ private $migrateConfiguration;
+
+ /**
+ * @var null|string[]
+ */
+ private $groups;
+
+ /**
+ * @var null|string[]
+ */
+ private $testsCovering;
+
+ /**
+ * @var null|string[]
+ */
+ private $testsUsing;
+
+ /**
+ * @var ?bool
+ */
+ private $help;
+
+ /**
+ * @var ?string
+ */
+ private $includePath;
+
+ /**
+ * @var null|string[]
+ */
+ private $iniSettings;
+
+ /**
+ * @var ?string
+ */
+ private $junitLogfile;
+
+ /**
+ * @var ?bool
+ */
+ private $listGroups;
+
+ /**
+ * @var ?bool
+ */
+ private $listSuites;
+
+ /**
+ * @var ?bool
+ */
+ private $listTests;
+
+ /**
+ * @var ?string
+ */
+ private $listTestsXml;
+
+ /**
+ * @var ?string
+ */
+ private $loader;
+
+ /**
+ * @var ?bool
+ */
+ private $noCoverage;
+
+ /**
+ * @var ?bool
+ */
+ private $noExtensions;
+
+ /**
+ * @var ?bool
+ */
+ private $noInteraction;
+
+ /**
+ * @var ?bool
+ */
+ private $noLogging;
+
+ /**
+ * @var ?string
+ */
+ private $printer;
+
+ /**
+ * @var ?bool
+ */
+ private $processIsolation;
+
+ /**
+ * @var ?int
+ */
+ private $randomOrderSeed;
+
+ /**
+ * @var ?int
+ */
+ private $repeat;
+
+ /**
+ * @var ?bool
+ */
+ private $reportUselessTests;
+
+ /**
+ * @var ?bool
+ */
+ private $resolveDependencies;
+
+ /**
+ * @var ?bool
+ */
+ private $reverseList;
+
+ /**
+ * @var ?bool
+ */
+ private $stderr;
+
+ /**
+ * @var ?bool
+ */
+ private $strictCoverage;
+
+ /**
+ * @var ?bool
+ */
+ private $stopOnDefect;
+
+ /**
+ * @var ?bool
+ */
+ private $stopOnError;
+
+ /**
+ * @var ?bool
+ */
+ private $stopOnFailure;
+
+ /**
+ * @var ?bool
+ */
+ private $stopOnIncomplete;
+
+ /**
+ * @var ?bool
+ */
+ private $stopOnRisky;
+
+ /**
+ * @var ?bool
+ */
+ private $stopOnSkipped;
+
+ /**
+ * @var ?bool
+ */
+ private $stopOnWarning;
+
+ /**
+ * @var ?string
+ */
+ private $teamcityLogfile;
+
+ /**
+ * @var null|string[]
+ */
+ private $testdoxExcludeGroups;
+
+ /**
+ * @var null|string[]
+ */
+ private $testdoxGroups;
+
+ /**
+ * @var ?string
+ */
+ private $testdoxHtmlFile;
+
+ /**
+ * @var ?string
+ */
+ private $testdoxTextFile;
+
+ /**
+ * @var ?string
+ */
+ private $testdoxXmlFile;
+
+ /**
+ * @var null|string[]
+ */
+ private $testSuffixes;
+
+ /**
+ * @var ?string
+ */
+ private $testSuite;
+
+ /**
+ * @var string[]
+ */
+ private $unrecognizedOptions;
+
+ /**
+ * @var ?string
+ */
+ private $unrecognizedOrderBy;
+
+ /**
+ * @var ?bool
+ */
+ private $useDefaultConfiguration;
+
+ /**
+ * @var ?bool
+ */
+ private $verbose;
+
+ /**
+ * @var ?bool
+ */
+ private $version;
+
+ /**
+ * @var ?string
+ */
+ private $xdebugFilterFile;
+
+ /**
+ * @param null|int|string $columns
+ */
+ public function __construct(?string $argument, ?string $atLeastVersion, ?bool $backupGlobals, ?bool $backupStaticAttributes, ?bool $beStrictAboutChangesToGlobalState, ?bool $beStrictAboutResourceUsageDuringSmallTests, ?string $bootstrap, ?bool $cacheResult, ?string $cacheResultFile, ?bool $checkVersion, ?string $colors, $columns, ?string $configuration, ?string $coverageClover, ?string $coverageCobertura, ?string $coverageCrap4J, ?string $coverageHtml, ?string $coveragePhp, ?string $coverageText, ?bool $coverageTextShowUncoveredFiles, ?bool $coverageTextShowOnlySummary, ?string $coverageXml, ?bool $pathCoverage, ?string $coverageCacheDirectory, ?bool $warmCoverageCache, ?bool $debug, ?int $defaultTimeLimit, ?bool $disableCodeCoverageIgnore, ?bool $disallowTestOutput, ?bool $disallowTodoAnnotatedTests, ?bool $enforceTimeLimit, ?array $excludeGroups, ?int $executionOrder, ?int $executionOrderDefects, ?array $extensions, ?array $unavailableExtensions, ?bool $failOnEmptyTestSuite, ?bool $failOnIncomplete, ?bool $failOnRisky, ?bool $failOnSkipped, ?bool $failOnWarning, ?string $filter, ?bool $generateConfiguration, ?bool $migrateConfiguration, ?array $groups, ?array $testsCovering, ?array $testsUsing, ?bool $help, ?string $includePath, ?array $iniSettings, ?string $junitLogfile, ?bool $listGroups, ?bool $listSuites, ?bool $listTests, ?string $listTestsXml, ?string $loader, ?bool $noCoverage, ?bool $noExtensions, ?bool $noInteraction, ?bool $noLogging, ?string $printer, ?bool $processIsolation, ?int $randomOrderSeed, ?int $repeat, ?bool $reportUselessTests, ?bool $resolveDependencies, ?bool $reverseList, ?bool $stderr, ?bool $strictCoverage, ?bool $stopOnDefect, ?bool $stopOnError, ?bool $stopOnFailure, ?bool $stopOnIncomplete, ?bool $stopOnRisky, ?bool $stopOnSkipped, ?bool $stopOnWarning, ?string $teamcityLogfile, ?array $testdoxExcludeGroups, ?array $testdoxGroups, ?string $testdoxHtmlFile, ?string $testdoxTextFile, ?string $testdoxXmlFile, ?array $testSuffixes, ?string $testSuite, array $unrecognizedOptions, ?string $unrecognizedOrderBy, ?bool $useDefaultConfiguration, ?bool $verbose, ?bool $version, ?array $coverageFilter, ?string $xdebugFilterFile)
+ {
+ $this->argument = $argument;
+ $this->atLeastVersion = $atLeastVersion;
+ $this->backupGlobals = $backupGlobals;
+ $this->backupStaticAttributes = $backupStaticAttributes;
+ $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState;
+ $this->beStrictAboutResourceUsageDuringSmallTests = $beStrictAboutResourceUsageDuringSmallTests;
+ $this->bootstrap = $bootstrap;
+ $this->cacheResult = $cacheResult;
+ $this->cacheResultFile = $cacheResultFile;
+ $this->checkVersion = $checkVersion;
+ $this->colors = $colors;
+ $this->columns = $columns;
+ $this->configuration = $configuration;
+ $this->coverageFilter = $coverageFilter;
+ $this->coverageClover = $coverageClover;
+ $this->coverageCobertura = $coverageCobertura;
+ $this->coverageCrap4J = $coverageCrap4J;
+ $this->coverageHtml = $coverageHtml;
+ $this->coveragePhp = $coveragePhp;
+ $this->coverageText = $coverageText;
+ $this->coverageTextShowUncoveredFiles = $coverageTextShowUncoveredFiles;
+ $this->coverageTextShowOnlySummary = $coverageTextShowOnlySummary;
+ $this->coverageXml = $coverageXml;
+ $this->pathCoverage = $pathCoverage;
+ $this->coverageCacheDirectory = $coverageCacheDirectory;
+ $this->warmCoverageCache = $warmCoverageCache;
+ $this->debug = $debug;
+ $this->defaultTimeLimit = $defaultTimeLimit;
+ $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore;
+ $this->disallowTestOutput = $disallowTestOutput;
+ $this->disallowTodoAnnotatedTests = $disallowTodoAnnotatedTests;
+ $this->enforceTimeLimit = $enforceTimeLimit;
+ $this->excludeGroups = $excludeGroups;
+ $this->executionOrder = $executionOrder;
+ $this->executionOrderDefects = $executionOrderDefects;
+ $this->extensions = $extensions;
+ $this->unavailableExtensions = $unavailableExtensions;
+ $this->failOnEmptyTestSuite = $failOnEmptyTestSuite;
+ $this->failOnIncomplete = $failOnIncomplete;
+ $this->failOnRisky = $failOnRisky;
+ $this->failOnSkipped = $failOnSkipped;
+ $this->failOnWarning = $failOnWarning;
+ $this->filter = $filter;
+ $this->generateConfiguration = $generateConfiguration;
+ $this->migrateConfiguration = $migrateConfiguration;
+ $this->groups = $groups;
+ $this->testsCovering = $testsCovering;
+ $this->testsUsing = $testsUsing;
+ $this->help = $help;
+ $this->includePath = $includePath;
+ $this->iniSettings = $iniSettings;
+ $this->junitLogfile = $junitLogfile;
+ $this->listGroups = $listGroups;
+ $this->listSuites = $listSuites;
+ $this->listTests = $listTests;
+ $this->listTestsXml = $listTestsXml;
+ $this->loader = $loader;
+ $this->noCoverage = $noCoverage;
+ $this->noExtensions = $noExtensions;
+ $this->noInteraction = $noInteraction;
+ $this->noLogging = $noLogging;
+ $this->printer = $printer;
+ $this->processIsolation = $processIsolation;
+ $this->randomOrderSeed = $randomOrderSeed;
+ $this->repeat = $repeat;
+ $this->reportUselessTests = $reportUselessTests;
+ $this->resolveDependencies = $resolveDependencies;
+ $this->reverseList = $reverseList;
+ $this->stderr = $stderr;
+ $this->strictCoverage = $strictCoverage;
+ $this->stopOnDefect = $stopOnDefect;
+ $this->stopOnError = $stopOnError;
+ $this->stopOnFailure = $stopOnFailure;
+ $this->stopOnIncomplete = $stopOnIncomplete;
+ $this->stopOnRisky = $stopOnRisky;
+ $this->stopOnSkipped = $stopOnSkipped;
+ $this->stopOnWarning = $stopOnWarning;
+ $this->teamcityLogfile = $teamcityLogfile;
+ $this->testdoxExcludeGroups = $testdoxExcludeGroups;
+ $this->testdoxGroups = $testdoxGroups;
+ $this->testdoxHtmlFile = $testdoxHtmlFile;
+ $this->testdoxTextFile = $testdoxTextFile;
+ $this->testdoxXmlFile = $testdoxXmlFile;
+ $this->testSuffixes = $testSuffixes;
+ $this->testSuite = $testSuite;
+ $this->unrecognizedOptions = $unrecognizedOptions;
+ $this->unrecognizedOrderBy = $unrecognizedOrderBy;
+ $this->useDefaultConfiguration = $useDefaultConfiguration;
+ $this->verbose = $verbose;
+ $this->version = $version;
+ $this->xdebugFilterFile = $xdebugFilterFile;
+ }
+
+ public function hasArgument(): bool
+ {
+ return $this->argument !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function argument(): string
+ {
+ if ($this->argument === null) {
+ throw new Exception;
+ }
+
+ return $this->argument;
+ }
+
+ public function hasAtLeastVersion(): bool
+ {
+ return $this->atLeastVersion !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function atLeastVersion(): string
+ {
+ if ($this->atLeastVersion === null) {
+ throw new Exception;
+ }
+
+ return $this->atLeastVersion;
+ }
+
+ public function hasBackupGlobals(): bool
+ {
+ return $this->backupGlobals !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function backupGlobals(): bool
+ {
+ if ($this->backupGlobals === null) {
+ throw new Exception;
+ }
+
+ return $this->backupGlobals;
+ }
+
+ public function hasBackupStaticAttributes(): bool
+ {
+ return $this->backupStaticAttributes !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function backupStaticAttributes(): bool
+ {
+ if ($this->backupStaticAttributes === null) {
+ throw new Exception;
+ }
+
+ return $this->backupStaticAttributes;
+ }
+
+ public function hasBeStrictAboutChangesToGlobalState(): bool
+ {
+ return $this->beStrictAboutChangesToGlobalState !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function beStrictAboutChangesToGlobalState(): bool
+ {
+ if ($this->beStrictAboutChangesToGlobalState === null) {
+ throw new Exception;
+ }
+
+ return $this->beStrictAboutChangesToGlobalState;
+ }
+
+ public function hasBeStrictAboutResourceUsageDuringSmallTests(): bool
+ {
+ return $this->beStrictAboutResourceUsageDuringSmallTests !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function beStrictAboutResourceUsageDuringSmallTests(): bool
+ {
+ if ($this->beStrictAboutResourceUsageDuringSmallTests === null) {
+ throw new Exception;
+ }
+
+ return $this->beStrictAboutResourceUsageDuringSmallTests;
+ }
+
+ public function hasBootstrap(): bool
+ {
+ return $this->bootstrap !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function bootstrap(): string
+ {
+ if ($this->bootstrap === null) {
+ throw new Exception;
+ }
+
+ return $this->bootstrap;
+ }
+
+ public function hasCacheResult(): bool
+ {
+ return $this->cacheResult !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function cacheResult(): bool
+ {
+ if ($this->cacheResult === null) {
+ throw new Exception;
+ }
+
+ return $this->cacheResult;
+ }
+
+ public function hasCacheResultFile(): bool
+ {
+ return $this->cacheResultFile !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function cacheResultFile(): string
+ {
+ if ($this->cacheResultFile === null) {
+ throw new Exception;
+ }
+
+ return $this->cacheResultFile;
+ }
+
+ public function hasCheckVersion(): bool
+ {
+ return $this->checkVersion !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function checkVersion(): bool
+ {
+ if ($this->checkVersion === null) {
+ throw new Exception;
+ }
+
+ return $this->checkVersion;
+ }
+
+ public function hasColors(): bool
+ {
+ return $this->colors !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function colors(): string
+ {
+ if ($this->colors === null) {
+ throw new Exception;
+ }
+
+ return $this->colors;
+ }
+
+ public function hasColumns(): bool
+ {
+ return $this->columns !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function columns()
+ {
+ if ($this->columns === null) {
+ throw new Exception;
+ }
+
+ return $this->columns;
+ }
+
+ public function hasConfiguration(): bool
+ {
+ return $this->configuration !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function configuration(): string
+ {
+ if ($this->configuration === null) {
+ throw new Exception;
+ }
+
+ return $this->configuration;
+ }
+
+ public function hasCoverageFilter(): bool
+ {
+ return $this->coverageFilter !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function coverageFilter(): array
+ {
+ if ($this->coverageFilter === null) {
+ throw new Exception;
+ }
+
+ return $this->coverageFilter;
+ }
+
+ public function hasCoverageClover(): bool
+ {
+ return $this->coverageClover !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function coverageClover(): string
+ {
+ if ($this->coverageClover === null) {
+ throw new Exception;
+ }
+
+ return $this->coverageClover;
+ }
+
+ public function hasCoverageCobertura(): bool
+ {
+ return $this->coverageCobertura !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function coverageCobertura(): string
+ {
+ if ($this->coverageCobertura === null) {
+ throw new Exception;
+ }
+
+ return $this->coverageCobertura;
+ }
+
+ public function hasCoverageCrap4J(): bool
+ {
+ return $this->coverageCrap4J !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function coverageCrap4J(): string
+ {
+ if ($this->coverageCrap4J === null) {
+ throw new Exception;
+ }
+
+ return $this->coverageCrap4J;
+ }
+
+ public function hasCoverageHtml(): bool
+ {
+ return $this->coverageHtml !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function coverageHtml(): string
+ {
+ if ($this->coverageHtml === null) {
+ throw new Exception;
+ }
+
+ return $this->coverageHtml;
+ }
+
+ public function hasCoveragePhp(): bool
+ {
+ return $this->coveragePhp !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function coveragePhp(): string
+ {
+ if ($this->coveragePhp === null) {
+ throw new Exception;
+ }
+
+ return $this->coveragePhp;
+ }
+
+ public function hasCoverageText(): bool
+ {
+ return $this->coverageText !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function coverageText(): string
+ {
+ if ($this->coverageText === null) {
+ throw new Exception;
+ }
+
+ return $this->coverageText;
+ }
+
+ public function hasCoverageTextShowUncoveredFiles(): bool
+ {
+ return $this->coverageTextShowUncoveredFiles !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function coverageTextShowUncoveredFiles(): bool
+ {
+ if ($this->coverageTextShowUncoveredFiles === null) {
+ throw new Exception;
+ }
+
+ return $this->coverageTextShowUncoveredFiles;
+ }
+
+ public function hasCoverageTextShowOnlySummary(): bool
+ {
+ return $this->coverageTextShowOnlySummary !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function coverageTextShowOnlySummary(): bool
+ {
+ if ($this->coverageTextShowOnlySummary === null) {
+ throw new Exception;
+ }
+
+ return $this->coverageTextShowOnlySummary;
+ }
+
+ public function hasCoverageXml(): bool
+ {
+ return $this->coverageXml !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function coverageXml(): string
+ {
+ if ($this->coverageXml === null) {
+ throw new Exception;
+ }
+
+ return $this->coverageXml;
+ }
+
+ public function hasPathCoverage(): bool
+ {
+ return $this->pathCoverage !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function pathCoverage(): bool
+ {
+ if ($this->pathCoverage === null) {
+ throw new Exception;
+ }
+
+ return $this->pathCoverage;
+ }
+
+ public function hasCoverageCacheDirectory(): bool
+ {
+ return $this->coverageCacheDirectory !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function coverageCacheDirectory(): string
+ {
+ if ($this->coverageCacheDirectory === null) {
+ throw new Exception;
+ }
+
+ return $this->coverageCacheDirectory;
+ }
+
+ public function hasWarmCoverageCache(): bool
+ {
+ return $this->warmCoverageCache !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function warmCoverageCache(): bool
+ {
+ if ($this->warmCoverageCache === null) {
+ throw new Exception;
+ }
+
+ return $this->warmCoverageCache;
+ }
+
+ public function hasDebug(): bool
+ {
+ return $this->debug !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function debug(): bool
+ {
+ if ($this->debug === null) {
+ throw new Exception;
+ }
+
+ return $this->debug;
+ }
+
+ public function hasDefaultTimeLimit(): bool
+ {
+ return $this->defaultTimeLimit !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function defaultTimeLimit(): int
+ {
+ if ($this->defaultTimeLimit === null) {
+ throw new Exception;
+ }
+
+ return $this->defaultTimeLimit;
+ }
+
+ public function hasDisableCodeCoverageIgnore(): bool
+ {
+ return $this->disableCodeCoverageIgnore !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function disableCodeCoverageIgnore(): bool
+ {
+ if ($this->disableCodeCoverageIgnore === null) {
+ throw new Exception;
+ }
+
+ return $this->disableCodeCoverageIgnore;
+ }
+
+ public function hasDisallowTestOutput(): bool
+ {
+ return $this->disallowTestOutput !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function disallowTestOutput(): bool
+ {
+ if ($this->disallowTestOutput === null) {
+ throw new Exception;
+ }
+
+ return $this->disallowTestOutput;
+ }
+
+ public function hasDisallowTodoAnnotatedTests(): bool
+ {
+ return $this->disallowTodoAnnotatedTests !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function disallowTodoAnnotatedTests(): bool
+ {
+ if ($this->disallowTodoAnnotatedTests === null) {
+ throw new Exception;
+ }
+
+ return $this->disallowTodoAnnotatedTests;
+ }
+
+ public function hasEnforceTimeLimit(): bool
+ {
+ return $this->enforceTimeLimit !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function enforceTimeLimit(): bool
+ {
+ if ($this->enforceTimeLimit === null) {
+ throw new Exception;
+ }
+
+ return $this->enforceTimeLimit;
+ }
+
+ public function hasExcludeGroups(): bool
+ {
+ return $this->excludeGroups !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function excludeGroups(): array
+ {
+ if ($this->excludeGroups === null) {
+ throw new Exception;
+ }
+
+ return $this->excludeGroups;
+ }
+
+ public function hasExecutionOrder(): bool
+ {
+ return $this->executionOrder !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function executionOrder(): int
+ {
+ if ($this->executionOrder === null) {
+ throw new Exception;
+ }
+
+ return $this->executionOrder;
+ }
+
+ public function hasExecutionOrderDefects(): bool
+ {
+ return $this->executionOrderDefects !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function executionOrderDefects(): int
+ {
+ if ($this->executionOrderDefects === null) {
+ throw new Exception;
+ }
+
+ return $this->executionOrderDefects;
+ }
+
+ public function hasFailOnEmptyTestSuite(): bool
+ {
+ return $this->failOnEmptyTestSuite !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function failOnEmptyTestSuite(): bool
+ {
+ if ($this->failOnEmptyTestSuite === null) {
+ throw new Exception;
+ }
+
+ return $this->failOnEmptyTestSuite;
+ }
+
+ public function hasFailOnIncomplete(): bool
+ {
+ return $this->failOnIncomplete !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function failOnIncomplete(): bool
+ {
+ if ($this->failOnIncomplete === null) {
+ throw new Exception;
+ }
+
+ return $this->failOnIncomplete;
+ }
+
+ public function hasFailOnRisky(): bool
+ {
+ return $this->failOnRisky !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function failOnRisky(): bool
+ {
+ if ($this->failOnRisky === null) {
+ throw new Exception;
+ }
+
+ return $this->failOnRisky;
+ }
+
+ public function hasFailOnSkipped(): bool
+ {
+ return $this->failOnSkipped !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function failOnSkipped(): bool
+ {
+ if ($this->failOnSkipped === null) {
+ throw new Exception;
+ }
+
+ return $this->failOnSkipped;
+ }
+
+ public function hasFailOnWarning(): bool
+ {
+ return $this->failOnWarning !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function failOnWarning(): bool
+ {
+ if ($this->failOnWarning === null) {
+ throw new Exception;
+ }
+
+ return $this->failOnWarning;
+ }
+
+ public function hasFilter(): bool
+ {
+ return $this->filter !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function filter(): string
+ {
+ if ($this->filter === null) {
+ throw new Exception;
+ }
+
+ return $this->filter;
+ }
+
+ public function hasGenerateConfiguration(): bool
+ {
+ return $this->generateConfiguration !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function generateConfiguration(): bool
+ {
+ if ($this->generateConfiguration === null) {
+ throw new Exception;
+ }
+
+ return $this->generateConfiguration;
+ }
+
+ public function hasMigrateConfiguration(): bool
+ {
+ return $this->migrateConfiguration !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function migrateConfiguration(): bool
+ {
+ if ($this->migrateConfiguration === null) {
+ throw new Exception;
+ }
+
+ return $this->migrateConfiguration;
+ }
+
+ public function hasGroups(): bool
+ {
+ return $this->groups !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function groups(): array
+ {
+ if ($this->groups === null) {
+ throw new Exception;
+ }
+
+ return $this->groups;
+ }
+
+ public function hasTestsCovering(): bool
+ {
+ return $this->testsCovering !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testsCovering(): array
+ {
+ if ($this->testsCovering === null) {
+ throw new Exception;
+ }
+
+ return $this->testsCovering;
+ }
+
+ public function hasTestsUsing(): bool
+ {
+ return $this->testsUsing !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testsUsing(): array
+ {
+ if ($this->testsUsing === null) {
+ throw new Exception;
+ }
+
+ return $this->testsUsing;
+ }
+
+ public function hasHelp(): bool
+ {
+ return $this->help !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function help(): bool
+ {
+ if ($this->help === null) {
+ throw new Exception;
+ }
+
+ return $this->help;
+ }
+
+ public function hasIncludePath(): bool
+ {
+ return $this->includePath !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function includePath(): string
+ {
+ if ($this->includePath === null) {
+ throw new Exception;
+ }
+
+ return $this->includePath;
+ }
+
+ public function hasIniSettings(): bool
+ {
+ return $this->iniSettings !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function iniSettings(): array
+ {
+ if ($this->iniSettings === null) {
+ throw new Exception;
+ }
+
+ return $this->iniSettings;
+ }
+
+ public function hasJunitLogfile(): bool
+ {
+ return $this->junitLogfile !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function junitLogfile(): string
+ {
+ if ($this->junitLogfile === null) {
+ throw new Exception;
+ }
+
+ return $this->junitLogfile;
+ }
+
+ public function hasListGroups(): bool
+ {
+ return $this->listGroups !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function listGroups(): bool
+ {
+ if ($this->listGroups === null) {
+ throw new Exception;
+ }
+
+ return $this->listGroups;
+ }
+
+ public function hasListSuites(): bool
+ {
+ return $this->listSuites !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function listSuites(): bool
+ {
+ if ($this->listSuites === null) {
+ throw new Exception;
+ }
+
+ return $this->listSuites;
+ }
+
+ public function hasListTests(): bool
+ {
+ return $this->listTests !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function listTests(): bool
+ {
+ if ($this->listTests === null) {
+ throw new Exception;
+ }
+
+ return $this->listTests;
+ }
+
+ public function hasListTestsXml(): bool
+ {
+ return $this->listTestsXml !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function listTestsXml(): string
+ {
+ if ($this->listTestsXml === null) {
+ throw new Exception;
+ }
+
+ return $this->listTestsXml;
+ }
+
+ public function hasLoader(): bool
+ {
+ return $this->loader !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function loader(): string
+ {
+ if ($this->loader === null) {
+ throw new Exception;
+ }
+
+ return $this->loader;
+ }
+
+ public function hasNoCoverage(): bool
+ {
+ return $this->noCoverage !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function noCoverage(): bool
+ {
+ if ($this->noCoverage === null) {
+ throw new Exception;
+ }
+
+ return $this->noCoverage;
+ }
+
+ public function hasNoExtensions(): bool
+ {
+ return $this->noExtensions !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function noExtensions(): bool
+ {
+ if ($this->noExtensions === null) {
+ throw new Exception;
+ }
+
+ return $this->noExtensions;
+ }
+
+ public function hasExtensions(): bool
+ {
+ return $this->extensions !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function extensions(): array
+ {
+ if ($this->extensions === null) {
+ throw new Exception;
+ }
+
+ return $this->extensions;
+ }
+
+ public function hasUnavailableExtensions(): bool
+ {
+ return $this->unavailableExtensions !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function unavailableExtensions(): array
+ {
+ if ($this->unavailableExtensions === null) {
+ throw new Exception;
+ }
+
+ return $this->unavailableExtensions;
+ }
+
+ public function hasNoInteraction(): bool
+ {
+ return $this->noInteraction !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function noInteraction(): bool
+ {
+ if ($this->noInteraction === null) {
+ throw new Exception;
+ }
+
+ return $this->noInteraction;
+ }
+
+ public function hasNoLogging(): bool
+ {
+ return $this->noLogging !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function noLogging(): bool
+ {
+ if ($this->noLogging === null) {
+ throw new Exception;
+ }
+
+ return $this->noLogging;
+ }
+
+ public function hasPrinter(): bool
+ {
+ return $this->printer !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function printer(): string
+ {
+ if ($this->printer === null) {
+ throw new Exception;
+ }
+
+ return $this->printer;
+ }
+
+ public function hasProcessIsolation(): bool
+ {
+ return $this->processIsolation !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function processIsolation(): bool
+ {
+ if ($this->processIsolation === null) {
+ throw new Exception;
+ }
+
+ return $this->processIsolation;
+ }
+
+ public function hasRandomOrderSeed(): bool
+ {
+ return $this->randomOrderSeed !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function randomOrderSeed(): int
+ {
+ if ($this->randomOrderSeed === null) {
+ throw new Exception;
+ }
+
+ return $this->randomOrderSeed;
+ }
+
+ public function hasRepeat(): bool
+ {
+ return $this->repeat !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function repeat(): int
+ {
+ if ($this->repeat === null) {
+ throw new Exception;
+ }
+
+ return $this->repeat;
+ }
+
+ public function hasReportUselessTests(): bool
+ {
+ return $this->reportUselessTests !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function reportUselessTests(): bool
+ {
+ if ($this->reportUselessTests === null) {
+ throw new Exception;
+ }
+
+ return $this->reportUselessTests;
+ }
+
+ public function hasResolveDependencies(): bool
+ {
+ return $this->resolveDependencies !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function resolveDependencies(): bool
+ {
+ if ($this->resolveDependencies === null) {
+ throw new Exception;
+ }
+
+ return $this->resolveDependencies;
+ }
+
+ public function hasReverseList(): bool
+ {
+ return $this->reverseList !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function reverseList(): bool
+ {
+ if ($this->reverseList === null) {
+ throw new Exception;
+ }
+
+ return $this->reverseList;
+ }
+
+ public function hasStderr(): bool
+ {
+ return $this->stderr !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function stderr(): bool
+ {
+ if ($this->stderr === null) {
+ throw new Exception;
+ }
+
+ return $this->stderr;
+ }
+
+ public function hasStrictCoverage(): bool
+ {
+ return $this->strictCoverage !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function strictCoverage(): bool
+ {
+ if ($this->strictCoverage === null) {
+ throw new Exception;
+ }
+
+ return $this->strictCoverage;
+ }
+
+ public function hasStopOnDefect(): bool
+ {
+ return $this->stopOnDefect !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function stopOnDefect(): bool
+ {
+ if ($this->stopOnDefect === null) {
+ throw new Exception;
+ }
+
+ return $this->stopOnDefect;
+ }
+
+ public function hasStopOnError(): bool
+ {
+ return $this->stopOnError !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function stopOnError(): bool
+ {
+ if ($this->stopOnError === null) {
+ throw new Exception;
+ }
+
+ return $this->stopOnError;
+ }
+
+ public function hasStopOnFailure(): bool
+ {
+ return $this->stopOnFailure !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function stopOnFailure(): bool
+ {
+ if ($this->stopOnFailure === null) {
+ throw new Exception;
+ }
+
+ return $this->stopOnFailure;
+ }
+
+ public function hasStopOnIncomplete(): bool
+ {
+ return $this->stopOnIncomplete !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function stopOnIncomplete(): bool
+ {
+ if ($this->stopOnIncomplete === null) {
+ throw new Exception;
+ }
+
+ return $this->stopOnIncomplete;
+ }
+
+ public function hasStopOnRisky(): bool
+ {
+ return $this->stopOnRisky !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function stopOnRisky(): bool
+ {
+ if ($this->stopOnRisky === null) {
+ throw new Exception;
+ }
+
+ return $this->stopOnRisky;
+ }
+
+ public function hasStopOnSkipped(): bool
+ {
+ return $this->stopOnSkipped !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function stopOnSkipped(): bool
+ {
+ if ($this->stopOnSkipped === null) {
+ throw new Exception;
+ }
+
+ return $this->stopOnSkipped;
+ }
+
+ public function hasStopOnWarning(): bool
+ {
+ return $this->stopOnWarning !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function stopOnWarning(): bool
+ {
+ if ($this->stopOnWarning === null) {
+ throw new Exception;
+ }
+
+ return $this->stopOnWarning;
+ }
+
+ public function hasTeamcityLogfile(): bool
+ {
+ return $this->teamcityLogfile !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function teamcityLogfile(): string
+ {
+ if ($this->teamcityLogfile === null) {
+ throw new Exception;
+ }
+
+ return $this->teamcityLogfile;
+ }
+
+ public function hasTestdoxExcludeGroups(): bool
+ {
+ return $this->testdoxExcludeGroups !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testdoxExcludeGroups(): array
+ {
+ if ($this->testdoxExcludeGroups === null) {
+ throw new Exception;
+ }
+
+ return $this->testdoxExcludeGroups;
+ }
+
+ public function hasTestdoxGroups(): bool
+ {
+ return $this->testdoxGroups !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testdoxGroups(): array
+ {
+ if ($this->testdoxGroups === null) {
+ throw new Exception;
+ }
+
+ return $this->testdoxGroups;
+ }
+
+ public function hasTestdoxHtmlFile(): bool
+ {
+ return $this->testdoxHtmlFile !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testdoxHtmlFile(): string
+ {
+ if ($this->testdoxHtmlFile === null) {
+ throw new Exception;
+ }
+
+ return $this->testdoxHtmlFile;
+ }
+
+ public function hasTestdoxTextFile(): bool
+ {
+ return $this->testdoxTextFile !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testdoxTextFile(): string
+ {
+ if ($this->testdoxTextFile === null) {
+ throw new Exception;
+ }
+
+ return $this->testdoxTextFile;
+ }
+
+ public function hasTestdoxXmlFile(): bool
+ {
+ return $this->testdoxXmlFile !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testdoxXmlFile(): string
+ {
+ if ($this->testdoxXmlFile === null) {
+ throw new Exception;
+ }
+
+ return $this->testdoxXmlFile;
+ }
+
+ public function hasTestSuffixes(): bool
+ {
+ return $this->testSuffixes !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testSuffixes(): array
+ {
+ if ($this->testSuffixes === null) {
+ throw new Exception;
+ }
+
+ return $this->testSuffixes;
+ }
+
+ public function hasTestSuite(): bool
+ {
+ return $this->testSuite !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function testSuite(): string
+ {
+ if ($this->testSuite === null) {
+ throw new Exception;
+ }
+
+ return $this->testSuite;
+ }
+
+ public function unrecognizedOptions(): array
+ {
+ return $this->unrecognizedOptions;
+ }
+
+ public function hasUnrecognizedOrderBy(): bool
+ {
+ return $this->unrecognizedOrderBy !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function unrecognizedOrderBy(): string
+ {
+ if ($this->unrecognizedOrderBy === null) {
+ throw new Exception;
+ }
+
+ return $this->unrecognizedOrderBy;
+ }
+
+ public function hasUseDefaultConfiguration(): bool
+ {
+ return $this->useDefaultConfiguration !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function useDefaultConfiguration(): bool
+ {
+ if ($this->useDefaultConfiguration === null) {
+ throw new Exception;
+ }
+
+ return $this->useDefaultConfiguration;
+ }
+
+ public function hasVerbose(): bool
+ {
+ return $this->verbose !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function verbose(): bool
+ {
+ if ($this->verbose === null) {
+ throw new Exception;
+ }
+
+ return $this->verbose;
+ }
+
+ public function hasVersion(): bool
+ {
+ return $this->version !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function version(): bool
+ {
+ if ($this->version === null) {
+ throw new Exception;
+ }
+
+ return $this->version;
+ }
+
+ public function hasXdebugFilterFile(): bool
+ {
+ return $this->xdebugFilterFile !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function xdebugFilterFile(): string
+ {
+ if ($this->xdebugFilterFile === null) {
+ throw new Exception;
+ }
+
+ return $this->xdebugFilterFile;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/CliArguments/Exception.php b/vendor/phpunit/phpunit/src/TextUI/CliArguments/Exception.php
new file mode 100644
index 000000000..dd5536eaa
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/CliArguments/Exception.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Exception extends RuntimeException implements \PHPUnit\Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/CliArguments/Mapper.php b/vendor/phpunit/phpunit/src/TextUI/CliArguments/Mapper.php
new file mode 100644
index 000000000..9ceb8ab47
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/CliArguments/Mapper.php
@@ -0,0 +1,365 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\CliArguments;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Mapper
+{
+ /**
+ * @throws Exception
+ */
+ public function mapToLegacyArray(Configuration $arguments): array
+ {
+ $result = [
+ 'extensions' => [],
+ 'listGroups' => false,
+ 'listSuites' => false,
+ 'listTests' => false,
+ 'listTestsXml' => false,
+ 'loader' => null,
+ 'useDefaultConfiguration' => true,
+ 'loadedExtensions' => [],
+ 'unavailableExtensions' => [],
+ 'notLoadedExtensions' => [],
+ ];
+
+ if ($arguments->hasColors()) {
+ $result['colors'] = $arguments->colors();
+ }
+
+ if ($arguments->hasBootstrap()) {
+ $result['bootstrap'] = $arguments->bootstrap();
+ }
+
+ if ($arguments->hasCacheResult()) {
+ $result['cacheResult'] = $arguments->cacheResult();
+ }
+
+ if ($arguments->hasCacheResultFile()) {
+ $result['cacheResultFile'] = $arguments->cacheResultFile();
+ }
+
+ if ($arguments->hasColumns()) {
+ $result['columns'] = $arguments->columns();
+ }
+
+ if ($arguments->hasConfiguration()) {
+ $result['configuration'] = $arguments->configuration();
+ }
+
+ if ($arguments->hasCoverageCacheDirectory()) {
+ $result['coverageCacheDirectory'] = $arguments->coverageCacheDirectory();
+ }
+
+ if ($arguments->hasWarmCoverageCache()) {
+ $result['warmCoverageCache'] = $arguments->warmCoverageCache();
+ }
+
+ if ($arguments->hasCoverageClover()) {
+ $result['coverageClover'] = $arguments->coverageClover();
+ }
+
+ if ($arguments->hasCoverageCobertura()) {
+ $result['coverageCobertura'] = $arguments->coverageCobertura();
+ }
+
+ if ($arguments->hasCoverageCrap4J()) {
+ $result['coverageCrap4J'] = $arguments->coverageCrap4J();
+ }
+
+ if ($arguments->hasCoverageHtml()) {
+ $result['coverageHtml'] = $arguments->coverageHtml();
+ }
+
+ if ($arguments->hasCoveragePhp()) {
+ $result['coveragePHP'] = $arguments->coveragePhp();
+ }
+
+ if ($arguments->hasCoverageText()) {
+ $result['coverageText'] = $arguments->coverageText();
+ }
+
+ if ($arguments->hasCoverageTextShowUncoveredFiles()) {
+ $result['coverageTextShowUncoveredFiles'] = $arguments->hasCoverageTextShowUncoveredFiles();
+ }
+
+ if ($arguments->hasCoverageTextShowOnlySummary()) {
+ $result['coverageTextShowOnlySummary'] = $arguments->coverageTextShowOnlySummary();
+ }
+
+ if ($arguments->hasCoverageXml()) {
+ $result['coverageXml'] = $arguments->coverageXml();
+ }
+
+ if ($arguments->hasPathCoverage()) {
+ $result['pathCoverage'] = $arguments->pathCoverage();
+ }
+
+ if ($arguments->hasDebug()) {
+ $result['debug'] = $arguments->debug();
+ }
+
+ if ($arguments->hasHelp()) {
+ $result['help'] = $arguments->help();
+ }
+
+ if ($arguments->hasFilter()) {
+ $result['filter'] = $arguments->filter();
+ }
+
+ if ($arguments->hasTestSuite()) {
+ $result['testsuite'] = $arguments->testSuite();
+ }
+
+ if ($arguments->hasGroups()) {
+ $result['groups'] = $arguments->groups();
+ }
+
+ if ($arguments->hasExcludeGroups()) {
+ $result['excludeGroups'] = $arguments->excludeGroups();
+ }
+
+ if ($arguments->hasTestsCovering()) {
+ $result['testsCovering'] = $arguments->testsCovering();
+ }
+
+ if ($arguments->hasTestsUsing()) {
+ $result['testsUsing'] = $arguments->testsUsing();
+ }
+
+ if ($arguments->hasTestSuffixes()) {
+ $result['testSuffixes'] = $arguments->testSuffixes();
+ }
+
+ if ($arguments->hasIncludePath()) {
+ $result['includePath'] = $arguments->includePath();
+ }
+
+ if ($arguments->hasListGroups()) {
+ $result['listGroups'] = $arguments->listGroups();
+ }
+
+ if ($arguments->hasListSuites()) {
+ $result['listSuites'] = $arguments->listSuites();
+ }
+
+ if ($arguments->hasListTests()) {
+ $result['listTests'] = $arguments->listTests();
+ }
+
+ if ($arguments->hasListTestsXml()) {
+ $result['listTestsXml'] = $arguments->listTestsXml();
+ }
+
+ if ($arguments->hasPrinter()) {
+ $result['printer'] = $arguments->printer();
+ }
+
+ if ($arguments->hasLoader()) {
+ $result['loader'] = $arguments->loader();
+ }
+
+ if ($arguments->hasJunitLogfile()) {
+ $result['junitLogfile'] = $arguments->junitLogfile();
+ }
+
+ if ($arguments->hasTeamcityLogfile()) {
+ $result['teamcityLogfile'] = $arguments->teamcityLogfile();
+ }
+
+ if ($arguments->hasExecutionOrder()) {
+ $result['executionOrder'] = $arguments->executionOrder();
+ }
+
+ if ($arguments->hasExecutionOrderDefects()) {
+ $result['executionOrderDefects'] = $arguments->executionOrderDefects();
+ }
+
+ if ($arguments->hasExtensions()) {
+ $result['extensions'] = $arguments->extensions();
+ }
+
+ if ($arguments->hasUnavailableExtensions()) {
+ $result['unavailableExtensions'] = $arguments->unavailableExtensions();
+ }
+
+ if ($arguments->hasResolveDependencies()) {
+ $result['resolveDependencies'] = $arguments->resolveDependencies();
+ }
+
+ if ($arguments->hasProcessIsolation()) {
+ $result['processIsolation'] = $arguments->processIsolation();
+ }
+
+ if ($arguments->hasRepeat()) {
+ $result['repeat'] = $arguments->repeat();
+ }
+
+ if ($arguments->hasStderr()) {
+ $result['stderr'] = $arguments->stderr();
+ }
+
+ if ($arguments->hasStopOnDefect()) {
+ $result['stopOnDefect'] = $arguments->stopOnDefect();
+ }
+
+ if ($arguments->hasStopOnError()) {
+ $result['stopOnError'] = $arguments->stopOnError();
+ }
+
+ if ($arguments->hasStopOnFailure()) {
+ $result['stopOnFailure'] = $arguments->stopOnFailure();
+ }
+
+ if ($arguments->hasStopOnWarning()) {
+ $result['stopOnWarning'] = $arguments->stopOnWarning();
+ }
+
+ if ($arguments->hasStopOnIncomplete()) {
+ $result['stopOnIncomplete'] = $arguments->stopOnIncomplete();
+ }
+
+ if ($arguments->hasStopOnRisky()) {
+ $result['stopOnRisky'] = $arguments->stopOnRisky();
+ }
+
+ if ($arguments->hasStopOnSkipped()) {
+ $result['stopOnSkipped'] = $arguments->stopOnSkipped();
+ }
+
+ if ($arguments->hasFailOnEmptyTestSuite()) {
+ $result['failOnEmptyTestSuite'] = $arguments->failOnEmptyTestSuite();
+ }
+
+ if ($arguments->hasFailOnIncomplete()) {
+ $result['failOnIncomplete'] = $arguments->failOnIncomplete();
+ }
+
+ if ($arguments->hasFailOnRisky()) {
+ $result['failOnRisky'] = $arguments->failOnRisky();
+ }
+
+ if ($arguments->hasFailOnSkipped()) {
+ $result['failOnSkipped'] = $arguments->failOnSkipped();
+ }
+
+ if ($arguments->hasFailOnWarning()) {
+ $result['failOnWarning'] = $arguments->failOnWarning();
+ }
+
+ if ($arguments->hasTestdoxGroups()) {
+ $result['testdoxGroups'] = $arguments->testdoxGroups();
+ }
+
+ if ($arguments->hasTestdoxExcludeGroups()) {
+ $result['testdoxExcludeGroups'] = $arguments->testdoxExcludeGroups();
+ }
+
+ if ($arguments->hasTestdoxHtmlFile()) {
+ $result['testdoxHTMLFile'] = $arguments->testdoxHtmlFile();
+ }
+
+ if ($arguments->hasTestdoxTextFile()) {
+ $result['testdoxTextFile'] = $arguments->testdoxTextFile();
+ }
+
+ if ($arguments->hasTestdoxXmlFile()) {
+ $result['testdoxXMLFile'] = $arguments->testdoxXmlFile();
+ }
+
+ if ($arguments->hasUseDefaultConfiguration()) {
+ $result['useDefaultConfiguration'] = $arguments->useDefaultConfiguration();
+ }
+
+ if ($arguments->hasNoExtensions()) {
+ $result['noExtensions'] = $arguments->noExtensions();
+ }
+
+ if ($arguments->hasNoCoverage()) {
+ $result['noCoverage'] = $arguments->noCoverage();
+ }
+
+ if ($arguments->hasNoLogging()) {
+ $result['noLogging'] = $arguments->noLogging();
+ }
+
+ if ($arguments->hasNoInteraction()) {
+ $result['noInteraction'] = $arguments->noInteraction();
+ }
+
+ if ($arguments->hasBackupGlobals()) {
+ $result['backupGlobals'] = $arguments->backupGlobals();
+ }
+
+ if ($arguments->hasBackupStaticAttributes()) {
+ $result['backupStaticAttributes'] = $arguments->backupStaticAttributes();
+ }
+
+ if ($arguments->hasVerbose()) {
+ $result['verbose'] = $arguments->verbose();
+ }
+
+ if ($arguments->hasReportUselessTests()) {
+ $result['reportUselessTests'] = $arguments->reportUselessTests();
+ }
+
+ if ($arguments->hasStrictCoverage()) {
+ $result['strictCoverage'] = $arguments->strictCoverage();
+ }
+
+ if ($arguments->hasDisableCodeCoverageIgnore()) {
+ $result['disableCodeCoverageIgnore'] = $arguments->disableCodeCoverageIgnore();
+ }
+
+ if ($arguments->hasBeStrictAboutChangesToGlobalState()) {
+ $result['beStrictAboutChangesToGlobalState'] = $arguments->beStrictAboutChangesToGlobalState();
+ }
+
+ if ($arguments->hasDisallowTestOutput()) {
+ $result['disallowTestOutput'] = $arguments->disallowTestOutput();
+ }
+
+ if ($arguments->hasBeStrictAboutResourceUsageDuringSmallTests()) {
+ $result['beStrictAboutResourceUsageDuringSmallTests'] = $arguments->beStrictAboutResourceUsageDuringSmallTests();
+ }
+
+ if ($arguments->hasDefaultTimeLimit()) {
+ $result['defaultTimeLimit'] = $arguments->defaultTimeLimit();
+ }
+
+ if ($arguments->hasEnforceTimeLimit()) {
+ $result['enforceTimeLimit'] = $arguments->enforceTimeLimit();
+ }
+
+ if ($arguments->hasDisallowTodoAnnotatedTests()) {
+ $result['disallowTodoAnnotatedTests'] = $arguments->disallowTodoAnnotatedTests();
+ }
+
+ if ($arguments->hasReverseList()) {
+ $result['reverseList'] = $arguments->reverseList();
+ }
+
+ if ($arguments->hasCoverageFilter()) {
+ $result['coverageFilter'] = $arguments->coverageFilter();
+ }
+
+ if ($arguments->hasRandomOrderSeed()) {
+ $result['randomOrderSeed'] = $arguments->randomOrderSeed();
+ }
+
+ if ($arguments->hasXdebugFilterFile()) {
+ $result['xdebugFilterFile'] = $arguments->xdebugFilterFile();
+ }
+
+ return $result;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/Command.php b/vendor/phpunit/phpunit/src/TextUI/Command.php
new file mode 100644
index 000000000..e5dd7a01d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/Command.php
@@ -0,0 +1,903 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI;
+
+use const PATH_SEPARATOR;
+use const PHP_EOL;
+use const STDIN;
+use function array_keys;
+use function assert;
+use function class_exists;
+use function copy;
+use function extension_loaded;
+use function fgets;
+use function file_get_contents;
+use function file_put_contents;
+use function get_class;
+use function getcwd;
+use function ini_get;
+use function ini_set;
+use function is_callable;
+use function is_dir;
+use function is_file;
+use function is_string;
+use function printf;
+use function realpath;
+use function sort;
+use function sprintf;
+use function stream_resolve_include_path;
+use function strpos;
+use function trim;
+use function version_compare;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Runner\Extension\PharLoader;
+use PHPUnit\Runner\StandardTestSuiteLoader;
+use PHPUnit\Runner\TestSuiteLoader;
+use PHPUnit\Runner\Version;
+use PHPUnit\TextUI\CliArguments\Builder;
+use PHPUnit\TextUI\CliArguments\Configuration;
+use PHPUnit\TextUI\CliArguments\Exception as ArgumentsException;
+use PHPUnit\TextUI\CliArguments\Mapper;
+use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\FilterMapper;
+use PHPUnit\TextUI\XmlConfiguration\Generator;
+use PHPUnit\TextUI\XmlConfiguration\Loader;
+use PHPUnit\TextUI\XmlConfiguration\Migrator;
+use PHPUnit\TextUI\XmlConfiguration\PhpHandler;
+use PHPUnit\Util\FileLoader;
+use PHPUnit\Util\Filesystem;
+use PHPUnit\Util\Printer;
+use PHPUnit\Util\TextTestListRenderer;
+use PHPUnit\Util\Xml\SchemaDetector;
+use PHPUnit\Util\XmlTestListRenderer;
+use ReflectionClass;
+use SebastianBergmann\CodeCoverage\Filter;
+use SebastianBergmann\CodeCoverage\StaticAnalysis\CacheWarmer;
+use SebastianBergmann\Timer\Timer;
+use Throwable;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+class Command
+{
+ /**
+ * @var array<string,mixed>
+ */
+ protected $arguments = [];
+
+ /**
+ * @var array<string,mixed>
+ */
+ protected $longOptions = [];
+
+ /**
+ * @var bool
+ */
+ private $versionStringPrinted = false;
+
+ /**
+ * @psalm-var list<string>
+ */
+ private $warnings = [];
+
+ /**
+ * @throws Exception
+ */
+ public static function main(bool $exit = true): int
+ {
+ try {
+ return (new static)->run($_SERVER['argv'], $exit);
+ } catch (Throwable $t) {
+ throw new RuntimeException(
+ $t->getMessage(),
+ (int) $t->getCode(),
+ $t
+ );
+ }
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function run(array $argv, bool $exit = true): int
+ {
+ $this->handleArguments($argv);
+
+ $runner = $this->createRunner();
+
+ if ($this->arguments['test'] instanceof TestSuite) {
+ $suite = $this->arguments['test'];
+ } else {
+ $suite = $runner->getTest(
+ $this->arguments['test'],
+ $this->arguments['testSuffixes']
+ );
+ }
+
+ if ($this->arguments['listGroups']) {
+ return $this->handleListGroups($suite, $exit);
+ }
+
+ if ($this->arguments['listSuites']) {
+ return $this->handleListSuites($exit);
+ }
+
+ if ($this->arguments['listTests']) {
+ return $this->handleListTests($suite, $exit);
+ }
+
+ if ($this->arguments['listTestsXml']) {
+ return $this->handleListTestsXml($suite, $this->arguments['listTestsXml'], $exit);
+ }
+
+ unset($this->arguments['test'], $this->arguments['testFile']);
+
+ try {
+ $result = $runner->run($suite, $this->arguments, $this->warnings, $exit);
+ } catch (Throwable $t) {
+ print $t->getMessage() . PHP_EOL;
+ }
+
+ $return = TestRunner::FAILURE_EXIT;
+
+ if (isset($result) && $result->wasSuccessful()) {
+ $return = TestRunner::SUCCESS_EXIT;
+ } elseif (!isset($result) || $result->errorCount() > 0) {
+ $return = TestRunner::EXCEPTION_EXIT;
+ }
+
+ if ($exit) {
+ exit($return);
+ }
+
+ return $return;
+ }
+
+ /**
+ * Create a TestRunner, override in subclasses.
+ */
+ protected function createRunner(): TestRunner
+ {
+ return new TestRunner($this->arguments['loader']);
+ }
+
+ /**
+ * Handles the command-line arguments.
+ *
+ * A child class of PHPUnit\TextUI\Command can hook into the argument
+ * parsing by adding the switch(es) to the $longOptions array and point to a
+ * callback method that handles the switch(es) in the child class like this
+ *
+ * <code>
+ * <?php
+ * class MyCommand extends PHPUnit\TextUI\Command
+ * {
+ * public function __construct()
+ * {
+ * // my-switch won't accept a value, it's an on/off
+ * $this->longOptions['my-switch'] = 'myHandler';
+ * // my-secondswitch will accept a value - note the equals sign
+ * $this->longOptions['my-secondswitch='] = 'myOtherHandler';
+ * }
+ *
+ * // --my-switch -> myHandler()
+ * protected function myHandler()
+ * {
+ * }
+ *
+ * // --my-secondswitch foo -> myOtherHandler('foo')
+ * protected function myOtherHandler ($value)
+ * {
+ * }
+ *
+ * // You will also need this - the static keyword in the
+ * // PHPUnit\TextUI\Command will mean that it'll be
+ * // PHPUnit\TextUI\Command that gets instantiated,
+ * // not MyCommand
+ * public static function main($exit = true)
+ * {
+ * $command = new static;
+ *
+ * return $command->run($_SERVER['argv'], $exit);
+ * }
+ *
+ * }
+ * </code>
+ *
+ * @throws Exception
+ */
+ protected function handleArguments(array $argv): void
+ {
+ try {
+ $arguments = (new Builder)->fromParameters($argv, array_keys($this->longOptions));
+ } catch (ArgumentsException $e) {
+ $this->exitWithErrorMessage($e->getMessage());
+ }
+
+ assert(isset($arguments) && $arguments instanceof Configuration);
+
+ if ($arguments->hasGenerateConfiguration() && $arguments->generateConfiguration()) {
+ $this->generateConfiguration();
+ }
+
+ if ($arguments->hasAtLeastVersion()) {
+ if (version_compare(Version::id(), $arguments->atLeastVersion(), '>=')) {
+ exit(TestRunner::SUCCESS_EXIT);
+ }
+
+ exit(TestRunner::FAILURE_EXIT);
+ }
+
+ if ($arguments->hasVersion() && $arguments->version()) {
+ $this->printVersionString();
+
+ exit(TestRunner::SUCCESS_EXIT);
+ }
+
+ if ($arguments->hasCheckVersion() && $arguments->checkVersion()) {
+ $this->handleVersionCheck();
+ }
+
+ if ($arguments->hasHelp()) {
+ $this->showHelp();
+
+ exit(TestRunner::SUCCESS_EXIT);
+ }
+
+ if ($arguments->hasUnrecognizedOrderBy()) {
+ $this->exitWithErrorMessage(
+ sprintf(
+ 'unrecognized --order-by option: %s',
+ $arguments->unrecognizedOrderBy()
+ )
+ );
+ }
+
+ if ($arguments->hasIniSettings()) {
+ foreach ($arguments->iniSettings() as $name => $value) {
+ ini_set($name, $value);
+ }
+ }
+
+ if ($arguments->hasIncludePath()) {
+ ini_set(
+ 'include_path',
+ $arguments->includePath() . PATH_SEPARATOR . ini_get('include_path')
+ );
+ }
+
+ $this->arguments = (new Mapper)->mapToLegacyArray($arguments);
+
+ $this->handleCustomOptions($arguments->unrecognizedOptions());
+ $this->handleCustomTestSuite();
+
+ if (!isset($this->arguments['testSuffixes'])) {
+ $this->arguments['testSuffixes'] = ['Test.php', '.phpt'];
+ }
+
+ if (!isset($this->arguments['test']) && $arguments->hasArgument()) {
+ $this->arguments['test'] = realpath($arguments->argument());
+
+ if ($this->arguments['test'] === false) {
+ $this->exitWithErrorMessage(
+ sprintf(
+ 'Cannot open file "%s".',
+ $arguments->argument()
+ )
+ );
+ }
+ }
+
+ if ($this->arguments['loader'] !== null) {
+ $this->arguments['loader'] = $this->handleLoader($this->arguments['loader']);
+ }
+
+ if (isset($this->arguments['configuration'])) {
+ if (is_dir($this->arguments['configuration'])) {
+ $candidate = $this->configurationFileInDirectory($this->arguments['configuration']);
+
+ if ($candidate !== null) {
+ $this->arguments['configuration'] = $candidate;
+ }
+ }
+ } elseif ($this->arguments['useDefaultConfiguration']) {
+ $candidate = $this->configurationFileInDirectory(getcwd());
+
+ if ($candidate !== null) {
+ $this->arguments['configuration'] = $candidate;
+ }
+ }
+
+ if ($arguments->hasMigrateConfiguration() && $arguments->migrateConfiguration()) {
+ if (!isset($this->arguments['configuration'])) {
+ print 'No configuration file found to migrate.' . PHP_EOL;
+
+ exit(TestRunner::EXCEPTION_EXIT);
+ }
+
+ $this->migrateConfiguration(realpath($this->arguments['configuration']));
+ }
+
+ if (isset($this->arguments['configuration'])) {
+ try {
+ $this->arguments['configurationObject'] = (new Loader)->load($this->arguments['configuration']);
+ } catch (Throwable $e) {
+ print $e->getMessage() . PHP_EOL;
+
+ exit(TestRunner::FAILURE_EXIT);
+ }
+
+ $phpunitConfiguration = $this->arguments['configurationObject']->phpunit();
+
+ (new PhpHandler)->handle($this->arguments['configurationObject']->php());
+
+ if (isset($this->arguments['bootstrap'])) {
+ $this->handleBootstrap($this->arguments['bootstrap']);
+ } elseif ($phpunitConfiguration->hasBootstrap()) {
+ $this->handleBootstrap($phpunitConfiguration->bootstrap());
+ }
+
+ if (!isset($this->arguments['stderr'])) {
+ $this->arguments['stderr'] = $phpunitConfiguration->stderr();
+ }
+
+ if (!isset($this->arguments['noExtensions']) && $phpunitConfiguration->hasExtensionsDirectory() && extension_loaded('phar')) {
+ $result = (new PharLoader)->loadPharExtensionsInDirectory($phpunitConfiguration->extensionsDirectory());
+
+ $this->arguments['loadedExtensions'] = $result['loadedExtensions'];
+ $this->arguments['notLoadedExtensions'] = $result['notLoadedExtensions'];
+
+ unset($result);
+ }
+
+ if (!isset($this->arguments['columns'])) {
+ $this->arguments['columns'] = $phpunitConfiguration->columns();
+ }
+
+ if (!isset($this->arguments['printer']) && $phpunitConfiguration->hasPrinterClass()) {
+ $file = $phpunitConfiguration->hasPrinterFile() ? $phpunitConfiguration->printerFile() : '';
+
+ $this->arguments['printer'] = $this->handlePrinter(
+ $phpunitConfiguration->printerClass(),
+ $file
+ );
+ }
+
+ if ($phpunitConfiguration->hasTestSuiteLoaderClass()) {
+ $file = $phpunitConfiguration->hasTestSuiteLoaderFile() ? $phpunitConfiguration->testSuiteLoaderFile() : '';
+
+ $this->arguments['loader'] = $this->handleLoader(
+ $phpunitConfiguration->testSuiteLoaderClass(),
+ $file
+ );
+ }
+
+ if (!isset($this->arguments['testsuite']) && $phpunitConfiguration->hasDefaultTestSuite()) {
+ $this->arguments['testsuite'] = $phpunitConfiguration->defaultTestSuite();
+ }
+
+ if (!isset($this->arguments['test'])) {
+ try {
+ $this->arguments['test'] = (new TestSuiteMapper)->map(
+ $this->arguments['configurationObject']->testSuite(),
+ $this->arguments['testsuite'] ?? ''
+ );
+ } catch (Exception $e) {
+ $this->printVersionString();
+
+ print $e->getMessage() . PHP_EOL;
+
+ exit(TestRunner::EXCEPTION_EXIT);
+ }
+ }
+ } elseif (isset($this->arguments['bootstrap'])) {
+ $this->handleBootstrap($this->arguments['bootstrap']);
+ }
+
+ if (isset($this->arguments['printer']) && is_string($this->arguments['printer'])) {
+ $this->arguments['printer'] = $this->handlePrinter($this->arguments['printer']);
+ }
+
+ if (isset($this->arguments['configurationObject'], $this->arguments['warmCoverageCache'])) {
+ $this->handleWarmCoverageCache($this->arguments['configurationObject']);
+ }
+
+ if (!isset($this->arguments['test'])) {
+ $this->showHelp();
+
+ exit(TestRunner::EXCEPTION_EXIT);
+ }
+ }
+
+ /**
+ * Handles the loading of the PHPUnit\Runner\TestSuiteLoader implementation.
+ *
+ * @deprecated see https://github.com/sebastianbergmann/phpunit/issues/4039
+ */
+ protected function handleLoader(string $loaderClass, string $loaderFile = ''): ?TestSuiteLoader
+ {
+ $this->warnings[] = 'Using a custom test suite loader is deprecated';
+
+ if (!class_exists($loaderClass, false)) {
+ if ($loaderFile == '') {
+ $loaderFile = Filesystem::classNameToFilename(
+ $loaderClass
+ );
+ }
+
+ $loaderFile = stream_resolve_include_path($loaderFile);
+
+ if ($loaderFile) {
+ /**
+ * @noinspection PhpIncludeInspection
+ * @psalm-suppress UnresolvableInclude
+ */
+ require $loaderFile;
+ }
+ }
+
+ if (class_exists($loaderClass, false)) {
+ try {
+ $class = new ReflectionClass($loaderClass);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ if ($class->implementsInterface(TestSuiteLoader::class) && $class->isInstantiable()) {
+ $object = $class->newInstance();
+
+ assert($object instanceof TestSuiteLoader);
+
+ return $object;
+ }
+ }
+
+ if ($loaderClass == StandardTestSuiteLoader::class) {
+ return null;
+ }
+
+ $this->exitWithErrorMessage(
+ sprintf(
+ 'Could not use "%s" as loader.',
+ $loaderClass
+ )
+ );
+
+ return null;
+ }
+
+ /**
+ * Handles the loading of the PHPUnit\Util\Printer implementation.
+ *
+ * @return null|Printer|string
+ */
+ protected function handlePrinter(string $printerClass, string $printerFile = '')
+ {
+ if (!class_exists($printerClass, false)) {
+ if ($printerFile === '') {
+ $printerFile = Filesystem::classNameToFilename(
+ $printerClass
+ );
+ }
+
+ $printerFile = stream_resolve_include_path($printerFile);
+
+ if ($printerFile) {
+ /**
+ * @noinspection PhpIncludeInspection
+ * @psalm-suppress UnresolvableInclude
+ */
+ require $printerFile;
+ }
+ }
+
+ if (!class_exists($printerClass)) {
+ $this->exitWithErrorMessage(
+ sprintf(
+ 'Could not use "%s" as printer: class does not exist',
+ $printerClass
+ )
+ );
+ }
+
+ try {
+ $class = new ReflectionClass($printerClass);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ // @codeCoverageIgnoreEnd
+ }
+
+ if (!$class->implementsInterface(ResultPrinter::class)) {
+ $this->exitWithErrorMessage(
+ sprintf(
+ 'Could not use "%s" as printer: class does not implement %s',
+ $printerClass,
+ ResultPrinter::class
+ )
+ );
+ }
+
+ if (!$class->isInstantiable()) {
+ $this->exitWithErrorMessage(
+ sprintf(
+ 'Could not use "%s" as printer: class cannot be instantiated',
+ $printerClass
+ )
+ );
+ }
+
+ if ($class->isSubclassOf(ResultPrinter::class)) {
+ return $printerClass;
+ }
+
+ $outputStream = isset($this->arguments['stderr']) ? 'php://stderr' : null;
+
+ return $class->newInstance($outputStream);
+ }
+
+ /**
+ * Loads a bootstrap file.
+ */
+ protected function handleBootstrap(string $filename): void
+ {
+ try {
+ FileLoader::checkAndLoad($filename);
+ } catch (Throwable $t) {
+ if ($t instanceof \PHPUnit\Exception) {
+ $this->exitWithErrorMessage($t->getMessage());
+ }
+
+ $this->exitWithErrorMessage(
+ sprintf(
+ 'Error in bootstrap script: %s:%s%s',
+ get_class($t),
+ PHP_EOL,
+ $t->getMessage()
+ )
+ );
+ }
+ }
+
+ protected function handleVersionCheck(): void
+ {
+ $this->printVersionString();
+
+ $latestVersion = file_get_contents('https://phar.phpunit.de/latest-version-of/phpunit');
+ $isOutdated = version_compare($latestVersion, Version::id(), '>');
+
+ if ($isOutdated) {
+ printf(
+ 'You are not using the latest version of PHPUnit.' . PHP_EOL .
+ 'The latest version is PHPUnit %s.' . PHP_EOL,
+ $latestVersion
+ );
+ } else {
+ print 'You are using the latest version of PHPUnit.' . PHP_EOL;
+ }
+
+ exit(TestRunner::SUCCESS_EXIT);
+ }
+
+ /**
+ * Show the help message.
+ */
+ protected function showHelp(): void
+ {
+ $this->printVersionString();
+ (new Help)->writeToConsole();
+ }
+
+ /**
+ * Custom callback for test suite discovery.
+ */
+ protected function handleCustomTestSuite(): void
+ {
+ }
+
+ private function printVersionString(): void
+ {
+ if ($this->versionStringPrinted) {
+ return;
+ }
+
+ print Version::getVersionString() . PHP_EOL . PHP_EOL;
+
+ $this->versionStringPrinted = true;
+ }
+
+ private function exitWithErrorMessage(string $message): void
+ {
+ $this->printVersionString();
+
+ print $message . PHP_EOL;
+
+ exit(TestRunner::FAILURE_EXIT);
+ }
+
+ private function handleListGroups(TestSuite $suite, bool $exit): int
+ {
+ $this->printVersionString();
+
+ print 'Available test group(s):' . PHP_EOL;
+
+ $groups = $suite->getGroups();
+ sort($groups);
+
+ foreach ($groups as $group) {
+ if (strpos($group, '__phpunit_') === 0) {
+ continue;
+ }
+
+ printf(
+ ' - %s' . PHP_EOL,
+ $group
+ );
+ }
+
+ if ($exit) {
+ exit(TestRunner::SUCCESS_EXIT);
+ }
+
+ return TestRunner::SUCCESS_EXIT;
+ }
+
+ /**
+ * @throws \PHPUnit\Framework\Exception
+ * @throws \PHPUnit\TextUI\XmlConfiguration\Exception
+ */
+ private function handleListSuites(bool $exit): int
+ {
+ $this->printVersionString();
+
+ print 'Available test suite(s):' . PHP_EOL;
+
+ foreach ($this->arguments['configurationObject']->testSuite() as $testSuite) {
+ printf(
+ ' - %s' . PHP_EOL,
+ $testSuite->name()
+ );
+ }
+
+ if ($exit) {
+ exit(TestRunner::SUCCESS_EXIT);
+ }
+
+ return TestRunner::SUCCESS_EXIT;
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ private function handleListTests(TestSuite $suite, bool $exit): int
+ {
+ $this->printVersionString();
+
+ $renderer = new TextTestListRenderer;
+
+ print $renderer->render($suite);
+
+ if ($exit) {
+ exit(TestRunner::SUCCESS_EXIT);
+ }
+
+ return TestRunner::SUCCESS_EXIT;
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ private function handleListTestsXml(TestSuite $suite, string $target, bool $exit): int
+ {
+ $this->printVersionString();
+
+ $renderer = new XmlTestListRenderer;
+
+ file_put_contents($target, $renderer->render($suite));
+
+ printf(
+ 'Wrote list of tests that would have been run to %s' . PHP_EOL,
+ $target
+ );
+
+ if ($exit) {
+ exit(TestRunner::SUCCESS_EXIT);
+ }
+
+ return TestRunner::SUCCESS_EXIT;
+ }
+
+ private function generateConfiguration(): void
+ {
+ $this->printVersionString();
+
+ print 'Generating phpunit.xml in ' . getcwd() . PHP_EOL . PHP_EOL;
+ print 'Bootstrap script (relative to path shown above; default: vendor/autoload.php): ';
+
+ $bootstrapScript = trim(fgets(STDIN));
+
+ print 'Tests directory (relative to path shown above; default: tests): ';
+
+ $testsDirectory = trim(fgets(STDIN));
+
+ print 'Source directory (relative to path shown above; default: src): ';
+
+ $src = trim(fgets(STDIN));
+
+ print 'Cache directory (relative to path shown above; default: .phpunit.cache): ';
+
+ $cacheDirectory = trim(fgets(STDIN));
+
+ if ($bootstrapScript === '') {
+ $bootstrapScript = 'vendor/autoload.php';
+ }
+
+ if ($testsDirectory === '') {
+ $testsDirectory = 'tests';
+ }
+
+ if ($src === '') {
+ $src = 'src';
+ }
+
+ if ($cacheDirectory === '') {
+ $cacheDirectory = '.phpunit.cache';
+ }
+
+ $generator = new Generator;
+
+ file_put_contents(
+ 'phpunit.xml',
+ $generator->generateDefaultConfiguration(
+ Version::series(),
+ $bootstrapScript,
+ $testsDirectory,
+ $src,
+ $cacheDirectory
+ )
+ );
+
+ print PHP_EOL . 'Generated phpunit.xml in ' . getcwd() . '.' . PHP_EOL;
+ print 'Make sure to exclude the ' . $cacheDirectory . ' directory from version control.' . PHP_EOL;
+
+ exit(TestRunner::SUCCESS_EXIT);
+ }
+
+ private function migrateConfiguration(string $filename): void
+ {
+ $this->printVersionString();
+
+ if (!(new SchemaDetector)->detect($filename)->detected()) {
+ print $filename . ' does not need to be migrated.' . PHP_EOL;
+
+ exit(TestRunner::EXCEPTION_EXIT);
+ }
+
+ copy($filename, $filename . '.bak');
+
+ print 'Created backup: ' . $filename . '.bak' . PHP_EOL;
+
+ try {
+ file_put_contents(
+ $filename,
+ (new Migrator)->migrate($filename)
+ );
+
+ print 'Migrated configuration: ' . $filename . PHP_EOL;
+ } catch (Throwable $t) {
+ print 'Migration failed: ' . $t->getMessage() . PHP_EOL;
+
+ exit(TestRunner::EXCEPTION_EXIT);
+ }
+
+ exit(TestRunner::SUCCESS_EXIT);
+ }
+
+ private function handleCustomOptions(array $unrecognizedOptions): void
+ {
+ foreach ($unrecognizedOptions as $name => $value) {
+ if (isset($this->longOptions[$name])) {
+ $handler = $this->longOptions[$name];
+ }
+
+ $name .= '=';
+
+ if (isset($this->longOptions[$name])) {
+ $handler = $this->longOptions[$name];
+ }
+
+ if (isset($handler) && is_callable([$this, $handler])) {
+ $this->{$handler}($value);
+
+ unset($handler);
+ }
+ }
+ }
+
+ private function handleWarmCoverageCache(XmlConfiguration\Configuration $configuration): void
+ {
+ $this->printVersionString();
+
+ if (isset($this->arguments['coverageCacheDirectory'])) {
+ $cacheDirectory = $this->arguments['coverageCacheDirectory'];
+ } elseif ($configuration->codeCoverage()->hasCacheDirectory()) {
+ $cacheDirectory = $configuration->codeCoverage()->cacheDirectory()->path();
+ } else {
+ print 'Cache for static analysis has not been configured' . PHP_EOL;
+
+ exit(TestRunner::EXCEPTION_EXIT);
+ }
+
+ $filter = new Filter;
+
+ if ($configuration->codeCoverage()->hasNonEmptyListOfFilesToBeIncludedInCodeCoverageReport()) {
+ (new FilterMapper)->map(
+ $filter,
+ $configuration->codeCoverage()
+ );
+ } elseif (isset($this->arguments['coverageFilter'])) {
+ if (!is_array($this->arguments['coverageFilter'])) {
+ $coverageFilterDirectories = [$this->arguments['coverageFilter']];
+ } else {
+ $coverageFilterDirectories = $this->arguments['coverageFilter'];
+ }
+
+ foreach ($coverageFilterDirectories as $coverageFilterDirectory) {
+ $filter->includeDirectory($coverageFilterDirectory);
+ }
+ } else {
+ print 'Filter for code coverage has not been configured' . PHP_EOL;
+
+ exit(TestRunner::EXCEPTION_EXIT);
+ }
+
+ $timer = new Timer;
+ $timer->start();
+
+ print 'Warming cache for static analysis ... ';
+
+ (new CacheWarmer)->warmCache(
+ $cacheDirectory,
+ !$configuration->codeCoverage()->disableCodeCoverageIgnore(),
+ $configuration->codeCoverage()->ignoreDeprecatedCodeUnits(),
+ $filter
+ );
+
+ print 'done [' . $timer->stop()->asString() . ']' . PHP_EOL;
+
+ exit(TestRunner::SUCCESS_EXIT);
+ }
+
+ private function configurationFileInDirectory(string $directory): ?string
+ {
+ $candidates = [
+ $directory . '/phpunit.xml',
+ $directory . '/phpunit.xml.dist',
+ ];
+
+ foreach ($candidates as $candidate) {
+ if (is_file($candidate)) {
+ return realpath($candidate);
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php b/vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php
new file mode 100644
index 000000000..6a0ad2c79
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/DefaultResultPrinter.php
@@ -0,0 +1,592 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 array_map;
+use function array_reverse;
+use function count;
+use function floor;
+use function implode;
+use function in_array;
+use function is_int;
+use function max;
+use function preg_split;
+use function sprintf;
+use function str_pad;
+use function str_repeat;
+use function strlen;
+use function vsprintf;
+use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\Exception;
+use PHPUnit\Framework\InvalidArgumentException;
+use PHPUnit\Framework\Test;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestFailure;
+use PHPUnit\Framework\TestResult;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Framework\Warning;
+use PHPUnit\Runner\PhptTestCase;
+use PHPUnit\Util\Color;
+use PHPUnit\Util\Printer;
+use SebastianBergmann\Environment\Console;
+use SebastianBergmann\Timer\ResourceUsageFormatter;
+use SebastianBergmann\Timer\Timer;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class DefaultResultPrinter extends Printer implements ResultPrinter
+{
+ public const EVENT_TEST_START = 0;
+
+ public const EVENT_TEST_END = 1;
+
+ public const EVENT_TESTSUITE_START = 2;
+
+ public const EVENT_TESTSUITE_END = 3;
+
+ public const COLOR_NEVER = 'never';
+
+ public const COLOR_AUTO = 'auto';
+
+ public const COLOR_ALWAYS = 'always';
+
+ public const COLOR_DEFAULT = self::COLOR_NEVER;
+
+ private const AVAILABLE_COLORS = [self::COLOR_NEVER, self::COLOR_AUTO, self::COLOR_ALWAYS];
+
+ /**
+ * @var int
+ */
+ protected $column = 0;
+
+ /**
+ * @var int
+ */
+ protected $maxColumn;
+
+ /**
+ * @var bool
+ */
+ protected $lastTestFailed = false;
+
+ /**
+ * @var int
+ */
+ protected $numAssertions = 0;
+
+ /**
+ * @var int
+ */
+ protected $numTests = -1;
+
+ /**
+ * @var int
+ */
+ protected $numTestsRun = 0;
+
+ /**
+ * @var int
+ */
+ protected $numTestsWidth;
+
+ /**
+ * @var bool
+ */
+ protected $colors = false;
+
+ /**
+ * @var bool
+ */
+ protected $debug = false;
+
+ /**
+ * @var bool
+ */
+ protected $verbose = false;
+
+ /**
+ * @var int
+ */
+ private $numberOfColumns;
+
+ /**
+ * @var bool
+ */
+ private $reverse;
+
+ /**
+ * @var bool
+ */
+ private $defectListPrinted = false;
+
+ /**
+ * @var Timer
+ */
+ private $timer;
+
+ /**
+ * Constructor.
+ *
+ * @param null|resource|string $out
+ * @param int|string $numberOfColumns
+ *
+ * @throws Exception
+ */
+ public function __construct($out = null, bool $verbose = false, string $colors = self::COLOR_DEFAULT, bool $debug = false, $numberOfColumns = 80, bool $reverse = false)
+ {
+ parent::__construct($out);
+
+ if (!in_array($colors, self::AVAILABLE_COLORS, true)) {
+ throw InvalidArgumentException::create(
+ 3,
+ vsprintf('value from "%s", "%s" or "%s"', self::AVAILABLE_COLORS)
+ );
+ }
+
+ if (!is_int($numberOfColumns) && $numberOfColumns !== 'max') {
+ throw InvalidArgumentException::create(5, 'integer or "max"');
+ }
+
+ $console = new Console;
+ $maxNumberOfColumns = $console->getNumberOfColumns();
+
+ if ($numberOfColumns === 'max' || ($numberOfColumns !== 80 && $numberOfColumns > $maxNumberOfColumns)) {
+ $numberOfColumns = $maxNumberOfColumns;
+ }
+
+ $this->numberOfColumns = $numberOfColumns;
+ $this->verbose = $verbose;
+ $this->debug = $debug;
+ $this->reverse = $reverse;
+
+ if ($colors === self::COLOR_AUTO && $console->hasColorSupport()) {
+ $this->colors = true;
+ } else {
+ $this->colors = (self::COLOR_ALWAYS === $colors);
+ }
+
+ $this->timer = new Timer;
+
+ $this->timer->start();
+ }
+
+ public function printResult(TestResult $result): void
+ {
+ $this->printHeader($result);
+ $this->printErrors($result);
+ $this->printWarnings($result);
+ $this->printFailures($result);
+ $this->printRisky($result);
+
+ if ($this->verbose) {
+ $this->printIncompletes($result);
+ $this->printSkipped($result);
+ }
+
+ $this->printFooter($result);
+ }
+
+ /**
+ * An error occurred.
+ */
+ public function addError(Test $test, Throwable $t, float $time): void
+ {
+ $this->writeProgressWithColor('fg-red, bold', 'E');
+ $this->lastTestFailed = true;
+ }
+
+ /**
+ * A failure occurred.
+ */
+ public function addFailure(Test $test, AssertionFailedError $e, float $time): void
+ {
+ $this->writeProgressWithColor('bg-red, fg-white', 'F');
+ $this->lastTestFailed = true;
+ }
+
+ /**
+ * A warning occurred.
+ */
+ public function addWarning(Test $test, Warning $e, float $time): void
+ {
+ $this->writeProgressWithColor('fg-yellow, bold', 'W');
+ $this->lastTestFailed = true;
+ }
+
+ /**
+ * Incomplete test.
+ */
+ public function addIncompleteTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->writeProgressWithColor('fg-yellow, bold', 'I');
+ $this->lastTestFailed = true;
+ }
+
+ /**
+ * Risky test.
+ */
+ public function addRiskyTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->writeProgressWithColor('fg-yellow, bold', 'R');
+ $this->lastTestFailed = true;
+ }
+
+ /**
+ * Skipped test.
+ */
+ public function addSkippedTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->writeProgressWithColor('fg-cyan, bold', 'S');
+ $this->lastTestFailed = true;
+ }
+
+ /**
+ * A testsuite started.
+ */
+ public function startTestSuite(TestSuite $suite): void
+ {
+ if ($this->numTests == -1) {
+ $this->numTests = count($suite);
+ $this->numTestsWidth = strlen((string) $this->numTests);
+ $this->maxColumn = $this->numberOfColumns - strlen(' / (XXX%)') - (2 * $this->numTestsWidth);
+ }
+ }
+
+ /**
+ * A testsuite ended.
+ */
+ public function endTestSuite(TestSuite $suite): void
+ {
+ }
+
+ /**
+ * A test started.
+ */
+ public function startTest(Test $test): void
+ {
+ if ($this->debug) {
+ $this->write(
+ sprintf(
+ "Test '%s' started\n",
+ \PHPUnit\Util\Test::describeAsString($test)
+ )
+ );
+ }
+ }
+
+ /**
+ * A test ended.
+ */
+ public function endTest(Test $test, float $time): void
+ {
+ if ($this->debug) {
+ $this->write(
+ sprintf(
+ "Test '%s' ended\n",
+ \PHPUnit\Util\Test::describeAsString($test)
+ )
+ );
+ }
+
+ if (!$this->lastTestFailed) {
+ $this->writeProgress('.');
+ }
+
+ if ($test instanceof TestCase) {
+ $this->numAssertions += $test->getNumAssertions();
+ } elseif ($test instanceof PhptTestCase) {
+ $this->numAssertions++;
+ }
+
+ $this->lastTestFailed = false;
+
+ if ($test instanceof TestCase && !$test->hasExpectationOnOutput()) {
+ $this->write($test->getActualOutput());
+ }
+ }
+
+ protected function printDefects(array $defects, string $type): void
+ {
+ $count = count($defects);
+
+ if ($count == 0) {
+ return;
+ }
+
+ if ($this->defectListPrinted) {
+ $this->write("\n--\n\n");
+ }
+
+ $this->write(
+ sprintf(
+ "There %s %d %s%s:\n",
+ ($count == 1) ? 'was' : 'were',
+ $count,
+ $type,
+ ($count == 1) ? '' : 's'
+ )
+ );
+
+ $i = 1;
+
+ if ($this->reverse) {
+ $defects = array_reverse($defects);
+ }
+
+ foreach ($defects as $defect) {
+ $this->printDefect($defect, $i++);
+ }
+
+ $this->defectListPrinted = true;
+ }
+
+ protected function printDefect(TestFailure $defect, int $count): void
+ {
+ $this->printDefectHeader($defect, $count);
+ $this->printDefectTrace($defect);
+ }
+
+ protected function printDefectHeader(TestFailure $defect, int $count): void
+ {
+ $this->write(
+ sprintf(
+ "\n%d) %s\n",
+ $count,
+ $defect->getTestName()
+ )
+ );
+ }
+
+ protected function printDefectTrace(TestFailure $defect): void
+ {
+ $e = $defect->thrownException();
+
+ $this->write((string) $e);
+
+ while ($e = $e->getPrevious()) {
+ $this->write("\nCaused by\n" . $e);
+ }
+ }
+
+ protected function printErrors(TestResult $result): void
+ {
+ $this->printDefects($result->errors(), 'error');
+ }
+
+ protected function printFailures(TestResult $result): void
+ {
+ $this->printDefects($result->failures(), 'failure');
+ }
+
+ protected function printWarnings(TestResult $result): void
+ {
+ $this->printDefects($result->warnings(), 'warning');
+ }
+
+ protected function printIncompletes(TestResult $result): void
+ {
+ $this->printDefects($result->notImplemented(), 'incomplete test');
+ }
+
+ protected function printRisky(TestResult $result): void
+ {
+ $this->printDefects($result->risky(), 'risky test');
+ }
+
+ protected function printSkipped(TestResult $result): void
+ {
+ $this->printDefects($result->skipped(), 'skipped test');
+ }
+
+ protected function printHeader(TestResult $result): void
+ {
+ if (count($result) > 0) {
+ $this->write(PHP_EOL . PHP_EOL . (new ResourceUsageFormatter)->resourceUsage($this->timer->stop()) . PHP_EOL . PHP_EOL);
+ }
+ }
+
+ protected function printFooter(TestResult $result): void
+ {
+ if (count($result) === 0) {
+ $this->writeWithColor(
+ 'fg-black, bg-yellow',
+ 'No tests executed!'
+ );
+
+ return;
+ }
+
+ if ($result->wasSuccessfulAndNoTestIsRiskyOrSkippedOrIncomplete()) {
+ $this->writeWithColor(
+ 'fg-black, bg-green',
+ sprintf(
+ 'OK (%d test%s, %d assertion%s)',
+ count($result),
+ (count($result) === 1) ? '' : 's',
+ $this->numAssertions,
+ ($this->numAssertions === 1) ? '' : 's'
+ )
+ );
+
+ return;
+ }
+
+ $color = 'fg-black, bg-yellow';
+
+ if ($result->wasSuccessful()) {
+ if ($this->verbose || !$result->allHarmless()) {
+ $this->write("\n");
+ }
+
+ $this->writeWithColor(
+ $color,
+ 'OK, but incomplete, skipped, or risky tests!'
+ );
+ } else {
+ $this->write("\n");
+
+ if ($result->errorCount()) {
+ $color = 'fg-white, bg-red';
+
+ $this->writeWithColor(
+ $color,
+ 'ERRORS!'
+ );
+ } elseif ($result->failureCount()) {
+ $color = 'fg-white, bg-red';
+
+ $this->writeWithColor(
+ $color,
+ 'FAILURES!'
+ );
+ } elseif ($result->warningCount()) {
+ $color = 'fg-black, bg-yellow';
+
+ $this->writeWithColor(
+ $color,
+ 'WARNINGS!'
+ );
+ }
+ }
+
+ $this->writeCountString(count($result), 'Tests', $color, true);
+ $this->writeCountString($this->numAssertions, 'Assertions', $color, true);
+ $this->writeCountString($result->errorCount(), 'Errors', $color);
+ $this->writeCountString($result->failureCount(), 'Failures', $color);
+ $this->writeCountString($result->warningCount(), 'Warnings', $color);
+ $this->writeCountString($result->skippedCount(), 'Skipped', $color);
+ $this->writeCountString($result->notImplementedCount(), 'Incomplete', $color);
+ $this->writeCountString($result->riskyCount(), 'Risky', $color);
+ $this->writeWithColor($color, '.');
+ }
+
+ protected function writeProgress(string $progress): void
+ {
+ if ($this->debug) {
+ return;
+ }
+
+ $this->write($progress);
+ $this->column++;
+ $this->numTestsRun++;
+
+ if ($this->column == $this->maxColumn || $this->numTestsRun == $this->numTests) {
+ if ($this->numTestsRun == $this->numTests) {
+ $this->write(str_repeat(' ', $this->maxColumn - $this->column));
+ }
+
+ $this->write(
+ sprintf(
+ ' %' . $this->numTestsWidth . 'd / %' .
+ $this->numTestsWidth . 'd (%3s%%)',
+ $this->numTestsRun,
+ $this->numTests,
+ floor(($this->numTestsRun / $this->numTests) * 100)
+ )
+ );
+
+ if ($this->column == $this->maxColumn) {
+ $this->writeNewLine();
+ }
+ }
+ }
+
+ protected function writeNewLine(): void
+ {
+ $this->column = 0;
+ $this->write("\n");
+ }
+
+ /**
+ * Formats a buffer with a specified ANSI color sequence if colors are
+ * enabled.
+ */
+ protected function colorizeTextBox(string $color, string $buffer): string
+ {
+ if (!$this->colors) {
+ return $buffer;
+ }
+
+ $lines = preg_split('/\r\n|\r|\n/', $buffer);
+ $padding = max(array_map('\strlen', $lines));
+
+ $styledLines = [];
+
+ foreach ($lines as $line) {
+ $styledLines[] = Color::colorize($color, str_pad($line, $padding));
+ }
+
+ return implode(PHP_EOL, $styledLines);
+ }
+
+ /**
+ * Writes a buffer out with a color sequence if colors are enabled.
+ */
+ protected function writeWithColor(string $color, string $buffer, bool $lf = true): void
+ {
+ $this->write($this->colorizeTextBox($color, $buffer));
+
+ if ($lf) {
+ $this->write(PHP_EOL);
+ }
+ }
+
+ /**
+ * Writes progress with a color sequence if colors are enabled.
+ */
+ protected function writeProgressWithColor(string $color, string $buffer): void
+ {
+ $buffer = $this->colorizeTextBox($color, $buffer);
+ $this->writeProgress($buffer);
+ }
+
+ private function writeCountString(int $count, string $name, string $color, bool $always = false): void
+ {
+ static $first = true;
+
+ if ($always || $count > 0) {
+ $this->writeWithColor(
+ $color,
+ sprintf(
+ '%s%s: %d',
+ !$first ? ', ' : '',
+ $name,
+ $count
+ ),
+ false
+ );
+
+ $first = false;
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/Exception/Exception.php b/vendor/phpunit/phpunit/src/TextUI/Exception/Exception.php
new file mode 100644
index 000000000..ee2ae4ffa
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/Exception/Exception.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI;
+
+use Throwable;
+
+/**
+ * @internal This interface is not covered by the backward compatibility promise for PHPUnit
+ */
+interface Exception extends Throwable
+{
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/Exception/ReflectionException.php b/vendor/phpunit/phpunit/src/TextUI/Exception/ReflectionException.php
new file mode 100644
index 000000000..74e9d25dd
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/Exception/ReflectionException.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI;
+
+use RuntimeException;
+
+/**
+ * @internal This interface is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ReflectionException extends RuntimeException implements Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/Exception/RuntimeException.php b/vendor/phpunit/phpunit/src/TextUI/Exception/RuntimeException.php
new file mode 100644
index 000000000..790a84634
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/Exception/RuntimeException.php
@@ -0,0 +1,17 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI;
+
+/**
+ * @internal This interface is not covered by the backward compatibility promise for PHPUnit
+ */
+final class RuntimeException extends \RuntimeException implements Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/Exception/TestDirectoryNotFoundException.php b/vendor/phpunit/phpunit/src/TextUI/Exception/TestDirectoryNotFoundException.php
new file mode 100644
index 000000000..770ad8742
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/Exception/TestDirectoryNotFoundException.php
@@ -0,0 +1,29 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This interface is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestDirectoryNotFoundException extends RuntimeException implements Exception
+{
+ public function __construct(string $path)
+ {
+ parent::__construct(
+ sprintf(
+ 'Test directory "%s" not found',
+ $path
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/Exception/TestFileNotFoundException.php b/vendor/phpunit/phpunit/src/TextUI/Exception/TestFileNotFoundException.php
new file mode 100644
index 000000000..7ffd2c78c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/Exception/TestFileNotFoundException.php
@@ -0,0 +1,29 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This interface is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestFileNotFoundException extends RuntimeException implements Exception
+{
+ public function __construct(string $path)
+ {
+ parent::__construct(
+ sprintf(
+ 'Test file "%s" not found',
+ $path
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/Help.php b/vendor/phpunit/phpunit/src/TextUI/Help.php
new file mode 100644
index 000000000..084f2a218
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/Help.php
@@ -0,0 +1,265 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 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 SebastianBergmann\Environment\Console;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Help
+{
+ private const LEFT_MARGIN = ' ';
+
+ private const HELP_TEXT = [
+ 'Usage' => [
+ ['text' => 'phpunit [options] UnitTest.php'],
+ ['text' => 'phpunit [options] <directory>'],
+ ],
+
+ 'Code Coverage Options' => [
+ ['arg' => '--coverage-clover <file>', 'desc' => 'Generate code coverage report in Clover XML format'],
+ ['arg' => '--coverage-cobertura <file>', 'desc' => 'Generate code coverage report in Cobertura XML format'],
+ ['arg' => '--coverage-crap4j <file>', 'desc' => 'Generate code coverage report in Crap4J XML format'],
+ ['arg' => '--coverage-html <dir>', 'desc' => 'Generate code coverage report in HTML format'],
+ ['arg' => '--coverage-php <file>', 'desc' => 'Export PHP_CodeCoverage object to file'],
+ ['arg' => '--coverage-text=<file>', 'desc' => 'Generate code coverage report in text format [default: standard output]'],
+ ['arg' => '--coverage-xml <dir>', 'desc' => 'Generate code coverage report in PHPUnit XML format'],
+ ['arg' => '--coverage-cache <dir>', 'desc' => 'Cache static analysis results'],
+ ['arg' => '--warm-coverage-cache', 'desc' => 'Warm static analysis cache'],
+ ['arg' => '--coverage-filter <dir>', 'desc' => 'Include <dir> in code coverage analysis'],
+ ['arg' => '--path-coverage', 'desc' => 'Perform path coverage analysis'],
+ ['arg' => '--disable-coverage-ignore', 'desc' => 'Disable annotations for ignoring code coverage'],
+ ['arg' => '--no-coverage', 'desc' => 'Ignore code coverage configuration'],
+ ],
+
+ 'Logging Options' => [
+ ['arg' => '--log-junit <file>', 'desc' => 'Log test execution in JUnit XML format to file'],
+ ['arg' => '--log-teamcity <file>', 'desc' => 'Log test execution in TeamCity format to file'],
+ ['arg' => '--testdox-html <file>', 'desc' => 'Write agile documentation in HTML format to file'],
+ ['arg' => '--testdox-text <file>', 'desc' => 'Write agile documentation in Text format to file'],
+ ['arg' => '--testdox-xml <file>', 'desc' => 'Write agile documentation in XML format to file'],
+ ['arg' => '--reverse-list', 'desc' => 'Print defects in reverse order'],
+ ['arg' => '--no-logging', 'desc' => 'Ignore logging configuration'],
+ ],
+
+ 'Test Selection Options' => [
+ ['arg' => '--list-suites', 'desc' => 'List available test suites'],
+ ['arg' => '--testsuite <name>', 'desc' => 'Filter which testsuite to run'],
+ ['arg' => '--list-groups', 'desc' => 'List available test groups'],
+ ['arg' => '--group <name>', 'desc' => 'Only runs tests from the specified group(s)'],
+ ['arg' => '--exclude-group <name>', 'desc' => 'Exclude tests from the specified group(s)'],
+ ['arg' => '--covers <name>', 'desc' => 'Only runs tests annotated with "@covers <name>"'],
+ ['arg' => '--uses <name>', 'desc' => 'Only runs tests annotated with "@uses <name>"'],
+ ['arg' => '--list-tests', 'desc' => 'List available tests'],
+ ['arg' => '--list-tests-xml <file>', 'desc' => 'List available tests in XML format'],
+ ['arg' => '--filter <pattern>', 'desc' => 'Filter which tests to run'],
+ ['arg' => '--test-suffix <suffixes>', 'desc' => 'Only search for test in files with specified suffix(es). Default: Test.php,.phpt'],
+ ],
+
+ 'Test Execution Options' => [
+ ['arg' => '--dont-report-useless-tests', 'desc' => 'Do not report tests that do not test anything'],
+ ['arg' => '--strict-coverage', 'desc' => 'Be strict about @covers annotation usage'],
+ ['arg' => '--strict-global-state', 'desc' => 'Be strict about changes to global state'],
+ ['arg' => '--disallow-test-output', 'desc' => 'Be strict about output during tests'],
+ ['arg' => '--disallow-resource-usage', 'desc' => 'Be strict about resource usage during small tests'],
+ ['arg' => '--enforce-time-limit', 'desc' => 'Enforce time limit based on test size'],
+ ['arg' => '--default-time-limit <sec>', 'desc' => 'Timeout in seconds for tests without @small, @medium or @large'],
+ ['arg' => '--disallow-todo-tests', 'desc' => 'Disallow @todo-annotated tests'],
+ ['spacer' => ''],
+
+ ['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 attributes for each test'],
+ ['spacer' => ''],
+
+ ['arg' => '--colors <flag>', 'desc' => 'Use colors in output ("never", "auto" or "always")'],
+ ['arg' => '--columns <n>', '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'],
+ ['arg' => '--stop-on-defect', 'desc' => 'Stop execution upon first not-passed test'],
+ ['arg' => '--stop-on-error', 'desc' => 'Stop execution upon first error'],
+ ['arg' => '--stop-on-failure', 'desc' => 'Stop execution upon first error or failure'],
+ ['arg' => '--stop-on-warning', 'desc' => 'Stop execution upon first warning'],
+ ['arg' => '--stop-on-risky', 'desc' => 'Stop execution upon first risky test'],
+ ['arg' => '--stop-on-skipped', 'desc' => 'Stop execution upon first skipped test'],
+ ['arg' => '--stop-on-incomplete', 'desc' => 'Stop execution upon first incomplete test'],
+ ['arg' => '--fail-on-incomplete', 'desc' => 'Treat incomplete tests as failures'],
+ ['arg' => '--fail-on-risky', 'desc' => 'Treat risky tests as failures'],
+ ['arg' => '--fail-on-skipped', 'desc' => 'Treat skipped tests as failures'],
+ ['arg' => '--fail-on-warning', 'desc' => 'Treat tests with warnings as failures'],
+ ['arg' => '-v|--verbose', 'desc' => 'Output more verbose information'],
+ ['arg' => '--debug', 'desc' => 'Display debugging information'],
+ ['spacer' => ''],
+
+ ['arg' => '--repeat <times>', 'desc' => 'Runs the test(s) repeatedly'],
+ ['arg' => '--teamcity', 'desc' => 'Report test execution progress in TeamCity format'],
+ ['arg' => '--testdox', 'desc' => 'Report test execution progress in TestDox format'],
+ ['arg' => '--testdox-group', 'desc' => 'Only include tests from the specified group(s)'],
+ ['arg' => '--testdox-exclude-group', 'desc' => 'Exclude tests from the specified group(s)'],
+ ['arg' => '--no-interaction', 'desc' => 'Disable TestDox progress animation'],
+ ['arg' => '--printer <printer>', 'desc' => 'TestListener implementation to use'],
+ ['spacer' => ''],
+
+ ['arg' => '--order-by <order>', 'desc' => 'Run tests in order: default|defects|duration|no-depends|random|reverse|size'],
+ ['arg' => '--random-order-seed <N>', 'desc' => 'Use a specific random seed <N> for random order'],
+ ['arg' => '--cache-result', 'desc' => 'Write test results to cache file'],
+ ['arg' => '--do-not-cache-result', 'desc' => 'Do not write test results to cache file'],
+ ],
+
+ 'Configuration Options' => [
+ ['arg' => '--prepend <file>', 'desc' => 'A PHP script that is included as early as possible'],
+ ['arg' => '--bootstrap <file>', 'desc' => 'A PHP script that is included before the tests run'],
+ ['arg' => '-c|--configuration <file>', 'desc' => 'Read configuration from XML file'],
+ ['arg' => '--no-configuration', 'desc' => 'Ignore default configuration file (phpunit.xml)'],
+ ['arg' => '--extensions <extensions>', 'desc' => 'A comma separated list of PHPUnit extensions to load'],
+ ['arg' => '--no-extensions', 'desc' => 'Do not load PHPUnit extensions'],
+ ['arg' => '--include-path <path(s)>', 'desc' => 'Prepend PHP\'s include_path with given path(s)'],
+ ['arg' => '-d <key[=value]>', 'desc' => 'Sets a php.ini value'],
+ ['arg' => '--cache-result-file <file>', 'desc' => 'Specify result cache path and filename'],
+ ['arg' => '--generate-configuration', 'desc' => 'Generate configuration file with suggested settings'],
+ ['arg' => '--migrate-configuration', 'desc' => 'Migrate configuration file to current format'],
+ ],
+
+ 'Miscellaneous Options' => [
+ ['arg' => '-h|--help', 'desc' => 'Prints this usage information'],
+ ['arg' => '--version', 'desc' => 'Prints the version and exits'],
+ ['arg' => '--atleast-version <min>', 'desc' => 'Checks that version is greater than min and exits'],
+ ['arg' => '--check-version', 'desc' => 'Check whether PHPUnit is the latest version'],
+ ],
+
+ ];
+
+ /**
+ * @var int Number of columns required to write the longest option name to the console
+ */
+ private $maxArgLength = 0;
+
+ /**
+ * @var int Number of columns left for the description field after padding and option
+ */
+ private $maxDescLength;
+
+ /**
+ * @var bool Use color highlights for sections, options and parameters
+ */
+ private $hasColor = false;
+
+ 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 (self::HELP_TEXT as $options) {
+ foreach ($options as $option) {
+ if (isset($option['arg'])) {
+ $this->maxArgLength = max($this->maxArgLength, isset($option['arg']) ? strlen($option['arg']) : 0);
+ }
+ }
+ }
+
+ $this->maxDescLength = $width - $this->maxArgLength - 4;
+ }
+
+ /**
+ * Write the help file to the CLI, adapting width and colors to the console.
+ */
+ public function writeToConsole(): void
+ {
+ if ($this->hasColor) {
+ $this->writeWithColor();
+ } else {
+ $this->writePlaintext();
+ }
+ }
+
+ private function writePlaintext(): void
+ {
+ foreach (self::HELP_TEXT as $section => $options) {
+ print "{$section}:" . PHP_EOL;
+
+ if ($section !== 'Usage') {
+ print PHP_EOL;
+ }
+
+ foreach ($options as $option) {
+ if (isset($option['spacer'])) {
+ print PHP_EOL;
+ }
+
+ if (isset($option['text'])) {
+ print self::LEFT_MARGIN . $option['text'] . PHP_EOL;
+ }
+
+ if (isset($option['arg'])) {
+ $arg = str_pad($option['arg'], $this->maxArgLength);
+ print self::LEFT_MARGIN . $arg . ' ' . $option['desc'] . PHP_EOL;
+ }
+ }
+
+ print PHP_EOL;
+ }
+ }
+
+ private function writeWithColor(): void
+ {
+ foreach (self::HELP_TEXT as $section => $options) {
+ print Color::colorize('fg-yellow', "{$section}:") . PHP_EOL;
+
+ foreach ($options as $option) {
+ if (isset($option['spacer'])) {
+ print PHP_EOL;
+ }
+
+ if (isset($option['text'])) {
+ print self::LEFT_MARGIN . $option['text'] . PHP_EOL;
+ }
+
+ if (isset($option['arg'])) {
+ $arg = Color::colorize('fg-green', str_pad($option['arg'], $this->maxArgLength));
+ $arg = preg_replace_callback(
+ '/(<[^>]+>)/',
+ static function ($matches)
+ {
+ return Color::colorize('fg-cyan', $matches[0]);
+ },
+ $arg
+ );
+ $desc = explode(PHP_EOL, wordwrap($option['desc'], $this->maxDescLength, PHP_EOL));
+
+ print self::LEFT_MARGIN . $arg . ' ' . $desc[0] . PHP_EOL;
+
+ for ($i = 1; $i < count($desc); $i++) {
+ print str_repeat(' ', $this->maxArgLength + 3) . $desc[$i] . PHP_EOL;
+ }
+ }
+ }
+
+ print PHP_EOL;
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/ResultPrinter.php b/vendor/phpunit/phpunit/src/TextUI/ResultPrinter.php
new file mode 100644
index 000000000..ec89f6006
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/ResultPrinter.php
@@ -0,0 +1,23 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI;
+
+use PHPUnit\Framework\TestListener;
+use PHPUnit\Framework\TestResult;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+interface ResultPrinter extends TestListener
+{
+ public function printResult(TestResult $result): void;
+
+ public function write(string $buffer): void;
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/TestRunner.php b/vendor/phpunit/phpunit/src/TextUI/TestRunner.php
new file mode 100644
index 000000000..dfda9359b
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/TestRunner.php
@@ -0,0 +1,1272 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_SAPI;
+use const PHP_VERSION;
+use function array_diff;
+use function array_map;
+use function array_merge;
+use function assert;
+use function class_exists;
+use function count;
+use function dirname;
+use function file_put_contents;
+use function htmlspecialchars;
+use function is_array;
+use function is_int;
+use function is_string;
+use function mt_srand;
+use function range;
+use function realpath;
+use function sprintf;
+use function time;
+use PHPUnit\Framework\Exception;
+use PHPUnit\Framework\TestResult;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Runner\AfterLastTestHook;
+use PHPUnit\Runner\BaseTestRunner;
+use PHPUnit\Runner\BeforeFirstTestHook;
+use PHPUnit\Runner\DefaultTestResultCache;
+use PHPUnit\Runner\Extension\ExtensionHandler;
+use PHPUnit\Runner\Filter\ExcludeGroupFilterIterator;
+use PHPUnit\Runner\Filter\Factory;
+use PHPUnit\Runner\Filter\IncludeGroupFilterIterator;
+use PHPUnit\Runner\Filter\NameFilterIterator;
+use PHPUnit\Runner\Hook;
+use PHPUnit\Runner\NullTestResultCache;
+use PHPUnit\Runner\ResultCacheExtension;
+use PHPUnit\Runner\StandardTestSuiteLoader;
+use PHPUnit\Runner\TestHook;
+use PHPUnit\Runner\TestListenerAdapter;
+use PHPUnit\Runner\TestSuiteLoader;
+use PHPUnit\Runner\TestSuiteSorter;
+use PHPUnit\Runner\Version;
+use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\FilterMapper;
+use PHPUnit\TextUI\XmlConfiguration\Configuration;
+use PHPUnit\TextUI\XmlConfiguration\Loader;
+use PHPUnit\TextUI\XmlConfiguration\PhpHandler;
+use PHPUnit\Util\Filesystem;
+use PHPUnit\Util\Log\JUnit;
+use PHPUnit\Util\Log\TeamCity;
+use PHPUnit\Util\Printer;
+use PHPUnit\Util\TestDox\CliTestDoxPrinter;
+use PHPUnit\Util\TestDox\HtmlResultPrinter;
+use PHPUnit\Util\TestDox\TextResultPrinter;
+use PHPUnit\Util\TestDox\XmlResultPrinter;
+use PHPUnit\Util\XdebugFilterScriptGenerator;
+use PHPUnit\Util\Xml\SchemaDetector;
+use ReflectionClass;
+use ReflectionException;
+use SebastianBergmann\CodeCoverage\CodeCoverage;
+use SebastianBergmann\CodeCoverage\Driver\Selector;
+use SebastianBergmann\CodeCoverage\Exception as CodeCoverageException;
+use SebastianBergmann\CodeCoverage\Filter as CodeCoverageFilter;
+use SebastianBergmann\CodeCoverage\Report\Clover as CloverReport;
+use SebastianBergmann\CodeCoverage\Report\Cobertura as CoberturaReport;
+use SebastianBergmann\CodeCoverage\Report\Crap4j as Crap4jReport;
+use SebastianBergmann\CodeCoverage\Report\Html\Facade as HtmlReport;
+use SebastianBergmann\CodeCoverage\Report\PHP as PhpReport;
+use SebastianBergmann\CodeCoverage\Report\Text as TextReport;
+use SebastianBergmann\CodeCoverage\Report\Xml\Facade as XmlReport;
+use SebastianBergmann\Comparator\Comparator;
+use SebastianBergmann\Environment\Runtime;
+use SebastianBergmann\Invoker\Invoker;
+use SebastianBergmann\Timer\Timer;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestRunner extends BaseTestRunner
+{
+ public const SUCCESS_EXIT = 0;
+
+ public const FAILURE_EXIT = 1;
+
+ public const EXCEPTION_EXIT = 2;
+
+ /**
+ * @var CodeCoverageFilter
+ */
+ private $codeCoverageFilter;
+
+ /**
+ * @var TestSuiteLoader
+ */
+ private $loader;
+
+ /**
+ * @var ResultPrinter
+ */
+ private $printer;
+
+ /**
+ * @var bool
+ */
+ private $messagePrinted = false;
+
+ /**
+ * @var Hook[]
+ */
+ private $extensions = [];
+
+ /**
+ * @var Timer
+ */
+ private $timer;
+
+ public function __construct(TestSuiteLoader $loader = null, CodeCoverageFilter $filter = null)
+ {
+ if ($filter === null) {
+ $filter = new CodeCoverageFilter;
+ }
+
+ $this->codeCoverageFilter = $filter;
+ $this->loader = $loader;
+ $this->timer = new Timer;
+ }
+
+ /**
+ * @throws \PHPUnit\Runner\Exception
+ * @throws \PHPUnit\TextUI\XmlConfiguration\Exception
+ * @throws Exception
+ */
+ public function run(TestSuite $suite, array $arguments = [], array $warnings = [], bool $exit = true): TestResult
+ {
+ if (isset($arguments['configuration'])) {
+ $GLOBALS['__PHPUNIT_CONFIGURATION_FILE'] = $arguments['configuration'];
+ }
+
+ $this->handleConfiguration($arguments);
+
+ $warnings = array_merge($warnings, $arguments['warnings']);
+
+ if (is_int($arguments['columns']) && $arguments['columns'] < 16) {
+ $arguments['columns'] = 16;
+ $tooFewColumnsRequested = true;
+ }
+
+ if (isset($arguments['bootstrap'])) {
+ $GLOBALS['__PHPUNIT_BOOTSTRAP'] = $arguments['bootstrap'];
+ }
+
+ if ($arguments['backupGlobals'] === true) {
+ $suite->setBackupGlobals(true);
+ }
+
+ if ($arguments['backupStaticAttributes'] === true) {
+ $suite->setBackupStaticAttributes(true);
+ }
+
+ if ($arguments['beStrictAboutChangesToGlobalState'] === true) {
+ $suite->setBeStrictAboutChangesToGlobalState(true);
+ }
+
+ if ($arguments['executionOrder'] === TestSuiteSorter::ORDER_RANDOMIZED) {
+ mt_srand($arguments['randomOrderSeed']);
+ }
+
+ if ($arguments['cacheResult']) {
+ if (!isset($arguments['cacheResultFile'])) {
+ if (isset($arguments['configurationObject'])) {
+ assert($arguments['configurationObject'] instanceof Configuration);
+
+ $cacheLocation = $arguments['configurationObject']->filename();
+ } else {
+ $cacheLocation = $_SERVER['PHP_SELF'];
+ }
+
+ $arguments['cacheResultFile'] = null;
+
+ $cacheResultFile = realpath($cacheLocation);
+
+ if ($cacheResultFile !== false) {
+ $arguments['cacheResultFile'] = dirname($cacheResultFile);
+ }
+ }
+
+ $cache = new DefaultTestResultCache($arguments['cacheResultFile']);
+
+ $this->addExtension(new ResultCacheExtension($cache));
+ }
+
+ if ($arguments['executionOrder'] !== TestSuiteSorter::ORDER_DEFAULT || $arguments['executionOrderDefects'] !== TestSuiteSorter::ORDER_DEFAULT || $arguments['resolveDependencies']) {
+ $cache = $cache ?? new NullTestResultCache;
+
+ $cache->load();
+
+ $sorter = new TestSuiteSorter($cache);
+
+ $sorter->reorderTestsInSuite($suite, $arguments['executionOrder'], $arguments['resolveDependencies'], $arguments['executionOrderDefects']);
+ $originalExecutionOrder = $sorter->getOriginalExecutionOrder();
+
+ unset($sorter);
+ }
+
+ if (is_int($arguments['repeat']) && $arguments['repeat'] > 0) {
+ $_suite = new TestSuite;
+
+ /* @noinspection PhpUnusedLocalVariableInspection */
+ foreach (range(1, $arguments['repeat']) as $step) {
+ $_suite->addTest($suite);
+ }
+
+ $suite = $_suite;
+
+ unset($_suite);
+ }
+
+ $result = $this->createTestResult();
+
+ $listener = new TestListenerAdapter;
+ $listenerNeeded = false;
+
+ foreach ($this->extensions as $extension) {
+ if ($extension instanceof TestHook) {
+ $listener->add($extension);
+
+ $listenerNeeded = true;
+ }
+ }
+
+ if ($listenerNeeded) {
+ $result->addListener($listener);
+ }
+
+ unset($listener, $listenerNeeded);
+
+ if ($arguments['convertDeprecationsToExceptions']) {
+ $result->convertDeprecationsToExceptions(true);
+ }
+
+ if (!$arguments['convertErrorsToExceptions']) {
+ $result->convertErrorsToExceptions(false);
+ }
+
+ if (!$arguments['convertNoticesToExceptions']) {
+ $result->convertNoticesToExceptions(false);
+ }
+
+ if (!$arguments['convertWarningsToExceptions']) {
+ $result->convertWarningsToExceptions(false);
+ }
+
+ if ($arguments['stopOnError']) {
+ $result->stopOnError(true);
+ }
+
+ if ($arguments['stopOnFailure']) {
+ $result->stopOnFailure(true);
+ }
+
+ if ($arguments['stopOnWarning']) {
+ $result->stopOnWarning(true);
+ }
+
+ if ($arguments['stopOnIncomplete']) {
+ $result->stopOnIncomplete(true);
+ }
+
+ if ($arguments['stopOnRisky']) {
+ $result->stopOnRisky(true);
+ }
+
+ if ($arguments['stopOnSkipped']) {
+ $result->stopOnSkipped(true);
+ }
+
+ if ($arguments['stopOnDefect']) {
+ $result->stopOnDefect(true);
+ }
+
+ if ($arguments['registerMockObjectsFromTestArgumentsRecursively']) {
+ $result->setRegisterMockObjectsFromTestArgumentsRecursively(true);
+ }
+
+ if ($this->printer === null) {
+ if (isset($arguments['printer'])) {
+ if ($arguments['printer'] instanceof ResultPrinter) {
+ $this->printer = $arguments['printer'];
+ } elseif (is_string($arguments['printer']) && class_exists($arguments['printer'], false)) {
+ try {
+ $reflector = new ReflectionClass($arguments['printer']);
+
+ if ($reflector->implementsInterface(ResultPrinter::class)) {
+ $this->printer = $this->createPrinter($arguments['printer'], $arguments);
+ }
+
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+ } else {
+ $this->printer = $this->createPrinter(DefaultResultPrinter::class, $arguments);
+ }
+ }
+
+ if (isset($originalExecutionOrder) && $this->printer instanceof CliTestDoxPrinter) {
+ assert($this->printer instanceof CliTestDoxPrinter);
+
+ $this->printer->setOriginalExecutionOrder($originalExecutionOrder);
+ $this->printer->setShowProgressAnimation(!$arguments['noInteraction']);
+ }
+
+ $this->printer->write(
+ Version::getVersionString() . "\n"
+ );
+
+ foreach ($arguments['listeners'] as $listener) {
+ $result->addListener($listener);
+ }
+
+ $result->addListener($this->printer);
+
+ $coverageFilterFromConfigurationFile = false;
+ $coverageFilterFromOption = false;
+ $codeCoverageReports = 0;
+
+ if (isset($arguments['testdoxHTMLFile'])) {
+ $result->addListener(
+ new HtmlResultPrinter(
+ $arguments['testdoxHTMLFile'],
+ $arguments['testdoxGroups'],
+ $arguments['testdoxExcludeGroups']
+ )
+ );
+ }
+
+ if (isset($arguments['testdoxTextFile'])) {
+ $result->addListener(
+ new TextResultPrinter(
+ $arguments['testdoxTextFile'],
+ $arguments['testdoxGroups'],
+ $arguments['testdoxExcludeGroups']
+ )
+ );
+ }
+
+ if (isset($arguments['testdoxXMLFile'])) {
+ $result->addListener(
+ new XmlResultPrinter(
+ $arguments['testdoxXMLFile']
+ )
+ );
+ }
+
+ if (isset($arguments['teamcityLogfile'])) {
+ $result->addListener(
+ new TeamCity($arguments['teamcityLogfile'])
+ );
+ }
+
+ if (isset($arguments['junitLogfile'])) {
+ $result->addListener(
+ new JUnit(
+ $arguments['junitLogfile'],
+ $arguments['reportUselessTests']
+ )
+ );
+ }
+
+ if (isset($arguments['coverageClover'])) {
+ $codeCoverageReports++;
+ }
+
+ if (isset($arguments['coverageCobertura'])) {
+ $codeCoverageReports++;
+ }
+
+ if (isset($arguments['coverageCrap4J'])) {
+ $codeCoverageReports++;
+ }
+
+ if (isset($arguments['coverageHtml'])) {
+ $codeCoverageReports++;
+ }
+
+ if (isset($arguments['coveragePHP'])) {
+ $codeCoverageReports++;
+ }
+
+ if (isset($arguments['coverageText'])) {
+ $codeCoverageReports++;
+ }
+
+ if (isset($arguments['coverageXml'])) {
+ $codeCoverageReports++;
+ }
+
+ if ($codeCoverageReports > 0 || isset($arguments['xdebugFilterFile'])) {
+ if (isset($arguments['coverageFilter'])) {
+ if (!is_array($arguments['coverageFilter'])) {
+ $coverageFilterDirectories = [$arguments['coverageFilter']];
+ } else {
+ $coverageFilterDirectories = $arguments['coverageFilter'];
+ }
+
+ foreach ($coverageFilterDirectories as $coverageFilterDirectory) {
+ $this->codeCoverageFilter->includeDirectory($coverageFilterDirectory);
+ }
+
+ $coverageFilterFromOption = true;
+ }
+
+ if (isset($arguments['configurationObject'])) {
+ assert($arguments['configurationObject'] instanceof Configuration);
+
+ $codeCoverageConfiguration = $arguments['configurationObject']->codeCoverage();
+
+ if ($codeCoverageConfiguration->hasNonEmptyListOfFilesToBeIncludedInCodeCoverageReport()) {
+ $coverageFilterFromConfigurationFile = true;
+
+ (new FilterMapper)->map(
+ $this->codeCoverageFilter,
+ $codeCoverageConfiguration
+ );
+ }
+ }
+ }
+
+ if ($codeCoverageReports > 0) {
+ try {
+ if (isset($codeCoverageConfiguration) &&
+ ($codeCoverageConfiguration->pathCoverage() || (isset($arguments['pathCoverage']) && $arguments['pathCoverage'] === true))) {
+ $codeCoverageDriver = (new Selector)->forLineAndPathCoverage($this->codeCoverageFilter);
+ } else {
+ $codeCoverageDriver = (new Selector)->forLineCoverage($this->codeCoverageFilter);
+ }
+
+ $codeCoverage = new CodeCoverage(
+ $codeCoverageDriver,
+ $this->codeCoverageFilter
+ );
+
+ if (isset($codeCoverageConfiguration) && $codeCoverageConfiguration->hasCacheDirectory()) {
+ $codeCoverage->cacheStaticAnalysis($codeCoverageConfiguration->cacheDirectory()->path());
+ }
+
+ if (isset($arguments['coverageCacheDirectory'])) {
+ $codeCoverage->cacheStaticAnalysis($arguments['coverageCacheDirectory']);
+ }
+
+ $codeCoverage->excludeSubclassesOfThisClassFromUnintentionallyCoveredCodeCheck(Comparator::class);
+
+ if ($arguments['strictCoverage']) {
+ $codeCoverage->enableCheckForUnintentionallyCoveredCode();
+ }
+
+ if (isset($arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage'])) {
+ if ($arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage']) {
+ $codeCoverage->ignoreDeprecatedCode();
+ } else {
+ $codeCoverage->doNotIgnoreDeprecatedCode();
+ }
+ }
+
+ if (isset($arguments['disableCodeCoverageIgnore'])) {
+ if ($arguments['disableCodeCoverageIgnore']) {
+ $codeCoverage->disableAnnotationsForIgnoringCode();
+ } else {
+ $codeCoverage->enableAnnotationsForIgnoringCode();
+ }
+ }
+
+ if (isset($arguments['configurationObject'])) {
+ $codeCoverageConfiguration = $arguments['configurationObject']->codeCoverage();
+
+ if ($codeCoverageConfiguration->hasNonEmptyListOfFilesToBeIncludedInCodeCoverageReport()) {
+ if ($codeCoverageConfiguration->includeUncoveredFiles()) {
+ $codeCoverage->includeUncoveredFiles();
+ } else {
+ $codeCoverage->excludeUncoveredFiles();
+ }
+
+ if ($codeCoverageConfiguration->processUncoveredFiles()) {
+ $codeCoverage->processUncoveredFiles();
+ } else {
+ $codeCoverage->doNotProcessUncoveredFiles();
+ }
+ }
+ }
+
+ if ($this->codeCoverageFilter->isEmpty()) {
+ if (!$coverageFilterFromConfigurationFile && !$coverageFilterFromOption) {
+ $warnings[] = 'No filter is configured, code coverage will not be processed';
+ } else {
+ $warnings[] = 'Incorrect filter configuration, code coverage will not be processed';
+ }
+
+ unset($codeCoverage);
+ }
+ } catch (CodeCoverageException $e) {
+ $warnings[] = $e->getMessage();
+ }
+ }
+
+ if ($arguments['verbose']) {
+ if (PHP_SAPI === 'phpdbg') {
+ $this->writeMessage('Runtime', 'PHPDBG ' . PHP_VERSION);
+ } else {
+ $runtime = 'PHP ' . PHP_VERSION;
+
+ if (isset($codeCoverageDriver)) {
+ $runtime .= ' with ' . $codeCoverageDriver->nameAndVersion();
+ }
+
+ $this->writeMessage('Runtime', $runtime);
+ }
+
+ if (isset($arguments['configurationObject'])) {
+ assert($arguments['configurationObject'] instanceof Configuration);
+
+ $this->writeMessage(
+ 'Configuration',
+ $arguments['configurationObject']->filename()
+ );
+ }
+
+ foreach ($arguments['loadedExtensions'] as $extension) {
+ $this->writeMessage(
+ 'Extension',
+ $extension
+ );
+ }
+
+ foreach ($arguments['notLoadedExtensions'] as $extension) {
+ $this->writeMessage(
+ 'Extension',
+ $extension
+ );
+ }
+ }
+
+ if ($arguments['executionOrder'] === TestSuiteSorter::ORDER_RANDOMIZED) {
+ $this->writeMessage(
+ 'Random Seed',
+ (string) $arguments['randomOrderSeed']
+ );
+ }
+
+ if (isset($tooFewColumnsRequested)) {
+ $warnings[] = 'Less than 16 columns requested, number of columns set to 16';
+ }
+
+ if ((new Runtime)->discardsComments()) {
+ $warnings[] = 'opcache.save_comments=0 set; annotations will not work';
+ }
+
+ if (isset($arguments['conflictBetweenPrinterClassAndTestdox'])) {
+ $warnings[] = 'Directives printerClass and testdox are mutually exclusive';
+ }
+
+ foreach ($warnings as $warning) {
+ $this->writeMessage('Warning', $warning);
+ }
+
+ if (isset($arguments['configurationObject'])) {
+ assert($arguments['configurationObject'] instanceof Configuration);
+
+ if ($arguments['configurationObject']->hasValidationErrors()) {
+ if ((new SchemaDetector)->detect($arguments['configurationObject']->filename())->detected()) {
+ $this->writeMessage('Warning', 'Your XML configuration validates against a deprecated schema.');
+ $this->writeMessage('Suggestion', 'Migrate your XML configuration using "--migrate-configuration"!');
+ } else {
+ $this->write(
+ "\n Warning - The configuration file did not pass validation!\n The following problems have been detected:\n"
+ );
+
+ $this->write($arguments['configurationObject']->validationErrors());
+
+ $this->write("\n Test results may not be as expected.\n\n");
+ }
+ }
+ }
+
+ if (isset($arguments['xdebugFilterFile'], $codeCoverageConfiguration)) {
+ $this->write(PHP_EOL . 'Please note that --dump-xdebug-filter and --prepend are deprecated and will be removed in PHPUnit 10.' . PHP_EOL);
+
+ $script = (new XdebugFilterScriptGenerator)->generate($codeCoverageConfiguration);
+
+ if ($arguments['xdebugFilterFile'] !== 'php://stdout' && $arguments['xdebugFilterFile'] !== 'php://stderr' && !Filesystem::createDirectory(dirname($arguments['xdebugFilterFile']))) {
+ $this->write(sprintf('Cannot write Xdebug filter script to %s ' . PHP_EOL, $arguments['xdebugFilterFile']));
+
+ exit(self::EXCEPTION_EXIT);
+ }
+
+ file_put_contents($arguments['xdebugFilterFile'], $script);
+
+ $this->write(sprintf('Wrote Xdebug filter script to %s ' . PHP_EOL . PHP_EOL, $arguments['xdebugFilterFile']));
+
+ exit(self::SUCCESS_EXIT);
+ }
+
+ $this->printer->write("\n");
+
+ if (isset($codeCoverage)) {
+ $result->setCodeCoverage($codeCoverage);
+ }
+
+ $result->beStrictAboutTestsThatDoNotTestAnything($arguments['reportUselessTests']);
+ $result->beStrictAboutOutputDuringTests($arguments['disallowTestOutput']);
+ $result->beStrictAboutTodoAnnotatedTests($arguments['disallowTodoAnnotatedTests']);
+ $result->beStrictAboutResourceUsageDuringSmallTests($arguments['beStrictAboutResourceUsageDuringSmallTests']);
+
+ if ($arguments['enforceTimeLimit'] === true && !(new Invoker)->canInvokeWithTimeout()) {
+ $this->writeMessage('Error', 'PHP extension pcntl is required for enforcing time limits');
+ }
+
+ $result->enforceTimeLimit($arguments['enforceTimeLimit']);
+ $result->setDefaultTimeLimit($arguments['defaultTimeLimit']);
+ $result->setTimeoutForSmallTests($arguments['timeoutForSmallTests']);
+ $result->setTimeoutForMediumTests($arguments['timeoutForMediumTests']);
+ $result->setTimeoutForLargeTests($arguments['timeoutForLargeTests']);
+
+ if (isset($arguments['forceCoversAnnotation']) && $arguments['forceCoversAnnotation'] === true) {
+ $result->forceCoversAnnotation();
+ }
+
+ $this->processSuiteFilters($suite, $arguments);
+ $suite->setRunTestInSeparateProcess($arguments['processIsolation']);
+
+ foreach ($this->extensions as $extension) {
+ if ($extension instanceof BeforeFirstTestHook) {
+ $extension->executeBeforeFirstTest();
+ }
+ }
+
+ $testSuiteWarningsPrinted = false;
+
+ foreach ($suite->warnings() as $warning) {
+ $this->writeMessage('Warning', $warning);
+
+ $testSuiteWarningsPrinted = true;
+ }
+
+ if ($testSuiteWarningsPrinted) {
+ $this->write(PHP_EOL);
+ }
+
+ $suite->run($result);
+
+ foreach ($this->extensions as $extension) {
+ if ($extension instanceof AfterLastTestHook) {
+ $extension->executeAfterLastTest();
+ }
+ }
+
+ $result->flushListeners();
+ $this->printer->printResult($result);
+
+ if (isset($codeCoverage)) {
+ if (isset($arguments['coverageClover'])) {
+ $this->codeCoverageGenerationStart('Clover XML');
+
+ try {
+ $writer = new CloverReport;
+ $writer->process($codeCoverage, $arguments['coverageClover']);
+
+ $this->codeCoverageGenerationSucceeded();
+
+ unset($writer);
+ } catch (CodeCoverageException $e) {
+ $this->codeCoverageGenerationFailed($e);
+ }
+ }
+
+ if (isset($arguments['coverageCobertura'])) {
+ $this->codeCoverageGenerationStart('Cobertura XML');
+
+ try {
+ $writer = new CoberturaReport;
+ $writer->process($codeCoverage, $arguments['coverageCobertura']);
+
+ $this->codeCoverageGenerationSucceeded();
+
+ unset($writer);
+ } catch (CodeCoverageException $e) {
+ $this->codeCoverageGenerationFailed($e);
+ }
+ }
+
+ if (isset($arguments['coverageCrap4J'])) {
+ $this->codeCoverageGenerationStart('Crap4J XML');
+
+ try {
+ $writer = new Crap4jReport($arguments['crap4jThreshold']);
+ $writer->process($codeCoverage, $arguments['coverageCrap4J']);
+
+ $this->codeCoverageGenerationSucceeded();
+
+ unset($writer);
+ } catch (CodeCoverageException $e) {
+ $this->codeCoverageGenerationFailed($e);
+ }
+ }
+
+ if (isset($arguments['coverageHtml'])) {
+ $this->codeCoverageGenerationStart('HTML');
+
+ try {
+ $writer = new HtmlReport(
+ $arguments['reportLowUpperBound'],
+ $arguments['reportHighLowerBound'],
+ sprintf(
+ ' and <a href="https://phpunit.de/">PHPUnit %s</a>',
+ Version::id()
+ )
+ );
+
+ $writer->process($codeCoverage, $arguments['coverageHtml']);
+
+ $this->codeCoverageGenerationSucceeded();
+
+ unset($writer);
+ } catch (CodeCoverageException $e) {
+ $this->codeCoverageGenerationFailed($e);
+ }
+ }
+
+ if (isset($arguments['coveragePHP'])) {
+ $this->codeCoverageGenerationStart('PHP');
+
+ try {
+ $writer = new PhpReport;
+ $writer->process($codeCoverage, $arguments['coveragePHP']);
+
+ $this->codeCoverageGenerationSucceeded();
+
+ unset($writer);
+ } catch (CodeCoverageException $e) {
+ $this->codeCoverageGenerationFailed($e);
+ }
+ }
+
+ if (isset($arguments['coverageText'])) {
+ if ($arguments['coverageText'] === 'php://stdout') {
+ $outputStream = $this->printer;
+ $colors = $arguments['colors'] && $arguments['colors'] !== DefaultResultPrinter::COLOR_NEVER;
+ } else {
+ $outputStream = new Printer($arguments['coverageText']);
+ $colors = false;
+ }
+
+ $processor = new TextReport(
+ $arguments['reportLowUpperBound'],
+ $arguments['reportHighLowerBound'],
+ $arguments['coverageTextShowUncoveredFiles'],
+ $arguments['coverageTextShowOnlySummary']
+ );
+
+ $outputStream->write(
+ $processor->process($codeCoverage, $colors)
+ );
+ }
+
+ if (isset($arguments['coverageXml'])) {
+ $this->codeCoverageGenerationStart('PHPUnit XML');
+
+ try {
+ $writer = new XmlReport(Version::id());
+ $writer->process($codeCoverage, $arguments['coverageXml']);
+
+ $this->codeCoverageGenerationSucceeded();
+
+ unset($writer);
+ } catch (CodeCoverageException $e) {
+ $this->codeCoverageGenerationFailed($e);
+ }
+ }
+ }
+
+ if ($exit) {
+ if (isset($arguments['failOnEmptyTestSuite']) && $arguments['failOnEmptyTestSuite'] === true && count($result) === 0) {
+ exit(self::FAILURE_EXIT);
+ }
+
+ if ($result->wasSuccessfulIgnoringWarnings()) {
+ if ($arguments['failOnRisky'] && !$result->allHarmless()) {
+ exit(self::FAILURE_EXIT);
+ }
+
+ if ($arguments['failOnWarning'] && $result->warningCount() > 0) {
+ exit(self::FAILURE_EXIT);
+ }
+
+ if ($arguments['failOnIncomplete'] && $result->notImplementedCount() > 0) {
+ exit(self::FAILURE_EXIT);
+ }
+
+ if ($arguments['failOnSkipped'] && $result->skippedCount() > 0) {
+ exit(self::FAILURE_EXIT);
+ }
+
+ exit(self::SUCCESS_EXIT);
+ }
+
+ if ($result->errorCount() > 0) {
+ exit(self::EXCEPTION_EXIT);
+ }
+
+ if ($result->failureCount() > 0) {
+ exit(self::FAILURE_EXIT);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns the loader to be used.
+ */
+ public function getLoader(): TestSuiteLoader
+ {
+ if ($this->loader === null) {
+ $this->loader = new StandardTestSuiteLoader;
+ }
+
+ return $this->loader;
+ }
+
+ public function addExtension(Hook $extension): void
+ {
+ $this->extensions[] = $extension;
+ }
+
+ /**
+ * Override to define how to handle a failed loading of
+ * a test suite.
+ */
+ protected function runFailed(string $message): void
+ {
+ $this->write($message . PHP_EOL);
+
+ exit(self::FAILURE_EXIT);
+ }
+
+ private function createTestResult(): TestResult
+ {
+ return new TestResult;
+ }
+
+ private function write(string $buffer): void
+ {
+ if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') {
+ $buffer = htmlspecialchars($buffer);
+ }
+
+ if ($this->printer !== null) {
+ $this->printer->write($buffer);
+ } else {
+ print $buffer;
+ }
+ }
+
+ /**
+ * @throws \PHPUnit\TextUI\XmlConfiguration\Exception
+ * @throws Exception
+ */
+ private function handleConfiguration(array &$arguments): void
+ {
+ if (!isset($arguments['configurationObject']) && isset($arguments['configuration'])) {
+ $arguments['configurationObject'] = (new Loader)->load($arguments['configuration']);
+ }
+
+ if (!isset($arguments['warnings'])) {
+ $arguments['warnings'] = [];
+ }
+
+ $arguments['debug'] = $arguments['debug'] ?? false;
+ $arguments['filter'] = $arguments['filter'] ?? false;
+ $arguments['listeners'] = $arguments['listeners'] ?? [];
+
+ if (isset($arguments['configurationObject'])) {
+ (new PhpHandler)->handle($arguments['configurationObject']->php());
+
+ $codeCoverageConfiguration = $arguments['configurationObject']->codeCoverage();
+
+ if (!isset($arguments['noCoverage'])) {
+ if (!isset($arguments['coverageClover']) && $codeCoverageConfiguration->hasClover()) {
+ $arguments['coverageClover'] = $codeCoverageConfiguration->clover()->target()->path();
+ }
+
+ if (!isset($arguments['coverageCobertura']) && $codeCoverageConfiguration->hasCobertura()) {
+ $arguments['coverageCobertura'] = $codeCoverageConfiguration->cobertura()->target()->path();
+ }
+
+ if (!isset($arguments['coverageCrap4J']) && $codeCoverageConfiguration->hasCrap4j()) {
+ $arguments['coverageCrap4J'] = $codeCoverageConfiguration->crap4j()->target()->path();
+
+ if (!isset($arguments['crap4jThreshold'])) {
+ $arguments['crap4jThreshold'] = $codeCoverageConfiguration->crap4j()->threshold();
+ }
+ }
+
+ if (!isset($arguments['coverageHtml']) && $codeCoverageConfiguration->hasHtml()) {
+ $arguments['coverageHtml'] = $codeCoverageConfiguration->html()->target()->path();
+
+ if (!isset($arguments['reportLowUpperBound'])) {
+ $arguments['reportLowUpperBound'] = $codeCoverageConfiguration->html()->lowUpperBound();
+ }
+
+ if (!isset($arguments['reportHighLowerBound'])) {
+ $arguments['reportHighLowerBound'] = $codeCoverageConfiguration->html()->highLowerBound();
+ }
+ }
+
+ if (!isset($arguments['coveragePHP']) && $codeCoverageConfiguration->hasPhp()) {
+ $arguments['coveragePHP'] = $codeCoverageConfiguration->php()->target()->path();
+ }
+
+ if (!isset($arguments['coverageText']) && $codeCoverageConfiguration->hasText()) {
+ $arguments['coverageText'] = $codeCoverageConfiguration->text()->target()->path();
+ $arguments['coverageTextShowUncoveredFiles'] = $codeCoverageConfiguration->text()->showUncoveredFiles();
+ $arguments['coverageTextShowOnlySummary'] = $codeCoverageConfiguration->text()->showOnlySummary();
+ }
+
+ if (!isset($arguments['coverageXml']) && $codeCoverageConfiguration->hasXml()) {
+ $arguments['coverageXml'] = $codeCoverageConfiguration->xml()->target()->path();
+ }
+ }
+
+ $phpunitConfiguration = $arguments['configurationObject']->phpunit();
+
+ $arguments['backupGlobals'] = $arguments['backupGlobals'] ?? $phpunitConfiguration->backupGlobals();
+ $arguments['backupStaticAttributes'] = $arguments['backupStaticAttributes'] ?? $phpunitConfiguration->backupStaticAttributes();
+ $arguments['beStrictAboutChangesToGlobalState'] = $arguments['beStrictAboutChangesToGlobalState'] ?? $phpunitConfiguration->beStrictAboutChangesToGlobalState();
+ $arguments['cacheResult'] = $arguments['cacheResult'] ?? $phpunitConfiguration->cacheResult();
+ $arguments['colors'] = $arguments['colors'] ?? $phpunitConfiguration->colors();
+ $arguments['convertDeprecationsToExceptions'] = $arguments['convertDeprecationsToExceptions'] ?? $phpunitConfiguration->convertDeprecationsToExceptions();
+ $arguments['convertErrorsToExceptions'] = $arguments['convertErrorsToExceptions'] ?? $phpunitConfiguration->convertErrorsToExceptions();
+ $arguments['convertNoticesToExceptions'] = $arguments['convertNoticesToExceptions'] ?? $phpunitConfiguration->convertNoticesToExceptions();
+ $arguments['convertWarningsToExceptions'] = $arguments['convertWarningsToExceptions'] ?? $phpunitConfiguration->convertWarningsToExceptions();
+ $arguments['processIsolation'] = $arguments['processIsolation'] ?? $phpunitConfiguration->processIsolation();
+ $arguments['stopOnDefect'] = $arguments['stopOnDefect'] ?? $phpunitConfiguration->stopOnDefect();
+ $arguments['stopOnError'] = $arguments['stopOnError'] ?? $phpunitConfiguration->stopOnError();
+ $arguments['stopOnFailure'] = $arguments['stopOnFailure'] ?? $phpunitConfiguration->stopOnFailure();
+ $arguments['stopOnWarning'] = $arguments['stopOnWarning'] ?? $phpunitConfiguration->stopOnWarning();
+ $arguments['stopOnIncomplete'] = $arguments['stopOnIncomplete'] ?? $phpunitConfiguration->stopOnIncomplete();
+ $arguments['stopOnRisky'] = $arguments['stopOnRisky'] ?? $phpunitConfiguration->stopOnRisky();
+ $arguments['stopOnSkipped'] = $arguments['stopOnSkipped'] ?? $phpunitConfiguration->stopOnSkipped();
+ $arguments['failOnEmptyTestSuite'] = $arguments['failOnEmptyTestSuite'] ?? $phpunitConfiguration->failOnEmptyTestSuite();
+ $arguments['failOnIncomplete'] = $arguments['failOnIncomplete'] ?? $phpunitConfiguration->failOnIncomplete();
+ $arguments['failOnRisky'] = $arguments['failOnRisky'] ?? $phpunitConfiguration->failOnRisky();
+ $arguments['failOnSkipped'] = $arguments['failOnSkipped'] ?? $phpunitConfiguration->failOnSkipped();
+ $arguments['failOnWarning'] = $arguments['failOnWarning'] ?? $phpunitConfiguration->failOnWarning();
+ $arguments['enforceTimeLimit'] = $arguments['enforceTimeLimit'] ?? $phpunitConfiguration->enforceTimeLimit();
+ $arguments['defaultTimeLimit'] = $arguments['defaultTimeLimit'] ?? $phpunitConfiguration->defaultTimeLimit();
+ $arguments['timeoutForSmallTests'] = $arguments['timeoutForSmallTests'] ?? $phpunitConfiguration->timeoutForSmallTests();
+ $arguments['timeoutForMediumTests'] = $arguments['timeoutForMediumTests'] ?? $phpunitConfiguration->timeoutForMediumTests();
+ $arguments['timeoutForLargeTests'] = $arguments['timeoutForLargeTests'] ?? $phpunitConfiguration->timeoutForLargeTests();
+ $arguments['reportUselessTests'] = $arguments['reportUselessTests'] ?? $phpunitConfiguration->beStrictAboutTestsThatDoNotTestAnything();
+ $arguments['strictCoverage'] = $arguments['strictCoverage'] ?? $phpunitConfiguration->beStrictAboutCoversAnnotation();
+ $arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage'] = $arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage'] ?? $codeCoverageConfiguration->ignoreDeprecatedCodeUnits();
+ $arguments['disallowTestOutput'] = $arguments['disallowTestOutput'] ?? $phpunitConfiguration->beStrictAboutOutputDuringTests();
+ $arguments['disallowTodoAnnotatedTests'] = $arguments['disallowTodoAnnotatedTests'] ?? $phpunitConfiguration->beStrictAboutTodoAnnotatedTests();
+ $arguments['beStrictAboutResourceUsageDuringSmallTests'] = $arguments['beStrictAboutResourceUsageDuringSmallTests'] ?? $phpunitConfiguration->beStrictAboutResourceUsageDuringSmallTests();
+ $arguments['verbose'] = $arguments['verbose'] ?? $phpunitConfiguration->verbose();
+ $arguments['reverseDefectList'] = $arguments['reverseDefectList'] ?? $phpunitConfiguration->reverseDefectList();
+ $arguments['forceCoversAnnotation'] = $arguments['forceCoversAnnotation'] ?? $phpunitConfiguration->forceCoversAnnotation();
+ $arguments['disableCodeCoverageIgnore'] = $arguments['disableCodeCoverageIgnore'] ?? $codeCoverageConfiguration->disableCodeCoverageIgnore();
+ $arguments['registerMockObjectsFromTestArgumentsRecursively'] = $arguments['registerMockObjectsFromTestArgumentsRecursively'] ?? $phpunitConfiguration->registerMockObjectsFromTestArgumentsRecursively();
+ $arguments['noInteraction'] = $arguments['noInteraction'] ?? $phpunitConfiguration->noInteraction();
+ $arguments['executionOrder'] = $arguments['executionOrder'] ?? $phpunitConfiguration->executionOrder();
+ $arguments['resolveDependencies'] = $arguments['resolveDependencies'] ?? $phpunitConfiguration->resolveDependencies();
+
+ if (!isset($arguments['bootstrap']) && $phpunitConfiguration->hasBootstrap()) {
+ $arguments['bootstrap'] = $phpunitConfiguration->bootstrap();
+ }
+
+ if (!isset($arguments['cacheResultFile']) && $phpunitConfiguration->hasCacheResultFile()) {
+ $arguments['cacheResultFile'] = $phpunitConfiguration->cacheResultFile();
+ }
+
+ if (!isset($arguments['executionOrderDefects'])) {
+ $arguments['executionOrderDefects'] = $phpunitConfiguration->defectsFirst() ? TestSuiteSorter::ORDER_DEFECTS_FIRST : TestSuiteSorter::ORDER_DEFAULT;
+ }
+
+ if ($phpunitConfiguration->conflictBetweenPrinterClassAndTestdox()) {
+ $arguments['conflictBetweenPrinterClassAndTestdox'] = true;
+ }
+
+ $groupCliArgs = [];
+
+ if (!empty($arguments['groups'])) {
+ $groupCliArgs = $arguments['groups'];
+ }
+
+ $groupConfiguration = $arguments['configurationObject']->groups();
+
+ if (!isset($arguments['groups']) && $groupConfiguration->hasInclude()) {
+ $arguments['groups'] = $groupConfiguration->include()->asArrayOfStrings();
+ }
+
+ if (!isset($arguments['excludeGroups']) && $groupConfiguration->hasExclude()) {
+ $arguments['excludeGroups'] = array_diff($groupConfiguration->exclude()->asArrayOfStrings(), $groupCliArgs);
+ }
+
+ $extensionHandler = new ExtensionHandler;
+
+ foreach ($arguments['configurationObject']->extensions() as $extension) {
+ $extensionHandler->registerExtension($extension, $this);
+ }
+
+ foreach ($arguments['configurationObject']->listeners() as $listener) {
+ $arguments['listeners'][] = $extensionHandler->createTestListenerInstance($listener);
+ }
+
+ unset($extensionHandler);
+
+ foreach ($arguments['unavailableExtensions'] as $extension) {
+ $arguments['warnings'][] = sprintf(
+ 'Extension "%s" is not available',
+ $extension
+ );
+ }
+
+ $loggingConfiguration = $arguments['configurationObject']->logging();
+
+ if (!isset($arguments['noLogging'])) {
+ if ($loggingConfiguration->hasText()) {
+ $arguments['listeners'][] = new DefaultResultPrinter(
+ $loggingConfiguration->text()->target()->path(),
+ true
+ );
+ }
+
+ if (!isset($arguments['teamcityLogfile']) && $loggingConfiguration->hasTeamCity()) {
+ $arguments['teamcityLogfile'] = $loggingConfiguration->teamCity()->target()->path();
+ }
+
+ if (!isset($arguments['junitLogfile']) && $loggingConfiguration->hasJunit()) {
+ $arguments['junitLogfile'] = $loggingConfiguration->junit()->target()->path();
+ }
+
+ if (!isset($arguments['testdoxHTMLFile']) && $loggingConfiguration->hasTestDoxHtml()) {
+ $arguments['testdoxHTMLFile'] = $loggingConfiguration->testDoxHtml()->target()->path();
+ }
+
+ if (!isset($arguments['testdoxTextFile']) && $loggingConfiguration->hasTestDoxText()) {
+ $arguments['testdoxTextFile'] = $loggingConfiguration->testDoxText()->target()->path();
+ }
+
+ if (!isset($arguments['testdoxXMLFile']) && $loggingConfiguration->hasTestDoxXml()) {
+ $arguments['testdoxXMLFile'] = $loggingConfiguration->testDoxXml()->target()->path();
+ }
+ }
+
+ $testdoxGroupConfiguration = $arguments['configurationObject']->testdoxGroups();
+
+ if (!isset($arguments['testdoxGroups']) && $testdoxGroupConfiguration->hasInclude()) {
+ $arguments['testdoxGroups'] = $testdoxGroupConfiguration->include()->asArrayOfStrings();
+ }
+
+ if (!isset($arguments['testdoxExcludeGroups']) && $testdoxGroupConfiguration->hasExclude()) {
+ $arguments['testdoxExcludeGroups'] = $testdoxGroupConfiguration->exclude()->asArrayOfStrings();
+ }
+ }
+
+ $extensionHandler = new ExtensionHandler;
+
+ foreach ($arguments['extensions'] as $extension) {
+ $extensionHandler->registerExtension($extension, $this);
+ }
+
+ unset($extensionHandler);
+
+ $arguments['backupGlobals'] = $arguments['backupGlobals'] ?? null;
+ $arguments['backupStaticAttributes'] = $arguments['backupStaticAttributes'] ?? null;
+ $arguments['beStrictAboutChangesToGlobalState'] = $arguments['beStrictAboutChangesToGlobalState'] ?? null;
+ $arguments['beStrictAboutResourceUsageDuringSmallTests'] = $arguments['beStrictAboutResourceUsageDuringSmallTests'] ?? false;
+ $arguments['cacheResult'] = $arguments['cacheResult'] ?? true;
+ $arguments['colors'] = $arguments['colors'] ?? DefaultResultPrinter::COLOR_DEFAULT;
+ $arguments['columns'] = $arguments['columns'] ?? 80;
+ $arguments['convertDeprecationsToExceptions'] = $arguments['convertDeprecationsToExceptions'] ?? false;
+ $arguments['convertErrorsToExceptions'] = $arguments['convertErrorsToExceptions'] ?? true;
+ $arguments['convertNoticesToExceptions'] = $arguments['convertNoticesToExceptions'] ?? true;
+ $arguments['convertWarningsToExceptions'] = $arguments['convertWarningsToExceptions'] ?? true;
+ $arguments['crap4jThreshold'] = $arguments['crap4jThreshold'] ?? 30;
+ $arguments['disallowTestOutput'] = $arguments['disallowTestOutput'] ?? false;
+ $arguments['disallowTodoAnnotatedTests'] = $arguments['disallowTodoAnnotatedTests'] ?? false;
+ $arguments['defaultTimeLimit'] = $arguments['defaultTimeLimit'] ?? 0;
+ $arguments['enforceTimeLimit'] = $arguments['enforceTimeLimit'] ?? false;
+ $arguments['excludeGroups'] = $arguments['excludeGroups'] ?? [];
+ $arguments['executionOrder'] = $arguments['executionOrder'] ?? TestSuiteSorter::ORDER_DEFAULT;
+ $arguments['executionOrderDefects'] = $arguments['executionOrderDefects'] ?? TestSuiteSorter::ORDER_DEFAULT;
+ $arguments['failOnIncomplete'] = $arguments['failOnIncomplete'] ?? false;
+ $arguments['failOnRisky'] = $arguments['failOnRisky'] ?? false;
+ $arguments['failOnSkipped'] = $arguments['failOnSkipped'] ?? false;
+ $arguments['failOnWarning'] = $arguments['failOnWarning'] ?? false;
+ $arguments['groups'] = $arguments['groups'] ?? [];
+ $arguments['noInteraction'] = $arguments['noInteraction'] ?? false;
+ $arguments['processIsolation'] = $arguments['processIsolation'] ?? false;
+ $arguments['randomOrderSeed'] = $arguments['randomOrderSeed'] ?? time();
+ $arguments['registerMockObjectsFromTestArgumentsRecursively'] = $arguments['registerMockObjectsFromTestArgumentsRecursively'] ?? false;
+ $arguments['repeat'] = $arguments['repeat'] ?? false;
+ $arguments['reportHighLowerBound'] = $arguments['reportHighLowerBound'] ?? 90;
+ $arguments['reportLowUpperBound'] = $arguments['reportLowUpperBound'] ?? 50;
+ $arguments['reportUselessTests'] = $arguments['reportUselessTests'] ?? true;
+ $arguments['reverseList'] = $arguments['reverseList'] ?? false;
+ $arguments['resolveDependencies'] = $arguments['resolveDependencies'] ?? true;
+ $arguments['stopOnError'] = $arguments['stopOnError'] ?? false;
+ $arguments['stopOnFailure'] = $arguments['stopOnFailure'] ?? false;
+ $arguments['stopOnIncomplete'] = $arguments['stopOnIncomplete'] ?? false;
+ $arguments['stopOnRisky'] = $arguments['stopOnRisky'] ?? false;
+ $arguments['stopOnSkipped'] = $arguments['stopOnSkipped'] ?? false;
+ $arguments['stopOnWarning'] = $arguments['stopOnWarning'] ?? false;
+ $arguments['stopOnDefect'] = $arguments['stopOnDefect'] ?? false;
+ $arguments['strictCoverage'] = $arguments['strictCoverage'] ?? false;
+ $arguments['testdoxExcludeGroups'] = $arguments['testdoxExcludeGroups'] ?? [];
+ $arguments['testdoxGroups'] = $arguments['testdoxGroups'] ?? [];
+ $arguments['timeoutForLargeTests'] = $arguments['timeoutForLargeTests'] ?? 60;
+ $arguments['timeoutForMediumTests'] = $arguments['timeoutForMediumTests'] ?? 10;
+ $arguments['timeoutForSmallTests'] = $arguments['timeoutForSmallTests'] ?? 1;
+ $arguments['verbose'] = $arguments['verbose'] ?? false;
+
+ if ($arguments['reportLowUpperBound'] > $arguments['reportHighLowerBound']) {
+ $arguments['reportLowUpperBound'] = 50;
+ $arguments['reportHighLowerBound'] = 90;
+ }
+ }
+
+ private function processSuiteFilters(TestSuite $suite, array $arguments): void
+ {
+ if (!$arguments['filter'] &&
+ empty($arguments['groups']) &&
+ empty($arguments['excludeGroups']) &&
+ empty($arguments['testsCovering']) &&
+ empty($arguments['testsUsing'])) {
+ return;
+ }
+
+ $filterFactory = new Factory;
+
+ if (!empty($arguments['excludeGroups'])) {
+ $filterFactory->addFilter(
+ new ReflectionClass(ExcludeGroupFilterIterator::class),
+ $arguments['excludeGroups']
+ );
+ }
+
+ if (!empty($arguments['groups'])) {
+ $filterFactory->addFilter(
+ new ReflectionClass(IncludeGroupFilterIterator::class),
+ $arguments['groups']
+ );
+ }
+
+ if (!empty($arguments['testsCovering'])) {
+ $filterFactory->addFilter(
+ new ReflectionClass(IncludeGroupFilterIterator::class),
+ array_map(
+ static function (string $name): string
+ {
+ return '__phpunit_covers_' . $name;
+ },
+ $arguments['testsCovering']
+ )
+ );
+ }
+
+ if (!empty($arguments['testsUsing'])) {
+ $filterFactory->addFilter(
+ new ReflectionClass(IncludeGroupFilterIterator::class),
+ array_map(
+ static function (string $name): string
+ {
+ return '__phpunit_uses_' . $name;
+ },
+ $arguments['testsUsing']
+ )
+ );
+ }
+
+ if ($arguments['filter']) {
+ $filterFactory->addFilter(
+ new ReflectionClass(NameFilterIterator::class),
+ $arguments['filter']
+ );
+ }
+
+ $suite->injectFilter($filterFactory);
+ }
+
+ private function writeMessage(string $type, string $message): void
+ {
+ if (!$this->messagePrinted) {
+ $this->write("\n");
+ }
+
+ $this->write(
+ sprintf(
+ "%-15s%s\n",
+ $type . ':',
+ $message
+ )
+ );
+
+ $this->messagePrinted = true;
+ }
+
+ private function createPrinter(string $class, array $arguments): ResultPrinter
+ {
+ $object = new $class(
+ (isset($arguments['stderr']) && $arguments['stderr'] === true) ? 'php://stderr' : null,
+ $arguments['verbose'],
+ $arguments['colors'],
+ $arguments['debug'],
+ $arguments['columns'],
+ $arguments['reverseList']
+ );
+
+ assert($object instanceof ResultPrinter);
+
+ return $object;
+ }
+
+ private function codeCoverageGenerationStart(string $format): void
+ {
+ $this->printer->write(
+ sprintf(
+ "\nGenerating code coverage report in %s format ... ",
+ $format
+ )
+ );
+
+ $this->timer->start();
+ }
+
+ private function codeCoverageGenerationSucceeded(): void
+ {
+ $this->printer->write(
+ sprintf(
+ "done [%s]\n",
+ $this->timer->stop()->asString()
+ )
+ );
+ }
+
+ private function codeCoverageGenerationFailed(\Exception $e): void
+ {
+ $this->printer->write(
+ sprintf(
+ "failed [%s]\n%s\n",
+ $this->timer->stop()->asString(),
+ $e->getMessage()
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/TestSuiteMapper.php b/vendor/phpunit/phpunit/src/TextUI/TestSuiteMapper.php
new file mode 100644
index 000000000..8a703aeea
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/TestSuiteMapper.php
@@ -0,0 +1,103 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_VERSION;
+use function explode;
+use function in_array;
+use function is_dir;
+use function is_file;
+use function strpos;
+use function version_compare;
+use PHPUnit\Framework\Exception as FrameworkException;
+use PHPUnit\Framework\TestSuite as TestSuiteObject;
+use PHPUnit\TextUI\XmlConfiguration\TestSuiteCollection;
+use SebastianBergmann\FileIterator\Facade;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestSuiteMapper
+{
+ /**
+ * @throws RuntimeException
+ * @throws TestDirectoryNotFoundException
+ * @throws TestFileNotFoundException
+ */
+ public function map(TestSuiteCollection $configuration, string $filter): TestSuiteObject
+ {
+ try {
+ $filterAsArray = $filter ? explode(',', $filter) : [];
+ $result = new TestSuiteObject;
+
+ foreach ($configuration as $testSuiteConfiguration) {
+ if (!empty($filterAsArray) && !in_array($testSuiteConfiguration->name(), $filterAsArray, true)) {
+ continue;
+ }
+
+ $testSuite = new TestSuiteObject($testSuiteConfiguration->name());
+ $testSuiteEmpty = true;
+
+ foreach ($testSuiteConfiguration->directories() as $directory) {
+ if (!version_compare(PHP_VERSION, $directory->phpVersion(), $directory->phpVersionOperator()->asString())) {
+ continue;
+ }
+
+ $exclude = [];
+
+ foreach ($testSuiteConfiguration->exclude()->asArray() as $file) {
+ $exclude[] = $file->path();
+ }
+
+ $files = (new Facade)->getFilesAsArray(
+ $directory->path(),
+ $directory->suffix(),
+ $directory->prefix(),
+ $exclude
+ );
+
+ if (!empty($files)) {
+ $testSuite->addTestFiles($files);
+
+ $testSuiteEmpty = false;
+ } elseif (strpos($directory->path(), '*') === false && !is_dir($directory->path())) {
+ throw new TestDirectoryNotFoundException($directory->path());
+ }
+ }
+
+ foreach ($testSuiteConfiguration->files() as $file) {
+ if (!is_file($file->path())) {
+ throw new TestFileNotFoundException($file->path());
+ }
+
+ if (!version_compare(PHP_VERSION, $file->phpVersion(), $file->phpVersionOperator()->asString())) {
+ continue;
+ }
+
+ $testSuite->addTestFile($file->path());
+
+ $testSuiteEmpty = false;
+ }
+
+ if (!$testSuiteEmpty) {
+ $result->addTest($testSuite);
+ }
+ }
+
+ return $result;
+ } catch (FrameworkException $e) {
+ throw new RuntimeException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/CodeCoverage.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/CodeCoverage.php
new file mode 100644
index 000000000..33cbea321
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/CodeCoverage.php
@@ -0,0 +1,362 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function count;
+use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Filter\DirectoryCollection;
+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\Php;
+use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Text;
+use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Xml;
+use PHPUnit\TextUI\XmlConfiguration\Directory;
+use PHPUnit\TextUI\XmlConfiguration\Exception;
+use PHPUnit\TextUI\XmlConfiguration\FileCollection;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class CodeCoverage
+{
+ /**
+ * @var ?Directory
+ */
+ private $cacheDirectory;
+
+ /**
+ * @var DirectoryCollection
+ */
+ private $directories;
+
+ /**
+ * @var FileCollection
+ */
+ private $files;
+
+ /**
+ * @var DirectoryCollection
+ */
+ private $excludeDirectories;
+
+ /**
+ * @var FileCollection
+ */
+ private $excludeFiles;
+
+ /**
+ * @var bool
+ */
+ private $pathCoverage;
+
+ /**
+ * @var bool
+ */
+ private $includeUncoveredFiles;
+
+ /**
+ * @var bool
+ */
+ private $processUncoveredFiles;
+
+ /**
+ * @var bool
+ */
+ private $ignoreDeprecatedCodeUnits;
+
+ /**
+ * @var bool
+ */
+ private $disableCodeCoverageIgnore;
+
+ /**
+ * @var ?Clover
+ */
+ private $clover;
+
+ /**
+ * @var ?Cobertura
+ */
+ private $cobertura;
+
+ /**
+ * @var ?Crap4j
+ */
+ private $crap4j;
+
+ /**
+ * @var ?Html
+ */
+ private $html;
+
+ /**
+ * @var ?Php
+ */
+ private $php;
+
+ /**
+ * @var ?Text
+ */
+ private $text;
+
+ /**
+ * @var ?Xml
+ */
+ private $xml;
+
+ public function __construct(?Directory $cacheDirectory, DirectoryCollection $directories, FileCollection $files, DirectoryCollection $excludeDirectories, FileCollection $excludeFiles, bool $pathCoverage, bool $includeUncoveredFiles, bool $processUncoveredFiles, bool $ignoreDeprecatedCodeUnits, bool $disableCodeCoverageIgnore, ?Clover $clover, ?Cobertura $cobertura, ?Crap4j $crap4j, ?Html $html, ?Php $php, ?Text $text, ?Xml $xml)
+ {
+ $this->cacheDirectory = $cacheDirectory;
+ $this->directories = $directories;
+ $this->files = $files;
+ $this->excludeDirectories = $excludeDirectories;
+ $this->excludeFiles = $excludeFiles;
+ $this->pathCoverage = $pathCoverage;
+ $this->includeUncoveredFiles = $includeUncoveredFiles;
+ $this->processUncoveredFiles = $processUncoveredFiles;
+ $this->ignoreDeprecatedCodeUnits = $ignoreDeprecatedCodeUnits;
+ $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore;
+ $this->clover = $clover;
+ $this->cobertura = $cobertura;
+ $this->crap4j = $crap4j;
+ $this->html = $html;
+ $this->php = $php;
+ $this->text = $text;
+ $this->xml = $xml;
+ }
+
+ /**
+ * @psalm-assert-if-true !null $this->cacheDirectory
+ */
+ public function hasCacheDirectory(): bool
+ {
+ return $this->cacheDirectory !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function cacheDirectory(): Directory
+ {
+ if (!$this->hasCacheDirectory()) {
+ throw new Exception(
+ 'No cache directory has been configured'
+ );
+ }
+
+ return $this->cacheDirectory;
+ }
+
+ public function hasNonEmptyListOfFilesToBeIncludedInCodeCoverageReport(): bool
+ {
+ return count($this->directories) > 0 || count($this->files) > 0;
+ }
+
+ public function directories(): DirectoryCollection
+ {
+ return $this->directories;
+ }
+
+ public function files(): FileCollection
+ {
+ return $this->files;
+ }
+
+ public function excludeDirectories(): DirectoryCollection
+ {
+ return $this->excludeDirectories;
+ }
+
+ public function excludeFiles(): FileCollection
+ {
+ return $this->excludeFiles;
+ }
+
+ 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;
+ }
+
+ public function processUncoveredFiles(): bool
+ {
+ return $this->processUncoveredFiles;
+ }
+
+ /**
+ * @psalm-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;
+ }
+
+ /**
+ * @psalm-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;
+ }
+
+ /**
+ * @psalm-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;
+ }
+
+ /**
+ * @psalm-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;
+ }
+
+ /**
+ * @psalm-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;
+ }
+
+ /**
+ * @psalm-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;
+ }
+
+ /**
+ * @psalm-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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/Directory.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/Directory.php
new file mode 100644
index 000000000..3bf99c39d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/Directory.php
@@ -0,0 +1,65 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Filter;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Directory
+{
+ /**
+ * @var string
+ */
+ private $path;
+
+ /**
+ * @var string
+ */
+ private $prefix;
+
+ /**
+ * @var string
+ */
+ private $suffix;
+
+ /**
+ * @var string
+ */
+ private $group;
+
+ public function __construct(string $path, string $prefix, string $suffix, string $group)
+ {
+ $this->path = $path;
+ $this->prefix = $prefix;
+ $this->suffix = $suffix;
+ $this->group = $group;
+ }
+
+ public function path(): string
+ {
+ return $this->path;
+ }
+
+ public function prefix(): string
+ {
+ return $this->prefix;
+ }
+
+ public function suffix(): string
+ {
+ return $this->suffix;
+ }
+
+ public function group(): string
+ {
+ return $this->group;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/DirectoryCollection.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/DirectoryCollection.php
new file mode 100644
index 000000000..803ccda20
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/DirectoryCollection.php
@@ -0,0 +1,57 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Filter;
+
+use function count;
+use Countable;
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class DirectoryCollection implements Countable, IteratorAggregate
+{
+ /**
+ * @var Directory[]
+ */
+ private $directories;
+
+ /**
+ * @param Directory[] $directories
+ */
+ public static function fromArray(array $directories): self
+ {
+ return new self(...$directories);
+ }
+
+ private function __construct(Directory ...$directories)
+ {
+ $this->directories = $directories;
+ }
+
+ /**
+ * @return Directory[]
+ */
+ public function asArray(): array
+ {
+ return $this->directories;
+ }
+
+ public function count(): int
+ {
+ return count($this->directories);
+ }
+
+ public function getIterator(): DirectoryCollectionIterator
+ {
+ return new DirectoryCollectionIterator($this);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/DirectoryCollectionIterator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/DirectoryCollectionIterator.php
new file mode 100644
index 000000000..c59a3ba99
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Filter/DirectoryCollectionIterator.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Filter;
+
+use function count;
+use function iterator_count;
+use Countable;
+use Iterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class DirectoryCollectionIterator implements Countable, Iterator
+{
+ /**
+ * @var Directory[]
+ */
+ private $directories;
+
+ /**
+ * @var int
+ */
+ private $position;
+
+ public function __construct(DirectoryCollection $directories)
+ {
+ $this->directories = $directories->asArray();
+ }
+
+ public function count(): int
+ {
+ return iterator_count($this);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->directories);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): Directory
+ {
+ return $this->directories[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/FilterMapper.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/FilterMapper.php
new file mode 100644
index 000000000..102c96ebc
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/FilterMapper.php
@@ -0,0 +1,45 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 SebastianBergmann\CodeCoverage\Filter;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class FilterMapper
+{
+ public function map(Filter $filter, CodeCoverage $configuration): void
+ {
+ foreach ($configuration->directories() as $directory) {
+ $filter->includeDirectory(
+ $directory->path(),
+ $directory->suffix(),
+ $directory->prefix()
+ );
+ }
+
+ foreach ($configuration->files() as $file) {
+ $filter->includeFile($file->path());
+ }
+
+ foreach ($configuration->excludeDirectories() as $directory) {
+ $filter->excludeDirectory(
+ $directory->path(),
+ $directory->suffix(),
+ $directory->prefix()
+ );
+ }
+
+ foreach ($configuration->excludeFiles() as $file) {
+ $filter->excludeFile($file->path());
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Clover.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Clover.php
new file mode 100644
index 000000000..e7ff407be
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Clover.php
@@ -0,0 +1,34 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\XmlConfiguration\File;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Clover
+{
+ /**
+ * @var File
+ */
+ private $target;
+
+ public function __construct(File $target)
+ {
+ $this->target = $target;
+ }
+
+ public function target(): File
+ {
+ return $this->target;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Cobertura.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Cobertura.php
new file mode 100644
index 000000000..e6ee7c9f6
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Cobertura.php
@@ -0,0 +1,34 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\XmlConfiguration\File;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Cobertura
+{
+ /**
+ * @var File
+ */
+ private $target;
+
+ public function __construct(File $target)
+ {
+ $this->target = $target;
+ }
+
+ public function target(): File
+ {
+ return $this->target;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Crap4j.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Crap4j.php
new file mode 100644
index 000000000..fd4d42912
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Crap4j.php
@@ -0,0 +1,45 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\XmlConfiguration\File;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Crap4j
+{
+ /**
+ * @var File
+ */
+ private $target;
+
+ /**
+ * @var int
+ */
+ private $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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Html.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Html.php
new file mode 100644
index 000000000..7084ffe5e
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Html.php
@@ -0,0 +1,56 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\XmlConfiguration\Directory;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Html
+{
+ /**
+ * @var Directory
+ */
+ private $target;
+
+ /**
+ * @var int
+ */
+ private $lowUpperBound;
+
+ /**
+ * @var int
+ */
+ private $highLowerBound;
+
+ public function __construct(Directory $target, int $lowUpperBound, int $highLowerBound)
+ {
+ $this->target = $target;
+ $this->lowUpperBound = $lowUpperBound;
+ $this->highLowerBound = $highLowerBound;
+ }
+
+ public function target(): Directory
+ {
+ return $this->target;
+ }
+
+ public function lowUpperBound(): int
+ {
+ return $this->lowUpperBound;
+ }
+
+ public function highLowerBound(): int
+ {
+ return $this->highLowerBound;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Php.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Php.php
new file mode 100644
index 000000000..d86b66216
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Php.php
@@ -0,0 +1,34 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\XmlConfiguration\File;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Php
+{
+ /**
+ * @var File
+ */
+ private $target;
+
+ public function __construct(File $target)
+ {
+ $this->target = $target;
+ }
+
+ public function target(): File
+ {
+ return $this->target;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Text.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Text.php
new file mode 100644
index 000000000..b7e9f3da3
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Text.php
@@ -0,0 +1,56 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\XmlConfiguration\File;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Text
+{
+ /**
+ * @var File
+ */
+ private $target;
+
+ /**
+ * @var bool
+ */
+ private $showUncoveredFiles;
+
+ /**
+ * @var bool
+ */
+ private $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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Xml.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Xml.php
new file mode 100644
index 000000000..977685c46
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/CodeCoverage/Report/Xml.php
@@ -0,0 +1,34 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\XmlConfiguration\Directory;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Xml
+{
+ /**
+ * @var Directory
+ */
+ private $target;
+
+ public function __construct(Directory $target)
+ {
+ $this->target = $target;
+ }
+
+ public function target(): Directory
+ {
+ return $this->target;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Configuration.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Configuration.php
new file mode 100644
index 000000000..8f102e3ba
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Configuration.php
@@ -0,0 +1,151 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\XmlConfiguration\CodeCoverage\CodeCoverage;
+use PHPUnit\TextUI\XmlConfiguration\Logging\Logging;
+use PHPUnit\Util\Xml\ValidationResult;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Configuration
+{
+ /**
+ * @var string
+ */
+ private $filename;
+
+ /**
+ * @var ValidationResult
+ */
+ private $validationResult;
+
+ /**
+ * @var ExtensionCollection
+ */
+ private $extensions;
+
+ /**
+ * @var CodeCoverage
+ */
+ private $codeCoverage;
+
+ /**
+ * @var Groups
+ */
+ private $groups;
+
+ /**
+ * @var Groups
+ */
+ private $testdoxGroups;
+
+ /**
+ * @var ExtensionCollection
+ */
+ private $listeners;
+
+ /**
+ * @var Logging
+ */
+ private $logging;
+
+ /**
+ * @var Php
+ */
+ private $php;
+
+ /**
+ * @var PHPUnit
+ */
+ private $phpunit;
+
+ /**
+ * @var TestSuiteCollection
+ */
+ private $testSuite;
+
+ public function __construct(string $filename, ValidationResult $validationResult, ExtensionCollection $extensions, CodeCoverage $codeCoverage, Groups $groups, Groups $testdoxGroups, ExtensionCollection $listeners, Logging $logging, Php $php, PHPUnit $phpunit, TestSuiteCollection $testSuite)
+ {
+ $this->filename = $filename;
+ $this->validationResult = $validationResult;
+ $this->extensions = $extensions;
+ $this->codeCoverage = $codeCoverage;
+ $this->groups = $groups;
+ $this->testdoxGroups = $testdoxGroups;
+ $this->listeners = $listeners;
+ $this->logging = $logging;
+ $this->php = $php;
+ $this->phpunit = $phpunit;
+ $this->testSuite = $testSuite;
+ }
+
+ 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 extensions(): ExtensionCollection
+ {
+ return $this->extensions;
+ }
+
+ public function codeCoverage(): CodeCoverage
+ {
+ return $this->codeCoverage;
+ }
+
+ public function groups(): Groups
+ {
+ return $this->groups;
+ }
+
+ public function testdoxGroups(): Groups
+ {
+ return $this->testdoxGroups;
+ }
+
+ public function listeners(): ExtensionCollection
+ {
+ return $this->listeners;
+ }
+
+ public function logging(): Logging
+ {
+ return $this->logging;
+ }
+
+ public function php(): Php
+ {
+ return $this->php;
+ }
+
+ public function phpunit(): PHPUnit
+ {
+ return $this->phpunit;
+ }
+
+ public function testSuite(): TestSuiteCollection
+ {
+ return $this->testSuite;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Exception.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Exception.php
new file mode 100644
index 000000000..162b37e88
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Exception.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Exception extends RuntimeException implements \PHPUnit\Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/Directory.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/Directory.php
new file mode 100644
index 000000000..1629603b7
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/Directory.php
@@ -0,0 +1,32 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Directory
+{
+ /**
+ * @var string
+ */
+ private $path;
+
+ public function __construct(string $path)
+ {
+ $this->path = $path;
+ }
+
+ public function path(): string
+ {
+ return $this->path;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/DirectoryCollection.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/DirectoryCollection.php
new file mode 100644
index 000000000..c8ae59641
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/DirectoryCollection.php
@@ -0,0 +1,62 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Countable;
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class DirectoryCollection implements Countable, IteratorAggregate
+{
+ /**
+ * @var Directory[]
+ */
+ private $directories;
+
+ /**
+ * @param Directory[] $directories
+ */
+ public static function fromArray(array $directories): self
+ {
+ return new self(...$directories);
+ }
+
+ private function __construct(Directory ...$directories)
+ {
+ $this->directories = $directories;
+ }
+
+ /**
+ * @return Directory[]
+ */
+ public function asArray(): array
+ {
+ return $this->directories;
+ }
+
+ public function count(): int
+ {
+ return count($this->directories);
+ }
+
+ public function getIterator(): DirectoryCollectionIterator
+ {
+ return new DirectoryCollectionIterator($this);
+ }
+
+ public function isEmpty(): bool
+ {
+ return $this->count() === 0;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/DirectoryCollectionIterator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/DirectoryCollectionIterator.php
new file mode 100644
index 000000000..7f354eea5
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/DirectoryCollectionIterator.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function iterator_count;
+use Countable;
+use Iterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class DirectoryCollectionIterator implements Countable, Iterator
+{
+ /**
+ * @var Directory[]
+ */
+ private $directories;
+
+ /**
+ * @var int
+ */
+ private $position;
+
+ public function __construct(DirectoryCollection $directories)
+ {
+ $this->directories = $directories->asArray();
+ }
+
+ public function count(): int
+ {
+ return iterator_count($this);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->directories);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): Directory
+ {
+ return $this->directories[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/File.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/File.php
new file mode 100644
index 000000000..0af5000d1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/File.php
@@ -0,0 +1,32 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class File
+{
+ /**
+ * @var string
+ */
+ private $path;
+
+ public function __construct(string $path)
+ {
+ $this->path = $path;
+ }
+
+ public function path(): string
+ {
+ return $this->path;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/FileCollection.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/FileCollection.php
new file mode 100644
index 000000000..bfc1e33e4
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/FileCollection.php
@@ -0,0 +1,62 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Countable;
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class FileCollection implements Countable, IteratorAggregate
+{
+ /**
+ * @var File[]
+ */
+ private $files;
+
+ /**
+ * @param File[] $files
+ */
+ public static function fromArray(array $files): self
+ {
+ return new self(...$files);
+ }
+
+ private function __construct(File ...$files)
+ {
+ $this->files = $files;
+ }
+
+ /**
+ * @return File[]
+ */
+ public function asArray(): array
+ {
+ return $this->files;
+ }
+
+ public function count(): int
+ {
+ return count($this->files);
+ }
+
+ public function getIterator(): FileCollectionIterator
+ {
+ return new FileCollectionIterator($this);
+ }
+
+ public function isEmpty(): bool
+ {
+ return $this->count() === 0;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/FileCollectionIterator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/FileCollectionIterator.php
new file mode 100644
index 000000000..d9bab1f8b
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Filesystem/FileCollectionIterator.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function iterator_count;
+use Countable;
+use Iterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class FileCollectionIterator implements Countable, Iterator
+{
+ /**
+ * @var File[]
+ */
+ private $files;
+
+ /**
+ * @var int
+ */
+ private $position;
+
+ public function __construct(FileCollection $files)
+ {
+ $this->files = $files->asArray();
+ }
+
+ public function count(): int
+ {
+ return iterator_count($this);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->files);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): File
+ {
+ return $this->files[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Generator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Generator.php
new file mode 100644
index 000000000..cc77b1a3c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Generator.php
@@ -0,0 +1,73 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Generator
+{
+ /**
+ * @var string
+ */
+ private const TEMPLATE = <<<'EOT'
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/{phpunit_version}/phpunit.xsd"
+ bootstrap="{bootstrap_script}"
+ cacheResultFile="{cache_directory}/test-results"
+ executionOrder="depends,defects"
+ forceCoversAnnotation="true"
+ beStrictAboutCoversAnnotation="true"
+ beStrictAboutOutputDuringTests="true"
+ beStrictAboutTodoAnnotatedTests="true"
+ convertDeprecationsToExceptions="true"
+ failOnRisky="true"
+ failOnWarning="true"
+ verbose="true">
+ <testsuites>
+ <testsuite name="default">
+ <directory>{tests_directory}</directory>
+ </testsuite>
+ </testsuites>
+
+ <coverage cacheDirectory="{cache_directory}/code-coverage"
+ processUncoveredFiles="true">
+ <include>
+ <directory suffix=".php">{src_directory}</directory>
+ </include>
+ </coverage>
+</phpunit>
+
+EOT;
+
+ public function generateDefaultConfiguration(string $phpunitVersion, string $bootstrapScript, string $testsDirectory, string $srcDirectory, string $cacheDirectory): string
+ {
+ return str_replace(
+ [
+ '{phpunit_version}',
+ '{bootstrap_script}',
+ '{tests_directory}',
+ '{src_directory}',
+ '{cache_directory}',
+ ],
+ [
+ $phpunitVersion,
+ $bootstrapScript,
+ $testsDirectory,
+ $srcDirectory,
+ $cacheDirectory,
+ ],
+ self::TEMPLATE
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/Group.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/Group.php
new file mode 100644
index 000000000..e59844053
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/Group.php
@@ -0,0 +1,32 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Group
+{
+ /**
+ * @var string
+ */
+ private $name;
+
+ public function __construct(string $name)
+ {
+ $this->name = $name;
+ }
+
+ public function name(): string
+ {
+ return $this->name;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/GroupCollection.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/GroupCollection.php
new file mode 100644
index 000000000..2ad9fef68
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/GroupCollection.php
@@ -0,0 +1,69 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class GroupCollection implements IteratorAggregate
+{
+ /**
+ * @var Group[]
+ */
+ private $groups;
+
+ /**
+ * @param Group[] $groups
+ */
+ public static function fromArray(array $groups): self
+ {
+ return new self(...$groups);
+ }
+
+ private function __construct(Group ...$groups)
+ {
+ $this->groups = $groups;
+ }
+
+ /**
+ * @return Group[]
+ */
+ public function asArray(): array
+ {
+ return $this->groups;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function asArrayOfStrings(): array
+ {
+ $result = [];
+
+ foreach ($this->groups as $group) {
+ $result[] = $group->name();
+ }
+
+ return $result;
+ }
+
+ public function isEmpty(): bool
+ {
+ return empty($this->groups);
+ }
+
+ public function getIterator(): GroupCollectionIterator
+ {
+ return new GroupCollectionIterator($this);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/GroupCollectionIterator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/GroupCollectionIterator.php
new file mode 100644
index 000000000..0755fdac4
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/GroupCollectionIterator.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function iterator_count;
+use Countable;
+use Iterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class GroupCollectionIterator implements Countable, Iterator
+{
+ /**
+ * @var Group[]
+ */
+ private $groups;
+
+ /**
+ * @var int
+ */
+ private $position;
+
+ public function __construct(GroupCollection $groups)
+ {
+ $this->groups = $groups->asArray();
+ }
+
+ public function count(): int
+ {
+ return iterator_count($this);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->groups);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): Group
+ {
+ return $this->groups[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/Groups.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/Groups.php
new file mode 100644
index 000000000..9004fe43b
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Group/Groups.php
@@ -0,0 +1,53 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Groups
+{
+ /**
+ * @var GroupCollection
+ */
+ private $include;
+
+ /**
+ * @var GroupCollection
+ */
+ private $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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Loader.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Loader.php
new file mode 100644
index 000000000..d705a6056
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Loader.php
@@ -0,0 +1,1264 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_VERSION;
+use function assert;
+use function defined;
+use function dirname;
+use function explode;
+use function is_file;
+use function is_numeric;
+use function preg_match;
+use function stream_resolve_include_path;
+use function strlen;
+use function strpos;
+use function strtolower;
+use function substr;
+use function trim;
+use DOMDocument;
+use DOMElement;
+use DOMNodeList;
+use DOMXPath;
+use PHPUnit\Runner\TestSuiteSorter;
+use PHPUnit\Runner\Version;
+use PHPUnit\TextUI\DefaultResultPrinter;
+use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage;
+use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Filter\Directory as FilterDirectory;
+use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Filter\DirectoryCollection as FilterDirectoryCollection;
+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\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\TeamCity;
+use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Html as TestDoxHtml;
+use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Text as TestDoxText;
+use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Xml as TestDoxXml;
+use PHPUnit\TextUI\XmlConfiguration\Logging\Text;
+use PHPUnit\TextUI\XmlConfiguration\TestSuite as TestSuiteConfiguration;
+use PHPUnit\Util\TestDox\CliTestDoxPrinter;
+use PHPUnit\Util\VersionComparisonOperator;
+use PHPUnit\Util\Xml;
+use PHPUnit\Util\Xml\Exception as XmlException;
+use PHPUnit\Util\Xml\Loader as XmlLoader;
+use PHPUnit\Util\Xml\SchemaFinder;
+use PHPUnit\Util\Xml\Validator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Loader
+{
+ /**
+ * @throws Exception
+ */
+ public function load(string $filename): Configuration
+ {
+ try {
+ $document = (new XmlLoader)->loadFile($filename, false, true, true);
+ } catch (XmlException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+
+ $xpath = new DOMXPath($document);
+
+ try {
+ $xsdFilename = (new SchemaFinder)->find(Version::series());
+ } catch (XmlException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+
+ return new Configuration(
+ $filename,
+ (new Validator)->validate($document, $xsdFilename),
+ $this->extensions($filename, $xpath),
+ $this->codeCoverage($filename, $xpath, $document),
+ $this->groups($xpath),
+ $this->testdoxGroups($xpath),
+ $this->listeners($filename, $xpath),
+ $this->logging($filename, $xpath),
+ $this->php($filename, $xpath),
+ $this->phpunit($filename, $document),
+ $this->testSuite($filename, $xpath)
+ );
+ }
+
+ public function logging(string $filename, DOMXPath $xpath): Logging
+ {
+ if ($xpath->query('logging/log')->length !== 0) {
+ return $this->legacyLogging($filename, $xpath);
+ }
+
+ $junit = null;
+ $element = $this->element($xpath, 'logging/junit');
+
+ if ($element) {
+ $junit = new Junit(
+ new File(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputFile')
+ )
+ )
+ );
+ }
+
+ $text = null;
+ $element = $this->element($xpath, 'logging/text');
+
+ if ($element) {
+ $text = new Text(
+ new File(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputFile')
+ )
+ )
+ );
+ }
+
+ $teamCity = null;
+ $element = $this->element($xpath, 'logging/teamcity');
+
+ if ($element) {
+ $teamCity = new TeamCity(
+ new File(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputFile')
+ )
+ )
+ );
+ }
+
+ $testDoxHtml = null;
+ $element = $this->element($xpath, 'logging/testdoxHtml');
+
+ if ($element) {
+ $testDoxHtml = new TestDoxHtml(
+ new File(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputFile')
+ )
+ )
+ );
+ }
+
+ $testDoxText = null;
+ $element = $this->element($xpath, 'logging/testdoxText');
+
+ if ($element) {
+ $testDoxText = new TestDoxText(
+ new File(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputFile')
+ )
+ )
+ );
+ }
+
+ $testDoxXml = null;
+ $element = $this->element($xpath, 'logging/testdoxXml');
+
+ if ($element) {
+ $testDoxXml = new TestDoxXml(
+ new File(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputFile')
+ )
+ )
+ );
+ }
+
+ return new Logging(
+ $junit,
+ $text,
+ $teamCity,
+ $testDoxHtml,
+ $testDoxText,
+ $testDoxXml
+ );
+ }
+
+ public function legacyLogging(string $filename, DOMXPath $xpath): Logging
+ {
+ $junit = null;
+ $teamCity = null;
+ $testDoxHtml = null;
+ $testDoxText = null;
+ $testDoxXml = null;
+ $text = null;
+
+ foreach ($xpath->query('logging/log') as $log) {
+ assert($log instanceof DOMElement);
+
+ $type = (string) $log->getAttribute('type');
+ $target = (string) $log->getAttribute('target');
+
+ if (!$target) {
+ continue;
+ }
+
+ $target = $this->toAbsolutePath($filename, $target);
+
+ switch ($type) {
+ case 'plain':
+ $text = new Text(
+ new File($target)
+ );
+
+ break;
+
+ case 'junit':
+ $junit = new Junit(
+ new File($target)
+ );
+
+ break;
+
+ case 'teamcity':
+ $teamCity = new TeamCity(
+ new File($target)
+ );
+
+ break;
+
+ case 'testdox-html':
+ $testDoxHtml = new TestDoxHtml(
+ new File($target)
+ );
+
+ break;
+
+ case 'testdox-text':
+ $testDoxText = new TestDoxText(
+ new File($target)
+ );
+
+ break;
+
+ case 'testdox-xml':
+ $testDoxXml = new TestDoxXml(
+ new File($target)
+ );
+
+ break;
+ }
+ }
+
+ return new Logging(
+ $junit,
+ $text,
+ $teamCity,
+ $testDoxHtml,
+ $testDoxText,
+ $testDoxXml
+ );
+ }
+
+ private function extensions(string $filename, DOMXPath $xpath): ExtensionCollection
+ {
+ $extensions = [];
+
+ foreach ($xpath->query('extensions/extension') as $extension) {
+ assert($extension instanceof DOMElement);
+
+ $extensions[] = $this->getElementConfigurationParameters($filename, $extension);
+ }
+
+ return ExtensionCollection::fromArray($extensions);
+ }
+
+ private function getElementConfigurationParameters(string $filename, DOMElement $element): Extension
+ {
+ /** @psalm-var class-string $class */
+ $class = (string) $element->getAttribute('class');
+ $file = '';
+ $arguments = $this->getConfigurationArguments($filename, $element->childNodes);
+
+ if ($element->getAttribute('file')) {
+ $file = $this->toAbsolutePath(
+ $filename,
+ (string) $element->getAttribute('file'),
+ true
+ );
+ }
+
+ return new Extension($class, $file, $arguments);
+ }
+
+ private function toAbsolutePath(string $filename, string $path, bool $useIncludePath = false): string
+ {
+ $path = trim($path);
+
+ if (strpos($path, '/') === 0) {
+ 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[0] === '\\' || (strlen($path) >= 3 && preg_match('#^[A-Z]\:[/\\\]#i', substr($path, 0, 3))))) {
+ return $path;
+ }
+
+ if (strpos($path, '://') !== false) {
+ return $path;
+ }
+
+ $file = dirname($filename) . DIRECTORY_SEPARATOR . $path;
+
+ if ($useIncludePath && !is_file($file)) {
+ $includePathFile = stream_resolve_include_path($path);
+
+ if ($includePathFile) {
+ $file = $includePathFile;
+ }
+ }
+
+ return $file;
+ }
+
+ private function getConfigurationArguments(string $filename, DOMNodeList $nodes): array
+ {
+ $arguments = [];
+
+ if ($nodes->length === 0) {
+ return $arguments;
+ }
+
+ foreach ($nodes as $node) {
+ if (!$node instanceof DOMElement) {
+ continue;
+ }
+
+ if ($node->tagName !== 'arguments') {
+ continue;
+ }
+
+ foreach ($node->childNodes as $argument) {
+ if (!$argument instanceof DOMElement) {
+ continue;
+ }
+
+ if ($argument->tagName === 'file' || $argument->tagName === 'directory') {
+ $arguments[] = $this->toAbsolutePath($filename, (string) $argument->textContent);
+ } else {
+ $arguments[] = Xml::xmlToVariable($argument);
+ }
+ }
+ }
+
+ return $arguments;
+ }
+
+ private function codeCoverage(string $filename, DOMXPath $xpath, DOMDocument $document): CodeCoverage
+ {
+ if ($xpath->query('filter/whitelist')->length !== 0) {
+ return $this->legacyCodeCoverage($filename, $xpath, $document);
+ }
+
+ $cacheDirectory = null;
+ $pathCoverage = false;
+ $includeUncoveredFiles = true;
+ $processUncoveredFiles = false;
+ $ignoreDeprecatedCodeUnits = false;
+ $disableCodeCoverageIgnore = false;
+
+ $element = $this->element($xpath, 'coverage');
+
+ if ($element) {
+ $cacheDirectory = $this->getStringAttribute($element, 'cacheDirectory');
+
+ if ($cacheDirectory !== null) {
+ $cacheDirectory = new Directory(
+ $this->toAbsolutePath($filename, $cacheDirectory)
+ );
+ }
+
+ $pathCoverage = $this->getBooleanAttribute(
+ $element,
+ 'pathCoverage',
+ false
+ );
+
+ $includeUncoveredFiles = $this->getBooleanAttribute(
+ $element,
+ 'includeUncoveredFiles',
+ true
+ );
+
+ $processUncoveredFiles = $this->getBooleanAttribute(
+ $element,
+ 'processUncoveredFiles',
+ false
+ );
+
+ $ignoreDeprecatedCodeUnits = $this->getBooleanAttribute(
+ $element,
+ 'ignoreDeprecatedCodeUnits',
+ false
+ );
+
+ $disableCodeCoverageIgnore = $this->getBooleanAttribute(
+ $element,
+ 'disableCodeCoverageIgnore',
+ false
+ );
+ }
+
+ $clover = null;
+ $element = $this->element($xpath, 'coverage/report/clover');
+
+ if ($element) {
+ $clover = new Clover(
+ new File(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputFile')
+ )
+ )
+ );
+ }
+
+ $cobertura = null;
+ $element = $this->element($xpath, 'coverage/report/cobertura');
+
+ if ($element) {
+ $cobertura = new Cobertura(
+ new File(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputFile')
+ )
+ )
+ );
+ }
+
+ $crap4j = null;
+ $element = $this->element($xpath, 'coverage/report/crap4j');
+
+ if ($element) {
+ $crap4j = new Crap4j(
+ new File(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputFile')
+ )
+ ),
+ $this->getIntegerAttribute($element, 'threshold', 30)
+ );
+ }
+
+ $html = null;
+ $element = $this->element($xpath, 'coverage/report/html');
+
+ if ($element) {
+ $html = new CodeCoverageHtml(
+ new Directory(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputDirectory')
+ )
+ ),
+ $this->getIntegerAttribute($element, 'lowUpperBound', 50),
+ $this->getIntegerAttribute($element, 'highLowerBound', 90)
+ );
+ }
+
+ $php = null;
+ $element = $this->element($xpath, 'coverage/report/php');
+
+ if ($element) {
+ $php = new CodeCoveragePhp(
+ new File(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputFile')
+ )
+ )
+ );
+ }
+
+ $text = null;
+ $element = $this->element($xpath, 'coverage/report/text');
+
+ if ($element) {
+ $text = new CodeCoverageText(
+ new File(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputFile')
+ )
+ ),
+ $this->getBooleanAttribute($element, 'showUncoveredFiles', false),
+ $this->getBooleanAttribute($element, 'showOnlySummary', false)
+ );
+ }
+
+ $xml = null;
+ $element = $this->element($xpath, 'coverage/report/xml');
+
+ if ($element) {
+ $xml = new CodeCoverageXml(
+ new Directory(
+ $this->toAbsolutePath(
+ $filename,
+ (string) $this->getStringAttribute($element, 'outputDirectory')
+ )
+ )
+ );
+ }
+
+ return new CodeCoverage(
+ $cacheDirectory,
+ $this->readFilterDirectories($filename, $xpath, 'coverage/include/directory'),
+ $this->readFilterFiles($filename, $xpath, 'coverage/include/file'),
+ $this->readFilterDirectories($filename, $xpath, 'coverage/exclude/directory'),
+ $this->readFilterFiles($filename, $xpath, 'coverage/exclude/file'),
+ $pathCoverage,
+ $includeUncoveredFiles,
+ $processUncoveredFiles,
+ $ignoreDeprecatedCodeUnits,
+ $disableCodeCoverageIgnore,
+ $clover,
+ $cobertura,
+ $crap4j,
+ $html,
+ $php,
+ $text,
+ $xml
+ );
+ }
+
+ /**
+ * @deprecated
+ */
+ private function legacyCodeCoverage(string $filename, DOMXPath $xpath, DOMDocument $document): CodeCoverage
+ {
+ $ignoreDeprecatedCodeUnits = $this->getBooleanAttribute(
+ $document->documentElement,
+ 'ignoreDeprecatedCodeUnitsFromCodeCoverage',
+ false
+ );
+
+ $disableCodeCoverageIgnore = $this->getBooleanAttribute(
+ $document->documentElement,
+ 'disableCodeCoverageIgnore',
+ false
+ );
+
+ $includeUncoveredFiles = true;
+ $processUncoveredFiles = false;
+
+ $element = $this->element($xpath, 'filter/whitelist');
+
+ if ($element) {
+ if ($element->hasAttribute('addUncoveredFilesFromWhitelist')) {
+ $includeUncoveredFiles = (bool) $this->getBoolean(
+ (string) $element->getAttribute('addUncoveredFilesFromWhitelist'),
+ true
+ );
+ }
+
+ if ($element->hasAttribute('processUncoveredFilesFromWhitelist')) {
+ $processUncoveredFiles = (bool) $this->getBoolean(
+ (string) $element->getAttribute('processUncoveredFilesFromWhitelist'),
+ false
+ );
+ }
+ }
+
+ $clover = null;
+ $cobertura = null;
+ $crap4j = null;
+ $html = null;
+ $php = null;
+ $text = null;
+ $xml = null;
+
+ foreach ($xpath->query('logging/log') as $log) {
+ assert($log instanceof DOMElement);
+
+ $type = (string) $log->getAttribute('type');
+ $target = (string) $log->getAttribute('target');
+
+ if (!$target) {
+ continue;
+ }
+
+ $target = $this->toAbsolutePath($filename, $target);
+
+ switch ($type) {
+ case 'coverage-clover':
+ $clover = new Clover(
+ new File($target)
+ );
+
+ break;
+
+ case 'coverage-cobertura':
+ $cobertura = new Cobertura(
+ new File($target)
+ );
+
+ break;
+
+ case 'coverage-crap4j':
+ $crap4j = new Crap4j(
+ new File($target),
+ $this->getIntegerAttribute($log, 'threshold', 30)
+ );
+
+ break;
+
+ case 'coverage-html':
+ $html = new CodeCoverageHtml(
+ new Directory($target),
+ $this->getIntegerAttribute($log, 'lowUpperBound', 50),
+ $this->getIntegerAttribute($log, 'highLowerBound', 90)
+ );
+
+ break;
+
+ case 'coverage-php':
+ $php = new CodeCoveragePhp(
+ new File($target)
+ );
+
+ break;
+
+ case 'coverage-text':
+ $text = new CodeCoverageText(
+ new File($target),
+ $this->getBooleanAttribute($log, 'showUncoveredFiles', false),
+ $this->getBooleanAttribute($log, 'showOnlySummary', false)
+ );
+
+ break;
+
+ case 'coverage-xml':
+ $xml = new CodeCoverageXml(
+ new Directory($target)
+ );
+
+ break;
+ }
+ }
+
+ return new CodeCoverage(
+ null,
+ $this->readFilterDirectories($filename, $xpath, 'filter/whitelist/directory'),
+ $this->readFilterFiles($filename, $xpath, 'filter/whitelist/file'),
+ $this->readFilterDirectories($filename, $xpath, 'filter/whitelist/exclude/directory'),
+ $this->readFilterFiles($filename, $xpath, 'filter/whitelist/exclude/file'),
+ false,
+ $includeUncoveredFiles,
+ $processUncoveredFiles,
+ $ignoreDeprecatedCodeUnits,
+ $disableCodeCoverageIgnore,
+ $clover,
+ $cobertura,
+ $crap4j,
+ $html,
+ $php,
+ $text,
+ $xml
+ );
+ }
+
+ /**
+ * If $value is 'false' or 'true', this returns the value that $value represents.
+ * Otherwise, returns $default, which may be a string in rare cases.
+ *
+ * @see \PHPUnit\TextUI\XmlConfigurationTest::testPHPConfigurationIsReadCorrectly
+ *
+ * @param bool|string $default
+ *
+ * @return bool|string
+ */
+ private function getBoolean(string $value, $default)
+ {
+ if (strtolower($value) === 'false') {
+ return false;
+ }
+
+ if (strtolower($value) === 'true') {
+ return true;
+ }
+
+ return $default;
+ }
+
+ private function readFilterDirectories(string $filename, DOMXPath $xpath, string $query): FilterDirectoryCollection
+ {
+ $directories = [];
+
+ foreach ($xpath->query($query) as $directoryNode) {
+ assert($directoryNode instanceof DOMElement);
+
+ $directoryPath = (string) $directoryNode->textContent;
+
+ if (!$directoryPath) {
+ continue;
+ }
+
+ $directories[] = new FilterDirectory(
+ $this->toAbsolutePath($filename, $directoryPath),
+ $directoryNode->hasAttribute('prefix') ? (string) $directoryNode->getAttribute('prefix') : '',
+ $directoryNode->hasAttribute('suffix') ? (string) $directoryNode->getAttribute('suffix') : '.php',
+ $directoryNode->hasAttribute('group') ? (string) $directoryNode->getAttribute('group') : 'DEFAULT'
+ );
+ }
+
+ return FilterDirectoryCollection::fromArray($directories);
+ }
+
+ private function readFilterFiles(string $filename, DOMXPath $xpath, string $query): FileCollection
+ {
+ $files = [];
+
+ foreach ($xpath->query($query) as $file) {
+ $filePath = (string) $file->textContent;
+
+ if ($filePath) {
+ $files[] = new File($this->toAbsolutePath($filename, $filePath));
+ }
+ }
+
+ return FileCollection::fromArray($files);
+ }
+
+ private function groups(DOMXPath $xpath): Groups
+ {
+ return $this->parseGroupConfiguration($xpath, 'groups');
+ }
+
+ private function testdoxGroups(DOMXPath $xpath): Groups
+ {
+ return $this->parseGroupConfiguration($xpath, 'testdoxGroups');
+ }
+
+ private function parseGroupConfiguration(DOMXPath $xpath, string $root): Groups
+ {
+ $include = [];
+ $exclude = [];
+
+ foreach ($xpath->query($root . '/include/group') as $group) {
+ $include[] = new Group((string) $group->textContent);
+ }
+
+ foreach ($xpath->query($root . '/exclude/group') as $group) {
+ $exclude[] = new Group((string) $group->textContent);
+ }
+
+ return new Groups(
+ GroupCollection::fromArray($include),
+ GroupCollection::fromArray($exclude)
+ );
+ }
+
+ private function listeners(string $filename, DOMXPath $xpath): ExtensionCollection
+ {
+ $listeners = [];
+
+ foreach ($xpath->query('listeners/listener') as $listener) {
+ assert($listener instanceof DOMElement);
+
+ $listeners[] = $this->getElementConfigurationParameters($filename, $listener);
+ }
+
+ return ExtensionCollection::fromArray($listeners);
+ }
+
+ private function getBooleanAttribute(DOMElement $element, string $attribute, bool $default): bool
+ {
+ if (!$element->hasAttribute($attribute)) {
+ return $default;
+ }
+
+ return (bool) $this->getBoolean(
+ (string) $element->getAttribute($attribute),
+ false
+ );
+ }
+
+ private function getIntegerAttribute(DOMElement $element, string $attribute, int $default): int
+ {
+ if (!$element->hasAttribute($attribute)) {
+ return $default;
+ }
+
+ return $this->getInteger(
+ (string) $element->getAttribute($attribute),
+ $default
+ );
+ }
+
+ private function getStringAttribute(DOMElement $element, string $attribute): ?string
+ {
+ if (!$element->hasAttribute($attribute)) {
+ return null;
+ }
+
+ return (string) $element->getAttribute($attribute);
+ }
+
+ private function getInteger(string $value, int $default): int
+ {
+ if (is_numeric($value)) {
+ return (int) $value;
+ }
+
+ return $default;
+ }
+
+ private function php(string $filename, DOMXPath $xpath): Php
+ {
+ $includePaths = [];
+
+ foreach ($xpath->query('php/includePath') as $includePath) {
+ $path = (string) $includePath->textContent;
+
+ if ($path) {
+ $includePaths[] = new Directory($this->toAbsolutePath($filename, $path));
+ }
+ }
+
+ $iniSettings = [];
+
+ foreach ($xpath->query('php/ini') as $ini) {
+ assert($ini instanceof DOMElement);
+
+ $iniSettings[] = new IniSetting(
+ (string) $ini->getAttribute('name'),
+ (string) $ini->getAttribute('value')
+ );
+ }
+
+ $constants = [];
+
+ foreach ($xpath->query('php/const') as $const) {
+ assert($const instanceof DOMElement);
+
+ $value = (string) $const->getAttribute('value');
+
+ $constants[] = new Constant(
+ (string) $const->getAttribute('name'),
+ $this->getBoolean($value, $value)
+ );
+ }
+
+ $variables = [
+ 'var' => [],
+ 'env' => [],
+ 'post' => [],
+ 'get' => [],
+ 'cookie' => [],
+ 'server' => [],
+ 'files' => [],
+ 'request' => [],
+ ];
+
+ foreach (['var', 'env', 'post', 'get', 'cookie', 'server', 'files', 'request'] as $array) {
+ foreach ($xpath->query('php/' . $array) as $var) {
+ assert($var instanceof DOMElement);
+
+ $name = (string) $var->getAttribute('name');
+ $value = (string) $var->getAttribute('value');
+ $force = false;
+ $verbatim = false;
+
+ if ($var->hasAttribute('force')) {
+ $force = (bool) $this->getBoolean($var->getAttribute('force'), false);
+ }
+
+ if ($var->hasAttribute('verbatim')) {
+ $verbatim = $this->getBoolean($var->getAttribute('verbatim'), false);
+ }
+
+ if (!$verbatim) {
+ $value = $this->getBoolean($value, $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): PHPUnit
+ {
+ $executionOrder = TestSuiteSorter::ORDER_DEFAULT;
+ $defectsFirst = false;
+ $resolveDependencies = $this->getBooleanAttribute($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;
+ }
+ }
+ }
+
+ $printerClass = $this->getStringAttribute($document->documentElement, 'printerClass');
+ $testdox = $this->getBooleanAttribute($document->documentElement, 'testdox', false);
+ $conflictBetweenPrinterClassAndTestdox = false;
+
+ if ($testdox) {
+ if ($printerClass !== null) {
+ $conflictBetweenPrinterClassAndTestdox = true;
+ }
+
+ $printerClass = CliTestDoxPrinter::class;
+ }
+
+ $cacheResultFile = $this->getStringAttribute($document->documentElement, 'cacheResultFile');
+
+ if ($cacheResultFile !== null) {
+ $cacheResultFile = $this->toAbsolutePath($filename, $cacheResultFile);
+ }
+
+ $bootstrap = $this->getStringAttribute($document->documentElement, 'bootstrap');
+
+ if ($bootstrap !== null) {
+ $bootstrap = $this->toAbsolutePath($filename, $bootstrap);
+ }
+
+ $extensionsDirectory = $this->getStringAttribute($document->documentElement, 'extensionsDirectory');
+
+ if ($extensionsDirectory !== null) {
+ $extensionsDirectory = $this->toAbsolutePath($filename, $extensionsDirectory);
+ }
+
+ $testSuiteLoaderFile = $this->getStringAttribute($document->documentElement, 'testSuiteLoaderFile');
+
+ if ($testSuiteLoaderFile !== null) {
+ $testSuiteLoaderFile = $this->toAbsolutePath($filename, $testSuiteLoaderFile);
+ }
+
+ $printerFile = $this->getStringAttribute($document->documentElement, 'printerFile');
+
+ if ($printerFile !== null) {
+ $printerFile = $this->toAbsolutePath($filename, $printerFile);
+ }
+
+ return new PHPUnit(
+ $this->getBooleanAttribute($document->documentElement, 'cacheResult', true),
+ $cacheResultFile,
+ $this->getColumns($document),
+ $this->getColors($document),
+ $this->getBooleanAttribute($document->documentElement, 'stderr', false),
+ $this->getBooleanAttribute($document->documentElement, 'noInteraction', false),
+ $this->getBooleanAttribute($document->documentElement, 'verbose', false),
+ $this->getBooleanAttribute($document->documentElement, 'reverseDefectList', false),
+ $this->getBooleanAttribute($document->documentElement, 'convertDeprecationsToExceptions', false),
+ $this->getBooleanAttribute($document->documentElement, 'convertErrorsToExceptions', true),
+ $this->getBooleanAttribute($document->documentElement, 'convertNoticesToExceptions', true),
+ $this->getBooleanAttribute($document->documentElement, 'convertWarningsToExceptions', true),
+ $this->getBooleanAttribute($document->documentElement, 'forceCoversAnnotation', false),
+ $bootstrap,
+ $this->getBooleanAttribute($document->documentElement, 'processIsolation', false),
+ $this->getBooleanAttribute($document->documentElement, 'failOnEmptyTestSuite', false),
+ $this->getBooleanAttribute($document->documentElement, 'failOnIncomplete', false),
+ $this->getBooleanAttribute($document->documentElement, 'failOnRisky', false),
+ $this->getBooleanAttribute($document->documentElement, 'failOnSkipped', false),
+ $this->getBooleanAttribute($document->documentElement, 'failOnWarning', false),
+ $this->getBooleanAttribute($document->documentElement, 'stopOnDefect', false),
+ $this->getBooleanAttribute($document->documentElement, 'stopOnError', false),
+ $this->getBooleanAttribute($document->documentElement, 'stopOnFailure', false),
+ $this->getBooleanAttribute($document->documentElement, 'stopOnWarning', false),
+ $this->getBooleanAttribute($document->documentElement, 'stopOnIncomplete', false),
+ $this->getBooleanAttribute($document->documentElement, 'stopOnRisky', false),
+ $this->getBooleanAttribute($document->documentElement, 'stopOnSkipped', false),
+ $extensionsDirectory,
+ $this->getStringAttribute($document->documentElement, 'testSuiteLoaderClass'),
+ $testSuiteLoaderFile,
+ $printerClass,
+ $printerFile,
+ $this->getBooleanAttribute($document->documentElement, 'beStrictAboutChangesToGlobalState', false),
+ $this->getBooleanAttribute($document->documentElement, 'beStrictAboutOutputDuringTests', false),
+ $this->getBooleanAttribute($document->documentElement, 'beStrictAboutResourceUsageDuringSmallTests', false),
+ $this->getBooleanAttribute($document->documentElement, 'beStrictAboutTestsThatDoNotTestAnything', true),
+ $this->getBooleanAttribute($document->documentElement, 'beStrictAboutTodoAnnotatedTests', false),
+ $this->getBooleanAttribute($document->documentElement, 'beStrictAboutCoversAnnotation', false),
+ $this->getBooleanAttribute($document->documentElement, 'enforceTimeLimit', false),
+ $this->getIntegerAttribute($document->documentElement, 'defaultTimeLimit', 1),
+ $this->getIntegerAttribute($document->documentElement, 'timeoutForSmallTests', 1),
+ $this->getIntegerAttribute($document->documentElement, 'timeoutForMediumTests', 10),
+ $this->getIntegerAttribute($document->documentElement, 'timeoutForLargeTests', 60),
+ $this->getStringAttribute($document->documentElement, 'defaultTestSuite'),
+ $executionOrder,
+ $resolveDependencies,
+ $defectsFirst,
+ $this->getBooleanAttribute($document->documentElement, 'backupGlobals', false),
+ $this->getBooleanAttribute($document->documentElement, 'backupStaticAttributes', false),
+ $this->getBooleanAttribute($document->documentElement, 'registerMockObjectsFromTestArgumentsRecursively', false),
+ $conflictBetweenPrinterClassAndTestdox
+ );
+ }
+
+ private function getColors(DOMDocument $document): string
+ {
+ $colors = DefaultResultPrinter::COLOR_DEFAULT;
+
+ if ($document->documentElement->hasAttribute('colors')) {
+ /* only allow boolean for compatibility with previous versions
+ 'always' only allowed from command line */
+ if ($this->getBoolean($document->documentElement->getAttribute('colors'), false)) {
+ $colors = DefaultResultPrinter::COLOR_AUTO;
+ } else {
+ $colors = DefaultResultPrinter::COLOR_NEVER;
+ }
+ }
+
+ return $colors;
+ }
+
+ /**
+ * @return int|string
+ */
+ private function getColumns(DOMDocument $document)
+ {
+ $columns = 80;
+
+ if ($document->documentElement->hasAttribute('columns')) {
+ $columns = (string) $document->documentElement->getAttribute('columns');
+
+ if ($columns !== 'max') {
+ $columns = $this->getInteger($columns, 80);
+ }
+ }
+
+ return $columns;
+ }
+
+ private function testSuite(string $filename, DOMXPath $xpath): TestSuiteCollection
+ {
+ $testSuites = [];
+
+ foreach ($this->getTestSuiteElements($xpath) as $element) {
+ $exclude = [];
+
+ foreach ($element->getElementsByTagName('exclude') as $excludeNode) {
+ $excludeFile = (string) $excludeNode->textContent;
+
+ if ($excludeFile) {
+ $exclude[] = new File($this->toAbsolutePath($filename, $excludeFile));
+ }
+ }
+
+ $directories = [];
+
+ foreach ($element->getElementsByTagName('directory') as $directoryNode) {
+ assert($directoryNode instanceof DOMElement);
+
+ $directory = (string) $directoryNode->textContent;
+
+ if (empty($directory)) {
+ continue;
+ }
+
+ $prefix = '';
+
+ if ($directoryNode->hasAttribute('prefix')) {
+ $prefix = (string) $directoryNode->getAttribute('prefix');
+ }
+
+ $suffix = 'Test.php';
+
+ if ($directoryNode->hasAttribute('suffix')) {
+ $suffix = (string) $directoryNode->getAttribute('suffix');
+ }
+
+ $phpVersion = PHP_VERSION;
+
+ if ($directoryNode->hasAttribute('phpVersion')) {
+ $phpVersion = (string) $directoryNode->getAttribute('phpVersion');
+ }
+
+ $phpVersionOperator = new VersionComparisonOperator('>=');
+
+ if ($directoryNode->hasAttribute('phpVersionOperator')) {
+ $phpVersionOperator = new VersionComparisonOperator((string) $directoryNode->getAttribute('phpVersionOperator'));
+ }
+
+ $directories[] = new TestDirectory(
+ $this->toAbsolutePath($filename, $directory),
+ $prefix,
+ $suffix,
+ $phpVersion,
+ $phpVersionOperator
+ );
+ }
+
+ $files = [];
+
+ foreach ($element->getElementsByTagName('file') as $fileNode) {
+ assert($fileNode instanceof DOMElement);
+
+ $file = (string) $fileNode->textContent;
+
+ if (empty($file)) {
+ continue;
+ }
+
+ $phpVersion = PHP_VERSION;
+
+ if ($fileNode->hasAttribute('phpVersion')) {
+ $phpVersion = (string) $fileNode->getAttribute('phpVersion');
+ }
+
+ $phpVersionOperator = new VersionComparisonOperator('>=');
+
+ if ($fileNode->hasAttribute('phpVersionOperator')) {
+ $phpVersionOperator = new VersionComparisonOperator((string) $fileNode->getAttribute('phpVersionOperator'));
+ }
+
+ $files[] = new TestFile(
+ $this->toAbsolutePath($filename, $file),
+ $phpVersion,
+ $phpVersionOperator
+ );
+ }
+
+ $testSuites[] = new TestSuiteConfiguration(
+ (string) $element->getAttribute('name'),
+ TestDirectoryCollection::fromArray($directories),
+ TestFileCollection::fromArray($files),
+ FileCollection::fromArray($exclude)
+ );
+ }
+
+ return TestSuiteCollection::fromArray($testSuites);
+ }
+
+ /**
+ * @return DOMElement[]
+ */
+ private function getTestSuiteElements(DOMXPath $xpath): array
+ {
+ /** @var DOMElement[] $elements */
+ $elements = [];
+
+ $testSuiteNodes = $xpath->query('testsuites/testsuite');
+
+ if ($testSuiteNodes->length === 0) {
+ $testSuiteNodes = $xpath->query('testsuite');
+ }
+
+ 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);
+
+ if ($nodes->length === 1) {
+ $node = $nodes->item(0);
+
+ assert($node instanceof DOMElement);
+
+ return $node;
+ }
+
+ return null;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Junit.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Junit.php
new file mode 100644
index 000000000..efde962d9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Junit.php
@@ -0,0 +1,34 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\File;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Junit
+{
+ /**
+ * @var File
+ */
+ private $target;
+
+ public function __construct(File $target)
+ {
+ $this->target = $target;
+ }
+
+ public function target(): File
+ {
+ return $this->target;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Logging.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Logging.php
new file mode 100644
index 000000000..cdceced50
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Logging.php
@@ -0,0 +1,146 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Xml as TestDoxXml;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Logging
+{
+ /**
+ * @var ?Junit
+ */
+ private $junit;
+
+ /**
+ * @var ?Text
+ */
+ private $text;
+
+ /**
+ * @var ?TeamCity
+ */
+ private $teamCity;
+
+ /**
+ * @var ?TestDoxHtml
+ */
+ private $testDoxHtml;
+
+ /**
+ * @var ?TestDoxText
+ */
+ private $testDoxText;
+
+ /**
+ * @var ?TestDoxXml
+ */
+ private $testDoxXml;
+
+ public function __construct(?Junit $junit, ?Text $text, ?TeamCity $teamCity, ?TestDoxHtml $testDoxHtml, ?TestDoxText $testDoxText, ?TestDoxXml $testDoxXml)
+ {
+ $this->junit = $junit;
+ $this->text = $text;
+ $this->teamCity = $teamCity;
+ $this->testDoxHtml = $testDoxHtml;
+ $this->testDoxText = $testDoxText;
+ $this->testDoxXml = $testDoxXml;
+ }
+
+ public function hasJunit(): bool
+ {
+ return $this->junit !== null;
+ }
+
+ public function junit(): Junit
+ {
+ if ($this->junit === null) {
+ throw new Exception('Logger "JUnit XML" is not configured');
+ }
+
+ return $this->junit;
+ }
+
+ public function hasText(): bool
+ {
+ return $this->text !== null;
+ }
+
+ public function text(): Text
+ {
+ if ($this->text === null) {
+ throw new Exception('Logger "Text" is not configured');
+ }
+
+ return $this->text;
+ }
+
+ public function hasTeamCity(): bool
+ {
+ return $this->teamCity !== null;
+ }
+
+ public function teamCity(): 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;
+ }
+
+ 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;
+ }
+
+ public function testDoxText(): TestDoxText
+ {
+ if ($this->testDoxText === null) {
+ throw new Exception('Logger "TestDox Text" is not configured');
+ }
+
+ return $this->testDoxText;
+ }
+
+ public function hasTestDoxXml(): bool
+ {
+ return $this->testDoxXml !== null;
+ }
+
+ public function testDoxXml(): TestDoxXml
+ {
+ if ($this->testDoxXml === null) {
+ throw new Exception('Logger "TestDox XML" is not configured');
+ }
+
+ return $this->testDoxXml;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TeamCity.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TeamCity.php
new file mode 100644
index 000000000..03b2b56a9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TeamCity.php
@@ -0,0 +1,34 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\File;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class TeamCity
+{
+ /**
+ * @var File
+ */
+ private $target;
+
+ public function __construct(File $target)
+ {
+ $this->target = $target;
+ }
+
+ public function target(): File
+ {
+ return $this->target;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Html.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Html.php
new file mode 100644
index 000000000..310040b2e
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Html.php
@@ -0,0 +1,34 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\XmlConfiguration\File;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Html
+{
+ /**
+ * @var File
+ */
+ private $target;
+
+ public function __construct(File $target)
+ {
+ $this->target = $target;
+ }
+
+ public function target(): File
+ {
+ return $this->target;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Text.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Text.php
new file mode 100644
index 000000000..59d37e9b2
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Text.php
@@ -0,0 +1,34 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\XmlConfiguration\File;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Text
+{
+ /**
+ * @var File
+ */
+ private $target;
+
+ public function __construct(File $target)
+ {
+ $this->target = $target;
+ }
+
+ public function target(): File
+ {
+ return $this->target;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Xml.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Xml.php
new file mode 100644
index 000000000..b8c1576c1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/TestDox/Xml.php
@@ -0,0 +1,34 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\XmlConfiguration\File;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Xml
+{
+ /**
+ * @var File
+ */
+ private $target;
+
+ public function __construct(File $target)
+ {
+ $this->target = $target;
+ }
+
+ public function target(): File
+ {
+ return $this->target;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Text.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Text.php
new file mode 100644
index 000000000..2769ec967
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Logging/Text.php
@@ -0,0 +1,34 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\File;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Text
+{
+ /**
+ * @var File
+ */
+ private $target;
+
+ public function __construct(File $target)
+ {
+ $this->target = $target;
+ }
+
+ public function target(): File
+ {
+ return $this->target;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilder.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilder.php
new file mode 100644
index 000000000..abef49f10
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilder.php
@@ -0,0 +1,73 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 array_key_exists;
+use function sprintf;
+use function version_compare;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MigrationBuilder
+{
+ private const AVAILABLE_MIGRATIONS = [
+ '8.5' => [
+ RemoveLogTypes::class,
+ ],
+
+ '9.2' => [
+ RemoveCacheTokensAttribute::class,
+ IntroduceCoverageElement::class,
+ MoveAttributesFromRootToCoverage::class,
+ MoveAttributesFromFilterWhitelistToCoverage::class,
+ MoveWhitelistDirectoriesToCoverage::class,
+ MoveWhitelistExcludesToCoverage::class,
+ RemoveEmptyFilter::class,
+ CoverageCloverToReport::class,
+ CoverageCrap4jToReport::class,
+ CoverageHtmlToReport::class,
+ CoveragePhpToReport::class,
+ CoverageTextToReport::class,
+ CoverageXmlToReport::class,
+ ConvertLogTypes::class,
+ UpdateSchemaLocationTo93::class,
+ ],
+ ];
+
+ /**
+ * @throws MigrationBuilderException
+ */
+ public function build(string $fromVersion): array
+ {
+ if (!array_key_exists($fromVersion, self::AVAILABLE_MIGRATIONS)) {
+ throw new MigrationBuilderException(
+ sprintf(
+ 'Migration from schema version %s is not supported',
+ $fromVersion
+ )
+ );
+ }
+
+ $stack = [];
+
+ foreach (self::AVAILABLE_MIGRATIONS as $version => $migrations) {
+ if (version_compare($version, $fromVersion, '<')) {
+ continue;
+ }
+
+ foreach ($migrations as $migration) {
+ $stack[] = new $migration;
+ }
+ }
+
+ return $stack;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilderException.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilderException.php
new file mode 100644
index 000000000..3d3c767af
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilderException.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MigrationBuilderException extends RuntimeException implements \PHPUnit\Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationException.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationException.php
new file mode 100644
index 000000000..f92b2db30
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationException.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MigrationException extends RuntimeException implements \PHPUnit\Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/ConvertLogTypes.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/ConvertLogTypes.php
new file mode 100644
index 000000000..697bbe082
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/ConvertLogTypes.php
@@ -0,0 +1,53 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ConvertLogTypes implements 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);
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageCloverToReport.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageCloverToReport.php
new file mode 100644
index 000000000..5f1522b9c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageCloverToReport.php
@@ -0,0 +1,31 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class CoverageCloverToReport extends 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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageCrap4jToReport.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageCrap4jToReport.php
new file mode 100644
index 000000000..afbaaec18
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageCrap4jToReport.php
@@ -0,0 +1,33 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class CoverageCrap4jToReport extends 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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageHtmlToReport.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageHtmlToReport.php
new file mode 100644
index 000000000..7e12095b4
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageHtmlToReport.php
@@ -0,0 +1,33 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class CoverageHtmlToReport extends 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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoveragePhpToReport.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoveragePhpToReport.php
new file mode 100644
index 000000000..bfa10030b
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoveragePhpToReport.php
@@ -0,0 +1,31 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class CoveragePhpToReport extends 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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageTextToReport.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageTextToReport.php
new file mode 100644
index 000000000..063d8df0c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageTextToReport.php
@@ -0,0 +1,33 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class CoverageTextToReport extends 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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageXmlToReport.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageXmlToReport.php
new file mode 100644
index 000000000..480d7777e
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/CoverageXmlToReport.php
@@ -0,0 +1,31 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class CoverageXmlToReport extends 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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/IntroduceCoverageElement.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/IntroduceCoverageElement.php
new file mode 100644
index 000000000..867a84417
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/IntroduceCoverageElement.php
@@ -0,0 +1,28 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class IntroduceCoverageElement implements Migration
+{
+ public function migrate(DOMDocument $document): void
+ {
+ $coverage = $document->createElement('coverage');
+
+ $document->documentElement->insertBefore(
+ $coverage,
+ $document->documentElement->firstChild
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/LogToReportMigration.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/LogToReportMigration.php
new file mode 100644
index 000000000..e987308b7
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/LogToReportMigration.php
@@ -0,0 +1,79 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+use DOMXPath;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+abstract class LogToReportMigration implements Migration
+{
+ /**
+ * @throws MigrationException
+ */
+ public function migrate(DOMDocument $document): void
+ {
+ $coverage = $document->getElementsByTagName('coverage')->item(0);
+
+ if (!$coverage instanceof DOMElement) {
+ throw new 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);
+ }
+
+ 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
+ {
+ $logNode = (new DOMXPath($document))->query(
+ sprintf('//logging/log[@type="%s"]', $this->forType())
+ )->item(0);
+
+ if (!$logNode instanceof DOMElement) {
+ return null;
+ }
+
+ return $logNode;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/Migration.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/Migration.php
new file mode 100644
index 000000000..fa4092a9f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/Migration.php
@@ -0,0 +1,20 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+interface Migration
+{
+ public function migrate(DOMDocument $document): void;
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php
new file mode 100644
index 000000000..a7aab5e51
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php
@@ -0,0 +1,51 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MoveAttributesFromFilterWhitelistToCoverage implements Migration
+{
+ /**
+ * @throws MigrationException
+ */
+ public function migrate(DOMDocument $document): void
+ {
+ $whitelist = $document->getElementsByTagName('whitelist')->item(0);
+
+ if (!$whitelist) {
+ return;
+ }
+
+ $coverage = $document->getElementsByTagName('coverage')->item(0);
+
+ if (!$coverage instanceof DOMElement) {
+ throw new 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);
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromRootToCoverage.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromRootToCoverage.php
new file mode 100644
index 000000000..b86b259c3
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveAttributesFromRootToCoverage.php
@@ -0,0 +1,47 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MoveAttributesFromRootToCoverage implements Migration
+{
+ /**
+ * @throws MigrationException
+ */
+ public function migrate(DOMDocument $document): void
+ {
+ $map = [
+ 'disableCodeCoverageIgnore' => 'disableCodeCoverageIgnore',
+ 'ignoreDeprecatedCodeUnitsFromCodeCoverage' => 'ignoreDeprecatedCodeUnits',
+ ];
+
+ $root = $document->documentElement;
+
+ $coverage = $document->getElementsByTagName('coverage')->item(0);
+
+ if (!$coverage instanceof DOMElement) {
+ throw new 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);
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistDirectoriesToCoverage.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistDirectoriesToCoverage.php
new file mode 100644
index 000000000..14e6cec83
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistDirectoriesToCoverage.php
@@ -0,0 +1,49 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+use PHPUnit\Util\Xml\SnapshotNodeList;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MoveWhitelistDirectoriesToCoverage implements 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 MigrationException('Unexpected state - No coverage element');
+ }
+
+ $include = $document->createElement('include');
+ $coverage->appendChild($include);
+
+ foreach (SnapshotNodeList::fromNodeList($whitelist->childNodes) as $child) {
+ if (!$child instanceof DOMElement || $child->nodeName !== 'directory') {
+ continue;
+ }
+
+ $include->appendChild($child);
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistExcludesToCoverage.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistExcludesToCoverage.php
new file mode 100644
index 000000000..d8958cf4e
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/MoveWhitelistExcludesToCoverage.php
@@ -0,0 +1,70 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+use PHPUnit\Util\Xml\SnapshotNodeList;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class MoveWhitelistExcludesToCoverage implements Migration
+{
+ /**
+ * @throws MigrationException
+ */
+ public function migrate(DOMDocument $document): void
+ {
+ $whitelist = $document->getElementsByTagName('whitelist')->item(0);
+
+ if ($whitelist === null) {
+ return;
+ }
+
+ $excludeNodes = SnapshotNodeList::fromNodeList($whitelist->getElementsByTagName('exclude'));
+
+ if ($excludeNodes->count() === 0) {
+ return;
+ }
+
+ $coverage = $document->getElementsByTagName('coverage')->item(0);
+
+ if (!$coverage instanceof DOMElement) {
+ throw new 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 (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 MigrationException('Dangling child elements in exclude found.');
+ }
+
+ $whitelist->removeChild($excludeNode);
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveCacheTokensAttribute.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveCacheTokensAttribute.php
new file mode 100644
index 000000000..0eec12ac1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveCacheTokensAttribute.php
@@ -0,0 +1,27 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class RemoveCacheTokensAttribute implements Migration
+{
+ public function migrate(DOMDocument $document): void
+ {
+ $root = $document->documentElement;
+
+ if ($root->hasAttribute('cacheTokens')) {
+ $root->removeAttribute('cacheTokens');
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveEmptyFilter.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveEmptyFilter.php
new file mode 100644
index 000000000..8f1a6d547
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveEmptyFilter.php
@@ -0,0 +1,54 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class RemoveEmptyFilter implements 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 MigrationException(sprintf('%s element has unexpected attributes', $element->nodeName));
+ }
+
+ if ($element->getElementsByTagName('*')->length > 0) {
+ throw new MigrationException(sprintf('%s element has unexpected children', $element->nodeName));
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveLogTypes.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveLogTypes.php
new file mode 100644
index 000000000..99a762b18
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/RemoveLogTypes.php
@@ -0,0 +1,37 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+use PHPUnit\Util\Xml\SnapshotNodeList;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class RemoveLogTypes implements Migration
+{
+ public function migrate(DOMDocument $document): void
+ {
+ $logging = $document->getElementsByTagName('logging')->item(0);
+
+ if (!$logging instanceof DOMElement) {
+ return;
+ }
+
+ foreach (SnapshotNodeList::fromNodeList($logging->getElementsByTagName('log')) as $logNode) {
+ switch ($logNode->getAttribute('type')) {
+ case 'json':
+ case 'tap':
+ $logging->removeChild($logNode);
+ }
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/UpdateSchemaLocationTo93.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/UpdateSchemaLocationTo93.php
new file mode 100644
index 000000000..2e86ab6e9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrations/UpdateSchemaLocationTo93.php
@@ -0,0 +1,27 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class UpdateSchemaLocationTo93 implements Migration
+{
+ public function migrate(DOMDocument $document): void
+ {
+ $document->documentElement->setAttributeNS(
+ 'http://www.w3.org/2001/XMLSchema-instance',
+ 'xsi:noNamespaceSchemaLocation',
+ 'https://schema.phpunit.de/9.3/phpunit.xsd'
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrator.php
new file mode 100644
index 000000000..d173e7af2
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/Migrator.php
@@ -0,0 +1,57 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 PHPUnit\Util\Xml\Exception as XmlException;
+use PHPUnit\Util\Xml\Loader as XmlLoader;
+use PHPUnit\Util\Xml\SchemaDetector;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Migrator
+{
+ /**
+ * @throws Exception
+ * @throws MigrationBuilderException
+ * @throws MigrationException
+ * @throws XmlException
+ */
+ public function migrate(string $filename): string
+ {
+ $origin = (new SchemaDetector)->detect($filename);
+
+ if (!$origin->detected()) {
+ throw new Exception(
+ sprintf(
+ '"%s" is not a valid PHPUnit XML configuration file that can be migrated',
+ $filename,
+ )
+ );
+ }
+
+ $configurationDocument = (new XmlLoader)->loadFile(
+ $filename,
+ false,
+ true,
+ true
+ );
+
+ foreach ((new MigrationBuilder)->build($origin->version()) as $migration) {
+ $migration->migrate($configurationDocument);
+ }
+
+ $configurationDocument->formatOutput = true;
+ $configurationDocument->preserveWhiteSpace = false;
+
+ return $configurationDocument->saveXML();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Constant.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Constant.php
new file mode 100644
index 000000000..e9b28b9e8
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Constant.php
@@ -0,0 +1,43 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Constant
+{
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var mixed
+ */
+ private $value;
+
+ public function __construct(string $name, $value)
+ {
+ $this->name = $name;
+ $this->value = $value;
+ }
+
+ public function name(): string
+ {
+ return $this->name;
+ }
+
+ public function value()
+ {
+ return $this->value;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/ConstantCollection.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/ConstantCollection.php
new file mode 100644
index 000000000..51c14715f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/ConstantCollection.php
@@ -0,0 +1,57 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Countable;
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class ConstantCollection implements Countable, IteratorAggregate
+{
+ /**
+ * @var Constant[]
+ */
+ private $constants;
+
+ /**
+ * @param Constant[] $constants
+ */
+ public static function fromArray(array $constants): self
+ {
+ return new self(...$constants);
+ }
+
+ private function __construct(Constant ...$constants)
+ {
+ $this->constants = $constants;
+ }
+
+ /**
+ * @return Constant[]
+ */
+ public function asArray(): array
+ {
+ return $this->constants;
+ }
+
+ public function count(): int
+ {
+ return count($this->constants);
+ }
+
+ public function getIterator(): ConstantCollectionIterator
+ {
+ return new ConstantCollectionIterator($this);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/ConstantCollectionIterator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/ConstantCollectionIterator.php
new file mode 100644
index 000000000..c1c8d834b
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/ConstantCollectionIterator.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function iterator_count;
+use Countable;
+use Iterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ConstantCollectionIterator implements Countable, Iterator
+{
+ /**
+ * @var Constant[]
+ */
+ private $constants;
+
+ /**
+ * @var int
+ */
+ private $position;
+
+ public function __construct(ConstantCollection $constants)
+ {
+ $this->constants = $constants->asArray();
+ }
+
+ public function count(): int
+ {
+ return iterator_count($this);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->constants);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): Constant
+ {
+ return $this->constants[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSetting.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSetting.php
new file mode 100644
index 000000000..58cf735b0
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSetting.php
@@ -0,0 +1,43 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class IniSetting
+{
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var string
+ */
+ private $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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSettingCollection.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSettingCollection.php
new file mode 100644
index 000000000..216d85aec
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSettingCollection.php
@@ -0,0 +1,57 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Countable;
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class IniSettingCollection implements Countable, IteratorAggregate
+{
+ /**
+ * @var IniSetting[]
+ */
+ private $iniSettings;
+
+ /**
+ * @param IniSetting[] $iniSettings
+ */
+ public static function fromArray(array $iniSettings): self
+ {
+ return new self(...$iniSettings);
+ }
+
+ private function __construct(IniSetting ...$iniSettings)
+ {
+ $this->iniSettings = $iniSettings;
+ }
+
+ /**
+ * @return IniSetting[]
+ */
+ public function asArray(): array
+ {
+ return $this->iniSettings;
+ }
+
+ public function count(): int
+ {
+ return count($this->iniSettings);
+ }
+
+ public function getIterator(): IniSettingCollectionIterator
+ {
+ return new IniSettingCollectionIterator($this);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSettingCollectionIterator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSettingCollectionIterator.php
new file mode 100644
index 000000000..f31225e8f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/IniSettingCollectionIterator.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function iterator_count;
+use Countable;
+use Iterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class IniSettingCollectionIterator implements Countable, Iterator
+{
+ /**
+ * @var IniSetting[]
+ */
+ private $iniSettings;
+
+ /**
+ * @var int
+ */
+ private $position;
+
+ public function __construct(IniSettingCollection $iniSettings)
+ {
+ $this->iniSettings = $iniSettings->asArray();
+ }
+
+ public function count(): int
+ {
+ return iterator_count($this);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->iniSettings);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): IniSetting
+ {
+ return $this->iniSettings[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Php.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Php.php
new file mode 100644
index 000000000..26897e359
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Php.php
@@ -0,0 +1,142 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Php
+{
+ /**
+ * @var DirectoryCollection
+ */
+ private $includePaths;
+
+ /**
+ * @var IniSettingCollection
+ */
+ private $iniSettings;
+
+ /**
+ * @var ConstantCollection
+ */
+ private $constants;
+
+ /**
+ * @var VariableCollection
+ */
+ private $globalVariables;
+
+ /**
+ * @var VariableCollection
+ */
+ private $envVariables;
+
+ /**
+ * @var VariableCollection
+ */
+ private $postVariables;
+
+ /**
+ * @var VariableCollection
+ */
+ private $getVariables;
+
+ /**
+ * @var VariableCollection
+ */
+ private $cookieVariables;
+
+ /**
+ * @var VariableCollection
+ */
+ private $serverVariables;
+
+ /**
+ * @var VariableCollection
+ */
+ private $filesVariables;
+
+ /**
+ * @var VariableCollection
+ */
+ private $requestVariables;
+
+ public function __construct(DirectoryCollection $includePaths, IniSettingCollection $iniSettings, ConstantCollection $constants, VariableCollection $globalVariables, VariableCollection $envVariables, VariableCollection $postVariables, VariableCollection $getVariables, VariableCollection $cookieVariables, VariableCollection $serverVariables, VariableCollection $filesVariables, 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(): DirectoryCollection
+ {
+ return $this->includePaths;
+ }
+
+ public function iniSettings(): IniSettingCollection
+ {
+ return $this->iniSettings;
+ }
+
+ public function constants(): ConstantCollection
+ {
+ return $this->constants;
+ }
+
+ public function globalVariables(): VariableCollection
+ {
+ return $this->globalVariables;
+ }
+
+ public function envVariables(): VariableCollection
+ {
+ return $this->envVariables;
+ }
+
+ public function postVariables(): VariableCollection
+ {
+ return $this->postVariables;
+ }
+
+ public function getVariables(): VariableCollection
+ {
+ return $this->getVariables;
+ }
+
+ public function cookieVariables(): VariableCollection
+ {
+ return $this->cookieVariables;
+ }
+
+ public function serverVariables(): VariableCollection
+ {
+ return $this->serverVariables;
+ }
+
+ public function filesVariables(): VariableCollection
+ {
+ return $this->filesVariables;
+ }
+
+ public function requestVariables(): VariableCollection
+ {
+ return $this->requestVariables;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/PhpHandler.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/PhpHandler.php
new file mode 100644
index 000000000..5fb0c72b2
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/PhpHandler.php
@@ -0,0 +1,121 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 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;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class PhpHandler
+{
+ public function handle(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(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(IniSettingCollection $iniSettings): void
+ {
+ foreach ($iniSettings as $iniSetting) {
+ $value = $iniSetting->value();
+
+ if (defined($value)) {
+ $value = (string) constant($value);
+ }
+
+ ini_set($iniSetting->name(), $value);
+ }
+ }
+
+ private function handleConstants(ConstantCollection $constants): void
+ {
+ foreach ($constants as $constant) {
+ if (!defined($constant->name())) {
+ define($constant->name(), $constant->value());
+ }
+ }
+ }
+
+ private function handleGlobalVariables(VariableCollection $variables): void
+ {
+ foreach ($variables as $variable) {
+ $GLOBALS[$variable->name()] = $variable->value();
+ }
+ }
+
+ private function handleServerVariables(VariableCollection $variables): void
+ {
+ foreach ($variables as $variable) {
+ $_SERVER[$variable->name()] = $variable->value();
+ }
+ }
+
+ private function handleVariables(string $target, VariableCollection $variables): void
+ {
+ foreach ($variables as $variable) {
+ $GLOBALS[$target][$variable->name()] = $variable->value();
+ }
+ }
+
+ private function handleEnvVariables(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;
+ }
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Variable.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Variable.php
new file mode 100644
index 000000000..c2684e28f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/Variable.php
@@ -0,0 +1,54 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Variable
+{
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var mixed
+ */
+ private $value;
+
+ /**
+ * @var bool
+ */
+ private $force;
+
+ public function __construct(string $name, $value, bool $force)
+ {
+ $this->name = $name;
+ $this->value = $value;
+ $this->force = $force;
+ }
+
+ public function name(): string
+ {
+ return $this->name;
+ }
+
+ public function value()
+ {
+ return $this->value;
+ }
+
+ public function force(): bool
+ {
+ return $this->force;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/VariableCollection.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/VariableCollection.php
new file mode 100644
index 000000000..e84992168
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/VariableCollection.php
@@ -0,0 +1,57 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Countable;
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class VariableCollection implements Countable, IteratorAggregate
+{
+ /**
+ * @var Variable[]
+ */
+ private $variables;
+
+ /**
+ * @param Variable[] $variables
+ */
+ public static function fromArray(array $variables): self
+ {
+ return new self(...$variables);
+ }
+
+ private function __construct(Variable ...$variables)
+ {
+ $this->variables = $variables;
+ }
+
+ /**
+ * @return Variable[]
+ */
+ public function asArray(): array
+ {
+ return $this->variables;
+ }
+
+ public function count(): int
+ {
+ return count($this->variables);
+ }
+
+ public function getIterator(): VariableCollectionIterator
+ {
+ return new VariableCollectionIterator($this);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/VariableCollectionIterator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/VariableCollectionIterator.php
new file mode 100644
index 000000000..3d594c1ee
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHP/VariableCollectionIterator.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function iterator_count;
+use Countable;
+use Iterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class VariableCollectionIterator implements Countable, Iterator
+{
+ /**
+ * @var Variable[]
+ */
+ private $variables;
+
+ /**
+ * @var int
+ */
+ private $position;
+
+ public function __construct(VariableCollection $variables)
+ {
+ $this->variables = $variables->asArray();
+ }
+
+ public function count(): int
+ {
+ return iterator_count($this);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->variables);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): Variable
+ {
+ return $this->variables[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/Extension.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/Extension.php
new file mode 100644
index 000000000..77c5b2d0d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/Extension.php
@@ -0,0 +1,71 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class Extension
+{
+ /**
+ * @var string
+ * @psalm-var class-string
+ */
+ private $className;
+
+ /**
+ * @var string
+ */
+ private $sourceFile;
+
+ /**
+ * @var array
+ */
+ private $arguments;
+
+ /**
+ * @psalm-param class-string $className
+ */
+ public function __construct(string $className, string $sourceFile, array $arguments)
+ {
+ $this->className = $className;
+ $this->sourceFile = $sourceFile;
+ $this->arguments = $arguments;
+ }
+
+ /**
+ * @psalm-return class-string
+ */
+ public function className(): string
+ {
+ return $this->className;
+ }
+
+ public function hasSourceFile(): bool
+ {
+ return $this->sourceFile !== '';
+ }
+
+ public function sourceFile(): string
+ {
+ return $this->sourceFile;
+ }
+
+ public function hasArguments(): bool
+ {
+ return !empty($this->arguments);
+ }
+
+ public function arguments(): array
+ {
+ return $this->arguments;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/ExtensionCollection.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/ExtensionCollection.php
new file mode 100644
index 000000000..45be2eeeb
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/ExtensionCollection.php
@@ -0,0 +1,50 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class ExtensionCollection implements IteratorAggregate
+{
+ /**
+ * @var Extension[]
+ */
+ private $extensions;
+
+ /**
+ * @param Extension[] $extensions
+ */
+ public static function fromArray(array $extensions): self
+ {
+ return new self(...$extensions);
+ }
+
+ private function __construct(Extension ...$extensions)
+ {
+ $this->extensions = $extensions;
+ }
+
+ /**
+ * @return Extension[]
+ */
+ public function asArray(): array
+ {
+ return $this->extensions;
+ }
+
+ public function getIterator(): ExtensionCollectionIterator
+ {
+ return new ExtensionCollectionIterator($this);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/ExtensionCollectionIterator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/ExtensionCollectionIterator.php
new file mode 100644
index 000000000..4bd54be49
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/ExtensionCollectionIterator.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function iterator_count;
+use Countable;
+use Iterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ExtensionCollectionIterator implements Countable, Iterator
+{
+ /**
+ * @var Extension[]
+ */
+ private $extensions;
+
+ /**
+ * @var int
+ */
+ private $position;
+
+ public function __construct(ExtensionCollection $extensions)
+ {
+ $this->extensions = $extensions->asArray();
+ }
+
+ public function count(): int
+ {
+ return iterator_count($this);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->extensions);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): Extension
+ {
+ return $this->extensions[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/PHPUnit.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/PHPUnit.php
new file mode 100644
index 000000000..edf298dd5
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/PHPUnit/PHPUnit.php
@@ -0,0 +1,714 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class PHPUnit
+{
+ /**
+ * @var bool
+ */
+ private $cacheResult;
+
+ /**
+ * @var ?string
+ */
+ private $cacheResultFile;
+
+ /**
+ * @var int|string
+ */
+ private $columns;
+
+ /**
+ * @var string
+ */
+ private $colors;
+
+ /**
+ * @var bool
+ */
+ private $stderr;
+
+ /**
+ * @var bool
+ */
+ private $noInteraction;
+
+ /**
+ * @var bool
+ */
+ private $verbose;
+
+ /**
+ * @var bool
+ */
+ private $reverseDefectList;
+
+ /**
+ * @var bool
+ */
+ private $convertDeprecationsToExceptions;
+
+ /**
+ * @var bool
+ */
+ private $convertErrorsToExceptions;
+
+ /**
+ * @var bool
+ */
+ private $convertNoticesToExceptions;
+
+ /**
+ * @var bool
+ */
+ private $convertWarningsToExceptions;
+
+ /**
+ * @var bool
+ */
+ private $forceCoversAnnotation;
+
+ /**
+ * @var ?string
+ */
+ private $bootstrap;
+
+ /**
+ * @var bool
+ */
+ private $processIsolation;
+
+ /**
+ * @var bool
+ */
+ private $failOnEmptyTestSuite;
+
+ /**
+ * @var bool
+ */
+ private $failOnIncomplete;
+
+ /**
+ * @var bool
+ */
+ private $failOnRisky;
+
+ /**
+ * @var bool
+ */
+ private $failOnSkipped;
+
+ /**
+ * @var bool
+ */
+ private $failOnWarning;
+
+ /**
+ * @var bool
+ */
+ private $stopOnDefect;
+
+ /**
+ * @var bool
+ */
+ private $stopOnError;
+
+ /**
+ * @var bool
+ */
+ private $stopOnFailure;
+
+ /**
+ * @var bool
+ */
+ private $stopOnWarning;
+
+ /**
+ * @var bool
+ */
+ private $stopOnIncomplete;
+
+ /**
+ * @var bool
+ */
+ private $stopOnRisky;
+
+ /**
+ * @var bool
+ */
+ private $stopOnSkipped;
+
+ /**
+ * @var ?string
+ */
+ private $extensionsDirectory;
+
+ /**
+ * @var ?string
+ *
+ * @deprecated see https://github.com/sebastianbergmann/phpunit/issues/4039
+ */
+ private $testSuiteLoaderClass;
+
+ /**
+ * @var ?string
+ *
+ * @deprecated see https://github.com/sebastianbergmann/phpunit/issues/4039
+ */
+ private $testSuiteLoaderFile;
+
+ /**
+ * @var ?string
+ */
+ private $printerClass;
+
+ /**
+ * @var ?string
+ */
+ private $printerFile;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutChangesToGlobalState;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutOutputDuringTests;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutResourceUsageDuringSmallTests;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutTestsThatDoNotTestAnything;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutTodoAnnotatedTests;
+
+ /**
+ * @var bool
+ */
+ private $beStrictAboutCoversAnnotation;
+
+ /**
+ * @var bool
+ */
+ private $enforceTimeLimit;
+
+ /**
+ * @var int
+ */
+ private $defaultTimeLimit;
+
+ /**
+ * @var int
+ */
+ private $timeoutForSmallTests;
+
+ /**
+ * @var int
+ */
+ private $timeoutForMediumTests;
+
+ /**
+ * @var int
+ */
+ private $timeoutForLargeTests;
+
+ /**
+ * @var ?string
+ */
+ private $defaultTestSuite;
+
+ /**
+ * @var int
+ */
+ private $executionOrder;
+
+ /**
+ * @var bool
+ */
+ private $resolveDependencies;
+
+ /**
+ * @var bool
+ */
+ private $defectsFirst;
+
+ /**
+ * @var bool
+ */
+ private $backupGlobals;
+
+ /**
+ * @var bool
+ */
+ private $backupStaticAttributes;
+
+ /**
+ * @var bool
+ */
+ private $registerMockObjectsFromTestArgumentsRecursively;
+
+ /**
+ * @var bool
+ */
+ private $conflictBetweenPrinterClassAndTestdox;
+
+ public function __construct(bool $cacheResult, ?string $cacheResultFile, $columns, string $colors, bool $stderr, bool $noInteraction, bool $verbose, bool $reverseDefectList, bool $convertDeprecationsToExceptions, bool $convertErrorsToExceptions, bool $convertNoticesToExceptions, bool $convertWarningsToExceptions, bool $forceCoversAnnotation, ?string $bootstrap, bool $processIsolation, bool $failOnEmptyTestSuite, bool $failOnIncomplete, bool $failOnRisky, bool $failOnSkipped, bool $failOnWarning, bool $stopOnDefect, bool $stopOnError, bool $stopOnFailure, bool $stopOnWarning, bool $stopOnIncomplete, bool $stopOnRisky, bool $stopOnSkipped, ?string $extensionsDirectory, ?string $testSuiteLoaderClass, ?string $testSuiteLoaderFile, ?string $printerClass, ?string $printerFile, bool $beStrictAboutChangesToGlobalState, bool $beStrictAboutOutputDuringTests, bool $beStrictAboutResourceUsageDuringSmallTests, bool $beStrictAboutTestsThatDoNotTestAnything, bool $beStrictAboutTodoAnnotatedTests, bool $beStrictAboutCoversAnnotation, bool $enforceTimeLimit, int $defaultTimeLimit, int $timeoutForSmallTests, int $timeoutForMediumTests, int $timeoutForLargeTests, ?string $defaultTestSuite, int $executionOrder, bool $resolveDependencies, bool $defectsFirst, bool $backupGlobals, bool $backupStaticAttributes, bool $registerMockObjectsFromTestArgumentsRecursively, bool $conflictBetweenPrinterClassAndTestdox)
+ {
+ $this->cacheResult = $cacheResult;
+ $this->cacheResultFile = $cacheResultFile;
+ $this->columns = $columns;
+ $this->colors = $colors;
+ $this->stderr = $stderr;
+ $this->noInteraction = $noInteraction;
+ $this->verbose = $verbose;
+ $this->reverseDefectList = $reverseDefectList;
+ $this->convertDeprecationsToExceptions = $convertDeprecationsToExceptions;
+ $this->convertErrorsToExceptions = $convertErrorsToExceptions;
+ $this->convertNoticesToExceptions = $convertNoticesToExceptions;
+ $this->convertWarningsToExceptions = $convertWarningsToExceptions;
+ $this->forceCoversAnnotation = $forceCoversAnnotation;
+ $this->bootstrap = $bootstrap;
+ $this->processIsolation = $processIsolation;
+ $this->failOnEmptyTestSuite = $failOnEmptyTestSuite;
+ $this->failOnIncomplete = $failOnIncomplete;
+ $this->failOnRisky = $failOnRisky;
+ $this->failOnSkipped = $failOnSkipped;
+ $this->failOnWarning = $failOnWarning;
+ $this->stopOnDefect = $stopOnDefect;
+ $this->stopOnError = $stopOnError;
+ $this->stopOnFailure = $stopOnFailure;
+ $this->stopOnWarning = $stopOnWarning;
+ $this->stopOnIncomplete = $stopOnIncomplete;
+ $this->stopOnRisky = $stopOnRisky;
+ $this->stopOnSkipped = $stopOnSkipped;
+ $this->extensionsDirectory = $extensionsDirectory;
+ $this->testSuiteLoaderClass = $testSuiteLoaderClass;
+ $this->testSuiteLoaderFile = $testSuiteLoaderFile;
+ $this->printerClass = $printerClass;
+ $this->printerFile = $printerFile;
+ $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState;
+ $this->beStrictAboutOutputDuringTests = $beStrictAboutOutputDuringTests;
+ $this->beStrictAboutResourceUsageDuringSmallTests = $beStrictAboutResourceUsageDuringSmallTests;
+ $this->beStrictAboutTestsThatDoNotTestAnything = $beStrictAboutTestsThatDoNotTestAnything;
+ $this->beStrictAboutTodoAnnotatedTests = $beStrictAboutTodoAnnotatedTests;
+ $this->beStrictAboutCoversAnnotation = $beStrictAboutCoversAnnotation;
+ $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->backupStaticAttributes = $backupStaticAttributes;
+ $this->registerMockObjectsFromTestArgumentsRecursively = $registerMockObjectsFromTestArgumentsRecursively;
+ $this->conflictBetweenPrinterClassAndTestdox = $conflictBetweenPrinterClassAndTestdox;
+ }
+
+ public function cacheResult(): bool
+ {
+ return $this->cacheResult;
+ }
+
+ /**
+ * @psalm-assert-if-true !null $this->cacheResultFile
+ */
+ public function hasCacheResultFile(): bool
+ {
+ return $this->cacheResultFile !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function cacheResultFile(): string
+ {
+ if (!$this->hasCacheResultFile()) {
+ throw new Exception('Cache result file is not configured');
+ }
+
+ return (string) $this->cacheResultFile;
+ }
+
+ public function columns()
+ {
+ return $this->columns;
+ }
+
+ public function colors(): string
+ {
+ return $this->colors;
+ }
+
+ public function stderr(): bool
+ {
+ return $this->stderr;
+ }
+
+ public function noInteraction(): bool
+ {
+ return $this->noInteraction;
+ }
+
+ public function verbose(): bool
+ {
+ return $this->verbose;
+ }
+
+ public function reverseDefectList(): bool
+ {
+ return $this->reverseDefectList;
+ }
+
+ public function convertDeprecationsToExceptions(): bool
+ {
+ return $this->convertDeprecationsToExceptions;
+ }
+
+ public function convertErrorsToExceptions(): bool
+ {
+ return $this->convertErrorsToExceptions;
+ }
+
+ public function convertNoticesToExceptions(): bool
+ {
+ return $this->convertNoticesToExceptions;
+ }
+
+ public function convertWarningsToExceptions(): bool
+ {
+ return $this->convertWarningsToExceptions;
+ }
+
+ public function forceCoversAnnotation(): bool
+ {
+ return $this->forceCoversAnnotation;
+ }
+
+ /**
+ * @psalm-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 Exception('Bootstrap script is not configured');
+ }
+
+ return (string) $this->bootstrap;
+ }
+
+ public function processIsolation(): bool
+ {
+ return $this->processIsolation;
+ }
+
+ public function failOnEmptyTestSuite(): bool
+ {
+ return $this->failOnEmptyTestSuite;
+ }
+
+ public function failOnIncomplete(): bool
+ {
+ return $this->failOnIncomplete;
+ }
+
+ 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 stopOnError(): bool
+ {
+ return $this->stopOnError;
+ }
+
+ public function stopOnFailure(): bool
+ {
+ return $this->stopOnFailure;
+ }
+
+ public function stopOnWarning(): bool
+ {
+ return $this->stopOnWarning;
+ }
+
+ public function stopOnIncomplete(): bool
+ {
+ return $this->stopOnIncomplete;
+ }
+
+ public function stopOnRisky(): bool
+ {
+ return $this->stopOnRisky;
+ }
+
+ public function stopOnSkipped(): bool
+ {
+ return $this->stopOnSkipped;
+ }
+
+ /**
+ * @psalm-assert-if-true !null $this->extensionsDirectory
+ */
+ public function hasExtensionsDirectory(): bool
+ {
+ return $this->extensionsDirectory !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function extensionsDirectory(): string
+ {
+ if (!$this->hasExtensionsDirectory()) {
+ throw new Exception('Extensions directory is not configured');
+ }
+
+ return (string) $this->extensionsDirectory;
+ }
+
+ /**
+ * @psalm-assert-if-true !null $this->testSuiteLoaderClass
+ *
+ * @deprecated see https://github.com/sebastianbergmann/phpunit/issues/4039
+ */
+ public function hasTestSuiteLoaderClass(): bool
+ {
+ return $this->testSuiteLoaderClass !== null;
+ }
+
+ /**
+ * @throws Exception
+ *
+ * @deprecated see https://github.com/sebastianbergmann/phpunit/issues/4039
+ */
+ public function testSuiteLoaderClass(): string
+ {
+ if (!$this->hasTestSuiteLoaderClass()) {
+ throw new Exception('TestSuiteLoader class is not configured');
+ }
+
+ return (string) $this->testSuiteLoaderClass;
+ }
+
+ /**
+ * @psalm-assert-if-true !null $this->testSuiteLoaderFile
+ *
+ * @deprecated see https://github.com/sebastianbergmann/phpunit/issues/4039
+ */
+ public function hasTestSuiteLoaderFile(): bool
+ {
+ return $this->testSuiteLoaderFile !== null;
+ }
+
+ /**
+ * @throws Exception
+ *
+ * @deprecated see https://github.com/sebastianbergmann/phpunit/issues/4039
+ */
+ public function testSuiteLoaderFile(): string
+ {
+ if (!$this->hasTestSuiteLoaderFile()) {
+ throw new Exception('TestSuiteLoader sourcecode file is not configured');
+ }
+
+ return (string) $this->testSuiteLoaderFile;
+ }
+
+ /**
+ * @psalm-assert-if-true !null $this->printerClass
+ */
+ public function hasPrinterClass(): bool
+ {
+ return $this->printerClass !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function printerClass(): string
+ {
+ if (!$this->hasPrinterClass()) {
+ throw new Exception('ResultPrinter class is not configured');
+ }
+
+ return (string) $this->printerClass;
+ }
+
+ /**
+ * @psalm-assert-if-true !null $this->printerFile
+ */
+ public function hasPrinterFile(): bool
+ {
+ return $this->printerFile !== null;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function printerFile(): string
+ {
+ if (!$this->hasPrinterFile()) {
+ throw new Exception('ResultPrinter sourcecode file is not configured');
+ }
+
+ return (string) $this->printerFile;
+ }
+
+ public function beStrictAboutChangesToGlobalState(): bool
+ {
+ return $this->beStrictAboutChangesToGlobalState;
+ }
+
+ public function beStrictAboutOutputDuringTests(): bool
+ {
+ return $this->beStrictAboutOutputDuringTests;
+ }
+
+ public function beStrictAboutResourceUsageDuringSmallTests(): bool
+ {
+ return $this->beStrictAboutResourceUsageDuringSmallTests;
+ }
+
+ public function beStrictAboutTestsThatDoNotTestAnything(): bool
+ {
+ return $this->beStrictAboutTestsThatDoNotTestAnything;
+ }
+
+ public function beStrictAboutTodoAnnotatedTests(): bool
+ {
+ return $this->beStrictAboutTodoAnnotatedTests;
+ }
+
+ public function beStrictAboutCoversAnnotation(): bool
+ {
+ return $this->beStrictAboutCoversAnnotation;
+ }
+
+ 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;
+ }
+
+ /**
+ * @psalm-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 Exception('Default test suite is not configured');
+ }
+
+ return (string) $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 backupStaticAttributes(): bool
+ {
+ return $this->backupStaticAttributes;
+ }
+
+ public function registerMockObjectsFromTestArgumentsRecursively(): bool
+ {
+ return $this->registerMockObjectsFromTestArgumentsRecursively;
+ }
+
+ public function conflictBetweenPrinterClassAndTestdox(): bool
+ {
+ return $this->conflictBetweenPrinterClassAndTestdox;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectory.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectory.php
new file mode 100644
index 000000000..263d02ea9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectory.php
@@ -0,0 +1,78 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\VersionComparisonOperator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class TestDirectory
+{
+ /**
+ * @var string
+ */
+ private $path;
+
+ /**
+ * @var string
+ */
+ private $prefix;
+
+ /**
+ * @var string
+ */
+ private $suffix;
+
+ /**
+ * @var string
+ */
+ private $phpVersion;
+
+ /**
+ * @var VersionComparisonOperator
+ */
+ private $phpVersionOperator;
+
+ public function __construct(string $path, string $prefix, string $suffix, string $phpVersion, VersionComparisonOperator $phpVersionOperator)
+ {
+ $this->path = $path;
+ $this->prefix = $prefix;
+ $this->suffix = $suffix;
+ $this->phpVersion = $phpVersion;
+ $this->phpVersionOperator = $phpVersionOperator;
+ }
+
+ 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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectoryCollection.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectoryCollection.php
new file mode 100644
index 000000000..10111af05
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectoryCollection.php
@@ -0,0 +1,62 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Countable;
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class TestDirectoryCollection implements Countable, IteratorAggregate
+{
+ /**
+ * @var TestDirectory[]
+ */
+ private $directories;
+
+ /**
+ * @param TestDirectory[] $directories
+ */
+ public static function fromArray(array $directories): self
+ {
+ return new self(...$directories);
+ }
+
+ private function __construct(TestDirectory ...$directories)
+ {
+ $this->directories = $directories;
+ }
+
+ /**
+ * @return TestDirectory[]
+ */
+ public function asArray(): array
+ {
+ return $this->directories;
+ }
+
+ public function count(): int
+ {
+ return count($this->directories);
+ }
+
+ public function getIterator(): TestDirectoryCollectionIterator
+ {
+ return new TestDirectoryCollectionIterator($this);
+ }
+
+ public function isEmpty(): bool
+ {
+ return $this->count() === 0;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectoryCollectionIterator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectoryCollectionIterator.php
new file mode 100644
index 000000000..11a48a247
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestDirectoryCollectionIterator.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function iterator_count;
+use Countable;
+use Iterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestDirectoryCollectionIterator implements Countable, Iterator
+{
+ /**
+ * @var TestDirectory[]
+ */
+ private $directories;
+
+ /**
+ * @var int
+ */
+ private $position;
+
+ public function __construct(TestDirectoryCollection $directories)
+ {
+ $this->directories = $directories->asArray();
+ }
+
+ public function count(): int
+ {
+ return iterator_count($this);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->directories);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): TestDirectory
+ {
+ return $this->directories[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFile.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFile.php
new file mode 100644
index 000000000..2e69450c1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFile.php
@@ -0,0 +1,56 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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\VersionComparisonOperator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class TestFile
+{
+ /**
+ * @var string
+ */
+ private $path;
+
+ /**
+ * @var string
+ */
+ private $phpVersion;
+
+ /**
+ * @var VersionComparisonOperator
+ */
+ private $phpVersionOperator;
+
+ public function __construct(string $path, string $phpVersion, VersionComparisonOperator $phpVersionOperator)
+ {
+ $this->path = $path;
+ $this->phpVersion = $phpVersion;
+ $this->phpVersionOperator = $phpVersionOperator;
+ }
+
+ public function path(): string
+ {
+ return $this->path;
+ }
+
+ public function phpVersion(): string
+ {
+ return $this->phpVersion;
+ }
+
+ public function phpVersionOperator(): VersionComparisonOperator
+ {
+ return $this->phpVersionOperator;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFileCollection.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFileCollection.php
new file mode 100644
index 000000000..791ddf718
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFileCollection.php
@@ -0,0 +1,62 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Countable;
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class TestFileCollection implements Countable, IteratorAggregate
+{
+ /**
+ * @var TestFile[]
+ */
+ private $files;
+
+ /**
+ * @param TestFile[] $files
+ */
+ public static function fromArray(array $files): self
+ {
+ return new self(...$files);
+ }
+
+ private function __construct(TestFile ...$files)
+ {
+ $this->files = $files;
+ }
+
+ /**
+ * @return TestFile[]
+ */
+ public function asArray(): array
+ {
+ return $this->files;
+ }
+
+ public function count(): int
+ {
+ return count($this->files);
+ }
+
+ public function getIterator(): TestFileCollectionIterator
+ {
+ return new TestFileCollectionIterator($this);
+ }
+
+ public function isEmpty(): bool
+ {
+ return $this->count() === 0;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFileCollectionIterator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFileCollectionIterator.php
new file mode 100644
index 000000000..b44c36894
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestFileCollectionIterator.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function iterator_count;
+use Countable;
+use Iterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestFileCollectionIterator implements Countable, Iterator
+{
+ /**
+ * @var TestFile[]
+ */
+ private $files;
+
+ /**
+ * @var int
+ */
+ private $position;
+
+ public function __construct(TestFileCollection $files)
+ {
+ $this->files = $files->asArray();
+ }
+
+ public function count(): int
+ {
+ return iterator_count($this);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->files);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): TestFile
+ {
+ return $this->files[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuite.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuite.php
new file mode 100644
index 000000000..4a6098215
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuite.php
@@ -0,0 +1,65 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\TextUI\XmlConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class TestSuite
+{
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var TestDirectoryCollection
+ */
+ private $directories;
+
+ /**
+ * @var TestFileCollection
+ */
+ private $files;
+
+ /**
+ * @var FileCollection
+ */
+ private $exclude;
+
+ public function __construct(string $name, TestDirectoryCollection $directories, TestFileCollection $files, FileCollection $exclude)
+ {
+ $this->name = $name;
+ $this->directories = $directories;
+ $this->files = $files;
+ $this->exclude = $exclude;
+ }
+
+ public function name(): string
+ {
+ return $this->name;
+ }
+
+ public function directories(): TestDirectoryCollection
+ {
+ return $this->directories;
+ }
+
+ public function files(): TestFileCollection
+ {
+ return $this->files;
+ }
+
+ public function exclude(): FileCollection
+ {
+ return $this->exclude;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuiteCollection.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuiteCollection.php
new file mode 100644
index 000000000..124609d74
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuiteCollection.php
@@ -0,0 +1,62 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 Countable;
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class TestSuiteCollection implements Countable, IteratorAggregate
+{
+ /**
+ * @var TestSuite[]
+ */
+ private $testSuites;
+
+ /**
+ * @param TestSuite[] $testSuites
+ */
+ public static function fromArray(array $testSuites): self
+ {
+ return new self(...$testSuites);
+ }
+
+ private function __construct(TestSuite ...$testSuites)
+ {
+ $this->testSuites = $testSuites;
+ }
+
+ /**
+ * @return TestSuite[]
+ */
+ public function asArray(): array
+ {
+ return $this->testSuites;
+ }
+
+ public function count(): int
+ {
+ return count($this->testSuites);
+ }
+
+ public function getIterator(): TestSuiteCollectionIterator
+ {
+ return new TestSuiteCollectionIterator($this);
+ }
+
+ public function isEmpty(): bool
+ {
+ return $this->count() === 0;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuiteCollectionIterator.php b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuiteCollectionIterator.php
new file mode 100644
index 000000000..33b0f8495
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/TestSuite/TestSuiteCollectionIterator.php
@@ -0,0 +1,66 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 function iterator_count;
+use Countable;
+use Iterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TestSuiteCollectionIterator implements Countable, Iterator
+{
+ /**
+ * @var TestSuite[]
+ */
+ private $testSuites;
+
+ /**
+ * @var int
+ */
+ private $position;
+
+ public function __construct(TestSuiteCollection $testSuites)
+ {
+ $this->testSuites = $testSuites->asArray();
+ }
+
+ public function count(): int
+ {
+ return iterator_count($this);
+ }
+
+ public function rewind(): void
+ {
+ $this->position = 0;
+ }
+
+ public function valid(): bool
+ {
+ return $this->position < count($this->testSuites);
+ }
+
+ public function key(): int
+ {
+ return $this->position;
+ }
+
+ public function current(): TestSuite
+ {
+ return $this->testSuites[$this->position];
+ }
+
+ public function next(): void
+ {
+ $this->position++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php b/vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php
new file mode 100644
index 000000000..6aa069602
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Annotation/DocBlock.php
@@ -0,0 +1,551 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\Annotation;
+
+use const JSON_ERROR_NONE;
+use const PREG_OFFSET_CAPTURE;
+use function array_filter;
+use function array_key_exists;
+use function array_map;
+use function array_merge;
+use function array_pop;
+use function array_slice;
+use function array_values;
+use function count;
+use function explode;
+use function file;
+use function implode;
+use function is_array;
+use function is_int;
+use function json_decode;
+use function json_last_error;
+use function json_last_error_msg;
+use function preg_match;
+use function preg_match_all;
+use function preg_replace;
+use function preg_split;
+use function realpath;
+use function rtrim;
+use function sprintf;
+use function str_replace;
+use function strlen;
+use function strpos;
+use function strtolower;
+use function substr;
+use function trim;
+use PharIo\Version\VersionConstraintParser;
+use PHPUnit\Framework\InvalidDataProviderException;
+use PHPUnit\Framework\SkippedTestError;
+use PHPUnit\Framework\Warning;
+use PHPUnit\Util\Exception;
+use PHPUnit\Util\InvalidDataSetException;
+use ReflectionClass;
+use ReflectionException;
+use ReflectionFunctionAbstract;
+use ReflectionMethod;
+use Reflector;
+use Traversable;
+
+/**
+ * This is an abstraction around a PHPUnit-specific docBlock,
+ * allowing us to ask meaningful questions about a specific
+ * reflection symbol.
+ *
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class DocBlock
+{
+ /**
+ * @todo This constant should be private (it's public because of TestTest::testGetProvidedDataRegEx)
+ */
+ public const REGEX_DATA_PROVIDER = '/@dataProvider\s+([a-zA-Z0-9._:-\\\\x7f-\xff]+)/';
+
+ private const REGEX_REQUIRES_VERSION = '/@requires\s+(?P<name>PHP(?:Unit)?)\s+(?P<operator>[<>=!]{0,2})\s*(?P<version>[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m';
+
+ private const REGEX_REQUIRES_VERSION_CONSTRAINT = '/@requires\s+(?P<name>PHP(?:Unit)?)\s+(?P<constraint>[\d\t \-.|~^]+)[ \t]*\r?$/m';
+
+ private const REGEX_REQUIRES_OS = '/@requires\s+(?P<name>OS(?:FAMILY)?)\s+(?P<value>.+?)[ \t]*\r?$/m';
+
+ private const REGEX_REQUIRES_SETTING = '/@requires\s+(?P<name>setting)\s+(?P<setting>([^ ]+?))\s*(?P<value>[\w\.-]+[\w\.]?)?[ \t]*\r?$/m';
+
+ private const REGEX_REQUIRES = '/@requires\s+(?P<name>function|extension)\s+(?P<value>([^\s<>=!]+))\s*(?P<operator>[<>=!]{0,2})\s*(?P<version>[\d\.-]+[\d\.]?)?[ \t]*\r?$/m';
+
+ private const REGEX_TEST_WITH = '/@testWith\s+/';
+
+ /** @var string */
+ private $docComment;
+
+ /** @var bool */
+ private $isMethod;
+
+ /** @var array<string, array<int, string>> pre-parsed annotations indexed by name and occurrence index */
+ private $symbolAnnotations;
+
+ /**
+ * @var null|array<string, mixed>
+ *
+ * @psalm-var null|(array{
+ * __OFFSET: array<string, int>&array{__FILE: string},
+ * setting?: array<string, string>,
+ * extension_versions?: array<string, array{version: string, operator: string}>
+ * }&array<
+ * string,
+ * string|array{version: string, operator: string}|array{constraint: string}|array<int|string, string>
+ * >)
+ */
+ private $parsedRequirements;
+
+ /** @var int */
+ private $startLine;
+
+ /** @var int */
+ private $endLine;
+
+ /** @var string */
+ private $fileName;
+
+ /** @var string */
+ private $name;
+
+ /**
+ * @var string
+ *
+ * @psalm-var class-string
+ */
+ private $className;
+
+ public static function ofClass(ReflectionClass $class): self
+ {
+ $className = $class->getName();
+
+ return new self(
+ (string) $class->getDocComment(),
+ false,
+ self::extractAnnotationsFromReflector($class),
+ $class->getStartLine(),
+ $class->getEndLine(),
+ $class->getFileName(),
+ $className,
+ $className
+ );
+ }
+
+ /**
+ * @psalm-param class-string $classNameInHierarchy
+ */
+ public static function ofMethod(ReflectionMethod $method, string $classNameInHierarchy): self
+ {
+ return new self(
+ (string) $method->getDocComment(),
+ true,
+ self::extractAnnotationsFromReflector($method),
+ $method->getStartLine(),
+ $method->getEndLine(),
+ $method->getFileName(),
+ $method->getName(),
+ $classNameInHierarchy
+ );
+ }
+
+ /**
+ * Note: we do not preserve an instance of the reflection object, since it cannot be safely (de-)serialized.
+ *
+ * @param array<string, array<int, string>> $symbolAnnotations
+ *
+ * @psalm-param class-string $className
+ */
+ private function __construct(string $docComment, bool $isMethod, array $symbolAnnotations, int $startLine, int $endLine, string $fileName, string $name, string $className)
+ {
+ $this->docComment = $docComment;
+ $this->isMethod = $isMethod;
+ $this->symbolAnnotations = $symbolAnnotations;
+ $this->startLine = $startLine;
+ $this->endLine = $endLine;
+ $this->fileName = $fileName;
+ $this->name = $name;
+ $this->className = $className;
+ }
+
+ /**
+ * @psalm-return array{
+ * __OFFSET: array<string, int>&array{__FILE: string},
+ * setting?: array<string, string>,
+ * extension_versions?: array<string, array{version: string, operator: string}>
+ * }&array<
+ * string,
+ * string|array{version: string, operator: string}|array{constraint: string}|array<int|string, string>
+ * >
+ *
+ * @throws Warning if the requirements version constraint is not well-formed
+ */
+ public function requirements(): array
+ {
+ if ($this->parsedRequirements !== null) {
+ return $this->parsedRequirements;
+ }
+
+ $offset = $this->startLine;
+ $requires = [];
+ $recordedSettings = [];
+ $extensionVersions = [];
+ $recordedOffsets = [
+ '__FILE' => realpath($this->fileName),
+ ];
+
+ // Trim docblock markers, split it into lines and rewind offset to start of docblock
+ $lines = preg_replace(['#^/\*{2}#', '#\*/$#'], '', preg_split('/\r\n|\r|\n/', $this->docComment));
+ $offset -= count($lines);
+
+ foreach ($lines as $line) {
+ if (preg_match(self::REGEX_REQUIRES_OS, $line, $matches)) {
+ $requires[$matches['name']] = $matches['value'];
+ $recordedOffsets[$matches['name']] = $offset;
+ }
+
+ if (preg_match(self::REGEX_REQUIRES_VERSION, $line, $matches)) {
+ $requires[$matches['name']] = [
+ 'version' => $matches['version'],
+ 'operator' => $matches['operator'],
+ ];
+ $recordedOffsets[$matches['name']] = $offset;
+ }
+
+ if (preg_match(self::REGEX_REQUIRES_VERSION_CONSTRAINT, $line, $matches)) {
+ if (!empty($requires[$matches['name']])) {
+ $offset++;
+
+ continue;
+ }
+
+ try {
+ $versionConstraintParser = new VersionConstraintParser;
+
+ $requires[$matches['name'] . '_constraint'] = [
+ 'constraint' => $versionConstraintParser->parse(trim($matches['constraint'])),
+ ];
+ $recordedOffsets[$matches['name'] . '_constraint'] = $offset;
+ } catch (\PharIo\Version\Exception $e) {
+ throw new Warning($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+
+ if (preg_match(self::REGEX_REQUIRES_SETTING, $line, $matches)) {
+ $recordedSettings[$matches['setting']] = $matches['value'];
+ $recordedOffsets['__SETTING_' . $matches['setting']] = $offset;
+ }
+
+ if (preg_match(self::REGEX_REQUIRES, $line, $matches)) {
+ $name = $matches['name'] . 's';
+
+ if (!isset($requires[$name])) {
+ $requires[$name] = [];
+ }
+
+ $requires[$name][] = $matches['value'];
+ $recordedOffsets[$matches['name'] . '_' . $matches['value']] = $offset;
+
+ if ($name === 'extensions' && !empty($matches['version'])) {
+ $extensionVersions[$matches['value']] = [
+ 'version' => $matches['version'],
+ 'operator' => $matches['operator'],
+ ];
+ }
+ }
+
+ $offset++;
+ }
+
+ return $this->parsedRequirements = array_merge(
+ $requires,
+ ['__OFFSET' => $recordedOffsets],
+ array_filter([
+ 'setting' => $recordedSettings,
+ 'extension_versions' => $extensionVersions,
+ ])
+ );
+ }
+
+ /**
+ * Returns the provided data for a method.
+ *
+ * @throws Exception
+ */
+ public function getProvidedData(): ?array
+ {
+ /** @noinspection SuspiciousBinaryOperationInspection */
+ $data = $this->getDataFromDataProviderAnnotation($this->docComment) ?? $this->getDataFromTestWithAnnotation($this->docComment);
+
+ if ($data === null) {
+ return null;
+ }
+
+ if ($data === []) {
+ throw new SkippedTestError;
+ }
+
+ foreach ($data as $key => $value) {
+ if (!is_array($value)) {
+ throw new InvalidDataSetException(
+ sprintf(
+ 'Data set %s is invalid.',
+ is_int($key) ? '#' . $key : '"' . $key . '"'
+ )
+ );
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * @psalm-return array<string, array{line: int, value: string}>
+ */
+ public function getInlineAnnotations(): array
+ {
+ $code = file($this->fileName);
+ $lineNumber = $this->startLine;
+ $startLine = $this->startLine - 1;
+ $endLine = $this->endLine - 1;
+ $codeLines = array_slice($code, $startLine, $endLine - $startLine + 1);
+ $annotations = [];
+
+ foreach ($codeLines as $line) {
+ if (preg_match('#/\*\*?\s*@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?\*/$#m', $line, $matches)) {
+ $annotations[strtolower($matches['name'])] = [
+ 'line' => $lineNumber,
+ 'value' => $matches['value'],
+ ];
+ }
+
+ $lineNumber++;
+ }
+
+ return $annotations;
+ }
+
+ public function symbolAnnotations(): array
+ {
+ return $this->symbolAnnotations;
+ }
+
+ public function isHookToBeExecutedBeforeClass(): bool
+ {
+ return $this->isMethod &&
+ false !== strpos($this->docComment, '@beforeClass');
+ }
+
+ public function isHookToBeExecutedAfterClass(): bool
+ {
+ return $this->isMethod &&
+ false !== strpos($this->docComment, '@afterClass');
+ }
+
+ public function isToBeExecutedBeforeTest(): bool
+ {
+ return 1 === preg_match('/@before\b/', $this->docComment);
+ }
+
+ public function isToBeExecutedAfterTest(): bool
+ {
+ return 1 === preg_match('/@after\b/', $this->docComment);
+ }
+
+ public function isToBeExecutedAsPreCondition(): bool
+ {
+ return 1 === preg_match('/@preCondition\b/', $this->docComment);
+ }
+
+ public function isToBeExecutedAsPostCondition(): bool
+ {
+ return 1 === preg_match('/@postCondition\b/', $this->docComment);
+ }
+
+ private function getDataFromDataProviderAnnotation(string $docComment): ?array
+ {
+ $methodName = null;
+ $className = $this->className;
+
+ if ($this->isMethod) {
+ $methodName = $this->name;
+ }
+
+ if (!preg_match_all(self::REGEX_DATA_PROVIDER, $docComment, $matches)) {
+ return null;
+ }
+
+ $result = [];
+
+ foreach ($matches[1] as $match) {
+ $dataProviderMethodNameNamespace = explode('\\', $match);
+ $leaf = explode('::', array_pop($dataProviderMethodNameNamespace));
+ $dataProviderMethodName = array_pop($leaf);
+
+ if (empty($dataProviderMethodNameNamespace)) {
+ $dataProviderMethodNameNamespace = '';
+ } else {
+ $dataProviderMethodNameNamespace = implode('\\', $dataProviderMethodNameNamespace) . '\\';
+ }
+
+ if (empty($leaf)) {
+ $dataProviderClassName = $className;
+ } else {
+ /** @psalm-var class-string $dataProviderClassName */
+ $dataProviderClassName = $dataProviderMethodNameNamespace . array_pop($leaf);
+ }
+
+ try {
+ $dataProviderClass = new ReflectionClass($dataProviderClassName);
+
+ $dataProviderMethod = $dataProviderClass->getMethod(
+ $dataProviderMethodName
+ );
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ // @codeCoverageIgnoreEnd
+ }
+
+ if ($dataProviderMethod->isStatic()) {
+ $object = null;
+ } else {
+ $object = $dataProviderClass->newInstance();
+ }
+
+ if ($dataProviderMethod->getNumberOfParameters() === 0) {
+ $data = $dataProviderMethod->invoke($object);
+ } else {
+ $data = $dataProviderMethod->invoke($object, $methodName);
+ }
+
+ if ($data instanceof Traversable) {
+ $origData = $data;
+ $data = [];
+
+ foreach ($origData as $key => $value) {
+ if (is_int($key)) {
+ $data[] = $value;
+ } elseif (array_key_exists($key, $data)) {
+ throw new InvalidDataProviderException(
+ sprintf(
+ 'The key "%s" has already been defined in the data provider "%s".',
+ $key,
+ $match
+ )
+ );
+ } else {
+ $data[$key] = $value;
+ }
+ }
+ }
+
+ if (is_array($data)) {
+ $result = array_merge($result, $data);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * @throws Exception
+ */
+ private function getDataFromTestWithAnnotation(string $docComment): ?array
+ {
+ $docComment = $this->cleanUpMultiLineAnnotation($docComment);
+
+ if (!preg_match(self::REGEX_TEST_WITH, $docComment, $matches, PREG_OFFSET_CAPTURE)) {
+ return null;
+ }
+
+ $offset = strlen($matches[0][0]) + $matches[0][1];
+ $annotationContent = substr($docComment, $offset);
+ $data = [];
+
+ foreach (explode("\n", $annotationContent) as $candidateRow) {
+ $candidateRow = trim($candidateRow);
+
+ if ($candidateRow[0] !== '[') {
+ break;
+ }
+
+ $dataSet = json_decode($candidateRow, true);
+
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ throw new Exception(
+ 'The data set for the @testWith annotation cannot be parsed: ' . json_last_error_msg()
+ );
+ }
+
+ $data[] = $dataSet;
+ }
+
+ if (!$data) {
+ throw new Exception('The data set for the @testWith annotation cannot be parsed.');
+ }
+
+ return $data;
+ }
+
+ private function cleanUpMultiLineAnnotation(string $docComment): string
+ {
+ //removing initial ' * ' for docComment
+ $docComment = str_replace("\r\n", "\n", $docComment);
+ $docComment = preg_replace('/' . '\n' . '\s*' . '\*' . '\s?' . '/', "\n", $docComment);
+ $docComment = (string) substr($docComment, 0, -1);
+
+ return rtrim($docComment, "\n");
+ }
+
+ /** @return array<string, array<int, string>> */
+ private static function parseDocBlock(string $docBlock): array
+ {
+ // Strip away the docblock header and footer to ease parsing of one line annotations
+ $docBlock = (string) substr($docBlock, 3, -2);
+ $annotations = [];
+
+ if (preg_match_all('/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m', $docBlock, $matches)) {
+ $numMatches = count($matches[0]);
+
+ for ($i = 0; $i < $numMatches; $i++) {
+ $annotations[$matches['name'][$i]][] = (string) $matches['value'][$i];
+ }
+ }
+
+ return $annotations;
+ }
+
+ /** @param ReflectionClass|ReflectionFunctionAbstract $reflector */
+ private static function extractAnnotationsFromReflector(Reflector $reflector): array
+ {
+ $annotations = [];
+
+ if ($reflector instanceof ReflectionClass) {
+ $annotations = array_merge(
+ $annotations,
+ ...array_map(
+ static function (ReflectionClass $trait): array
+ {
+ return self::parseDocBlock((string) $trait->getDocComment());
+ },
+ array_values($reflector->getTraits())
+ )
+ );
+ }
+
+ return array_merge(
+ $annotations,
+ self::parseDocBlock((string) $reflector->getDocComment())
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Annotation/Registry.php b/vendor/phpunit/phpunit/src/Util/Annotation/Registry.php
new file mode 100644
index 000000000..8df14cfc0
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Annotation/Registry.php
@@ -0,0 +1,93 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\Annotation;
+
+use function array_key_exists;
+use PHPUnit\Util\Exception;
+use ReflectionClass;
+use ReflectionException;
+use ReflectionMethod;
+
+/**
+ * Reflection information, and therefore DocBlock information, is static within
+ * a single PHP process. It is therefore okay to use a Singleton registry here.
+ *
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Registry
+{
+ /** @var null|self */
+ private static $instance;
+
+ /** @var array<string, DocBlock> indexed by class name */
+ private $classDocBlocks = [];
+
+ /** @var array<string, array<string, DocBlock>> indexed by class name and method name */
+ private $methodDocBlocks = [];
+
+ public static function getInstance(): self
+ {
+ return self::$instance ?? self::$instance = new self;
+ }
+
+ private function __construct()
+ {
+ }
+
+ /**
+ * @throws Exception
+ * @psalm-param class-string $class
+ */
+ public function forClassName(string $class): DocBlock
+ {
+ if (array_key_exists($class, $this->classDocBlocks)) {
+ return $this->classDocBlocks[$class];
+ }
+
+ try {
+ $reflection = new ReflectionClass($class);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $this->classDocBlocks[$class] = DocBlock::ofClass($reflection);
+ }
+
+ /**
+ * @throws Exception
+ * @psalm-param class-string $classInHierarchy
+ */
+ public function forMethod(string $classInHierarchy, string $method): DocBlock
+ {
+ if (isset($this->methodDocBlocks[$classInHierarchy][$method])) {
+ return $this->methodDocBlocks[$classInHierarchy][$method];
+ }
+
+ try {
+ $reflection = new ReflectionMethod($classInHierarchy, $method);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $this->methodDocBlocks[$classInHierarchy][$method] = DocBlock::ofMethod($reflection, $classInHierarchy);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Blacklist.php b/vendor/phpunit/phpunit/src/Util/Blacklist.php
new file mode 100644
index 000000000..3b416e142
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Blacklist.php
@@ -0,0 +1,41 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util;
+
+/**
+ * @deprecated Use ExcludeList instead
+ *
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class Blacklist
+{
+ public static function addDirectory(string $directory): void
+ {
+ ExcludeList::addDirectory($directory);
+ }
+
+ /**
+ * @throws Exception
+ *
+ * @return string[]
+ */
+ public function getBlacklistedDirectories(): array
+ {
+ return (new ExcludeList)->getExcludedDirectories();
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function isBlacklisted(string $file): bool
+ {
+ return (new ExcludeList)->isExcluded($file);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Color.php b/vendor/phpunit/phpunit/src/Util/Color.php
new file mode 100644
index 000000000..b96eb4747
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Color.php
@@ -0,0 +1,159 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 array_keys;
+use function array_map;
+use function array_values;
+use function count;
+use function explode;
+use function implode;
+use function min;
+use function preg_replace;
+use function preg_replace_callback;
+use function sprintf;
+use function strtr;
+use function trim;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Color
+{
+ /**
+ * @var array<string,string>
+ */
+ private const WHITESPACE_MAP = [
+ ' ' => '·',
+ "\t" => '⇥',
+ ];
+
+ /**
+ * @var array<string,string>
+ */
+ private const WHITESPACE_EOL_MAP = [
+ ' ' => '·',
+ "\t" => '⇥',
+ "\n" => '↵',
+ "\r" => '⟵',
+ ];
+
+ /**
+ * @var array<string,string>
+ */
+ private static $ansiCodes = [
+ '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',
+ ];
+
+ public static function colorize(string $color, string $buffer): string
+ {
+ if (trim($buffer) === '') {
+ return $buffer;
+ }
+
+ $codes = array_map('\trim', explode(',', $color));
+ $styles = [];
+
+ foreach ($codes as $code) {
+ if (isset(self::$ansiCodes[$code])) {
+ $styles[] = self::$ansiCodes[$code] ?? '';
+ }
+ }
+
+ if (empty($styles)) {
+ return $buffer;
+ }
+
+ return self::optimizeColor(sprintf("\x1b[%sm", implode(';', $styles)) . $buffer . "\x1b[0m");
+ }
+
+ public static function colorizePath(string $path, ?string $prevPath = null, bool $colorizeFilename = false): string
+ {
+ if ($prevPath === null) {
+ $prevPath = '';
+ }
+
+ $path = explode(DIRECTORY_SEPARATOR, $path);
+ $prevPath = explode(DIRECTORY_SEPARATOR, $prevPath);
+
+ for ($i = 0; $i < min(count($path), count($prevPath)); $i++) {
+ if ($path[$i] == $prevPath[$i]) {
+ $path[$i] = self::dim($path[$i]);
+ }
+ }
+
+ if ($colorizeFilename) {
+ $last = count($path) - 1;
+ $path[$last] = preg_replace_callback(
+ '/([\-_\.]+|phpt$)/',
+ static function ($matches)
+ {
+ return 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 "\e[2m{$buffer}\e[22m";
+ }
+
+ public static function visualizeWhitespace(string $buffer, bool $visualizeEOL = false): string
+ {
+ $replaceMap = $visualizeEOL ? self::WHITESPACE_EOL_MAP : self::WHITESPACE_MAP;
+
+ return preg_replace_callback('/\s+/', static function ($matches) use ($replaceMap)
+ {
+ return self::dim(strtr($matches[0], $replaceMap));
+ }, $buffer);
+ }
+
+ private static function optimizeColor(string $buffer): string
+ {
+ $patterns = [
+ "/\e\\[22m\e\\[2m/" => '',
+ "/\e\\[([^m]*)m\e\\[([1-9][0-9;]*)m/" => "\e[$1;$2m",
+ "/(\e\\[[^m]*m)+(\e\\[0m)/" => '$2',
+ ];
+
+ return preg_replace(array_keys($patterns), array_values($patterns), $buffer);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/ErrorHandler.php b/vendor/phpunit/phpunit/src/Util/ErrorHandler.php
new file mode 100644
index 000000000..f8566347e
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/ErrorHandler.php
@@ -0,0 +1,156 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util;
+
+use const E_DEPRECATED;
+use const E_NOTICE;
+use const E_STRICT;
+use const E_USER_DEPRECATED;
+use const E_USER_NOTICE;
+use const E_USER_WARNING;
+use const E_WARNING;
+use function error_reporting;
+use function restore_error_handler;
+use function set_error_handler;
+use PHPUnit\Framework\Error\Deprecated;
+use PHPUnit\Framework\Error\Error;
+use PHPUnit\Framework\Error\Notice;
+use PHPUnit\Framework\Error\Warning;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class ErrorHandler
+{
+ /**
+ * @var bool
+ */
+ private $convertDeprecationsToExceptions;
+
+ /**
+ * @var bool
+ */
+ private $convertErrorsToExceptions;
+
+ /**
+ * @var bool
+ */
+ private $convertNoticesToExceptions;
+
+ /**
+ * @var bool
+ */
+ private $convertWarningsToExceptions;
+
+ /**
+ * @var bool
+ */
+ private $registered = false;
+
+ public static function invokeIgnoringWarnings(callable $callable)
+ {
+ set_error_handler(
+ static function ($errorNumber, $errorString)
+ {
+ if ($errorNumber === E_WARNING) {
+ return;
+ }
+
+ return false;
+ }
+ );
+
+ $result = $callable();
+
+ restore_error_handler();
+
+ return $result;
+ }
+
+ public function __construct(bool $convertDeprecationsToExceptions, bool $convertErrorsToExceptions, bool $convertNoticesToExceptions, bool $convertWarningsToExceptions)
+ {
+ $this->convertDeprecationsToExceptions = $convertDeprecationsToExceptions;
+ $this->convertErrorsToExceptions = $convertErrorsToExceptions;
+ $this->convertNoticesToExceptions = $convertNoticesToExceptions;
+ $this->convertWarningsToExceptions = $convertWarningsToExceptions;
+ }
+
+ public function __invoke(int $errorNumber, string $errorString, string $errorFile, int $errorLine): bool
+ {
+ /*
+ * Do not raise an exception when the error suppression operator (@) was used.
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/3739
+ */
+ if (!($errorNumber & error_reporting())) {
+ return false;
+ }
+
+ switch ($errorNumber) {
+ case E_NOTICE:
+ case E_USER_NOTICE:
+ case E_STRICT:
+ if (!$this->convertNoticesToExceptions) {
+ return false;
+ }
+
+ throw new Notice($errorString, $errorNumber, $errorFile, $errorLine);
+
+ case E_WARNING:
+ case E_USER_WARNING:
+ if (!$this->convertWarningsToExceptions) {
+ return false;
+ }
+
+ throw new Warning($errorString, $errorNumber, $errorFile, $errorLine);
+
+ case E_DEPRECATED:
+ case E_USER_DEPRECATED:
+ if (!$this->convertDeprecationsToExceptions) {
+ return false;
+ }
+
+ throw new Deprecated($errorString, $errorNumber, $errorFile, $errorLine);
+
+ default:
+ if (!$this->convertErrorsToExceptions) {
+ return false;
+ }
+
+ throw new Error($errorString, $errorNumber, $errorFile, $errorLine);
+ }
+ }
+
+ public function register(): void
+ {
+ if ($this->registered) {
+ return;
+ }
+
+ $oldErrorHandler = set_error_handler($this);
+
+ if ($oldErrorHandler !== null) {
+ restore_error_handler();
+
+ return;
+ }
+
+ $this->registered = true;
+ }
+
+ public function unregister(): void
+ {
+ if (!$this->registered) {
+ return;
+ }
+
+ restore_error_handler();
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Exception.php b/vendor/phpunit/phpunit/src/Util/Exception.php
new file mode 100644
index 000000000..6bcb3d140
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Exception.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util;
+
+use RuntimeException;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Exception extends RuntimeException implements \PHPUnit\Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Util/ExcludeList.php b/vendor/phpunit/phpunit/src/Util/ExcludeList.php
new file mode 100644
index 000000000..c7e6704a8
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/ExcludeList.php
@@ -0,0 +1,261 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 class_exists;
+use function defined;
+use function dirname;
+use function is_dir;
+use function realpath;
+use function sprintf;
+use function strpos;
+use function sys_get_temp_dir;
+use Composer\Autoload\ClassLoader;
+use DeepCopy\DeepCopy;
+use Doctrine\Instantiator\Instantiator;
+use PharIo\Manifest\Manifest;
+use PharIo\Version\Version as PharIoVersion;
+use phpDocumentor\Reflection\DocBlock;
+use phpDocumentor\Reflection\Project;
+use phpDocumentor\Reflection\Type;
+use PhpParser\Parser;
+use PHPUnit\Framework\TestCase;
+use Prophecy\Prophet;
+use ReflectionClass;
+use ReflectionException;
+use SebastianBergmann\CliParser\Parser as CliParser;
+use SebastianBergmann\CodeCoverage\CodeCoverage;
+use SebastianBergmann\CodeUnit\CodeUnit;
+use SebastianBergmann\CodeUnitReverseLookup\Wizard;
+use SebastianBergmann\Comparator\Comparator;
+use SebastianBergmann\Complexity\Calculator;
+use SebastianBergmann\Diff\Diff;
+use SebastianBergmann\Environment\Runtime;
+use SebastianBergmann\Exporter\Exporter;
+use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
+use SebastianBergmann\GlobalState\Snapshot;
+use SebastianBergmann\Invoker\Invoker;
+use SebastianBergmann\LinesOfCode\Counter;
+use SebastianBergmann\ObjectEnumerator\Enumerator;
+use SebastianBergmann\RecursionContext\Context;
+use SebastianBergmann\ResourceOperations\ResourceOperations;
+use SebastianBergmann\Template\Template;
+use SebastianBergmann\Timer\Timer;
+use SebastianBergmann\Type\TypeName;
+use SebastianBergmann\Version;
+use Symfony\Polyfill\Ctype\Ctype;
+use TheSeer\Tokenizer\Tokenizer;
+use Webmozart\Assert\Assert;
+
+/**
+ * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
+ */
+final class ExcludeList
+{
+ /**
+ * @var array<string,int>
+ */
+ private const EXCLUDED_CLASS_NAMES = [
+ // composer
+ ClassLoader::class => 1,
+
+ // doctrine/instantiator
+ Instantiator::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,
+
+ // phpdocumentor/reflection-common
+ Project::class => 1,
+
+ // phpdocumentor/reflection-docblock
+ DocBlock::class => 1,
+
+ // phpdocumentor/type-resolver
+ Type::class => 1,
+
+ // phpspec/prophecy
+ Prophet::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/code-unit
+ CodeUnit::class => 1,
+
+ // sebastian/code-unit-reverse-lookup
+ Wizard::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/recursion-context
+ Context::class => 1,
+
+ // sebastian/resource-operations
+ ResourceOperations::class => 1,
+
+ // sebastian/type
+ TypeName::class => 1,
+
+ // sebastian/version
+ Version::class => 1,
+
+ // symfony/polyfill-ctype
+ Ctype::class => 1,
+
+ // theseer/tokenizer
+ Tokenizer::class => 1,
+
+ // webmozart/assert
+ Assert::class => 1,
+ ];
+
+ /**
+ * @var string[]
+ */
+ private static $directories;
+
+ public static function addDirectory(string $directory): void
+ {
+ if (!is_dir($directory)) {
+ throw new Exception(
+ sprintf(
+ '"%s" is not a directory',
+ $directory
+ )
+ );
+ }
+
+ self::$directories[] = realpath($directory);
+ }
+
+ /**
+ * @throws Exception
+ *
+ * @return string[]
+ */
+ public function getExcludedDirectories(): array
+ {
+ $this->initialize();
+
+ return self::$directories;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function isExcluded(string $file): bool
+ {
+ if (defined('PHPUNIT_TESTSUITE')) {
+ return false;
+ }
+
+ $this->initialize();
+
+ foreach (self::$directories as $directory) {
+ if (strpos($file, $directory) === 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @throws Exception
+ */
+ private function initialize(): void
+ {
+ if (self::$directories === null) {
+ self::$directories = [];
+
+ foreach (self::EXCLUDED_CLASS_NAMES as $className => $parent) {
+ if (!class_exists($className)) {
+ continue;
+ }
+
+ try {
+ $directory = (new ReflectionClass($className))->getFileName();
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ for ($i = 0; $i < $parent; $i++) {
+ $directory = dirname($directory);
+ }
+
+ self::$directories[] = $directory;
+ }
+
+ // Hide process isolation workaround on Windows.
+ if (DIRECTORY_SEPARATOR === '\\') {
+ // tempnam() prefix is limited to first 3 chars.
+ // @see https://php.net/manual/en/function.tempnam.php
+ self::$directories[] = sys_get_temp_dir() . '\\PHP';
+ }
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/FileLoader.php b/vendor/phpunit/phpunit/src/Util/FileLoader.php
new file mode 100644
index 000000000..732870723
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/FileLoader.php
@@ -0,0 +1,83 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 array_diff;
+use function array_keys;
+use function fopen;
+use function get_defined_vars;
+use function sprintf;
+use function stream_resolve_include_path;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class FileLoader
+{
+ /**
+ * Checks if a PHP sourcecode file is readable. The sourcecode file is loaded through the load() method.
+ *
+ * As a fallback, PHP looks in the directory of the file executing the stream_resolve_include_path function.
+ * We do not want to load the Test.php file here, so skip it if it found that.
+ * PHP prioritizes the include_path setting, so if the current directory is in there, it will first look in the
+ * current working directory.
+ *
+ * @throws Exception
+ */
+ public static function checkAndLoad(string $filename): string
+ {
+ $includePathFilename = stream_resolve_include_path($filename);
+
+ $localFile = __DIR__ . DIRECTORY_SEPARATOR . $filename;
+
+ if (!$includePathFilename ||
+ $includePathFilename === $localFile ||
+ !self::isReadable($includePathFilename)) {
+ throw new Exception(
+ sprintf('Cannot open file "%s".' . "\n", $filename)
+ );
+ }
+
+ self::load($includePathFilename);
+
+ return $includePathFilename;
+ }
+
+ /**
+ * Loads a PHP sourcefile.
+ */
+ public static function load(string $filename): void
+ {
+ $oldVariableNames = array_keys(get_defined_vars());
+
+ /**
+ * @noinspection PhpIncludeInspection
+ * @psalm-suppress UnresolvableInclude
+ */
+ include_once $filename;
+
+ $newVariables = get_defined_vars();
+
+ foreach (array_diff(array_keys($newVariables), $oldVariableNames) as $variableName) {
+ if ($variableName !== 'oldVariableNames') {
+ $GLOBALS[$variableName] = $newVariables[$variableName];
+ }
+ }
+ }
+
+ /**
+ * @see https://github.com/sebastianbergmann/phpunit/pull/2751
+ */
+ private static function isReadable(string $filename): bool
+ {
+ return @fopen($filename, 'r') !== false;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Filesystem.php b/vendor/phpunit/phpunit/src/Util/Filesystem.php
new file mode 100644
index 000000000..35b2690b1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Filesystem.php
@@ -0,0 +1,41 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 is_dir;
+use function mkdir;
+use function str_replace;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Filesystem
+{
+ /**
+ * Maps class names to source file names.
+ *
+ * - PEAR CS: Foo_Bar_Baz -> Foo/Bar/Baz.php
+ * - Namespace: Foo\Bar\Baz -> Foo/Bar/Baz.php
+ */
+ public static function classNameToFilename(string $className): string
+ {
+ return str_replace(
+ ['_', '\\'],
+ DIRECTORY_SEPARATOR,
+ $className
+ ) . '.php';
+ }
+
+ public static function createDirectory(string $directory): bool
+ {
+ return !(!is_dir($directory) && !@mkdir($directory, 0777, true) && !is_dir($directory));
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Filter.php b/vendor/phpunit/phpunit/src/Util/Filter.php
new file mode 100644
index 000000000..42563937d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Filter.php
@@ -0,0 +1,115 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_unshift;
+use function defined;
+use function in_array;
+use function is_file;
+use function realpath;
+use function sprintf;
+use function strpos;
+use PHPUnit\Framework\Exception;
+use PHPUnit\Framework\SyntheticError;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Filter
+{
+ /**
+ * @throws Exception
+ */
+ public static function getFilteredStacktrace(Throwable $t): string
+ {
+ $filteredStacktrace = '';
+
+ if ($t instanceof SyntheticError) {
+ $eTrace = $t->getSyntheticTrace();
+ $eFile = $t->getSyntheticFile();
+ $eLine = $t->getSyntheticLine();
+ } elseif ($t instanceof Exception) {
+ $eTrace = $t->getSerializableTrace();
+ $eFile = $t->getFile();
+ $eLine = $t->getLine();
+ } else {
+ if ($t->getPrevious()) {
+ $t = $t->getPrevious();
+ }
+
+ $eTrace = $t->getTrace();
+ $eFile = $t->getFile();
+ $eLine = $t->getLine();
+ }
+
+ if (!self::frameExists($eTrace, $eFile, $eLine)) {
+ array_unshift(
+ $eTrace,
+ ['file' => $eFile, 'line' => $eLine]
+ );
+ }
+
+ $prefix = defined('__PHPUNIT_PHAR_ROOT__') ? __PHPUNIT_PHAR_ROOT__ : false;
+ $excludeList = new ExcludeList;
+
+ foreach ($eTrace as $frame) {
+ if (self::shouldPrintFrame($frame, $prefix, $excludeList)) {
+ $filteredStacktrace .= sprintf(
+ "%s:%s\n",
+ $frame['file'],
+ $frame['line'] ?? '?'
+ );
+ }
+ }
+
+ return $filteredStacktrace;
+ }
+
+ private static function shouldPrintFrame(array $frame, $prefix, ExcludeList $excludeList): bool
+ {
+ if (!isset($frame['file'])) {
+ return false;
+ }
+
+ $file = $frame['file'];
+ $fileIsNotPrefixed = $prefix === false || strpos($file, $prefix) !== 0;
+
+ // @see https://github.com/sebastianbergmann/phpunit/issues/4033
+ if (isset($GLOBALS['_SERVER']['SCRIPT_NAME'])) {
+ $script = realpath($GLOBALS['_SERVER']['SCRIPT_NAME']);
+ } else {
+ $script = '';
+ }
+
+ return is_file($file) &&
+ self::fileIsExcluded($file, $excludeList) &&
+ $fileIsNotPrefixed &&
+ $file !== $script;
+ }
+
+ private static function fileIsExcluded(string $file, ExcludeList $excludeList): bool
+ {
+ return (empty($GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST']) ||
+ !in_array($file, $GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'], true)) &&
+ !$excludeList->isExcluded($file);
+ }
+
+ private static function frameExists(array $trace, string $file, int $line): bool
+ {
+ foreach ($trace as $frame) {
+ if (isset($frame['file'], $frame['line']) && $frame['file'] === $file && $frame['line'] === $line) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/GlobalState.php b/vendor/phpunit/phpunit/src/Util/GlobalState.php
new file mode 100644
index 000000000..cc5c22286
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/GlobalState.php
@@ -0,0 +1,203 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_reverse;
+use function array_shift;
+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 strpos;
+use function strtr;
+use function substr;
+use function var_export;
+use Closure;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class GlobalState
+{
+ /**
+ * @var string[]
+ */
+ private const SUPER_GLOBAL_ARRAYS = [
+ '_ENV',
+ '_POST',
+ '_GET',
+ '_COOKIE',
+ '_SERVER',
+ '_FILES',
+ '_REQUEST',
+ ];
+
+ /**
+ * @throws Exception
+ */
+ public static function getIncludedFilesAsString(): string
+ {
+ return self::processIncludedFilesAsString(get_included_files());
+ }
+
+ /**
+ * @param string[] $files
+ *
+ * @throws Exception
+ */
+ public static function processIncludedFilesAsString(array $files): string
+ {
+ $excludeList = new ExcludeList;
+ $prefix = false;
+ $result = '';
+
+ if (defined('__PHPUNIT_PHAR__')) {
+ $prefix = 'phar://' . __PHPUNIT_PHAR__ . '/';
+ }
+
+ // Do not process bootstrap script
+ array_shift($files);
+
+ // If bootstrap script was a Composer bin proxy, skip the second entry as well
+ if (substr(strtr($files[0], '\\', '/'), -24) === '/phpunit/phpunit/phpunit') {
+ array_shift($files);
+ }
+
+ foreach (array_reverse($files) as $file) {
+ if (!empty($GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST']) &&
+ in_array($file, $GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'], true)) {
+ continue;
+ }
+
+ if ($prefix !== false && strpos($file, $prefix) === 0) {
+ continue;
+ }
+
+ // Skip virtual file system protocols
+ if (preg_match('/^(vfs|phpvfs[a-z0-9]+):/', $file)) {
+ continue;
+ }
+
+ if (!$excludeList->isExcluded($file) && is_file($file)) {
+ $result = 'require_once \'' . $file . "';\n" . $result;
+ }
+ }
+
+ return $result;
+ }
+
+ public static function getIniSettingsAsString(): string
+ {
+ $result = '';
+
+ foreach (ini_get_all(null, false) as $key => $value) {
+ $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 (array_keys($GLOBALS[$superGlobalArray]) as $key) {
+ if ($GLOBALS[$superGlobalArray][$key] 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 (array_keys($GLOBALS) as $key) {
+ if (!$GLOBALS[$key] instanceof Closure && !in_array($key, $excludeList, true)) {
+ $result .= sprintf(
+ '$GLOBALS[\'%s\'] = %s;' . "\n",
+ $key,
+ self::exportVariable($GLOBALS[$key])
+ );
+ }
+ }
+
+ return $result;
+ }
+
+ private static function exportVariable($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) . ')';
+ }
+
+ 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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/InvalidDataSetException.php b/vendor/phpunit/phpunit/src/Util/InvalidDataSetException.php
new file mode 100644
index 000000000..3493d113a
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/InvalidDataSetException.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util;
+
+use RuntimeException;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class InvalidDataSetException extends RuntimeException implements \PHPUnit\Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Json.php b/vendor/phpunit/phpunit/src/Util/Json.php
new file mode 100644
index 000000000..752c1fd60
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Json.php
@@ -0,0 +1,98 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_PRETTY_PRINT;
+use const JSON_UNESCAPED_SLASHES;
+use const JSON_UNESCAPED_UNICODE;
+use function count;
+use function is_array;
+use function is_object;
+use function json_decode;
+use function json_encode;
+use function json_last_error;
+use function ksort;
+use PHPUnit\Framework\Exception;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Json
+{
+ /**
+ * Prettify json string.
+ *
+ * @throws \PHPUnit\Framework\Exception
+ */
+ public static function prettify(string $json): string
+ {
+ $decodedJson = json_decode($json, false);
+
+ if (json_last_error()) {
+ throw new Exception(
+ 'Cannot prettify invalid json'
+ );
+ }
+
+ return json_encode($decodedJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+ }
+
+ /**
+ * To allow comparison of JSON strings, first process them into a consistent
+ * format so that they can be compared as strings.
+ *
+ * @return array ($error, $canonicalized_json) The $error parameter is used
+ * to indicate an error decoding the json. This is used to avoid ambiguity
+ * with JSON strings consisting entirely of 'null' or 'false'.
+ */
+ public static function canonicalize(string $json): array
+ {
+ $decodedJson = json_decode($json);
+
+ if (json_last_error()) {
+ 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(&$json): void
+ {
+ if (!is_array($json)) {
+ // If the object is not empty, change it to an associative array
+ // so we can sort the keys (and we will still re-encode it
+ // correctly, since PHP encodes associative arrays as JSON objects.)
+ // But EMPTY objects MUST remain empty objects. (Otherwise we will
+ // re-encode it as a JSON array rather than a JSON object.)
+ // See #2919.
+ if (is_object($json) && count((array) $json) > 0) {
+ $json = (array) $json;
+ } else {
+ return;
+ }
+ }
+
+ ksort($json);
+
+ foreach ($json as $key => &$value) {
+ self::recursiveSort($value);
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Log/JUnit.php b/vendor/phpunit/phpunit/src/Util/Log/JUnit.php
new file mode 100644
index 000000000..7a97682fc
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Log/JUnit.php
@@ -0,0 +1,424 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\Log;
+
+use function class_exists;
+use function get_class;
+use function method_exists;
+use function sprintf;
+use function str_replace;
+use function trim;
+use DOMDocument;
+use DOMElement;
+use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\ExceptionWrapper;
+use PHPUnit\Framework\SelfDescribing;
+use PHPUnit\Framework\Test;
+use PHPUnit\Framework\TestFailure;
+use PHPUnit\Framework\TestListener;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Framework\Warning;
+use PHPUnit\Util\Exception;
+use PHPUnit\Util\Filter;
+use PHPUnit\Util\Printer;
+use PHPUnit\Util\Xml;
+use ReflectionClass;
+use ReflectionException;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class JUnit extends Printer implements TestListener
+{
+ /**
+ * @var DOMDocument
+ */
+ private $document;
+
+ /**
+ * @var DOMElement
+ */
+ private $root;
+
+ /**
+ * @var bool
+ */
+ private $reportRiskyTests = false;
+
+ /**
+ * @var DOMElement[]
+ */
+ private $testSuites = [];
+
+ /**
+ * @var int[]
+ */
+ private $testSuiteTests = [0];
+
+ /**
+ * @var int[]
+ */
+ private $testSuiteAssertions = [0];
+
+ /**
+ * @var int[]
+ */
+ private $testSuiteErrors = [0];
+
+ /**
+ * @var int[]
+ */
+ private $testSuiteWarnings = [0];
+
+ /**
+ * @var int[]
+ */
+ private $testSuiteFailures = [0];
+
+ /**
+ * @var int[]
+ */
+ private $testSuiteSkipped = [0];
+
+ /**
+ * @var int[]
+ */
+ private $testSuiteTimes = [0];
+
+ /**
+ * @var int
+ */
+ private $testSuiteLevel = 0;
+
+ /**
+ * @var DOMElement
+ */
+ private $currentTestCase;
+
+ /**
+ * @param null|mixed $out
+ */
+ public function __construct($out = null, bool $reportRiskyTests = false)
+ {
+ $this->document = new DOMDocument('1.0', 'UTF-8');
+ $this->document->formatOutput = true;
+
+ $this->root = $this->document->createElement('testsuites');
+ $this->document->appendChild($this->root);
+
+ parent::__construct($out);
+
+ $this->reportRiskyTests = $reportRiskyTests;
+ }
+
+ /**
+ * Flush buffer and close output.
+ */
+ public function flush(): void
+ {
+ $this->write($this->getXML());
+
+ parent::flush();
+ }
+
+ /**
+ * An error occurred.
+ */
+ public function addError(Test $test, Throwable $t, float $time): void
+ {
+ $this->doAddFault($test, $t, 'error');
+ $this->testSuiteErrors[$this->testSuiteLevel]++;
+ }
+
+ /**
+ * A warning occurred.
+ */
+ public function addWarning(Test $test, Warning $e, float $time): void
+ {
+ $this->doAddFault($test, $e, 'warning');
+ $this->testSuiteWarnings[$this->testSuiteLevel]++;
+ }
+
+ /**
+ * A failure occurred.
+ */
+ public function addFailure(Test $test, AssertionFailedError $e, float $time): void
+ {
+ $this->doAddFault($test, $e, 'failure');
+ $this->testSuiteFailures[$this->testSuiteLevel]++;
+ }
+
+ /**
+ * Incomplete test.
+ */
+ public function addIncompleteTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->doAddSkipped();
+ }
+
+ /**
+ * Risky test.
+ */
+ public function addRiskyTest(Test $test, Throwable $t, float $time): void
+ {
+ if (!$this->reportRiskyTests) {
+ return;
+ }
+
+ $this->doAddFault($test, $t, 'error');
+ $this->testSuiteErrors[$this->testSuiteLevel]++;
+ }
+
+ /**
+ * Skipped test.
+ */
+ public function addSkippedTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->doAddSkipped();
+ }
+
+ /**
+ * A testsuite started.
+ */
+ public function startTestSuite(TestSuite $suite): void
+ {
+ $testSuite = $this->document->createElement('testsuite');
+ $testSuite->setAttribute('name', $suite->getName());
+
+ if (class_exists($suite->getName(), false)) {
+ try {
+ $class = new ReflectionClass($suite->getName());
+
+ $testSuite->setAttribute('file', $class->getFileName());
+ } catch (ReflectionException $e) {
+ }
+ }
+
+ 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->testSuiteWarnings[$this->testSuiteLevel] = 0;
+ $this->testSuiteFailures[$this->testSuiteLevel] = 0;
+ $this->testSuiteSkipped[$this->testSuiteLevel] = 0;
+ $this->testSuiteTimes[$this->testSuiteLevel] = 0;
+ }
+
+ /**
+ * A testsuite ended.
+ */
+ public function endTestSuite(TestSuite $suite): 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(
+ 'warnings',
+ (string) $this->testSuiteWarnings[$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->testSuiteWarnings[$this->testSuiteLevel - 1] += $this->testSuiteWarnings[$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--;
+ }
+
+ /**
+ * A test started.
+ */
+ public function startTest(Test $test): void
+ {
+ $usesDataprovider = false;
+
+ if (method_exists($test, 'usesDataProvider')) {
+ $usesDataprovider = $test->usesDataProvider();
+ }
+
+ $testCase = $this->document->createElement('testcase');
+ $testCase->setAttribute('name', $test->getName());
+
+ try {
+ $class = new ReflectionClass($test);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $methodName = $test->getName(!$usesDataprovider);
+
+ if ($class->hasMethod($methodName)) {
+ try {
+ $method = $class->getMethod($methodName);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $testCase->setAttribute('class', $class->getName());
+ $testCase->setAttribute('classname', str_replace('\\', '.', $class->getName()));
+ $testCase->setAttribute('file', $class->getFileName());
+ $testCase->setAttribute('line', (string) $method->getStartLine());
+ }
+
+ $this->currentTestCase = $testCase;
+ }
+
+ /**
+ * A test ended.
+ */
+ public function endTest(Test $test, float $time): void
+ {
+ $numAssertions = 0;
+
+ if (method_exists($test, 'getNumAssertions')) {
+ $numAssertions = $test->getNumAssertions();
+ }
+
+ $this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;
+
+ $this->currentTestCase->setAttribute(
+ 'assertions',
+ (string) $numAssertions
+ );
+
+ $this->currentTestCase->setAttribute(
+ 'time',
+ sprintf('%F', $time)
+ );
+
+ $this->testSuites[$this->testSuiteLevel]->appendChild(
+ $this->currentTestCase
+ );
+
+ $this->testSuiteTests[$this->testSuiteLevel]++;
+ $this->testSuiteTimes[$this->testSuiteLevel] += $time;
+
+ $testOutput = '';
+
+ if (method_exists($test, 'hasOutput') && method_exists($test, 'getActualOutput')) {
+ $testOutput = $test->hasOutput() ? $test->getActualOutput() : '';
+ }
+
+ if (!empty($testOutput)) {
+ $systemOut = $this->document->createElement(
+ 'system-out',
+ Xml::prepareString($testOutput)
+ );
+
+ $this->currentTestCase->appendChild($systemOut);
+ }
+
+ $this->currentTestCase = null;
+ }
+
+ /**
+ * Returns the XML as a string.
+ */
+ public function getXML(): string
+ {
+ return $this->document->saveXML();
+ }
+
+ private function doAddFault(Test $test, Throwable $t, string $type): void
+ {
+ if ($this->currentTestCase === null) {
+ return;
+ }
+
+ if ($test instanceof SelfDescribing) {
+ $buffer = $test->toString() . "\n";
+ } else {
+ $buffer = '';
+ }
+
+ $buffer .= trim(
+ TestFailure::exceptionToString($t) . "\n" .
+ Filter::getFilteredStacktrace($t)
+ );
+
+ $fault = $this->document->createElement(
+ $type,
+ Xml::prepareString($buffer)
+ );
+
+ if ($t instanceof ExceptionWrapper) {
+ $fault->setAttribute('type', $t->getClassName());
+ } else {
+ $fault->setAttribute('type', get_class($t));
+ }
+
+ $this->currentTestCase->appendChild($fault);
+ }
+
+ private function doAddSkipped(): void
+ {
+ if ($this->currentTestCase === null) {
+ return;
+ }
+
+ $skipped = $this->document->createElement('skipped');
+
+ $this->currentTestCase->appendChild($skipped);
+
+ $this->testSuiteSkipped[$this->testSuiteLevel]++;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Log/TeamCity.php b/vendor/phpunit/phpunit/src/Util/Log/TeamCity.php
new file mode 100644
index 000000000..f800ba72d
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Log/TeamCity.php
@@ -0,0 +1,383 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\Log;
+
+use function class_exists;
+use function count;
+use function explode;
+use function get_class;
+use function getmypid;
+use function ini_get;
+use function is_bool;
+use function is_scalar;
+use function method_exists;
+use function print_r;
+use function round;
+use function str_replace;
+use function stripos;
+use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\ExceptionWrapper;
+use PHPUnit\Framework\ExpectationFailedException;
+use PHPUnit\Framework\Test;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestFailure;
+use PHPUnit\Framework\TestResult;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Framework\Warning;
+use PHPUnit\TextUI\DefaultResultPrinter;
+use PHPUnit\Util\Exception;
+use PHPUnit\Util\Filter;
+use ReflectionClass;
+use ReflectionException;
+use SebastianBergmann\Comparator\ComparisonFailure;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TeamCity extends DefaultResultPrinter
+{
+ /**
+ * @var bool
+ */
+ private $isSummaryTestCountPrinted = false;
+
+ /**
+ * @var string
+ */
+ private $startedTestName;
+
+ /**
+ * @var false|int
+ */
+ private $flowId;
+
+ public function printResult(TestResult $result): void
+ {
+ $this->printHeader($result);
+ $this->printFooter($result);
+ }
+
+ /**
+ * An error occurred.
+ */
+ public function addError(Test $test, Throwable $t, float $time): void
+ {
+ $this->printEvent(
+ 'testFailed',
+ [
+ 'name' => $test->getName(),
+ 'message' => self::getMessage($t),
+ 'details' => self::getDetails($t),
+ 'duration' => self::toMilliseconds($time),
+ ]
+ );
+ }
+
+ /**
+ * A warning occurred.
+ */
+ public function addWarning(Test $test, Warning $e, float $time): void
+ {
+ $this->write(self::getMessage($e) . PHP_EOL);
+ }
+
+ /**
+ * A failure occurred.
+ */
+ public function addFailure(Test $test, AssertionFailedError $e, float $time): void
+ {
+ $parameters = [
+ 'name' => $test->getName(),
+ 'message' => self::getMessage($e),
+ 'details' => self::getDetails($e),
+ 'duration' => self::toMilliseconds($time),
+ ];
+
+ if ($e instanceof ExpectationFailedException) {
+ $comparisonFailure = $e->getComparisonFailure();
+
+ if ($comparisonFailure instanceof ComparisonFailure) {
+ $expectedString = $comparisonFailure->getExpectedAsString();
+
+ if ($expectedString === null || empty($expectedString)) {
+ $expectedString = self::getPrimitiveValueAsString($comparisonFailure->getExpected());
+ }
+
+ $actualString = $comparisonFailure->getActualAsString();
+
+ if ($actualString === null || empty($actualString)) {
+ $actualString = self::getPrimitiveValueAsString($comparisonFailure->getActual());
+ }
+
+ if ($actualString !== null && $expectedString !== null) {
+ $parameters['type'] = 'comparisonFailure';
+ $parameters['actual'] = $actualString;
+ $parameters['expected'] = $expectedString;
+ }
+ }
+ }
+
+ $this->printEvent('testFailed', $parameters);
+ }
+
+ /**
+ * Incomplete test.
+ */
+ public function addIncompleteTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->printIgnoredTest($test->getName(), $t, $time);
+ }
+
+ /**
+ * Risky test.
+ */
+ public function addRiskyTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->addError($test, $t, $time);
+ }
+
+ /**
+ * Skipped test.
+ */
+ public function addSkippedTest(Test $test, Throwable $t, float $time): void
+ {
+ $testName = $test->getName();
+
+ if ($this->startedTestName !== $testName) {
+ $this->startTest($test);
+ $this->printIgnoredTest($testName, $t, $time);
+ $this->endTest($test, $time);
+ } else {
+ $this->printIgnoredTest($testName, $t, $time);
+ }
+ }
+
+ public function printIgnoredTest(string $testName, Throwable $t, float $time): void
+ {
+ $this->printEvent(
+ 'testIgnored',
+ [
+ 'name' => $testName,
+ 'message' => self::getMessage($t),
+ 'details' => self::getDetails($t),
+ 'duration' => self::toMilliseconds($time),
+ ]
+ );
+ }
+
+ /**
+ * A testsuite started.
+ */
+ public function startTestSuite(TestSuite $suite): void
+ {
+ if (stripos(ini_get('disable_functions'), 'getmypid') === false) {
+ $this->flowId = getmypid();
+ } else {
+ $this->flowId = false;
+ }
+
+ if (!$this->isSummaryTestCountPrinted) {
+ $this->isSummaryTestCountPrinted = true;
+
+ $this->printEvent(
+ 'testCount',
+ ['count' => count($suite)]
+ );
+ }
+
+ $suiteName = $suite->getName();
+
+ if (empty($suiteName)) {
+ return;
+ }
+
+ $parameters = ['name' => $suiteName];
+
+ if (class_exists($suiteName, false)) {
+ $fileName = self::getFileName($suiteName);
+ $parameters['locationHint'] = "php_qn://{$fileName}::\\{$suiteName}";
+ } else {
+ $split = explode('::', $suiteName);
+
+ if (count($split) === 2 && class_exists($split[0]) && method_exists($split[0], $split[1])) {
+ $fileName = self::getFileName($split[0]);
+ $parameters['locationHint'] = "php_qn://{$fileName}::\\{$suiteName}";
+ $parameters['name'] = $split[1];
+ }
+ }
+
+ $this->printEvent('testSuiteStarted', $parameters);
+ }
+
+ /**
+ * A testsuite ended.
+ */
+ public function endTestSuite(TestSuite $suite): void
+ {
+ $suiteName = $suite->getName();
+
+ if (empty($suiteName)) {
+ return;
+ }
+
+ $parameters = ['name' => $suiteName];
+
+ if (!class_exists($suiteName, false)) {
+ $split = explode('::', $suiteName);
+
+ if (count($split) === 2 && class_exists($split[0]) && method_exists($split[0], $split[1])) {
+ $parameters['name'] = $split[1];
+ }
+ }
+
+ $this->printEvent('testSuiteFinished', $parameters);
+ }
+
+ /**
+ * A test started.
+ */
+ public function startTest(Test $test): void
+ {
+ $testName = $test->getName();
+ $this->startedTestName = $testName;
+ $params = ['name' => $testName];
+
+ if ($test instanceof TestCase) {
+ $className = get_class($test);
+ $fileName = self::getFileName($className);
+ $params['locationHint'] = "php_qn://{$fileName}::\\{$className}::{$testName}";
+ }
+
+ $this->printEvent('testStarted', $params);
+ }
+
+ /**
+ * A test ended.
+ */
+ public function endTest(Test $test, float $time): void
+ {
+ parent::endTest($test, $time);
+
+ $this->printEvent(
+ 'testFinished',
+ [
+ 'name' => $test->getName(),
+ 'duration' => self::toMilliseconds($time),
+ ]
+ );
+ }
+
+ protected function writeProgress(string $progress): void
+ {
+ }
+
+ private function printEvent(string $eventName, array $params = []): void
+ {
+ $this->write("\n##teamcity[{$eventName}");
+
+ if ($this->flowId) {
+ $params['flowId'] = $this->flowId;
+ }
+
+ foreach ($params as $key => $value) {
+ $escapedValue = self::escapeValue((string) $value);
+ $this->write(" {$key}='{$escapedValue}'");
+ }
+
+ $this->write("]\n");
+ }
+
+ private static function getMessage(Throwable $t): string
+ {
+ $message = '';
+
+ if ($t instanceof ExceptionWrapper) {
+ if ($t->getClassName() !== '') {
+ $message .= $t->getClassName();
+ }
+
+ if ($message !== '' && $t->getMessage() !== '') {
+ $message .= ' : ';
+ }
+ }
+
+ return $message . $t->getMessage();
+ }
+
+ private static function getDetails(Throwable $t): string
+ {
+ $stackTrace = Filter::getFilteredStacktrace($t);
+ $previous = $t instanceof ExceptionWrapper ? $t->getPreviousWrapped() : $t->getPrevious();
+
+ while ($previous) {
+ $stackTrace .= "\nCaused by\n" .
+ TestFailure::exceptionToString($previous) . "\n" .
+ Filter::getFilteredStacktrace($previous);
+
+ $previous = $previous instanceof ExceptionWrapper ?
+ $previous->getPreviousWrapped() : $previous->getPrevious();
+ }
+
+ return ' ' . str_replace("\n", "\n ", $stackTrace);
+ }
+
+ private static function getPrimitiveValueAsString($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 null;
+ }
+
+ private static function escapeValue(string $text): string
+ {
+ return str_replace(
+ ['|', "'", "\n", "\r", ']', '['],
+ ['||', "|'", '|n', '|r', '|]', '|['],
+ $text
+ );
+ }
+
+ /**
+ * @param string $className
+ */
+ private static function getFileName($className): string
+ {
+ try {
+ return (new ReflectionClass($className))->getFileName();
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * @param float $time microseconds
+ */
+ private static function toMilliseconds(float $time): int
+ {
+ return (int) round($time * 1000);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php b/vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php
new file mode 100644
index 000000000..8706ae1a1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php
@@ -0,0 +1,416 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 DIRECTORY_SEPARATOR;
+use const PHP_SAPI;
+use function array_keys;
+use function array_merge;
+use function assert;
+use function escapeshellarg;
+use function ini_get_all;
+use function restore_error_handler;
+use function set_error_handler;
+use function sprintf;
+use function str_replace;
+use function strpos;
+use function strrpos;
+use function substr;
+use function trim;
+use function unserialize;
+use __PHP_Incomplete_Class;
+use ErrorException;
+use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\Exception;
+use PHPUnit\Framework\SyntheticError;
+use PHPUnit\Framework\Test;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestFailure;
+use PHPUnit\Framework\TestResult;
+use SebastianBergmann\Environment\Runtime;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+abstract class AbstractPhpProcess
+{
+ /**
+ * @var Runtime
+ */
+ protected $runtime;
+
+ /**
+ * @var bool
+ */
+ protected $stderrRedirection = false;
+
+ /**
+ * @var string
+ */
+ protected $stdin = '';
+
+ /**
+ * @var string
+ */
+ protected $args = '';
+
+ /**
+ * @var array<string, string>
+ */
+ protected $env = [];
+
+ /**
+ * @var int
+ */
+ protected $timeout = 0;
+
+ public static function factory(): self
+ {
+ if (DIRECTORY_SEPARATOR === '\\') {
+ return new WindowsPhpProcess;
+ }
+
+ return new DefaultPhpProcess;
+ }
+
+ public function __construct()
+ {
+ $this->runtime = new Runtime;
+ }
+
+ /**
+ * Defines if should use STDERR redirection or not.
+ *
+ * Then $stderrRedirection is TRUE, STDERR is redirected to STDOUT.
+ */
+ public function setUseStderrRedirection(bool $stderrRedirection): void
+ {
+ $this->stderrRedirection = $stderrRedirection;
+ }
+
+ /**
+ * Returns TRUE if uses STDERR redirection or FALSE if not.
+ */
+ public function useStderrRedirection(): bool
+ {
+ return $this->stderrRedirection;
+ }
+
+ /**
+ * Sets the input string to be sent via STDIN.
+ */
+ public function setStdin(string $stdin): void
+ {
+ $this->stdin = $stdin;
+ }
+
+ /**
+ * Returns the input string to be sent via STDIN.
+ */
+ public function getStdin(): string
+ {
+ return $this->stdin;
+ }
+
+ /**
+ * Sets the string of arguments to pass to the php job.
+ */
+ public function setArgs(string $args): void
+ {
+ $this->args = $args;
+ }
+
+ /**
+ * Returns the string of arguments to pass to the php job.
+ */
+ public function getArgs(): string
+ {
+ return $this->args;
+ }
+
+ /**
+ * Sets the array of environment variables to start the child process with.
+ *
+ * @param array<string, string> $env
+ */
+ public function setEnv(array $env): void
+ {
+ $this->env = $env;
+ }
+
+ /**
+ * Returns the array of environment variables to start the child process with.
+ */
+ public function getEnv(): array
+ {
+ return $this->env;
+ }
+
+ /**
+ * Sets the amount of seconds to wait before timing out.
+ */
+ public function setTimeout(int $timeout): void
+ {
+ $this->timeout = $timeout;
+ }
+
+ /**
+ * Returns the amount of seconds to wait before timing out.
+ */
+ public function getTimeout(): int
+ {
+ return $this->timeout;
+ }
+
+ /**
+ * Runs a single test in a separate PHP process.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function runTestJob(string $job, Test $test, TestResult $result): void
+ {
+ $result->startTest($test);
+
+ $_result = $this->runJob($job);
+
+ $this->processChildResult(
+ $test,
+ $result,
+ $_result['stdout'],
+ $_result['stderr']
+ );
+ }
+
+ /**
+ * Returns the command based into the configurations.
+ */
+ public function getCommand(array $settings, string $file = null): string
+ {
+ $command = $this->runtime->getBinary();
+
+ if ($this->runtime->hasPCOV()) {
+ $settings = array_merge(
+ $settings,
+ $this->runtime->getCurrentSettings(
+ array_keys(ini_get_all('pcov'))
+ )
+ );
+ } elseif ($this->runtime->hasXdebug()) {
+ $settings = array_merge(
+ $settings,
+ $this->runtime->getCurrentSettings(
+ array_keys(ini_get_all('xdebug'))
+ )
+ );
+ }
+
+ $command .= $this->settingsToParameters($settings);
+
+ if (PHP_SAPI === 'phpdbg') {
+ $command .= ' -qrr';
+
+ if (!$file) {
+ $command .= 's=';
+ }
+ }
+
+ if ($file) {
+ $command .= ' ' . escapeshellarg($file);
+ }
+
+ if ($this->args) {
+ if (!$file) {
+ $command .= ' --';
+ }
+ $command .= ' ' . $this->args;
+ }
+
+ if ($this->stderrRedirection) {
+ $command .= ' 2>&1';
+ }
+
+ return $command;
+ }
+
+ /**
+ * Runs a single job (PHP code) using a separate PHP process.
+ */
+ abstract public function runJob(string $job, array $settings = []): array;
+
+ protected function settingsToParameters(array $settings): string
+ {
+ $buffer = '';
+
+ foreach ($settings as $setting) {
+ $buffer .= ' -d ' . escapeshellarg($setting);
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Processes the TestResult object from an isolated process.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ private function processChildResult(Test $test, TestResult $result, string $stdout, string $stderr): void
+ {
+ $time = 0;
+
+ if (!empty($stderr)) {
+ $result->addError(
+ $test,
+ new Exception(trim($stderr)),
+ $time
+ );
+ } else {
+ set_error_handler(
+ /**
+ * @throws ErrorException
+ */
+ static function ($errno, $errstr, $errfile, $errline): void
+ {
+ throw new ErrorException($errstr, $errno, $errno, $errfile, $errline);
+ }
+ );
+
+ try {
+ if (strpos($stdout, "#!/usr/bin/env php\n") === 0) {
+ $stdout = substr($stdout, 19);
+ }
+
+ $childResult = unserialize(str_replace("#!/usr/bin/env php\n", '', $stdout));
+ restore_error_handler();
+
+ if ($childResult === false) {
+ $result->addFailure(
+ $test,
+ new AssertionFailedError('Test was run in child process and ended unexpectedly'),
+ $time
+ );
+ }
+ } catch (ErrorException $e) {
+ restore_error_handler();
+ $childResult = false;
+
+ $result->addError(
+ $test,
+ new Exception(trim($stdout), 0, $e),
+ $time
+ );
+ }
+
+ if ($childResult !== false) {
+ if (!empty($childResult['output'])) {
+ $output = $childResult['output'];
+ }
+
+ /* @var TestCase $test */
+
+ $test->setResult($childResult['testResult']);
+ $test->addToAssertionCount($childResult['numAssertions']);
+
+ $childResult = $childResult['result'];
+ assert($childResult instanceof TestResult);
+
+ if ($result->getCollectCodeCoverageInformation()) {
+ $result->getCodeCoverage()->merge(
+ $childResult->getCodeCoverage()
+ );
+ }
+
+ $time = $childResult->time();
+ $notImplemented = $childResult->notImplemented();
+ $risky = $childResult->risky();
+ $skipped = $childResult->skipped();
+ $errors = $childResult->errors();
+ $warnings = $childResult->warnings();
+ $failures = $childResult->failures();
+
+ if (!empty($notImplemented)) {
+ $result->addError(
+ $test,
+ $this->getException($notImplemented[0]),
+ $time
+ );
+ } elseif (!empty($risky)) {
+ $result->addError(
+ $test,
+ $this->getException($risky[0]),
+ $time
+ );
+ } elseif (!empty($skipped)) {
+ $result->addError(
+ $test,
+ $this->getException($skipped[0]),
+ $time
+ );
+ } elseif (!empty($errors)) {
+ $result->addError(
+ $test,
+ $this->getException($errors[0]),
+ $time
+ );
+ } elseif (!empty($warnings)) {
+ $result->addWarning(
+ $test,
+ $this->getException($warnings[0]),
+ $time
+ );
+ } elseif (!empty($failures)) {
+ $result->addFailure(
+ $test,
+ $this->getException($failures[0]),
+ $time
+ );
+ }
+ }
+ }
+
+ $result->endTest($test, $time);
+
+ if (!empty($output)) {
+ print $output;
+ }
+ }
+
+ /**
+ * Gets the thrown exception from a PHPUnit\Framework\TestFailure.
+ *
+ * @see https://github.com/sebastianbergmann/phpunit/issues/74
+ */
+ private function getException(TestFailure $error): Exception
+ {
+ $exception = $error->thrownException();
+
+ if ($exception instanceof __PHP_Incomplete_Class) {
+ $exceptionArray = [];
+
+ foreach ((array) $exception as $key => $value) {
+ $key = substr($key, strrpos($key, "\0") + 1);
+ $exceptionArray[$key] = $value;
+ }
+
+ $exception = new SyntheticError(
+ sprintf(
+ '%s: %s',
+ $exceptionArray['_PHP_Incomplete_Class_Name'],
+ $exceptionArray['message']
+ ),
+ $exceptionArray['code'],
+ $exceptionArray['file'],
+ $exceptionArray['line'],
+ $exceptionArray['trace']
+ );
+ }
+
+ return $exception;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php b/vendor/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php
new file mode 100644
index 000000000..c4dc11146
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/PHP/DefaultPhpProcess.php
@@ -0,0 +1,236 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 array_merge;
+use function fclose;
+use function file_put_contents;
+use function fread;
+use function fwrite;
+use function is_array;
+use function is_resource;
+use function proc_close;
+use function proc_open;
+use function proc_terminate;
+use function rewind;
+use function sprintf;
+use function stream_get_contents;
+use function stream_select;
+use function sys_get_temp_dir;
+use function tempnam;
+use function unlink;
+use PHPUnit\Framework\Exception;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class DefaultPhpProcess extends AbstractPhpProcess
+{
+ /**
+ * @var string
+ */
+ protected $tempFile;
+
+ /**
+ * Runs a single job (PHP code) using a separate PHP process.
+ *
+ * @throws Exception
+ */
+ public function runJob(string $job, array $settings = []): array
+ {
+ if ($this->stdin || $this->useTemporaryFile()) {
+ if (!($this->tempFile = tempnam(sys_get_temp_dir(), 'PHPUnit')) ||
+ file_put_contents($this->tempFile, $job) === false) {
+ throw new Exception(
+ 'Unable to write temporary file'
+ );
+ }
+
+ $job = $this->stdin;
+ }
+
+ return $this->runProcess($job, $settings);
+ }
+
+ /**
+ * Returns an array of file handles to be used in place of pipes.
+ */
+ protected function getHandles(): array
+ {
+ return [];
+ }
+
+ /**
+ * Handles creating the child process and returning the STDOUT and STDERR.
+ *
+ * @throws Exception
+ */
+ protected function runProcess(string $job, array $settings): array
+ {
+ $handles = $this->getHandles();
+
+ $env = null;
+
+ if ($this->env) {
+ $env = $_SERVER ?? [];
+ unset($env['argv'], $env['argc']);
+ $env = array_merge($env, $this->env);
+
+ foreach ($env as $envKey => $envVar) {
+ if (is_array($envVar)) {
+ unset($env[$envKey]);
+ }
+ }
+ }
+
+ $pipeSpec = [
+ 0 => $handles[0] ?? ['pipe', 'r'],
+ 1 => $handles[1] ?? ['pipe', 'w'],
+ 2 => $handles[2] ?? ['pipe', 'w'],
+ ];
+
+ $process = proc_open(
+ $this->getCommand($settings, $this->tempFile),
+ $pipeSpec,
+ $pipes,
+ null,
+ $env
+ );
+
+ if (!is_resource($process)) {
+ throw new Exception(
+ 'Unable to spawn worker process'
+ );
+ }
+
+ if ($job) {
+ $this->process($pipes[0], $job);
+ }
+
+ fclose($pipes[0]);
+
+ $stderr = $stdout = '';
+
+ if ($this->timeout) {
+ unset($pipes[0]);
+
+ while (true) {
+ $r = $pipes;
+ $w = null;
+ $e = null;
+
+ $n = @stream_select($r, $w, $e, $this->timeout);
+
+ if ($n === false) {
+ break;
+ }
+
+ if ($n === 0) {
+ proc_terminate($process, 9);
+
+ throw new Exception(
+ sprintf(
+ 'Job execution aborted after %d seconds',
+ $this->timeout
+ )
+ );
+ }
+
+ if ($n > 0) {
+ foreach ($r as $pipe) {
+ $pipeOffset = 0;
+
+ foreach ($pipes as $i => $origPipe) {
+ if ($pipe === $origPipe) {
+ $pipeOffset = $i;
+
+ break;
+ }
+ }
+
+ if (!$pipeOffset) {
+ break;
+ }
+
+ $line = fread($pipe, 8192);
+
+ if ($line === '' || $line === false) {
+ fclose($pipes[$pipeOffset]);
+
+ unset($pipes[$pipeOffset]);
+ } elseif ($pipeOffset === 1) {
+ $stdout .= $line;
+ } else {
+ $stderr .= $line;
+ }
+ }
+
+ if (empty($pipes)) {
+ break;
+ }
+ }
+ }
+ } else {
+ 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]);
+ }
+ }
+
+ if (isset($handles[1])) {
+ rewind($handles[1]);
+
+ $stdout = stream_get_contents($handles[1]);
+
+ fclose($handles[1]);
+ }
+
+ if (isset($handles[2])) {
+ rewind($handles[2]);
+
+ $stderr = stream_get_contents($handles[2]);
+
+ fclose($handles[2]);
+ }
+
+ proc_close($process);
+
+ $this->cleanup();
+
+ return ['stdout' => $stdout, 'stderr' => $stderr];
+ }
+
+ /**
+ * @param resource $pipe
+ */
+ protected function process($pipe, string $job): void
+ {
+ fwrite($pipe, $job);
+ }
+
+ protected function cleanup(): void
+ {
+ if ($this->tempFile) {
+ unlink($this->tempFile);
+ }
+ }
+
+ protected function useTemporaryFile(): bool
+ {
+ return false;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/PHP/Template/PhptTestCase.tpl b/vendor/phpunit/phpunit/src/Util/PHP/Template/PhptTestCase.tpl
new file mode 100644
index 000000000..f23a0d1ae
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/PHP/Template/PhptTestCase.tpl
@@ -0,0 +1,57 @@
+<?php
+use SebastianBergmann\CodeCoverage\CodeCoverage;
+use SebastianBergmann\CodeCoverage\Driver\Selector;
+use SebastianBergmann\CodeCoverage\Filter;
+
+$composerAutoload = {composerAutoload};
+$phar = {phar};
+
+ob_start();
+
+$GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'][] = '{job}';
+
+if ($composerAutoload) {
+ require_once $composerAutoload;
+
+ define('PHPUNIT_COMPOSER_INSTALL', $composerAutoload);
+} else if ($phar) {
+ require $phar;
+}
+
+{globals}
+$coverage = null;
+
+if (isset($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
+ require_once $GLOBALS['__PHPUNIT_BOOTSTRAP'];
+}
+
+if (class_exists('SebastianBergmann\CodeCoverage\CodeCoverage')) {
+ $filter = new Filter;
+
+ $coverage = new CodeCoverage(
+ (new Selector)->{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}';
diff --git a/vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseClass.tpl b/vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseClass.tpl
new file mode 100644
index 000000000..95035e505
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseClass.tpl
@@ -0,0 +1,119 @@
+<?php
+use SebastianBergmann\CodeCoverage\CodeCoverage;
+use SebastianBergmann\CodeCoverage\Driver\Selector;
+use PHPUnit\TextUI\XmlConfiguration\Loader;
+use PHPUnit\TextUI\XmlConfiguration\PhpHandler;
+
+if (!defined('STDOUT')) {
+ // php://stdout does not obey output buffering. Any output would break
+ // unserialization of child process results in the parent process.
+ define('STDOUT', fopen('php://temp', 'w+b'));
+ define('STDERR', fopen('php://stderr', 'wb'));
+}
+
+{iniSettings}
+ini_set('display_errors', 'stderr');
+set_include_path('{include_path}');
+
+$composerAutoload = {composerAutoload};
+$phar = {phar};
+
+ob_start();
+
+if ($composerAutoload) {
+ require_once $composerAutoload;
+ define('PHPUNIT_COMPOSER_INSTALL', $composerAutoload);
+} else if ($phar) {
+ require $phar;
+}
+
+function __phpunit_run_isolated_test()
+{
+ if (!class_exists('{className}')) {
+ require_once '{filename}';
+ }
+
+ $result = new PHPUnit\Framework\TestResult;
+
+ if ({collectCodeCoverageInformation}) {
+ $filter = unserialize('{codeCoverageFilter}');
+
+ $codeCoverage = new CodeCoverage(
+ (new Selector)->{driverMethod}($filter),
+ $filter
+ );
+
+ if ({cachesStaticAnalysis}) {
+ $codeCoverage->cacheStaticAnalysis(unserialize('{codeCoverageCacheDirectory}'));
+ }
+
+ $result->setCodeCoverage($codeCoverage);
+ }
+
+ $result->beStrictAboutTestsThatDoNotTestAnything({isStrictAboutTestsThatDoNotTestAnything});
+ $result->beStrictAboutOutputDuringTests({isStrictAboutOutputDuringTests});
+ $result->enforceTimeLimit({enforcesTimeLimit});
+ $result->beStrictAboutTodoAnnotatedTests({isStrictAboutTodoAnnotatedTests});
+ $result->beStrictAboutResourceUsageDuringSmallTests({isStrictAboutResourceUsageDuringSmallTests});
+
+ $test = new {className}('{name}', unserialize('{data}'), '{dataName}');
+ $test->setDependencyInput(unserialize('{dependencyInput}'));
+ $test->setInIsolation(TRUE);
+
+ ob_end_clean();
+ $test->run($result);
+ $output = '';
+ if (!$test->hasExpectationOnOutput()) {
+ $output = $test->getActualOutput();
+ }
+
+ ini_set('xdebug.scream', '0');
+ @rewind(STDOUT); /* @ as not every STDOUT target stream is rewindable */
+ if ($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);
+ }
+ }
+
+ print serialize(
+ [
+ 'testResult' => $test->getResult(),
+ 'numAssertions' => $test->getNumAssertions(),
+ 'result' => $result,
+ 'output' => $output
+ ]
+ );
+}
+
+$configurationFilePath = '{configurationFilePath}';
+
+if ('' !== $configurationFilePath) {
+ $configuration = (new Loader)->load($configurationFilePath);
+
+ (new PhpHandler)->handle($configuration->php());
+
+ unset($configuration);
+}
+
+function __phpunit_error_handler($errno, $errstr, $errfile, $errline)
+{
+ return true;
+}
+
+set_error_handler('__phpunit_error_handler');
+
+{constants}
+{included_files}
+{globals}
+
+restore_error_handler();
+
+if (isset($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
+ require_once $GLOBALS['__PHPUNIT_BOOTSTRAP'];
+ unset($GLOBALS['__PHPUNIT_BOOTSTRAP']);
+}
+
+__phpunit_run_isolated_test();
diff --git a/vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseMethod.tpl b/vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseMethod.tpl
new file mode 100644
index 000000000..da824e720
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseMethod.tpl
@@ -0,0 +1,122 @@
+<?php
+use PHPUnit\Framework\TestCase;
+use SebastianBergmann\CodeCoverage\CodeCoverage;
+use SebastianBergmann\CodeCoverage\Driver\Selector;
+use PHPUnit\TextUI\XmlConfiguration\Loader;
+use PHPUnit\TextUI\XmlConfiguration\PhpHandler;
+
+if (!defined('STDOUT')) {
+ // php://stdout does not obey output buffering. Any output would break
+ // unserialization of child process results in the parent process.
+ define('STDOUT', fopen('php://temp', 'w+b'));
+ define('STDERR', fopen('php://stderr', 'wb'));
+}
+
+{iniSettings}
+ini_set('display_errors', 'stderr');
+set_include_path('{include_path}');
+
+$composerAutoload = {composerAutoload};
+$phar = {phar};
+
+ob_start();
+
+if ($composerAutoload) {
+ require_once $composerAutoload;
+ define('PHPUNIT_COMPOSER_INSTALL', $composerAutoload);
+} else if ($phar) {
+ require $phar;
+}
+
+function __phpunit_run_isolated_test()
+{
+ if (!class_exists('{className}')) {
+ require_once '{filename}';
+ }
+
+ $result = new PHPUnit\Framework\TestResult;
+
+ if ({collectCodeCoverageInformation}) {
+ $filter = unserialize('{codeCoverageFilter}');
+
+ $codeCoverage = new CodeCoverage(
+ (new Selector)->{driverMethod}($filter),
+ $filter
+ );
+
+ if ({cachesStaticAnalysis}) {
+ $codeCoverage->cacheStaticAnalysis(unserialize('{codeCoverageCacheDirectory}'));
+ }
+
+ $result->setCodeCoverage($codeCoverage);
+ }
+
+ $result->beStrictAboutTestsThatDoNotTestAnything({isStrictAboutTestsThatDoNotTestAnything});
+ $result->beStrictAboutOutputDuringTests({isStrictAboutOutputDuringTests});
+ $result->enforceTimeLimit({enforcesTimeLimit});
+ $result->beStrictAboutTodoAnnotatedTests({isStrictAboutTodoAnnotatedTests});
+ $result->beStrictAboutResourceUsageDuringSmallTests({isStrictAboutResourceUsageDuringSmallTests});
+
+ $test = new {className}('{methodName}', unserialize('{data}'), '{dataName}');
+ \assert($test instanceof TestCase);
+
+ $test->setDependencyInput(unserialize('{dependencyInput}'));
+ $test->setInIsolation(true);
+
+ ob_end_clean();
+ $test->run($result);
+ $output = '';
+ if (!$test->hasExpectationOnOutput()) {
+ $output = $test->getActualOutput();
+ }
+
+ ini_set('xdebug.scream', '0');
+ @rewind(STDOUT); /* @ as not every STDOUT target stream is rewindable */
+ if ($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);
+ }
+ }
+
+ print serialize(
+ [
+ 'testResult' => $test->getResult(),
+ 'numAssertions' => $test->getNumAssertions(),
+ 'result' => $result,
+ 'output' => $output
+ ]
+ );
+}
+
+$configurationFilePath = '{configurationFilePath}';
+
+if ('' !== $configurationFilePath) {
+ $configuration = (new Loader)->load($configurationFilePath);
+
+ (new PhpHandler)->handle($configuration->php());
+
+ unset($configuration);
+}
+
+function __phpunit_error_handler($errno, $errstr, $errfile, $errline)
+{
+ return true;
+}
+
+set_error_handler('__phpunit_error_handler');
+
+{constants}
+{included_files}
+{globals}
+
+restore_error_handler();
+
+if (isset($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
+ require_once $GLOBALS['__PHPUNIT_BOOTSTRAP'];
+ unset($GLOBALS['__PHPUNIT_BOOTSTRAP']);
+}
+
+__phpunit_run_isolated_test();
diff --git a/vendor/phpunit/phpunit/src/Util/PHP/WindowsPhpProcess.php b/vendor/phpunit/phpunit/src/Util/PHP/WindowsPhpProcess.php
new file mode 100644
index 000000000..9ef925556
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/PHP/WindowsPhpProcess.php
@@ -0,0 +1,52 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_MAJOR_VERSION;
+use function tmpfile;
+use PHPUnit\Framework\Exception;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ *
+ * @see https://bugs.php.net/bug.php?id=51800
+ */
+final class WindowsPhpProcess extends DefaultPhpProcess
+{
+ public function getCommand(array $settings, string $file = null): string
+ {
+ if (PHP_MAJOR_VERSION < 8) {
+ return '"' . parent::getCommand($settings, $file) . '"';
+ }
+
+ return parent::getCommand($settings, $file);
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected function getHandles(): array
+ {
+ if (false === $stdout_handle = tmpfile()) {
+ throw new Exception(
+ 'A temporary file could not be created; verify that your TEMP environment variable is writable'
+ );
+ }
+
+ return [
+ 1 => $stdout_handle,
+ ];
+ }
+
+ protected function useTemporaryFile(): bool
+ {
+ return true;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Printer.php b/vendor/phpunit/phpunit/src/Util/Printer.php
new file mode 100644
index 000000000..77b5745ad
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Printer.php
@@ -0,0 +1,116 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_COMPAT;
+use const ENT_SUBSTITUTE;
+use const PHP_SAPI;
+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 htmlspecialchars;
+use function is_resource;
+use function is_string;
+use function sprintf;
+use function str_replace;
+use function strncmp;
+use function strpos;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class Printer
+{
+ /**
+ * @psalm-var closed-resource|resource
+ */
+ private $stream;
+
+ /**
+ * @var bool
+ */
+ private $isPhpStream;
+
+ /**
+ * @param null|resource|string $out
+ *
+ * @throws Exception
+ */
+ public function __construct($out = null)
+ {
+ if (is_resource($out)) {
+ $this->stream = $out;
+
+ return;
+ }
+
+ if (!is_string($out)) {
+ return;
+ }
+
+ if (strpos($out, 'socket://') === 0) {
+ $tmp = explode(':', str_replace('socket://', '', $out));
+
+ if (count($tmp) !== 2) {
+ throw new Exception(
+ sprintf(
+ '"%s" does not match "socket://hostname:port" format',
+ $out
+ )
+ );
+ }
+
+ $this->stream = fsockopen($tmp[0], (int) $tmp[1]);
+
+ return;
+ }
+
+ if (strpos($out, 'php://') === false && !Filesystem::createDirectory(dirname($out))) {
+ throw new Exception(
+ sprintf(
+ 'Directory "%s" was not created',
+ dirname($out)
+ )
+ );
+ }
+
+ $this->stream = fopen($out, 'wb');
+ $this->isPhpStream = strncmp($out, 'php://', 6) !== 0;
+ }
+
+ public function write(string $buffer): void
+ {
+ if ($this->stream) {
+ assert(is_resource($this->stream));
+
+ fwrite($this->stream, $buffer);
+ } else {
+ if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') {
+ $buffer = htmlspecialchars($buffer, ENT_COMPAT | ENT_SUBSTITUTE);
+ }
+
+ print $buffer;
+ }
+ }
+
+ public function flush(): void
+ {
+ if ($this->stream && $this->isPhpStream) {
+ assert(is_resource($this->stream));
+
+ fclose($this->stream);
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/RegularExpression.php b/vendor/phpunit/phpunit/src/Util/RegularExpression.php
new file mode 100644
index 000000000..db1dae922
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/RegularExpression.php
@@ -0,0 +1,31 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util;
+
+use function preg_match;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class RegularExpression
+{
+ /**
+ * @return false|int
+ */
+ public static function safeMatch(string $pattern, string $subject)
+ {
+ return ErrorHandler::invokeIgnoringWarnings(
+ static function () use ($pattern, $subject)
+ {
+ return preg_match($pattern, $subject);
+ }
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Test.php b/vendor/phpunit/phpunit/src/Util/Test.php
new file mode 100644
index 000000000..0778f2f52
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Test.php
@@ -0,0 +1,784 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+use const PHP_VERSION;
+use function addcslashes;
+use function array_flip;
+use function array_key_exists;
+use function array_merge;
+use function array_unique;
+use function array_unshift;
+use function class_exists;
+use function count;
+use function explode;
+use function extension_loaded;
+use function function_exists;
+use function get_class;
+use function ini_get;
+use function interface_exists;
+use function is_array;
+use function is_int;
+use function method_exists;
+use function phpversion;
+use function preg_match;
+use function preg_replace;
+use function sprintf;
+use function strncmp;
+use function strpos;
+use function strtolower;
+use function trim;
+use function version_compare;
+use PHPUnit\Framework\Assert;
+use PHPUnit\Framework\CodeCoverageException;
+use PHPUnit\Framework\ExecutionOrderDependency;
+use PHPUnit\Framework\InvalidCoversTargetException;
+use PHPUnit\Framework\SelfDescribing;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\Warning;
+use PHPUnit\Runner\Version;
+use PHPUnit\Util\Annotation\Registry;
+use ReflectionClass;
+use ReflectionException;
+use ReflectionMethod;
+use SebastianBergmann\CodeUnit\CodeUnitCollection;
+use SebastianBergmann\CodeUnit\InvalidCodeUnitException;
+use SebastianBergmann\CodeUnit\Mapper;
+use SebastianBergmann\Environment\OperatingSystem;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Test
+{
+ /**
+ * @var int
+ */
+ public const UNKNOWN = -1;
+
+ /**
+ * @var int
+ */
+ public const SMALL = 0;
+
+ /**
+ * @var int
+ */
+ public const MEDIUM = 1;
+
+ /**
+ * @var int
+ */
+ public const LARGE = 2;
+
+ /**
+ * @var array
+ */
+ private static $hookMethods = [];
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public static function describe(\PHPUnit\Framework\Test $test): array
+ {
+ if ($test instanceof TestCase) {
+ return [get_class($test), $test->getName()];
+ }
+
+ if ($test instanceof SelfDescribing) {
+ return ['', $test->toString()];
+ }
+
+ return ['', get_class($test)];
+ }
+
+ public static function describeAsString(\PHPUnit\Framework\Test $test): string
+ {
+ if ($test instanceof SelfDescribing) {
+ return $test->toString();
+ }
+
+ return get_class($test);
+ }
+
+ /**
+ * @throws CodeCoverageException
+ *
+ * @return array|bool
+ * @psalm-param class-string $className
+ */
+ public static function getLinesToBeCovered(string $className, string $methodName)
+ {
+ $annotations = self::parseTestMethodAnnotations(
+ $className,
+ $methodName
+ );
+
+ if (!self::shouldCoversAnnotationBeUsed($annotations)) {
+ return false;
+ }
+
+ return self::getLinesToBeCoveredOrUsed($className, $methodName, 'covers');
+ }
+
+ /**
+ * Returns lines of code specified with the @uses annotation.
+ *
+ * @throws CodeCoverageException
+ * @psalm-param class-string $className
+ */
+ public static function getLinesToBeUsed(string $className, string $methodName): array
+ {
+ return self::getLinesToBeCoveredOrUsed($className, $methodName, 'uses');
+ }
+
+ public static function requiresCodeCoverageDataCollection(TestCase $test): bool
+ {
+ $annotations = self::parseTestMethodAnnotations(
+ get_class($test),
+ $test->getName(false)
+ );
+
+ // If there is no @covers annotation but a @coversNothing annotation on
+ // the test method then code coverage data does not need to be collected
+ if (isset($annotations['method']['coversNothing'])) {
+ return false;
+ }
+
+ // If there is at least one @covers annotation then
+ // code coverage data needs to be collected
+ if (isset($annotations['method']['covers'])) {
+ return true;
+ }
+
+ // If there is no @covers annotation but a @coversNothing annotation
+ // then code coverage data does not need to be collected
+ if (isset($annotations['class']['coversNothing'])) {
+ return false;
+ }
+
+ // If there is no @coversNothing annotation then
+ // code coverage data may be collected
+ return true;
+ }
+
+ /**
+ * @throws Exception
+ * @psalm-param class-string $className
+ */
+ public static function getRequirements(string $className, string $methodName): array
+ {
+ return self::mergeArraysRecursively(
+ Registry::getInstance()->forClassName($className)->requirements(),
+ Registry::getInstance()->forMethod($className, $methodName)->requirements()
+ );
+ }
+
+ /**
+ * Returns the missing requirements for a test.
+ *
+ * @throws Exception
+ * @throws Warning
+ * @psalm-param class-string $className
+ */
+ public static function getMissingRequirements(string $className, string $methodName): array
+ {
+ $required = self::getRequirements($className, $methodName);
+ $missing = [];
+ $hint = null;
+
+ if (!empty($required['PHP'])) {
+ $operator = new VersionComparisonOperator(empty($required['PHP']['operator']) ? '>=' : $required['PHP']['operator']);
+
+ if (!version_compare(PHP_VERSION, $required['PHP']['version'], $operator->asString())) {
+ $missing[] = sprintf('PHP %s %s is required.', $operator->asString(), $required['PHP']['version']);
+ $hint = 'PHP';
+ }
+ } elseif (!empty($required['PHP_constraint'])) {
+ $version = new \PharIo\Version\Version(self::sanitizeVersionNumber(PHP_VERSION));
+
+ if (!$required['PHP_constraint']['constraint']->complies($version)) {
+ $missing[] = sprintf(
+ 'PHP version does not match the required constraint %s.',
+ $required['PHP_constraint']['constraint']->asString()
+ );
+
+ $hint = 'PHP_constraint';
+ }
+ }
+
+ if (!empty($required['PHPUnit'])) {
+ $phpunitVersion = Version::id();
+
+ $operator = new VersionComparisonOperator(empty($required['PHPUnit']['operator']) ? '>=' : $required['PHPUnit']['operator']);
+
+ if (!version_compare($phpunitVersion, $required['PHPUnit']['version'], $operator->asString())) {
+ $missing[] = sprintf('PHPUnit %s %s is required.', $operator->asString(), $required['PHPUnit']['version']);
+ $hint = $hint ?? 'PHPUnit';
+ }
+ } elseif (!empty($required['PHPUnit_constraint'])) {
+ $phpunitVersion = new \PharIo\Version\Version(self::sanitizeVersionNumber(Version::id()));
+
+ if (!$required['PHPUnit_constraint']['constraint']->complies($phpunitVersion)) {
+ $missing[] = sprintf(
+ 'PHPUnit version does not match the required constraint %s.',
+ $required['PHPUnit_constraint']['constraint']->asString()
+ );
+
+ $hint = $hint ?? 'PHPUnit_constraint';
+ }
+ }
+
+ if (!empty($required['OSFAMILY']) && $required['OSFAMILY'] !== (new OperatingSystem)->getFamily()) {
+ $missing[] = sprintf('Operating system %s is required.', $required['OSFAMILY']);
+ $hint = $hint ?? 'OSFAMILY';
+ }
+
+ if (!empty($required['OS'])) {
+ $requiredOsPattern = sprintf('/%s/i', addcslashes($required['OS'], '/'));
+
+ if (!preg_match($requiredOsPattern, PHP_OS)) {
+ $missing[] = sprintf('Operating system matching %s is required.', $requiredOsPattern);
+ $hint = $hint ?? 'OS';
+ }
+ }
+
+ if (!empty($required['functions'])) {
+ foreach ($required['functions'] as $function) {
+ $pieces = explode('::', $function);
+
+ if (count($pieces) === 2 && class_exists($pieces[0]) && method_exists($pieces[0], $pieces[1])) {
+ continue;
+ }
+
+ if (function_exists($function)) {
+ continue;
+ }
+
+ $missing[] = sprintf('Function %s is required.', $function);
+ $hint = $hint ?? 'function_' . $function;
+ }
+ }
+
+ if (!empty($required['setting'])) {
+ foreach ($required['setting'] as $setting => $value) {
+ if (ini_get($setting) !== $value) {
+ $missing[] = sprintf('Setting "%s" must be "%s".', $setting, $value);
+ $hint = $hint ?? '__SETTING_' . $setting;
+ }
+ }
+ }
+
+ if (!empty($required['extensions'])) {
+ foreach ($required['extensions'] as $extension) {
+ if (isset($required['extension_versions'][$extension])) {
+ continue;
+ }
+
+ if (!extension_loaded($extension)) {
+ $missing[] = sprintf('Extension %s is required.', $extension);
+ $hint = $hint ?? 'extension_' . $extension;
+ }
+ }
+ }
+
+ if (!empty($required['extension_versions'])) {
+ foreach ($required['extension_versions'] as $extension => $req) {
+ $actualVersion = phpversion($extension);
+
+ $operator = new VersionComparisonOperator(empty($req['operator']) ? '>=' : $req['operator']);
+
+ if ($actualVersion === false || !version_compare($actualVersion, $req['version'], $operator->asString())) {
+ $missing[] = sprintf('Extension %s %s %s is required.', $extension, $operator->asString(), $req['version']);
+ $hint = $hint ?? 'extension_' . $extension;
+ }
+ }
+ }
+
+ if ($hint && isset($required['__OFFSET'])) {
+ array_unshift($missing, '__OFFSET_FILE=' . $required['__OFFSET']['__FILE']);
+ array_unshift($missing, '__OFFSET_LINE=' . ($required['__OFFSET'][$hint] ?? 1));
+ }
+
+ return $missing;
+ }
+
+ /**
+ * Returns the provided data for a method.
+ *
+ * @throws Exception
+ * @psalm-param class-string $className
+ */
+ public static function getProvidedData(string $className, string $methodName): ?array
+ {
+ return Registry::getInstance()->forMethod($className, $methodName)->getProvidedData();
+ }
+
+ /**
+ * @psalm-param class-string $className
+ */
+ public static function parseTestMethodAnnotations(string $className, ?string $methodName = ''): array
+ {
+ $registry = Registry::getInstance();
+
+ if ($methodName !== null) {
+ try {
+ return [
+ 'method' => $registry->forMethod($className, $methodName)->symbolAnnotations(),
+ 'class' => $registry->forClassName($className)->symbolAnnotations(),
+ ];
+ } catch (Exception $methodNotFound) {
+ // ignored
+ }
+ }
+
+ return [
+ 'method' => null,
+ 'class' => $registry->forClassName($className)->symbolAnnotations(),
+ ];
+ }
+
+ /**
+ * @psalm-param class-string $className
+ */
+ public static function getInlineAnnotations(string $className, string $methodName): array
+ {
+ return Registry::getInstance()->forMethod($className, $methodName)->getInlineAnnotations();
+ }
+
+ /** @psalm-param class-string $className */
+ public static function getBackupSettings(string $className, string $methodName): array
+ {
+ return [
+ 'backupGlobals' => self::getBooleanAnnotationSetting(
+ $className,
+ $methodName,
+ 'backupGlobals'
+ ),
+ 'backupStaticAttributes' => self::getBooleanAnnotationSetting(
+ $className,
+ $methodName,
+ 'backupStaticAttributes'
+ ),
+ ];
+ }
+
+ /**
+ * @psalm-param class-string $className
+ *
+ * @return ExecutionOrderDependency[]
+ */
+ public static function getDependencies(string $className, string $methodName): array
+ {
+ $annotations = self::parseTestMethodAnnotations(
+ $className,
+ $methodName
+ );
+
+ $dependsAnnotations = $annotations['class']['depends'] ?? [];
+
+ if (isset($annotations['method']['depends'])) {
+ $dependsAnnotations = array_merge(
+ $dependsAnnotations,
+ $annotations['method']['depends']
+ );
+ }
+
+ // Normalize dependency name to className::methodName
+ $dependencies = [];
+
+ foreach ($dependsAnnotations as $value) {
+ $dependencies[] = ExecutionOrderDependency::createFromDependsAnnotation($className, $value);
+ }
+
+ return array_unique($dependencies);
+ }
+
+ /** @psalm-param class-string $className */
+ public static function getGroups(string $className, ?string $methodName = ''): array
+ {
+ $annotations = self::parseTestMethodAnnotations(
+ $className,
+ $methodName
+ );
+
+ $groups = [];
+
+ if (isset($annotations['method']['author'])) {
+ $groups[] = $annotations['method']['author'];
+ } elseif (isset($annotations['class']['author'])) {
+ $groups[] = $annotations['class']['author'];
+ }
+
+ if (isset($annotations['class']['group'])) {
+ $groups[] = $annotations['class']['group'];
+ }
+
+ if (isset($annotations['method']['group'])) {
+ $groups[] = $annotations['method']['group'];
+ }
+
+ if (isset($annotations['class']['ticket'])) {
+ $groups[] = $annotations['class']['ticket'];
+ }
+
+ if (isset($annotations['method']['ticket'])) {
+ $groups[] = $annotations['method']['ticket'];
+ }
+
+ foreach (['method', 'class'] as $element) {
+ foreach (['small', 'medium', 'large'] as $size) {
+ if (isset($annotations[$element][$size])) {
+ $groups[] = [$size];
+
+ break 2;
+ }
+ }
+ }
+
+ foreach (['method', 'class'] as $element) {
+ if (isset($annotations[$element]['covers'])) {
+ foreach ($annotations[$element]['covers'] as $coversTarget) {
+ $groups[] = ['__phpunit_covers_' . self::canonicalizeName($coversTarget)];
+ }
+ }
+
+ if (isset($annotations[$element]['uses'])) {
+ foreach ($annotations[$element]['uses'] as $usesTarget) {
+ $groups[] = ['__phpunit_uses_' . self::canonicalizeName($usesTarget)];
+ }
+ }
+ }
+
+ return array_unique(array_merge([], ...$groups));
+ }
+
+ /** @psalm-param class-string $className */
+ public static function getSize(string $className, ?string $methodName): int
+ {
+ $groups = array_flip(self::getGroups($className, $methodName));
+
+ if (isset($groups['large'])) {
+ return self::LARGE;
+ }
+
+ if (isset($groups['medium'])) {
+ return self::MEDIUM;
+ }
+
+ if (isset($groups['small'])) {
+ return self::SMALL;
+ }
+
+ return self::UNKNOWN;
+ }
+
+ /** @psalm-param class-string $className */
+ public static function getProcessIsolationSettings(string $className, string $methodName): bool
+ {
+ $annotations = self::parseTestMethodAnnotations(
+ $className,
+ $methodName
+ );
+
+ return isset($annotations['class']['runTestsInSeparateProcesses']) || isset($annotations['method']['runInSeparateProcess']);
+ }
+
+ /** @psalm-param class-string $className */
+ public static function getClassProcessIsolationSettings(string $className, string $methodName): bool
+ {
+ $annotations = self::parseTestMethodAnnotations(
+ $className,
+ $methodName
+ );
+
+ return isset($annotations['class']['runClassInSeparateProcess']);
+ }
+
+ /** @psalm-param class-string $className */
+ public static function getPreserveGlobalStateSettings(string $className, string $methodName): ?bool
+ {
+ return self::getBooleanAnnotationSetting(
+ $className,
+ $methodName,
+ 'preserveGlobalState'
+ );
+ }
+
+ /** @psalm-param class-string $className */
+ public static function getHookMethods(string $className): array
+ {
+ if (!class_exists($className, false)) {
+ return self::emptyHookMethodsArray();
+ }
+
+ if (!isset(self::$hookMethods[$className])) {
+ self::$hookMethods[$className] = self::emptyHookMethodsArray();
+
+ try {
+ foreach ((new ReflectionClass($className))->getMethods() as $method) {
+ if ($method->getDeclaringClass()->getName() === Assert::class) {
+ continue;
+ }
+
+ if ($method->getDeclaringClass()->getName() === TestCase::class) {
+ continue;
+ }
+
+ $docBlock = Registry::getInstance()->forMethod($className, $method->getName());
+
+ if ($method->isStatic()) {
+ if ($docBlock->isHookToBeExecutedBeforeClass()) {
+ array_unshift(
+ self::$hookMethods[$className]['beforeClass'],
+ $method->getName()
+ );
+ }
+
+ if ($docBlock->isHookToBeExecutedAfterClass()) {
+ self::$hookMethods[$className]['afterClass'][] = $method->getName();
+ }
+ }
+
+ if ($docBlock->isToBeExecutedBeforeTest()) {
+ array_unshift(
+ self::$hookMethods[$className]['before'],
+ $method->getName()
+ );
+ }
+
+ if ($docBlock->isToBeExecutedAsPreCondition()) {
+ array_unshift(
+ self::$hookMethods[$className]['preCondition'],
+ $method->getName()
+ );
+ }
+
+ if ($docBlock->isToBeExecutedAsPostCondition()) {
+ self::$hookMethods[$className]['postCondition'][] = $method->getName();
+ }
+
+ if ($docBlock->isToBeExecutedAfterTest()) {
+ self::$hookMethods[$className]['after'][] = $method->getName();
+ }
+ }
+ } catch (ReflectionException $e) {
+ }
+ }
+
+ return self::$hookMethods[$className];
+ }
+
+ public static function isTestMethod(ReflectionMethod $method): bool
+ {
+ if (!$method->isPublic()) {
+ return false;
+ }
+
+ if (strpos($method->getName(), 'test') === 0) {
+ return true;
+ }
+
+ return array_key_exists(
+ 'test',
+ Registry::getInstance()->forMethod(
+ $method->getDeclaringClass()->getName(),
+ $method->getName()
+ )
+ ->symbolAnnotations()
+ );
+ }
+
+ /**
+ * @throws CodeCoverageException
+ * @psalm-param class-string $className
+ */
+ private static function getLinesToBeCoveredOrUsed(string $className, string $methodName, string $mode): array
+ {
+ $annotations = self::parseTestMethodAnnotations(
+ $className,
+ $methodName
+ );
+
+ $classShortcut = null;
+
+ if (!empty($annotations['class'][$mode . 'DefaultClass'])) {
+ if (count($annotations['class'][$mode . 'DefaultClass']) > 1) {
+ throw new CodeCoverageException(
+ sprintf(
+ 'More than one @%sClass annotation in class or interface "%s".',
+ $mode,
+ $className
+ )
+ );
+ }
+
+ $classShortcut = $annotations['class'][$mode . 'DefaultClass'][0];
+ }
+
+ $list = $annotations['class'][$mode] ?? [];
+
+ if (isset($annotations['method'][$mode])) {
+ $list = array_merge($list, $annotations['method'][$mode]);
+ }
+
+ $codeUnits = CodeUnitCollection::fromArray([]);
+ $mapper = new Mapper;
+
+ foreach (array_unique($list) as $element) {
+ if ($classShortcut && strncmp($element, '::', 2) === 0) {
+ $element = $classShortcut . $element;
+ }
+
+ $element = preg_replace('/[\s()]+$/', '', $element);
+ $element = explode(' ', $element);
+ $element = $element[0];
+
+ if ($mode === 'covers' && interface_exists($element)) {
+ throw new InvalidCoversTargetException(
+ sprintf(
+ 'Trying to @cover interface "%s".',
+ $element
+ )
+ );
+ }
+
+ try {
+ $codeUnits = $codeUnits->mergeWith($mapper->stringToCodeUnits($element));
+ } catch (InvalidCodeUnitException $e) {
+ throw new InvalidCoversTargetException(
+ sprintf(
+ '"@%s %s" is invalid',
+ $mode,
+ $element
+ ),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ }
+
+ return $mapper->codeUnitsToSourceLines($codeUnits);
+ }
+
+ private static function emptyHookMethodsArray(): array
+ {
+ return [
+ 'beforeClass' => ['setUpBeforeClass'],
+ 'before' => ['setUp'],
+ 'preCondition' => ['assertPreConditions'],
+ 'postCondition' => ['assertPostConditions'],
+ 'after' => ['tearDown'],
+ 'afterClass' => ['tearDownAfterClass'],
+ ];
+ }
+
+ /** @psalm-param class-string $className */
+ private static function getBooleanAnnotationSetting(string $className, ?string $methodName, string $settingName): ?bool
+ {
+ $annotations = self::parseTestMethodAnnotations(
+ $className,
+ $methodName
+ );
+
+ if (isset($annotations['method'][$settingName])) {
+ if ($annotations['method'][$settingName][0] === 'enabled') {
+ return true;
+ }
+
+ if ($annotations['method'][$settingName][0] === 'disabled') {
+ return false;
+ }
+ }
+
+ if (isset($annotations['class'][$settingName])) {
+ if ($annotations['class'][$settingName][0] === 'enabled') {
+ return true;
+ }
+
+ if ($annotations['class'][$settingName][0] === 'disabled') {
+ return false;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Trims any extensions from version string that follows after
+ * the <major>.<minor>[.<patch>] format.
+ */
+ private static function sanitizeVersionNumber(string $version)
+ {
+ return preg_replace(
+ '/^(\d+\.\d+(?:.\d+)?).*$/',
+ '$1',
+ $version
+ );
+ }
+
+ private static function shouldCoversAnnotationBeUsed(array $annotations): bool
+ {
+ if (isset($annotations['method']['coversNothing'])) {
+ return false;
+ }
+
+ if (isset($annotations['method']['covers'])) {
+ return true;
+ }
+
+ if (isset($annotations['class']['coversNothing'])) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Merge two arrays together.
+ *
+ * If an integer key exists in both arrays and preserveNumericKeys is false, the value
+ * from the second array will be appended to the first array. If both values are arrays, they
+ * are merged together, else the value of the second array overwrites the one of the first array.
+ *
+ * This implementation is copied from https://github.com/zendframework/zend-stdlib/blob/76b653c5e99b40eccf5966e3122c90615134ae46/src/ArrayUtils.php
+ *
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @see http://github.com/zendframework/zf2 for the canonical source repository
+ *
+ * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+ private static function mergeArraysRecursively(array $a, array $b): array
+ {
+ foreach ($b as $key => $value) {
+ if (array_key_exists($key, $a)) {
+ if (is_int($key)) {
+ $a[] = $value;
+ } elseif (is_array($value) && is_array($a[$key])) {
+ $a[$key] = self::mergeArraysRecursively($a[$key], $value);
+ } else {
+ $a[$key] = $value;
+ }
+ } else {
+ $a[$key] = $value;
+ }
+ }
+
+ return $a;
+ }
+
+ private static function canonicalizeName(string $name): string
+ {
+ return strtolower(trim($name, '\\'));
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php b/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php
new file mode 100644
index 000000000..def16c398
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php
@@ -0,0 +1,381 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\TestDox;
+
+use const PHP_EOL;
+use function array_map;
+use function ceil;
+use function count;
+use function explode;
+use function get_class;
+use function implode;
+use function preg_match;
+use function sprintf;
+use function strlen;
+use function strpos;
+use function trim;
+use PHPUnit\Framework\Test;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestResult;
+use PHPUnit\Runner\BaseTestRunner;
+use PHPUnit\Runner\PhptTestCase;
+use PHPUnit\Util\Color;
+use SebastianBergmann\Timer\ResourceUsageFormatter;
+use SebastianBergmann\Timer\Timer;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class CliTestDoxPrinter extends TestDoxPrinter
+{
+ /**
+ * The default Testdox left margin for messages is a vertical line.
+ */
+ private const PREFIX_SIMPLE = [
+ 'default' => '│',
+ 'start' => '│',
+ 'message' => '│',
+ 'diff' => '│',
+ 'trace' => '│',
+ 'last' => '│',
+ ];
+
+ /**
+ * Colored Testdox use box-drawing for a more textured map of the message.
+ */
+ private const PREFIX_DECORATED = [
+ 'default' => '│',
+ 'start' => '┐',
+ 'message' => '├',
+ 'diff' => '┊',
+ 'trace' => '╵',
+ 'last' => '┴',
+ ];
+
+ private const SPINNER_ICONS = [
+ " \e[36m◐\e[0m running tests",
+ " \e[36m◓\e[0m running tests",
+ " \e[36m◑\e[0m running tests",
+ " \e[36m◒\e[0m running tests",
+ ];
+
+ private const STATUS_STYLES = [
+ BaseTestRunner::STATUS_PASSED => [
+ 'symbol' => '✔',
+ 'color' => 'fg-green',
+ ],
+ BaseTestRunner::STATUS_ERROR => [
+ 'symbol' => '✘',
+ 'color' => 'fg-yellow',
+ 'message' => 'bg-yellow,fg-black',
+ ],
+ BaseTestRunner::STATUS_FAILURE => [
+ 'symbol' => '✘',
+ 'color' => 'fg-red',
+ 'message' => 'bg-red,fg-white',
+ ],
+ BaseTestRunner::STATUS_SKIPPED => [
+ 'symbol' => '↩',
+ 'color' => 'fg-cyan',
+ 'message' => 'fg-cyan',
+ ],
+ BaseTestRunner::STATUS_RISKY => [
+ 'symbol' => '☢',
+ 'color' => 'fg-yellow',
+ 'message' => 'fg-yellow',
+ ],
+ BaseTestRunner::STATUS_INCOMPLETE => [
+ 'symbol' => '∅',
+ 'color' => 'fg-yellow',
+ 'message' => 'fg-yellow',
+ ],
+ BaseTestRunner::STATUS_WARNING => [
+ 'symbol' => '⚠',
+ 'color' => 'fg-yellow',
+ 'message' => 'fg-yellow',
+ ],
+ BaseTestRunner::STATUS_UNKNOWN => [
+ 'symbol' => '?',
+ 'color' => 'fg-blue',
+ 'message' => 'fg-white,bg-blue',
+ ],
+ ];
+
+ /**
+ * @var int[]
+ */
+ private $nonSuccessfulTestResults = [];
+
+ /**
+ * @var Timer
+ */
+ private $timer;
+
+ /**
+ * @param null|resource|string $out
+ * @param int|string $numberOfColumns
+ *
+ * @throws \PHPUnit\Framework\Exception
+ */
+ public function __construct($out = null, bool $verbose = false, string $colors = self::COLOR_DEFAULT, bool $debug = false, $numberOfColumns = 80, bool $reverse = false)
+ {
+ parent::__construct($out, $verbose, $colors, $debug, $numberOfColumns, $reverse);
+
+ $this->timer = new Timer;
+
+ $this->timer->start();
+ }
+
+ public function printResult(TestResult $result): void
+ {
+ $this->printHeader($result);
+
+ $this->printNonSuccessfulTestsSummary($result->count());
+
+ $this->printFooter($result);
+ }
+
+ protected function printHeader(TestResult $result): void
+ {
+ $this->write("\n" . (new ResourceUsageFormatter)->resourceUsage($this->timer->stop()) . "\n\n");
+ }
+
+ protected function formatClassName(Test $test): string
+ {
+ if ($test instanceof TestCase) {
+ return $this->prettifier->prettifyTestClass(get_class($test));
+ }
+
+ return get_class($test);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function registerTestResult(Test $test, ?Throwable $t, int $status, float $time, bool $verbose): void
+ {
+ if ($status !== BaseTestRunner::STATUS_PASSED) {
+ $this->nonSuccessfulTestResults[] = $this->testIndex;
+ }
+
+ parent::registerTestResult($test, $t, $status, $time, $verbose);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function formatTestName(Test $test): string
+ {
+ if ($test instanceof TestCase) {
+ return $this->prettifier->prettifyTestCase($test);
+ }
+
+ return parent::formatTestName($test);
+ }
+
+ protected function writeTestResult(array $prevResult, array $result): void
+ {
+ // spacer line for new suite headers and after verbose messages
+ if ($prevResult['testName'] !== '' &&
+ (!empty($prevResult['message']) || $prevResult['className'] !== $result['className'])) {
+ $this->write(PHP_EOL);
+ }
+
+ // suite header
+ if ($prevResult['className'] !== $result['className']) {
+ $this->write($this->colorizeTextBox('underlined', $result['className']) . PHP_EOL);
+ }
+
+ // test result line
+ if ($this->colors && $result['className'] === PhptTestCase::class) {
+ $testName = Color::colorizePath($result['testName'], $prevResult['testName'], true);
+ } else {
+ $testName = $result['testMethod'];
+ }
+
+ $style = self::STATUS_STYLES[$result['status']];
+ $line = sprintf(
+ ' %s %s%s' . PHP_EOL,
+ $this->colorizeTextBox($style['color'], $style['symbol']),
+ $testName,
+ $this->verbose ? ' ' . $this->formatRuntime($result['time'], $style['color']) : ''
+ );
+
+ $this->write($line);
+
+ // additional information when verbose
+ $this->write($result['message']);
+ }
+
+ protected function formatThrowable(Throwable $t, ?int $status = null): string
+ {
+ return trim(\PHPUnit\Framework\TestFailure::exceptionToString($t));
+ }
+
+ protected function colorizeMessageAndDiff(string $style, string $buffer): array
+ {
+ $lines = $buffer ? 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 (strpos($line, '-') === 0) {
+ $line = Color::colorize('fg-red', Color::visualizeWhitespace($line, true));
+ } elseif (strpos($line, '+') === 0) {
+ $line = Color::colorize('fg-green', Color::visualizeWhitespace($line, true));
+ } elseif ($line === '@@ @@') {
+ $line = Color::colorize('fg-cyan', $line);
+ }
+ $diff[] = $line;
+ }
+ }
+ $diff = implode(PHP_EOL, $diff);
+
+ if (!empty($message)) {
+ $message = $this->colorizeTextBox($style, implode(PHP_EOL, $message));
+ }
+
+ return [$message, $diff];
+ }
+
+ protected function formatStacktrace(Throwable $t): string
+ {
+ $trace = \PHPUnit\Util\Filter::getFilteredStacktrace($t);
+
+ if (!$this->colors) {
+ return $trace;
+ }
+
+ $lines = [];
+ $prevPath = '';
+
+ foreach (explode(PHP_EOL, $trace) as $line) {
+ if (preg_match('/^(.*):(\d+)$/', $line, $matches)) {
+ $lines[] = Color::colorizePath($matches[1], $prevPath) .
+ Color::dim(':') .
+ Color::colorize('fg-blue', $matches[2]) .
+ "\n";
+ $prevPath = $matches[1];
+ } else {
+ $lines[] = $line;
+ $prevPath = '';
+ }
+ }
+
+ return implode('', $lines);
+ }
+
+ protected function formatTestResultMessage(Throwable $t, array $result, ?string $prefix = null): string
+ {
+ $message = $this->formatThrowable($t, $result['status']);
+ $diff = '';
+
+ if (!($this->verbose || $result['verbose'])) {
+ return '';
+ }
+
+ if ($message && $this->colors) {
+ $style = self::STATUS_STYLES[$result['status']]['message'] ?? '';
+ [$message, $diff] = $this->colorizeMessageAndDiff($style, $message);
+ }
+
+ if ($prefix === null || !$this->colors) {
+ $prefix = self::PREFIX_SIMPLE;
+ }
+
+ if ($this->colors) {
+ $color = self::STATUS_STYLES[$result['status']]['color'] ?? '';
+ $prefix = array_map(static function ($p) use ($color)
+ {
+ return Color::colorize($color, $p);
+ }, self::PREFIX_DECORATED);
+ }
+
+ $trace = $this->formatStacktrace($t);
+ $out = $this->prefixLines($prefix['start'], PHP_EOL) . PHP_EOL;
+
+ if ($message) {
+ $out .= $this->prefixLines($prefix['message'], $message . PHP_EOL) . PHP_EOL;
+ }
+
+ if ($diff) {
+ $out .= $this->prefixLines($prefix['diff'], $diff . PHP_EOL) . PHP_EOL;
+ }
+
+ if ($trace) {
+ if ($message || $diff) {
+ $out .= $this->prefixLines($prefix['default'], PHP_EOL) . PHP_EOL;
+ }
+ $out .= $this->prefixLines($prefix['trace'], $trace . PHP_EOL) . PHP_EOL;
+ }
+ $out .= $this->prefixLines($prefix['last'], PHP_EOL) . PHP_EOL;
+
+ return $out;
+ }
+
+ protected function drawSpinner(): void
+ {
+ if ($this->colors) {
+ $id = $this->spinState % count(self::SPINNER_ICONS);
+ $this->write(self::SPINNER_ICONS[$id]);
+ }
+ }
+
+ protected function undrawSpinner(): void
+ {
+ if ($this->colors) {
+ $id = $this->spinState % count(self::SPINNER_ICONS);
+ $this->write("\e[1K\e[" . strlen(self::SPINNER_ICONS[$id]) . 'D');
+ }
+ }
+
+ private function formatRuntime(float $time, string $color = ''): string
+ {
+ if (!$this->colors) {
+ return sprintf('[%.2f ms]', $time * 1000);
+ }
+
+ if ($time > 1) {
+ $color = 'fg-magenta';
+ }
+
+ return Color::colorize($color, ' ' . (int) ceil($time * 1000) . ' ' . Color::dim('ms'));
+ }
+
+ private function printNonSuccessfulTestsSummary(int $numberOfExecutedTests): void
+ {
+ if (empty($this->nonSuccessfulTestResults)) {
+ return;
+ }
+
+ if ((count($this->nonSuccessfulTestResults) / $numberOfExecutedTests) >= 0.7) {
+ return;
+ }
+
+ $this->write("Summary of non-successful tests:\n\n");
+
+ $prevResult = $this->getEmptyTestResult();
+
+ foreach ($this->nonSuccessfulTestResults as $testIndex) {
+ $result = $this->testResults[$testIndex];
+ $this->writeTestResult($prevResult, $result);
+ $prevResult = $result;
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/TestDox/HtmlResultPrinter.php b/vendor/phpunit/phpunit/src/Util/TestDox/HtmlResultPrinter.php
new file mode 100644
index 000000000..013d1de81
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/TestDox/HtmlResultPrinter.php
@@ -0,0 +1,140 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\TestDox;
+
+use function sprintf;
+use PHPUnit\Framework\TestResult;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class HtmlResultPrinter extends ResultPrinter
+{
+ /**
+ * @var string
+ */
+ private const PAGE_HEADER = <<<'EOT'
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8"/>
+ <title>Test Documentation</title>
+ <style>
+ body {
+ text-rendering: optimizeLegibility;
+ font-variant-ligatures: common-ligatures;
+ font-kerning: normal;
+ margin-left: 2em;
+ background-color: #ffffff;
+ color: #000000;
+ }
+
+ body > ul > li {
+ font-family: Source Serif Pro, PT Sans, Trebuchet MS, Helvetica, Arial;
+ font-size: 2em;
+ }
+
+ h2 {
+ font-family: Tahoma, Helvetica, Arial;
+ font-size: 3em;
+ }
+
+ ul {
+ list-style: none;
+ margin-bottom: 1em;
+ }
+ </style>
+ </head>
+ <body>
+EOT;
+
+ /**
+ * @var string
+ */
+ private const CLASS_HEADER = <<<'EOT'
+
+ <h2 id="%s">%s</h2>
+ <ul>
+
+EOT;
+
+ /**
+ * @var string
+ */
+ private const CLASS_FOOTER = <<<'EOT'
+ </ul>
+EOT;
+
+ /**
+ * @var string
+ */
+ private const PAGE_FOOTER = <<<'EOT'
+
+ </body>
+</html>
+EOT;
+
+ public function printResult(TestResult $result): void
+ {
+ }
+
+ /**
+ * Handler for 'start run' event.
+ */
+ protected function startRun(): void
+ {
+ $this->write(self::PAGE_HEADER);
+ }
+
+ /**
+ * Handler for 'start class' event.
+ */
+ protected function startClass(string $name): void
+ {
+ $this->write(
+ sprintf(
+ self::CLASS_HEADER,
+ $name,
+ $this->currentTestClassPrettified
+ )
+ );
+ }
+
+ /**
+ * Handler for 'on test' event.
+ */
+ protected function onTest(string $name, bool $success = true): void
+ {
+ $this->write(
+ sprintf(
+ " <li style=\"color: %s;\">%s %s</li>\n",
+ $success ? '#555753' : '#ef2929',
+ $success ? '✓' : '❌',
+ $name
+ )
+ );
+ }
+
+ /**
+ * Handler for 'end class' event.
+ */
+ protected function endClass(string $name): void
+ {
+ $this->write(self::CLASS_FOOTER);
+ }
+
+ /**
+ * Handler for 'end run' event.
+ */
+ protected function endRun(): void
+ {
+ $this->write(self::PAGE_FOOTER);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/TestDox/NamePrettifier.php b/vendor/phpunit/phpunit/src/Util/TestDox/NamePrettifier.php
new file mode 100644
index 000000000..d2808a83e
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/TestDox/NamePrettifier.php
@@ -0,0 +1,312 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\TestDox;
+
+use function array_key_exists;
+use function array_keys;
+use function array_map;
+use function array_pop;
+use function array_values;
+use function explode;
+use function get_class;
+use function gettype;
+use function implode;
+use function in_array;
+use function is_bool;
+use function is_float;
+use function is_int;
+use function is_numeric;
+use function is_object;
+use function is_scalar;
+use function is_string;
+use function ord;
+use function preg_quote;
+use function preg_replace;
+use function range;
+use function sprintf;
+use function str_replace;
+use function strlen;
+use function strpos;
+use function strtolower;
+use function strtoupper;
+use function substr;
+use function trim;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Util\Color;
+use PHPUnit\Util\Exception as UtilException;
+use PHPUnit\Util\Test;
+use ReflectionException;
+use ReflectionMethod;
+use ReflectionObject;
+use SebastianBergmann\Exporter\Exporter;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class NamePrettifier
+{
+ /**
+ * @var string[]
+ */
+ private $strings = [];
+
+ /**
+ * @var bool
+ */
+ private $useColor;
+
+ public function __construct(bool $useColor = false)
+ {
+ $this->useColor = $useColor;
+ }
+
+ /**
+ * Prettifies the name of a test class.
+ *
+ * @psalm-param class-string $className
+ */
+ public function prettifyTestClass(string $className): string
+ {
+ try {
+ $annotations = Test::parseTestMethodAnnotations($className);
+
+ if (isset($annotations['class']['testdox'][0])) {
+ return $annotations['class']['testdox'][0];
+ }
+ } catch (UtilException $e) {
+ // ignore, determine className by parsing the provided name
+ }
+
+ $parts = explode('\\', $className);
+ $className = array_pop($parts);
+
+ if (substr($className, -1 * strlen('Test')) === 'Test') {
+ $className = substr($className, 0, strlen($className) - strlen('Test'));
+ }
+
+ if (strpos($className, 'Tests') === 0) {
+ $className = substr($className, strlen('Tests'));
+ } elseif (strpos($className, 'Test') === 0) {
+ $className = substr($className, strlen('Test'));
+ }
+
+ if (empty($className)) {
+ $className = 'UnnamedTests';
+ }
+
+ if (!empty($parts)) {
+ $parts[] = $className;
+ $fullyQualifiedName = implode('\\', $parts);
+ } else {
+ $fullyQualifiedName = $className;
+ }
+
+ $result = preg_replace('/(?<=[[:lower:]])(?=[[:upper:]])/u', ' ', $className);
+
+ if ($fullyQualifiedName !== $className) {
+ return $result . ' (' . $fullyQualifiedName . ')';
+ }
+
+ return $result;
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function prettifyTestCase(TestCase $test): string
+ {
+ $annotations = Test::parseTestMethodAnnotations(
+ get_class($test),
+ $test->getName(false)
+ );
+
+ $annotationWithPlaceholders = false;
+
+ $callback = static function (string $variable): string
+ {
+ return sprintf('/%s(?=\b)/', preg_quote($variable, '/'));
+ };
+
+ if (isset($annotations['method']['testdox'][0])) {
+ $result = $annotations['method']['testdox'][0];
+
+ if (strpos($result, '$') !== false) {
+ $annotation = $annotations['method']['testdox'][0];
+ $providedData = $this->mapTestMethodParameterNamesToProvidedDataValues($test);
+ $variables = array_map($callback, array_keys($providedData));
+
+ $result = trim(preg_replace($variables, $providedData, $annotation));
+
+ $annotationWithPlaceholders = true;
+ }
+ } else {
+ $result = $this->prettifyTestMethod($test->getName(false));
+ }
+
+ if (!$annotationWithPlaceholders && $test->usesDataProvider()) {
+ $result .= $this->prettifyDataSet($test);
+ }
+
+ return $result;
+ }
+
+ public function prettifyDataSet(TestCase $test): string
+ {
+ if (!$this->useColor) {
+ return $test->getDataSetAsString(false);
+ }
+
+ if (is_int($test->dataName())) {
+ $data = Color::dim(' with data set ') . Color::colorize('fg-cyan', (string) $test->dataName());
+ } else {
+ $data = Color::dim(' with ') . Color::colorize('fg-cyan', Color::visualizeWhitespace((string) $test->dataName()));
+ }
+
+ return $data;
+ }
+
+ /**
+ * Prettifies the name of a test method.
+ */
+ public function prettifyTestMethod(string $name): string
+ {
+ $buffer = '';
+
+ if ($name === '') {
+ return $buffer;
+ }
+
+ $string = (string) preg_replace('#\d+$#', '', $name, -1, $count);
+
+ if (in_array($string, $this->strings, true)) {
+ $name = $string;
+ } elseif ($count === 0) {
+ $this->strings[] = $string;
+ }
+
+ if (strpos($name, 'test_') === 0) {
+ $name = substr($name, 5);
+ } elseif (strpos($name, 'test') === 0) {
+ $name = substr($name, 4);
+ }
+
+ if ($name === '') {
+ return $buffer;
+ }
+
+ $name[0] = strtoupper($name[0]);
+
+ if (strpos($name, '_') !== false) {
+ return trim(str_replace('_', ' ', $name));
+ }
+
+ $wasNumeric = false;
+
+ foreach (range(0, strlen($name) - 1) as $i) {
+ if ($i > 0 && ord($name[$i]) >= 65 && ord($name[$i]) <= 90) {
+ $buffer .= ' ' . strtolower($name[$i]);
+ } else {
+ $isNumeric = is_numeric($name[$i]);
+
+ if (!$wasNumeric && $isNumeric) {
+ $buffer .= ' ';
+ $wasNumeric = true;
+ }
+
+ if ($wasNumeric && !$isNumeric) {
+ $wasNumeric = false;
+ }
+
+ $buffer .= $name[$i];
+ }
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ private function mapTestMethodParameterNamesToProvidedDataValues(TestCase $test): array
+ {
+ try {
+ $reflector = new ReflectionMethod(get_class($test), $test->getName(false));
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new UtilException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ $providedData = [];
+ $providedDataValues = array_values($test->getProvidedData());
+ $i = 0;
+
+ $providedData['$_dataName'] = $test->dataName();
+
+ foreach ($reflector->getParameters() as $parameter) {
+ if (!array_key_exists($i, $providedDataValues) && $parameter->isDefaultValueAvailable()) {
+ try {
+ $providedDataValues[$i] = $parameter->getDefaultValue();
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new UtilException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ $value = $providedDataValues[$i++] ?? null;
+
+ if (is_object($value)) {
+ $reflector = new ReflectionObject($value);
+
+ if ($reflector->hasMethod('__toString')) {
+ $value = (string) $value;
+ } else {
+ $value = get_class($value);
+ }
+ }
+
+ if (!is_scalar($value)) {
+ $value = gettype($value);
+ }
+
+ if (is_bool($value) || is_int($value) || is_float($value)) {
+ $value = (new Exporter)->export($value);
+ }
+
+ if (is_string($value) && $value === '') {
+ if ($this->useColor) {
+ $value = Color::colorize('dim,underlined', 'empty');
+ } else {
+ $value = "''";
+ }
+ }
+
+ $providedData['$' . $parameter->getName()] = $value;
+ }
+
+ if ($this->useColor) {
+ $providedData = array_map(static function ($value)
+ {
+ return Color::colorize('fg-cyan', Color::visualizeWhitespace((string) $value, true));
+ }, $providedData);
+ }
+
+ return $providedData;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php b/vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php
new file mode 100644
index 000000000..c4b63644f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php
@@ -0,0 +1,343 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\TestDox;
+
+use function get_class;
+use function in_array;
+use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\ErrorTestCase;
+use PHPUnit\Framework\Test;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Framework\Warning;
+use PHPUnit\Framework\WarningTestCase;
+use PHPUnit\Runner\BaseTestRunner;
+use PHPUnit\TextUI\ResultPrinter as ResultPrinterInterface;
+use PHPUnit\Util\Printer;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+abstract class ResultPrinter extends Printer implements ResultPrinterInterface
+{
+ /**
+ * @var NamePrettifier
+ */
+ protected $prettifier;
+
+ /**
+ * @var string
+ */
+ protected $testClass = '';
+
+ /**
+ * @var int
+ */
+ protected $testStatus;
+
+ /**
+ * @var array
+ */
+ protected $tests = [];
+
+ /**
+ * @var int
+ */
+ protected $successful = 0;
+
+ /**
+ * @var int
+ */
+ protected $warned = 0;
+
+ /**
+ * @var int
+ */
+ protected $failed = 0;
+
+ /**
+ * @var int
+ */
+ protected $risky = 0;
+
+ /**
+ * @var int
+ */
+ protected $skipped = 0;
+
+ /**
+ * @var int
+ */
+ protected $incomplete = 0;
+
+ /**
+ * @var null|string
+ */
+ protected $currentTestClassPrettified;
+
+ /**
+ * @var null|string
+ */
+ protected $currentTestMethodPrettified;
+
+ /**
+ * @var array
+ */
+ private $groups;
+
+ /**
+ * @var array
+ */
+ private $excludeGroups;
+
+ /**
+ * @param resource $out
+ *
+ * @throws \PHPUnit\Framework\Exception
+ */
+ public function __construct($out = null, array $groups = [], array $excludeGroups = [])
+ {
+ parent::__construct($out);
+
+ $this->groups = $groups;
+ $this->excludeGroups = $excludeGroups;
+
+ $this->prettifier = new NamePrettifier;
+ $this->startRun();
+ }
+
+ /**
+ * Flush buffer and close output.
+ */
+ public function flush(): void
+ {
+ $this->doEndClass();
+ $this->endRun();
+
+ parent::flush();
+ }
+
+ /**
+ * An error occurred.
+ */
+ public function addError(Test $test, Throwable $t, float $time): void
+ {
+ if (!$this->isOfInterest($test)) {
+ return;
+ }
+
+ $this->testStatus = BaseTestRunner::STATUS_ERROR;
+ $this->failed++;
+ }
+
+ /**
+ * A warning occurred.
+ */
+ public function addWarning(Test $test, Warning $e, float $time): void
+ {
+ if (!$this->isOfInterest($test)) {
+ return;
+ }
+
+ $this->testStatus = BaseTestRunner::STATUS_WARNING;
+ $this->warned++;
+ }
+
+ /**
+ * A failure occurred.
+ */
+ public function addFailure(Test $test, AssertionFailedError $e, float $time): void
+ {
+ if (!$this->isOfInterest($test)) {
+ return;
+ }
+
+ $this->testStatus = BaseTestRunner::STATUS_FAILURE;
+ $this->failed++;
+ }
+
+ /**
+ * Incomplete test.
+ */
+ public function addIncompleteTest(Test $test, Throwable $t, float $time): void
+ {
+ if (!$this->isOfInterest($test)) {
+ return;
+ }
+
+ $this->testStatus = BaseTestRunner::STATUS_INCOMPLETE;
+ $this->incomplete++;
+ }
+
+ /**
+ * Risky test.
+ */
+ public function addRiskyTest(Test $test, Throwable $t, float $time): void
+ {
+ if (!$this->isOfInterest($test)) {
+ return;
+ }
+
+ $this->testStatus = BaseTestRunner::STATUS_RISKY;
+ $this->risky++;
+ }
+
+ /**
+ * Skipped test.
+ */
+ public function addSkippedTest(Test $test, Throwable $t, float $time): void
+ {
+ if (!$this->isOfInterest($test)) {
+ return;
+ }
+
+ $this->testStatus = BaseTestRunner::STATUS_SKIPPED;
+ $this->skipped++;
+ }
+
+ /**
+ * A testsuite started.
+ */
+ public function startTestSuite(TestSuite $suite): void
+ {
+ }
+
+ /**
+ * A testsuite ended.
+ */
+ public function endTestSuite(TestSuite $suite): void
+ {
+ }
+
+ /**
+ * A test started.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function startTest(Test $test): void
+ {
+ if (!$this->isOfInterest($test)) {
+ return;
+ }
+
+ $class = get_class($test);
+
+ if ($this->testClass !== $class) {
+ if ($this->testClass !== '') {
+ $this->doEndClass();
+ }
+
+ $this->currentTestClassPrettified = $this->prettifier->prettifyTestClass($class);
+ $this->testClass = $class;
+ $this->tests = [];
+
+ $this->startClass($class);
+ }
+
+ if ($test instanceof TestCase) {
+ $this->currentTestMethodPrettified = $this->prettifier->prettifyTestCase($test);
+ }
+
+ $this->testStatus = BaseTestRunner::STATUS_PASSED;
+ }
+
+ /**
+ * A test ended.
+ */
+ public function endTest(Test $test, float $time): void
+ {
+ if (!$this->isOfInterest($test)) {
+ return;
+ }
+
+ $this->tests[] = [$this->currentTestMethodPrettified, $this->testStatus];
+
+ $this->currentTestClassPrettified = null;
+ $this->currentTestMethodPrettified = null;
+ }
+
+ protected function doEndClass(): void
+ {
+ foreach ($this->tests as $test) {
+ $this->onTest($test[0], $test[1] === BaseTestRunner::STATUS_PASSED);
+ }
+
+ $this->endClass($this->testClass);
+ }
+
+ /**
+ * Handler for 'start run' event.
+ */
+ protected function startRun(): void
+ {
+ }
+
+ /**
+ * Handler for 'start class' event.
+ */
+ protected function startClass(string $name): void
+ {
+ }
+
+ /**
+ * Handler for 'on test' event.
+ */
+ protected function onTest(string $name, bool $success = true): void
+ {
+ }
+
+ /**
+ * Handler for 'end class' event.
+ */
+ protected function endClass(string $name): void
+ {
+ }
+
+ /**
+ * Handler for 'end run' event.
+ */
+ protected function endRun(): void
+ {
+ }
+
+ private function isOfInterest(Test $test): bool
+ {
+ if (!$test instanceof TestCase) {
+ return false;
+ }
+
+ if ($test instanceof ErrorTestCase || $test instanceof WarningTestCase) {
+ return false;
+ }
+
+ if (!empty($this->groups)) {
+ foreach ($test->getGroups() as $group) {
+ if (in_array($group, $this->groups, true)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ if (!empty($this->excludeGroups)) {
+ foreach ($test->getGroups() as $group) {
+ if (in_array($group, $this->excludeGroups, true)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return true;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php b/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php
new file mode 100644
index 000000000..bd64785c9
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php
@@ -0,0 +1,388 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\TestDox;
+
+use const PHP_EOL;
+use function array_map;
+use function get_class;
+use function implode;
+use function method_exists;
+use function preg_split;
+use function trim;
+use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\Reorderable;
+use PHPUnit\Framework\Test;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestResult;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Framework\Warning;
+use PHPUnit\Runner\BaseTestRunner;
+use PHPUnit\Runner\PhptTestCase;
+use PHPUnit\TextUI\DefaultResultPrinter;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+class TestDoxPrinter extends DefaultResultPrinter
+{
+ /**
+ * @var NamePrettifier
+ */
+ protected $prettifier;
+
+ /**
+ * @var int The number of test results received from the TestRunner
+ */
+ protected $testIndex = 0;
+
+ /**
+ * @var int The number of test results already sent to the output
+ */
+ protected $testFlushIndex = 0;
+
+ /**
+ * @var array<int, array> Buffer for test results
+ */
+ protected $testResults = [];
+
+ /**
+ * @var array<string, int> Lookup table for testname to testResults[index]
+ */
+ protected $testNameResultIndex = [];
+
+ /**
+ * @var bool
+ */
+ protected $enableOutputBuffer = false;
+
+ /**
+ * @var array array<string>
+ */
+ protected $originalExecutionOrder = [];
+
+ /**
+ * @var int
+ */
+ protected $spinState = 0;
+
+ /**
+ * @var bool
+ */
+ protected $showProgress = true;
+
+ /**
+ * @param null|resource|string $out
+ * @param int|string $numberOfColumns
+ *
+ * @throws \PHPUnit\Framework\Exception
+ */
+ public function __construct($out = null, bool $verbose = false, string $colors = self::COLOR_DEFAULT, bool $debug = false, $numberOfColumns = 80, bool $reverse = false)
+ {
+ parent::__construct($out, $verbose, $colors, $debug, $numberOfColumns, $reverse);
+
+ $this->prettifier = new NamePrettifier($this->colors);
+ }
+
+ public function setOriginalExecutionOrder(array $order): void
+ {
+ $this->originalExecutionOrder = $order;
+ $this->enableOutputBuffer = !empty($order);
+ }
+
+ public function setShowProgressAnimation(bool $showProgress): void
+ {
+ $this->showProgress = $showProgress;
+ }
+
+ public function printResult(TestResult $result): void
+ {
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function endTest(Test $test, float $time): void
+ {
+ if (!$test instanceof TestCase && !$test instanceof PhptTestCase && !$test instanceof TestSuite) {
+ return;
+ }
+
+ if ($this->testHasPassed()) {
+ $this->registerTestResult($test, null, BaseTestRunner::STATUS_PASSED, $time, false);
+ }
+
+ if ($test instanceof TestCase || $test instanceof PhptTestCase) {
+ $this->testIndex++;
+ }
+
+ parent::endTest($test, $time);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addError(Test $test, Throwable $t, float $time): void
+ {
+ $this->registerTestResult($test, $t, BaseTestRunner::STATUS_ERROR, $time, true);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addWarning(Test $test, Warning $e, float $time): void
+ {
+ $this->registerTestResult($test, $e, BaseTestRunner::STATUS_WARNING, $time, true);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addFailure(Test $test, AssertionFailedError $e, float $time): void
+ {
+ $this->registerTestResult($test, $e, BaseTestRunner::STATUS_FAILURE, $time, true);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addIncompleteTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->registerTestResult($test, $t, BaseTestRunner::STATUS_INCOMPLETE, $time, false);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addRiskyTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->registerTestResult($test, $t, BaseTestRunner::STATUS_RISKY, $time, false);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function addSkippedTest(Test $test, Throwable $t, float $time): void
+ {
+ $this->registerTestResult($test, $t, BaseTestRunner::STATUS_SKIPPED, $time, false);
+ }
+
+ public function writeProgress(string $progress): void
+ {
+ $this->flushOutputBuffer();
+ }
+
+ public function flush(): void
+ {
+ $this->flushOutputBuffer(true);
+ }
+
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ protected function registerTestResult(Test $test, ?Throwable $t, int $status, float $time, bool $verbose): void
+ {
+ $testName = $test instanceof Reorderable ? $test->sortId() : $test->getName();
+
+ $result = [
+ 'className' => $this->formatClassName($test),
+ 'testName' => $testName,
+ 'testMethod' => $this->formatTestName($test),
+ 'message' => '',
+ 'status' => $status,
+ 'time' => $time,
+ 'verbose' => $verbose,
+ ];
+
+ if ($t !== null) {
+ $result['message'] = $this->formatTestResultMessage($t, $result);
+ }
+
+ $this->testResults[$this->testIndex] = $result;
+ $this->testNameResultIndex[$testName] = $this->testIndex;
+ }
+
+ protected function formatTestName(Test $test): string
+ {
+ return method_exists($test, 'getName') ? $test->getName() : '';
+ }
+
+ protected function formatClassName(Test $test): string
+ {
+ return get_class($test);
+ }
+
+ protected function testHasPassed(): bool
+ {
+ if (!isset($this->testResults[$this->testIndex]['status'])) {
+ return true;
+ }
+
+ if ($this->testResults[$this->testIndex]['status'] === BaseTestRunner::STATUS_PASSED) {
+ return true;
+ }
+
+ return false;
+ }
+
+ protected function flushOutputBuffer(bool $forceFlush = false): void
+ {
+ if ($this->testFlushIndex === $this->testIndex) {
+ return;
+ }
+
+ if ($this->testFlushIndex > 0) {
+ if ($this->enableOutputBuffer &&
+ isset($this->originalExecutionOrder[$this->testFlushIndex - 1])) {
+ $prevResult = $this->getTestResultByName($this->originalExecutionOrder[$this->testFlushIndex - 1]);
+ } else {
+ $prevResult = $this->testResults[$this->testFlushIndex - 1];
+ }
+ } else {
+ $prevResult = $this->getEmptyTestResult();
+ }
+
+ if (!$this->enableOutputBuffer) {
+ $this->writeTestResult($prevResult, $this->testResults[$this->testFlushIndex++]);
+ } else {
+ do {
+ $flushed = false;
+
+ if (!$forceFlush && isset($this->originalExecutionOrder[$this->testFlushIndex])) {
+ $result = $this->getTestResultByName($this->originalExecutionOrder[$this->testFlushIndex]);
+ } else {
+ // This test(name) cannot found in original execution order,
+ // flush result to output stream right away
+ $result = $this->testResults[$this->testFlushIndex];
+ }
+
+ if (!empty($result)) {
+ $this->hideSpinner();
+ $this->writeTestResult($prevResult, $result);
+ $this->testFlushIndex++;
+ $prevResult = $result;
+ $flushed = true;
+ } else {
+ $this->showSpinner();
+ }
+ } while ($flushed && $this->testFlushIndex < $this->testIndex);
+ }
+ }
+
+ protected function showSpinner(): void
+ {
+ if (!$this->showProgress) {
+ return;
+ }
+
+ if ($this->spinState) {
+ $this->undrawSpinner();
+ }
+
+ $this->spinState++;
+ $this->drawSpinner();
+ }
+
+ protected function hideSpinner(): void
+ {
+ if (!$this->showProgress) {
+ return;
+ }
+
+ if ($this->spinState) {
+ $this->undrawSpinner();
+ }
+
+ $this->spinState = 0;
+ }
+
+ protected function drawSpinner(): void
+ {
+ // optional for CLI printers: show the user a 'buffering output' spinner
+ }
+
+ protected function undrawSpinner(): void
+ {
+ // remove the spinner from the current line
+ }
+
+ protected function writeTestResult(array $prevResult, array $result): void
+ {
+ }
+
+ protected function getEmptyTestResult(): array
+ {
+ return [
+ 'className' => '',
+ 'testName' => '',
+ 'message' => '',
+ 'failed' => '',
+ 'verbose' => '',
+ ];
+ }
+
+ protected function getTestResultByName(?string $testName): array
+ {
+ if (isset($this->testNameResultIndex[$testName])) {
+ return $this->testResults[$this->testNameResultIndex[$testName]];
+ }
+
+ return [];
+ }
+
+ protected function formatThrowable(Throwable $t, ?int $status = null): string
+ {
+ $message = trim(\PHPUnit\Framework\TestFailure::exceptionToString($t));
+
+ if ($message) {
+ $message .= PHP_EOL . PHP_EOL . $this->formatStacktrace($t);
+ } else {
+ $message = $this->formatStacktrace($t);
+ }
+
+ return $message;
+ }
+
+ protected function formatStacktrace(Throwable $t): string
+ {
+ return \PHPUnit\Util\Filter::getFilteredStacktrace($t);
+ }
+
+ protected function formatTestResultMessage(Throwable $t, array $result, string $prefix = '│'): string
+ {
+ $message = $this->formatThrowable($t, $result['status']);
+
+ if ($message === '') {
+ return '';
+ }
+
+ if (!($this->verbose || $result['verbose'])) {
+ return '';
+ }
+
+ return $this->prefixLines($prefix, $message);
+ }
+
+ protected function prefixLines(string $prefix, string $message): string
+ {
+ $message = trim($message);
+
+ return implode(
+ PHP_EOL,
+ array_map(
+ static function (string $text) use ($prefix)
+ {
+ return ' ' . $prefix . ($text ? ' ' . $text : '');
+ },
+ preg_split('/\r\n|\r|\n/', $message)
+ )
+ );
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/TestDox/TextResultPrinter.php b/vendor/phpunit/phpunit/src/Util/TestDox/TextResultPrinter.php
new file mode 100644
index 000000000..8a1893e55
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/TestDox/TextResultPrinter.php
@@ -0,0 +1,52 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\TestDox;
+
+use PHPUnit\Framework\TestResult;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TextResultPrinter extends ResultPrinter
+{
+ public function printResult(TestResult $result): void
+ {
+ }
+
+ /**
+ * Handler for 'start class' event.
+ */
+ protected function startClass(string $name): void
+ {
+ $this->write($this->currentTestClassPrettified . "\n");
+ }
+
+ /**
+ * Handler for 'on test' event.
+ */
+ protected function onTest(string $name, bool $success = true): void
+ {
+ if ($success) {
+ $this->write(' [x] ');
+ } else {
+ $this->write(' [ ] ');
+ }
+
+ $this->write($name . "\n");
+ }
+
+ /**
+ * Handler for 'end class' event.
+ */
+ protected function endClass(string $name): void
+ {
+ $this->write("\n");
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php b/vendor/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php
new file mode 100644
index 000000000..911604e06
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php
@@ -0,0 +1,261 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\TestDox;
+
+use function array_filter;
+use function get_class;
+use function implode;
+use function strpos;
+use DOMDocument;
+use DOMElement;
+use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\Exception;
+use PHPUnit\Framework\Test;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestListener;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Framework\Warning;
+use PHPUnit\Framework\WarningTestCase;
+use PHPUnit\Util\Printer;
+use PHPUnit\Util\Test as TestUtil;
+use ReflectionClass;
+use ReflectionException;
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class XmlResultPrinter extends Printer implements TestListener
+{
+ /**
+ * @var DOMDocument
+ */
+ private $document;
+
+ /**
+ * @var DOMElement
+ */
+ private $root;
+
+ /**
+ * @var NamePrettifier
+ */
+ private $prettifier;
+
+ /**
+ * @var null|Throwable
+ */
+ private $exception;
+
+ /**
+ * @param resource|string $out
+ *
+ * @throws Exception
+ */
+ public function __construct($out = null)
+ {
+ $this->document = new DOMDocument('1.0', 'UTF-8');
+ $this->document->formatOutput = true;
+
+ $this->root = $this->document->createElement('tests');
+ $this->document->appendChild($this->root);
+
+ $this->prettifier = new NamePrettifier;
+
+ parent::__construct($out);
+ }
+
+ /**
+ * Flush buffer and close output.
+ */
+ public function flush(): void
+ {
+ $this->write($this->document->saveXML());
+
+ parent::flush();
+ }
+
+ /**
+ * An error occurred.
+ */
+ public function addError(Test $test, Throwable $t, float $time): void
+ {
+ $this->exception = $t;
+ }
+
+ /**
+ * A warning occurred.
+ */
+ public function addWarning(Test $test, Warning $e, float $time): void
+ {
+ }
+
+ /**
+ * A failure occurred.
+ */
+ public function addFailure(Test $test, AssertionFailedError $e, float $time): void
+ {
+ $this->exception = $e;
+ }
+
+ /**
+ * Incomplete test.
+ */
+ public function addIncompleteTest(Test $test, Throwable $t, float $time): void
+ {
+ }
+
+ /**
+ * Risky test.
+ */
+ public function addRiskyTest(Test $test, Throwable $t, float $time): void
+ {
+ }
+
+ /**
+ * Skipped test.
+ */
+ public function addSkippedTest(Test $test, Throwable $t, float $time): void
+ {
+ }
+
+ /**
+ * A test suite started.
+ */
+ public function startTestSuite(TestSuite $suite): void
+ {
+ }
+
+ /**
+ * A test suite ended.
+ */
+ public function endTestSuite(TestSuite $suite): void
+ {
+ }
+
+ /**
+ * A test started.
+ */
+ public function startTest(Test $test): void
+ {
+ $this->exception = null;
+ }
+
+ /**
+ * A test ended.
+ *
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function endTest(Test $test, float $time): void
+ {
+ if (!$test instanceof TestCase || $test instanceof WarningTestCase) {
+ return;
+ }
+
+ $groups = array_filter(
+ $test->getGroups(),
+ static function ($group)
+ {
+ return !($group === 'small' || $group === 'medium' || $group === 'large' || strpos($group, '__phpunit_') === 0);
+ }
+ );
+
+ $testNode = $this->document->createElement('test');
+
+ $testNode->setAttribute('className', get_class($test));
+ $testNode->setAttribute('methodName', $test->getName());
+ $testNode->setAttribute('prettifiedClassName', $this->prettifier->prettifyTestClass(get_class($test)));
+ $testNode->setAttribute('prettifiedMethodName', $this->prettifier->prettifyTestCase($test));
+ $testNode->setAttribute('status', (string) $test->getStatus());
+ $testNode->setAttribute('time', (string) $time);
+ $testNode->setAttribute('size', (string) $test->getSize());
+ $testNode->setAttribute('groups', implode(',', $groups));
+
+ foreach ($groups as $group) {
+ $groupNode = $this->document->createElement('group');
+
+ $groupNode->setAttribute('name', $group);
+
+ $testNode->appendChild($groupNode);
+ }
+
+ $annotations = TestUtil::parseTestMethodAnnotations(
+ get_class($test),
+ $test->getName(false)
+ );
+
+ foreach (['class', 'method'] as $type) {
+ foreach ($annotations[$type] as $annotation => $values) {
+ if ($annotation !== 'covers' && $annotation !== 'uses') {
+ continue;
+ }
+
+ foreach ($values as $value) {
+ $coversNode = $this->document->createElement($annotation);
+
+ $coversNode->setAttribute('target', $value);
+
+ $testNode->appendChild($coversNode);
+ }
+ }
+ }
+
+ foreach ($test->doubledTypes() as $doubledType) {
+ $testDoubleNode = $this->document->createElement('testDouble');
+
+ $testDoubleNode->setAttribute('type', $doubledType);
+
+ $testNode->appendChild($testDoubleNode);
+ }
+
+ $inlineAnnotations = \PHPUnit\Util\Test::getInlineAnnotations(get_class($test), $test->getName(false));
+
+ if (isset($inlineAnnotations['given'], $inlineAnnotations['when'], $inlineAnnotations['then'])) {
+ $testNode->setAttribute('given', $inlineAnnotations['given']['value']);
+ $testNode->setAttribute('givenStartLine', (string) $inlineAnnotations['given']['line']);
+ $testNode->setAttribute('when', $inlineAnnotations['when']['value']);
+ $testNode->setAttribute('whenStartLine', (string) $inlineAnnotations['when']['line']);
+ $testNode->setAttribute('then', $inlineAnnotations['then']['value']);
+ $testNode->setAttribute('thenStartLine', (string) $inlineAnnotations['then']['line']);
+ }
+
+ if ($this->exception !== null) {
+ if ($this->exception instanceof Exception) {
+ $steps = $this->exception->getSerializableTrace();
+ } else {
+ $steps = $this->exception->getTrace();
+ }
+
+ try {
+ $file = (new ReflectionClass($test))->getFileName();
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+
+ foreach ($steps as $step) {
+ if (isset($step['file']) && $step['file'] === $file) {
+ $testNode->setAttribute('exceptionLine', (string) $step['line']);
+
+ break;
+ }
+ }
+
+ $testNode->setAttribute('exceptionMessage', $this->exception->getMessage());
+ }
+
+ $this->root->appendChild($testNode);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/TextTestListRenderer.php b/vendor/phpunit/phpunit/src/Util/TextTestListRenderer.php
new file mode 100644
index 000000000..67168a67f
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/TextTestListRenderer.php
@@ -0,0 +1,54 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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_EOL;
+use function get_class;
+use function sprintf;
+use function str_replace;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Runner\PhptTestCase;
+use RecursiveIteratorIterator;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class TextTestListRenderer
+{
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function render(TestSuite $suite): string
+ {
+ $buffer = 'Available test(s):' . PHP_EOL;
+
+ foreach (new RecursiveIteratorIterator($suite->getIterator()) as $test) {
+ if ($test instanceof TestCase) {
+ $name = sprintf(
+ '%s::%s',
+ get_class($test),
+ str_replace(' with data set ', '', $test->getName())
+ );
+ } elseif ($test instanceof PhptTestCase) {
+ $name = $test->getName();
+ } else {
+ continue;
+ }
+
+ $buffer .= sprintf(
+ ' - %s' . PHP_EOL,
+ $name
+ );
+ }
+
+ return $buffer;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Type.php b/vendor/phpunit/phpunit/src/Util/Type.php
new file mode 100644
index 000000000..01a6b1931
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Type.php
@@ -0,0 +1,52 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util;
+
+use Throwable;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Type
+{
+ public static function isType(string $type): bool
+ {
+ switch ($type) {
+ case 'numeric':
+ case 'integer':
+ case 'int':
+ case 'iterable':
+ case 'float':
+ case 'string':
+ case 'boolean':
+ case 'bool':
+ case 'null':
+ case 'array':
+ case 'object':
+ case 'resource':
+ case 'scalar':
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ public static function isCloneable(object $object): bool
+ {
+ try {
+ $clone = clone $object;
+ } catch (Throwable $t) {
+ return false;
+ }
+
+ return $clone instanceof $object;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/VersionComparisonOperator.php b/vendor/phpunit/phpunit/src/Util/VersionComparisonOperator.php
new file mode 100644
index 000000000..175ecd2d1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/VersionComparisonOperator.php
@@ -0,0 +1,57 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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;
+use function sprintf;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @psalm-immutable
+ */
+final class VersionComparisonOperator
+{
+ /**
+ * @psalm-var '<'|'lt'|'<='|'le'|'>'|'gt'|'>='|'ge'|'=='|'='|'eq'|'!='|'<>'|'ne'
+ */
+ private $operator;
+
+ 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;
+ }
+
+ /**
+ * @throws Exception
+ *
+ * @psalm-assert '<'|'lt'|'<='|'le'|'>'|'gt'|'>='|'ge'|'=='|'='|'eq'|'!='|'<>'|'ne' $operator
+ */
+ private function ensureOperatorIsValid(string $operator): void
+ {
+ if (!in_array($operator, ['<', 'lt', '<=', 'le', '>', 'gt', '>=', 'ge', '==', '=', 'eq', '!=', '<>', 'ne'], true)) {
+ throw new Exception(
+ sprintf(
+ '"%s" is not a valid version_compare() operator',
+ $operator
+ )
+ );
+ }
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/XdebugFilterScriptGenerator.php b/vendor/phpunit/phpunit/src/Util/XdebugFilterScriptGenerator.php
new file mode 100644
index 000000000..8b10d4152
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/XdebugFilterScriptGenerator.php
@@ -0,0 +1,81 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 addslashes;
+use function array_map;
+use function implode;
+use function is_string;
+use function realpath;
+use function sprintf;
+use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage as FilterConfiguration;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ *
+ * @deprecated
+ */
+final class XdebugFilterScriptGenerator
+{
+ public function generate(FilterConfiguration $filter): string
+ {
+ $files = array_map(
+ static function ($item)
+ {
+ return sprintf(
+ " '%s'",
+ $item
+ );
+ },
+ $this->getItems($filter)
+ );
+
+ $files = implode(",\n", $files);
+
+ return <<<EOF
+<?php declare(strict_types=1);
+if (!\\function_exists('xdebug_set_filter')) {
+ return;
+}
+
+\\xdebug_set_filter(
+ \\XDEBUG_FILTER_CODE_COVERAGE,
+ \\XDEBUG_PATH_WHITELIST,
+ [
+{$files}
+ ]
+);
+
+EOF;
+ }
+
+ private function getItems(FilterConfiguration $filter): array
+ {
+ $files = [];
+
+ foreach ($filter->directories() as $directory) {
+ $path = realpath($directory->path());
+
+ if (is_string($path)) {
+ $files[] = sprintf(
+ addslashes('%s' . DIRECTORY_SEPARATOR),
+ $path
+ );
+ }
+ }
+
+ foreach ($filter->files() as $file) {
+ $files[] = $file->path();
+ }
+
+ return $files;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Xml.php b/vendor/phpunit/phpunit/src/Util/Xml.php
new file mode 100644
index 000000000..0939e6c5b
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Xml.php
@@ -0,0 +1,193 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 class_exists;
+use function htmlspecialchars;
+use function mb_convert_encoding;
+use function ord;
+use function preg_replace;
+use function settype;
+use function strlen;
+use DOMCharacterData;
+use DOMDocument;
+use DOMElement;
+use DOMNode;
+use DOMText;
+use ReflectionClass;
+use ReflectionException;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Xml
+{
+ /**
+ * @deprecated Only used by assertEqualXMLStructure()
+ */
+ public static function import(DOMElement $element): DOMElement
+ {
+ return (new DOMDocument)->importNode($element, true);
+ }
+
+ /**
+ * @deprecated Only used by assertEqualXMLStructure()
+ */
+ public static function removeCharacterDataNodes(DOMNode $node): void
+ {
+ if ($node->hasChildNodes()) {
+ for ($i = $node->childNodes->length - 1; $i >= 0; $i--) {
+ if (($child = $node->childNodes->item($i)) instanceof DOMCharacterData) {
+ $node->removeChild($child);
+ }
+ }
+ }
+ }
+
+ /**
+ * 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
+ {
+ return preg_replace(
+ '/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/',
+ '',
+ htmlspecialchars(
+ self::convertToUtf8($string),
+ ENT_QUOTES
+ )
+ );
+ }
+
+ /**
+ * "Convert" a DOMElement object into a PHP variable.
+ */
+ public static function xmlToVariable(DOMElement $element)
+ {
+ $variable = null;
+
+ switch ($element->tagName) {
+ case 'array':
+ $variable = [];
+
+ foreach ($element->childNodes as $entry) {
+ if (!$entry instanceof DOMElement || $entry->tagName !== 'element') {
+ continue;
+ }
+ $item = $entry->childNodes->item(0);
+
+ if ($item instanceof DOMText) {
+ $item = $entry->childNodes->item(1);
+ }
+
+ $value = self::xmlToVariable($item);
+
+ if ($entry->hasAttribute('key')) {
+ $variable[(string) $entry->getAttribute('key')] = $value;
+ } else {
+ $variable[] = $value;
+ }
+ }
+
+ break;
+
+ case 'object':
+ $className = $element->getAttribute('class');
+
+ if ($element->hasChildNodes()) {
+ $arguments = $element->childNodes->item(0)->childNodes;
+ $constructorArgs = [];
+
+ foreach ($arguments as $argument) {
+ if ($argument instanceof DOMElement) {
+ $constructorArgs[] = self::xmlToVariable($argument);
+ }
+ }
+
+ try {
+ assert(class_exists($className));
+
+ $variable = (new ReflectionClass($className))->newInstanceArgs($constructorArgs);
+ // @codeCoverageIgnoreStart
+ } catch (ReflectionException $e) {
+ throw new Exception(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ } else {
+ $variable = new $className;
+ }
+
+ break;
+
+ case 'boolean':
+ $variable = $element->textContent === 'true';
+
+ break;
+
+ case 'integer':
+ case 'double':
+ case 'string':
+ $variable = $element->textContent;
+
+ settype($variable, $element->tagName);
+
+ break;
+ }
+
+ return $variable;
+ }
+
+ 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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Xml/Exception.php b/vendor/phpunit/phpunit/src/Util/Xml/Exception.php
new file mode 100644
index 000000000..09b73d8fa
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Xml/Exception.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\Xml;
+
+use RuntimeException;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Exception extends RuntimeException implements \PHPUnit\Exception
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Xml/FailedSchemaDetectionResult.php b/vendor/phpunit/phpunit/src/Util/Xml/FailedSchemaDetectionResult.php
new file mode 100644
index 000000000..0949f5684
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Xml/FailedSchemaDetectionResult.php
@@ -0,0 +1,19 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\Xml;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ *
+ * @psalm-immutable
+ */
+final class FailedSchemaDetectionResult extends SchemaDetectionResult
+{
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Xml/Loader.php b/vendor/phpunit/phpunit/src/Util/Xml/Loader.php
new file mode 100644
index 000000000..8d43d3278
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Xml/Loader.php
@@ -0,0 +1,117 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 chdir;
+use function dirname;
+use function error_reporting;
+use function file_get_contents;
+use function getcwd;
+use function libxml_get_errors;
+use function libxml_use_internal_errors;
+use function sprintf;
+use DOMDocument;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Loader
+{
+ /**
+ * @throws Exception
+ */
+ public function loadFile(string $filename, bool $isHtml = false, bool $xinclude = false, bool $strict = false): DOMDocument
+ {
+ $reporting = error_reporting(0);
+ $contents = file_get_contents($filename);
+
+ error_reporting($reporting);
+
+ if ($contents === false) {
+ throw new Exception(
+ sprintf(
+ 'Could not read "%s".',
+ $filename
+ )
+ );
+ }
+
+ return $this->load($contents, $isHtml, $filename, $xinclude, $strict);
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function load(string $actual, bool $isHtml = false, string $filename = '', bool $xinclude = false, bool $strict = false): DOMDocument
+ {
+ if ($actual === '') {
+ throw new Exception('Could not load XML from empty string');
+ }
+
+ // Required for XInclude on Windows.
+ if ($xinclude) {
+ $cwd = getcwd();
+ @chdir(dirname($filename));
+ }
+
+ $document = new DOMDocument;
+ $document->preserveWhiteSpace = false;
+
+ $internal = libxml_use_internal_errors(true);
+ $message = '';
+ $reporting = error_reporting(0);
+
+ if ($filename !== '') {
+ // Required for XInclude
+ $document->documentURI = $filename;
+ }
+
+ if ($isHtml) {
+ $loaded = $document->loadHTML($actual);
+ } else {
+ $loaded = $document->loadXML($actual);
+ }
+
+ if (!$isHtml && $xinclude) {
+ $document->xinclude();
+ }
+
+ foreach (libxml_get_errors() as $error) {
+ $message .= "\n" . $error->message;
+ }
+
+ libxml_use_internal_errors($internal);
+ error_reporting($reporting);
+
+ if (isset($cwd)) {
+ @chdir($cwd);
+ }
+
+ if ($loaded === false || ($strict && $message !== '')) {
+ if ($filename !== '') {
+ throw new Exception(
+ sprintf(
+ 'Could not load "%s".%s',
+ $filename,
+ $message !== '' ? "\n" . $message : ''
+ )
+ );
+ }
+
+ if ($message === '') {
+ $message = 'Could not load XML for unknown reason';
+ }
+
+ throw new Exception($message);
+ }
+
+ return $document;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Xml/SchemaDetectionResult.php b/vendor/phpunit/phpunit/src/Util/Xml/SchemaDetectionResult.php
new file mode 100644
index 000000000..442aae49c
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Xml/SchemaDetectionResult.php
@@ -0,0 +1,31 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\Xml;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ *
+ * @psalm-immutable
+ */
+abstract class SchemaDetectionResult
+{
+ public function detected(): bool
+ {
+ return false;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function version(): string
+ {
+ throw new Exception('No supported schema was detected');
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Xml/SchemaDetector.php b/vendor/phpunit/phpunit/src/Util/Xml/SchemaDetector.php
new file mode 100644
index 000000000..5864695b4
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Xml/SchemaDetector.php
@@ -0,0 +1,39 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\Xml;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class SchemaDetector
+{
+ /**
+ * @throws Exception
+ */
+ public function detect(string $filename): SchemaDetectionResult
+ {
+ $document = (new Loader)->loadFile(
+ $filename,
+ false,
+ true,
+ true
+ );
+
+ foreach (['9.2', '8.5'] as $candidate) {
+ $schema = (new SchemaFinder)->find($candidate);
+
+ if (!(new Validator)->validate($document, $schema)->hasValidationErrors()) {
+ return new SuccessfulSchemaDetectionResult($candidate);
+ }
+ }
+
+ return new FailedSchemaDetectionResult;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Xml/SchemaFinder.php b/vendor/phpunit/phpunit/src/Util/Xml/SchemaFinder.php
new file mode 100644
index 000000000..1e7b73c59
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Xml/SchemaFinder.php
@@ -0,0 +1,53 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 defined;
+use function is_file;
+use function sprintf;
+use PHPUnit\Runner\Version;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class SchemaFinder
+{
+ /**
+ * @throws Exception
+ */
+ 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 Exception(
+ 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__ . '/../../../';
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Xml/SnapshotNodeList.php b/vendor/phpunit/phpunit/src/Util/Xml/SnapshotNodeList.php
new file mode 100644
index 000000000..fdc95abb8
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Xml/SnapshotNodeList.php
@@ -0,0 +1,48 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\Xml;
+
+use ArrayIterator;
+use Countable;
+use DOMNode;
+use DOMNodeList;
+use IteratorAggregate;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class SnapshotNodeList implements Countable, IteratorAggregate
+{
+ /**
+ * @var DOMNode[]
+ */
+ private $nodes = [];
+
+ 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);
+ }
+
+ public function getIterator(): ArrayIterator
+ {
+ return new ArrayIterator($this->nodes);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Xml/SuccessfulSchemaDetectionResult.php b/vendor/phpunit/phpunit/src/Util/Xml/SuccessfulSchemaDetectionResult.php
new file mode 100644
index 000000000..8b517e29a
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Xml/SuccessfulSchemaDetectionResult.php
@@ -0,0 +1,38 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util\Xml;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ *
+ * @psalm-immutable
+ */
+final class SuccessfulSchemaDetectionResult extends SchemaDetectionResult
+{
+ /**
+ * @var string
+ */
+ private $version;
+
+ public function __construct(string $version)
+ {
+ $this->version = $version;
+ }
+
+ public function detected(): bool
+ {
+ return true;
+ }
+
+ public function version(): string
+ {
+ return $this->version;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Xml/ValidationResult.php b/vendor/phpunit/phpunit/src/Util/Xml/ValidationResult.php
new file mode 100644
index 000000000..3292267bd
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Xml/ValidationResult.php
@@ -0,0 +1,69 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 sprintf;
+use function trim;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ *
+ * @psalm-immutable
+ */
+final class ValidationResult
+{
+ /**
+ * @psalm-var array<int,list<string>>
+ */
+ private $validationErrors = [];
+
+ /**
+ * @psalm-param array<int,\LibXMLError> $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);
+ }
+
+ private function __construct(array $validationErrors)
+ {
+ $this->validationErrors = $validationErrors;
+ }
+
+ public function hasValidationErrors(): bool
+ {
+ return !empty($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;
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/Xml/Validator.php b/vendor/phpunit/phpunit/src/Util/Xml/Validator.php
new file mode 100644
index 000000000..b3c4e05b1
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/Xml/Validator.php
@@ -0,0 +1,35 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * 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 file_get_contents;
+use function libxml_clear_errors;
+use function libxml_get_errors;
+use function libxml_use_internal_errors;
+use DOMDocument;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class Validator
+{
+ public function validate(DOMDocument $document, string $xsdFilename): ValidationResult
+ {
+ $originalErrorHandling = libxml_use_internal_errors(true);
+
+ $document->schemaValidateSource(file_get_contents($xsdFilename));
+
+ $errors = libxml_get_errors();
+ libxml_clear_errors();
+ libxml_use_internal_errors($originalErrorHandling);
+
+ return ValidationResult::fromArray($errors);
+ }
+}
diff --git a/vendor/phpunit/phpunit/src/Util/XmlTestListRenderer.php b/vendor/phpunit/phpunit/src/Util/XmlTestListRenderer.php
new file mode 100644
index 000000000..d92e1fe26
--- /dev/null
+++ b/vendor/phpunit/phpunit/src/Util/XmlTestListRenderer.php
@@ -0,0 +1,90 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of PHPUnit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace PHPUnit\Util;
+
+use function get_class;
+use function implode;
+use function str_replace;
+use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestSuite;
+use PHPUnit\Runner\PhptTestCase;
+use RecursiveIteratorIterator;
+use XMLWriter;
+
+/**
+ * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ */
+final class XmlTestListRenderer
+{
+ /**
+ * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+ */
+ public function render(TestSuite $suite): string
+ {
+ $writer = new XMLWriter;
+
+ $writer->openMemory();
+ $writer->setIndent(true);
+ $writer->startDocument();
+ $writer->startElement('tests');
+
+ $currentTestCase = null;
+
+ foreach (new RecursiveIteratorIterator($suite->getIterator()) as $test) {
+ if ($test instanceof TestCase) {
+ if (get_class($test) !== $currentTestCase) {
+ if ($currentTestCase !== null) {
+ $writer->endElement();
+ }
+
+ $writer->startElement('testCaseClass');
+ $writer->writeAttribute('name', get_class($test));
+
+ $currentTestCase = get_class($test);
+ }
+
+ $writer->startElement('testCaseMethod');
+ $writer->writeAttribute('name', $test->getName(false));
+ $writer->writeAttribute('groups', implode(',', $test->getGroups()));
+
+ if (!empty($test->getDataSetAsString(false))) {
+ $writer->writeAttribute(
+ 'dataSet',
+ str_replace(
+ ' with data set ',
+ '',
+ $test->getDataSetAsString(false)
+ )
+ );
+ }
+
+ $writer->endElement();
+ } elseif ($test instanceof PhptTestCase) {
+ if ($currentTestCase !== null) {
+ $writer->endElement();
+
+ $currentTestCase = null;
+ }
+
+ $writer->startElement('phptFile');
+ $writer->writeAttribute('path', $test->getName());
+ $writer->endElement();
+ }
+ }
+
+ if ($currentTestCase !== null) {
+ $writer->endElement();
+ }
+
+ $writer->endElement();
+
+ return $writer->outputMemory();
+ }
+}