Tests: Backport two changes from PHPUnit 9.3:

* Replace the `Match` interface with `ParametersMatch`, to avoid parse errors due to `match` being a reserved keyword in PHP 8.
* Replace `ReflectionParameter::getClass()` usage, which is deprecated in PHP 8.

This allows tests relying on the `getMockForAbstractClass()` and `getMockBuilder()` methods to run again on PHP 8.

When the test suite is updated for compatibility with PHPUnit 9.x, these overrides can be removed.

Follow-up to [48972].

See #50913, #50902.

git-svn-id: https://develop.svn.wordpress.org/trunk@49037 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Sergey Biryukov 2020-09-23 13:52:02 +00:00
parent 7d15225ad0
commit c31a551273
21 changed files with 892 additions and 61 deletions

View File

@ -16,7 +16,21 @@
"dealerdirect/phpcodesniffer-composer-installer": "~0.6.0", "dealerdirect/phpcodesniffer-composer-installer": "~0.6.0",
"wp-coding-standards/wpcs": "~2.3.0", "wp-coding-standards/wpcs": "~2.3.0",
"phpcompatibility/phpcompatibility-wp": "^2.1.0", "phpcompatibility/phpcompatibility-wp": "^2.1.0",
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5" "phpunit/phpunit": "^7.5"
},
"autoload-dev": {
"files": [
"tests/phpunit/includes/phpunit7/MockObject/Builder/NamespaceMatch.php",
"tests/phpunit/includes/phpunit7/MockObject/Builder/ParametersMatch.php",
"tests/phpunit/includes/phpunit7/MockObject/InvocationMocker.php",
"tests/phpunit/includes/phpunit7/MockObject/MockMethod.php"
],
"exclude-from-classmap": [
"vendor/phpunit/phpunit/src/Framework/MockObject/Builder/NamespaceMatch.php",
"vendor/phpunit/phpunit/src/Framework/MockObject/Builder/ParametersMatch.php",
"vendor/phpunit/phpunit/src/Framework/MockObject/InvocationMocker.php",
"vendor/phpunit/phpunit/src/Framework/MockObject/MockMethod.php"
]
}, },
"scripts": { "scripts": {
"compat": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs --standard=phpcompat.xml.dist --report=summary,source", "compat": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs --standard=phpcompat.xml.dist --report=summary,source",

View File

@ -134,6 +134,7 @@
<exclude-pattern>/src/wp-includes/sodium_compat/*</exclude-pattern> <exclude-pattern>/src/wp-includes/sodium_compat/*</exclude-pattern>
<exclude-pattern>/src/wp-includes/Text/*</exclude-pattern> <exclude-pattern>/src/wp-includes/Text/*</exclude-pattern>
<exclude-pattern>/tests/phpunit/includes/phpunit7/MockObject/*</exclude-pattern>
<exclude-pattern>/tests/phpunit/includes/speed-trap-listener\.php</exclude-pattern> <exclude-pattern>/tests/phpunit/includes/speed-trap-listener\.php</exclude-pattern>
<!-- Test data and fixtures. --> <!-- Test data and fixtures. -->

View File

@ -0,0 +1,43 @@
<?php
/*
* This file is part of PHPUnit.
*
* This file is modified to replace the Match interface with ParametersMatch,
* to avoid parse errors due to `match` being a reserved keyword in PHP 8.
*
* When the test suite is updated for compatibility with PHPUnit 9.x,
* this override can be removed.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject\Builder;
/**
* Interface for builders which can register builders with a given identification.
*
* This interface relates to Identity.
*/
interface NamespaceMatch
{
/**
* Looks up the match builder with identification $id and returns it.
*
* @param string $id The identification of the match builder
*
* @return Match
*/
public function lookupId($id);
/**
* Registers the match builder $builder with the identification $id. The
* builder can later be looked up using lookupId() to figure out if it
* has been invoked.
*
* @param string $id The identification of the match builder
* @param Match $builder The builder which is being registered
*/
public function registerId($id, ParametersMatch $builder);
}

View File

@ -0,0 +1,66 @@
<?php
/*
* This file is part of PHPUnit.
*
* This file is modified to replace the Match interface with ParametersMatch,
* to avoid parse errors due to `match` being a reserved keyword in PHP 8.
*
* When the test suite is updated for compatibility with PHPUnit 9.x,
* this override can be removed.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject\Builder;
use PHPUnit\Framework\MockObject\Matcher\AnyParameters;
/**
* Builder interface for parameter matchers.
*/
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 matcher which allows any kind of parameters.
*
* Some examples:
* <code>
* // match any number of parameters
* $b->withAnyParameters();
* </code>
*
* @return AnyParameters
*/
public function withAnyParameters();
}

View File

@ -0,0 +1,2 @@
@trigger_error({deprecation}, E_USER_DEPRECATED);

View File

@ -0,0 +1,46 @@
{prologue}{class_declaration}
{
private $__phpunit_invocationMocker;
private $__phpunit_originalObject;
private $__phpunit_configurable = {configurable};
private $__phpunit_returnValueGeneration = true;
{clone}{mocked_methods}
public function expects(\PHPUnit\Framework\MockObject\Matcher\Invocation $matcher)
{
return $this->__phpunit_getInvocationMocker()->expects($matcher);
}
{method}
public function __phpunit_setOriginalObject($originalObject)
{
$this->__phpunit_originalObject = $originalObject;
}
public function __phpunit_setReturnValueGeneration(bool $returnValueGeneration)
{
$this->__phpunit_returnValueGeneration = $returnValueGeneration;
}
public function __phpunit_getInvocationMocker()
{
if ($this->__phpunit_invocationMocker === null) {
$this->__phpunit_invocationMocker = new \PHPUnit\Framework\MockObject\InvocationMocker($this->__phpunit_configurable, $this->__phpunit_returnValueGeneration);
}
return $this->__phpunit_invocationMocker;
}
public function __phpunit_hasMatchers()
{
return $this->__phpunit_getInvocationMocker()->hasMatchers();
}
public function __phpunit_verify(bool $unsetInvocationMocker = true)
{
$this->__phpunit_getInvocationMocker()->verify();
if ($unsetInvocationMocker) {
$this->__phpunit_invocationMocker = null;
}
}
}{epilogue}

View File

@ -0,0 +1,8 @@
public function method()
{
$any = new \PHPUnit\Framework\MockObject\Matcher\AnyInvokedCount;
$expects = $this->expects($any);
return call_user_func_array([$expects, 'method'], func_get_args());
}

View File

@ -0,0 +1,4 @@
public function __clone()
{
$this->__phpunit_invocationMocker = clone $this->__phpunit_getInvocationMocker();
}

View File

@ -0,0 +1,22 @@
{modifier} function {reference}{method_name}({arguments_decl}){return_delim}{return_type}
{{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_getInvocationMocker()->invoke(
new \PHPUnit\Framework\MockObject\Invocation\ObjectInvocation(
'{class_name}', '{method_name}', $__phpunit_arguments, '{return_type}', $this, {clone_arguments}
)
);
return $__phpunit_result;
}

View File

@ -0,0 +1,20 @@
{modifier} function {reference}{method_name}({arguments_decl}){return_delim}{return_type}
{{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_getInvocationMocker()->invoke(
new \PHPUnit\Framework\MockObject\Invocation\ObjectInvocation(
'{class_name}', '{method_name}', $__phpunit_arguments, '{return_type}', $this, {clone_arguments}
)
);
}

View File

@ -0,0 +1,5 @@
{modifier} function {reference}{method_name}({arguments_decl}){return_delim}{return_type}
{
throw new \PHPUnit\Framework\MockObject\BadMethodCallException('Static method "{method_name}" cannot be invoked on mock object');
}

View File

@ -0,0 +1,26 @@
{modifier} function {reference}{method_name}({arguments_decl}){return_delim}{return_type}
{
$__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_invocation = new \PHPUnit\Framework\MockObject\Invocation\ObjectInvocation(
'{class_name}', '{method_name}', $__phpunit_arguments, '{return_type}', $this, {clone_arguments}
);
$__phpunit_invocation->setProxiedCall();
$this->__phpunit_getInvocationMocker()->invoke($__phpunit_invocation);
unset($__phpunit_invocation);
return call_user_func_array(array($this->__phpunit_originalObject, "{method_name}"), $__phpunit_arguments);
}

View File

@ -0,0 +1,26 @@
{modifier} function {reference}{method_name}({arguments_decl}){return_delim}{return_type}
{
$__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_invocation = new \PHPUnit\Framework\MockObject\Invocation\ObjectInvocation(
'{class_name}', '{method_name}', $__phpunit_arguments, '{return_type}', $this, {clone_arguments}
);
$__phpunit_invocation->setProxiedCall();
$this->__phpunit_getInvocationMocker()->invoke($__phpunit_invocation);
unset($__phpunit_invocation);
call_user_func_array(array($this->__phpunit_originalObject, "{method_name}"), $__phpunit_arguments);
}

View File

@ -0,0 +1,4 @@
{prologue}class {class_name}
{
use {trait_name};
}

View File

@ -0,0 +1,5 @@
public function __clone()
{
$this->__phpunit_invocationMocker = clone $this->__phpunit_getInvocationMocker();
parent::__clone();
}

View File

@ -0,0 +1,7 @@
{namespace}class {class_name} extends \SoapClient
{
public function __construct($wsdl, array $options)
{
parent::__construct('{wsdl}', $options);
}
{methods}}

View File

@ -0,0 +1,4 @@
public function {method_name}({arguments})
{
}

View File

@ -0,0 +1,192 @@
<?php
/*
* This file is part of PHPUnit.
*
* This file is modified to replace the Match interface with ParametersMatch,
* to avoid parse errors due to `match` being a reserved keyword in PHP 8.
*
* When the test suite is updated for compatibility with PHPUnit 9.x,
* this override can be removed.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject;
use Exception;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Builder\InvocationMocker as BuilderInvocationMocker;
use PHPUnit\Framework\MockObject\Builder\ParametersMatch;
use PHPUnit\Framework\MockObject\Builder\NamespaceMatch;
use PHPUnit\Framework\MockObject\Matcher\DeferredError;
use PHPUnit\Framework\MockObject\Matcher\Invocation as MatcherInvocation;
use PHPUnit\Framework\MockObject\Stub\MatcherCollection;
/**
* Mocker for invocations which are sent from
* MockObject objects.
*
* Keeps track of all expectations and stubs as well as registering
* identifications for builders.
*/
class InvocationMocker implements Invokable, MatcherCollection, NamespaceMatch
{
/**
* @var MatcherInvocation[]
*/
private $matchers = [];
/**
* @var Match[]
*/
private $builderMap = [];
/**
* @var string[]
*/
private $configurableMethods;
/**
* @var bool
*/
private $returnValueGeneration;
public function __construct(array $configurableMethods, bool $returnValueGeneration)
{
$this->configurableMethods = $configurableMethods;
$this->returnValueGeneration = $returnValueGeneration;
}
public function addMatcher(MatcherInvocation $matcher): void
{
$this->matchers[] = $matcher;
}
public function hasMatchers()
{
foreach ($this->matchers as $matcher) {
if ($matcher->hasMatchers()) {
return true;
}
}
return false;
}
/**
* @return null|bool
*/
public function lookupId($id)
{
if (isset($this->builderMap[$id])) {
return $this->builderMap[$id];
}
}
/**
* @throws RuntimeException
*/
public function registerId($id, ParametersMatch $builder): void
{
if (isset($this->builderMap[$id])) {
throw new RuntimeException(
'Match builder with id <' . $id . '> is already registered.'
);
}
$this->builderMap[$id] = $builder;
}
/**
* @return BuilderInvocationMocker
*/
public function expects(MatcherInvocation $matcher)
{
return new BuilderInvocationMocker(
$this,
$matcher,
$this->configurableMethods
);
}
/**
* @throws Exception
*/
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 === false) {
$exception = new ExpectationFailedException(
\sprintf(
'Return value inference disabled and no expectation set up for %s::%s()',
$invocation->getClassName(),
$invocation->getMethodName()
)
);
if (\strtolower($invocation->getMethodName()) === '__tostring') {
$this->addMatcher(new DeferredError($exception));
return '';
}
throw $exception;
}
return $invocation->generateReturnValue();
}
/**
* @return bool
*/
public function matches(Invocation $invocation)
{
foreach ($this->matchers as $matcher) {
if (!$matcher->matches($invocation)) {
return false;
}
}
return true;
}
/**
* @throws \PHPUnit\Framework\ExpectationFailedException
*
* @return bool
*/
public function verify()
{
foreach ($this->matchers as $matcher) {
$matcher->verify();
}
}
}

View File

@ -0,0 +1,33 @@
PHPUnit
Copyright (c) 2001-2019, Sebastian Bergmann <sebastian@phpunit.de>.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Sebastian Bergmann nor the names of his
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,363 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* This file is modified to replace ReflectionParameter::getClass() usage,
* which is deprecated in PHP 8.
*
* When the test suite is updated for compatibility with PHPUnit 9.x,
* this override can be removed.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\Framework\MockObject;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use Text_Template;
final class MockMethod
{
/**
* @var Text_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 string
*/
private $returnType;
/**
* @var string
*/
private $reference;
/**
* @var bool
*/
private $callOriginalMethod;
/**
* @var bool
*/
private $static;
/**
* @var ?string
*/
private $deprecation;
/**
* @var bool
*/
private $allowsReturnNull;
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 = '';
}
if ($method->hasReturnType()) {
$returnType = $method->getReturnType()->getName();
} else {
$returnType = '';
}
$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::getMethodParameters($method),
self::getMethodParameters($method, true),
$returnType,
$reference,
$callOriginalMethod,
$method->isStatic(),
$deprecation,
$method->hasReturnType() && $method->getReturnType()->allowsNull()
);
}
public static function fromName(string $fullClassName, string $methodName, bool $cloneArguments): self
{
return new self(
$fullClassName,
$methodName,
$cloneArguments,
'public',
'',
'',
'',
'',
false,
false,
null,
false
);
}
public function __construct(string $className, string $methodName, bool $cloneArguments, string $modifier, string $argumentsForDeclaration, string $argumentsForCall, string $returnType, string $reference, bool $callOriginalMethod, bool $static, ?string $deprecation, bool $allowsReturnNull)
{
$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;
$this->allowsReturnNull = $allowsReturnNull;
}
public function getName(): string
{
return $this->methodName;
}
/**
* @throws \ReflectionException
* @throws \PHPUnit\Framework\MockObject\RuntimeException
* @throws \InvalidArgumentException
*/
public function generateCode(): string
{
if ($this->static) {
$templateFile = 'mocked_static_method.tpl';
} elseif ($this->returnType === 'void') {
$templateFile = \sprintf(
'%s_method_void.tpl',
$this->callOriginalMethod ? 'proxied' : 'mocked'
);
} else {
$templateFile = \sprintf(
'%s_method.tpl',
$this->callOriginalMethod ? 'proxied' : 'mocked'
);
}
$returnType = $this->returnType;
// @see https://bugs.php.net/bug.php?id=70722
if ($returnType === 'self') {
$returnType = $this->className;
}
// @see https://github.com/sebastianbergmann/phpunit-mock-objects/issues/406
if ($returnType === 'parent') {
$reflector = new ReflectionClass($this->className);
$parentClass = $reflector->getParentClass();
if ($parentClass === false) {
throw new RuntimeException(
\sprintf(
'Cannot mock %s::%s because "parent" return type declaration is used but %s does not have a parent class',
$this->className,
$this->methodName,
$this->className
)
);
}
$returnType = $parentClass->getName();
}
$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_delim' => $returnType ? ': ' : '',
'return_type' => $this->allowsReturnNull ? '?' . $returnType : $returnType,
'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();
}
private function getTemplate(string $template): Text_Template
{
$filename = __DIR__ . \DIRECTORY_SEPARATOR . 'Generator' . \DIRECTORY_SEPARATOR . $template;
if (!isset(self::$templates[$filename])) {
self::$templates[$filename] = new Text_Template($filename);
}
return self::$templates[$filename];
}
/**
* Returns the parameters of a function or method.
*
* @throws RuntimeException
*/
private static function getMethodParameters(ReflectionMethod $method, bool $forCall = false): 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()) {
if ($forCall) {
continue;
}
$name = '...' . $name;
}
$nullable = '';
$default = '';
$reference = '';
$typeDeclaration = '';
if (!$forCall) {
if ($parameter->hasType() && $parameter->allowsNull()) {
$nullable = '?';
}
if ($parameter->hasType() && $parameter->getType()->getName() !== 'self') {
$typeDeclaration = $parameter->getType()->getName() . ' ';
} else {
try {
$class = $parameter->getType() && !$parameter->getType()->isBuiltin()
? new ReflectionClass($parameter->getType()->getName())
: null;
} catch (ReflectionException $e) {
throw new RuntimeException(
\sprintf(
'Cannot mock %s::%s() because a class or ' .
'interface used in the signature is not loaded',
$method->getDeclaringClass()->getName(),
$method->getName()
),
0,
$e
);
}
if ($class !== null) {
$typeDeclaration = $class->getName() . ' ';
}
}
if (!$parameter->isVariadic()) {
if ($parameter->isDefaultValueAvailable()) {
try {
$value = \var_export($parameter->getDefaultValue(), true);
} catch (\ReflectionException $e) {
throw new RuntimeException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}
$default = ' = ' . $value;
} elseif ($parameter->isOptional()) {
$default = ' = null';
}
}
}
if ($parameter->isPassedByReference()) {
$reference = '&';
}
$parameters[] = $nullable . $typeDeclaration . $reference . $name . $default;
}
return \implode(', ', $parameters);
}
}

View File

@ -37,64 +37,4 @@ class WP_UnitTestCase extends WP_UnitTestCase_Base {
static::assertThat( $actual, $constraint, $message ); static::assertThat( $actual, $constraint, $message );
} }
/**
* 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 last parameter.
*
* This method replaces the native PHPUnit method to avoid parse errors
* due to `match` being a reserved keyword in PHP 8.
*
* To run on PHP 8, the tests using this method require PHPUnit 9.3 or later.
*
* When the test suite is updated for compatibility with PHPUnit 9.x,
* this override can be removed.
*
* @since 5.6.0
*
* @param string $original_class_name
* @param string $mock_class_name
* @param bool $call_original_constructor
* @param bool $call_original_clone
* @param bool $call_autoload
* @param array $mocked_methods
* @param bool $clone_arguments
*
* @throws \ReflectionException
* @throws RuntimeException
* @throws Exception
*
* @return MockObject
*/
public function getMockForAbstractClass( $original_class_name, array $arguments = array(), $mock_class_name = '', $call_original_constructor = true, $call_original_clone = true, $call_autoload = true, $mocked_methods = array(), $clone_arguments = false ): PHPUnit\Framework\MockObject\MockObject {
if ( PHP_VERSION_ID >= 80000 && version_compare( tests_get_phpunit_version(), '9.3', '<' ) ) {
$this->markTestSkipped( 'To run on PHP 8, this test requires PHPUnit 9.3 or later.' );
}
return parent::getMockForAbstractClass( $original_class_name, $arguments, $mock_class_name, $call_original_constructor, $call_original_clone, $call_autoload, $mocked_methods, $clone_arguments );
}
/**
* Returns a builder object to create mock objects using a fluent interface.
*
* This method replaces the native PHPUnit method to avoid parse errors
* due to `match` being a reserved keyword in PHP 8.
*
* To run on PHP 8, the tests using this method require PHPUnit 9.3 or later.
*
* When the test suite is updated for compatibility with PHPUnit 9.x,
* this override can be removed.
*
* @since 5.6.0
*
* @param string|string[] $class_name
*/
public function getMockBuilder( $class_name ): PHPUnit\Framework\MockObject\MockBuilder {
if ( PHP_VERSION_ID >= 80000 && version_compare( tests_get_phpunit_version(), '9.3', '<' ) ) {
$this->markTestSkipped( 'To run on PHP 8, this test requires PHPUnit 9.3 or later.' );
}
return parent::getMockBuilder( $class_name );
}
} }