This commit is contained in:
2020-02-01 16:47:12 +07:00
commit 4c619ad6e6
16739 changed files with 3329179 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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;
/**
* Builder interface for unique identifiers.
*
* Defines the interface for recording unique identifiers. The identifiers
* can be used to define the invocation order of expectations. The expectation
* is recorded using id() and then defined in order using
* PHPUnit\Framework\MockObject\Builder\Match::after().
*/
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);
}

View File

@@ -0,0 +1,299 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Constraint\Constraint;
use PHPUnit\Framework\MockObject\Matcher;
use PHPUnit\Framework\MockObject\Matcher\Invocation;
use PHPUnit\Framework\MockObject\RuntimeException;
use PHPUnit\Framework\MockObject\Stub;
use PHPUnit\Framework\MockObject\Stub\MatcherCollection;
/**
* Builder for mocked or stubbed invocations.
*
* Provides methods for building expectations without having to resort to
* instantiating the various matchers manually. These methods also form a
* more natural way of reading the expectation. This class should be together
* with the test case PHPUnit\Framework\MockObject\TestCase.
*/
class InvocationMocker implements MethodNameMatch
{
/**
* @var MatcherCollection
*/
private $collection;
/**
* @var Matcher
*/
private $matcher;
/**
* @var string[]
*/
private $configurableMethods = [];
/**
* @param MatcherCollection $collection
* @param Invocation $invocationMatcher
* @param array $configurableMethods
*/
public function __construct(MatcherCollection $collection, Invocation $invocationMatcher, array $configurableMethods)
{
$this->collection = $collection;
$this->matcher = new Matcher($invocationMatcher);
$this->collection->addMatcher($this->matcher);
$this->configurableMethods = $configurableMethods;
}
/**
* @return Matcher
*/
public function getMatcher()
{
return $this->matcher;
}
/**
* @param mixed $id
*
* @return InvocationMocker
*/
public function id($id)
{
$this->collection->registerId($id, $this);
return $this;
}
/**
* @param Stub $stub
*
* @return InvocationMocker
*/
public function will(Stub $stub)
{
$this->matcher->setStub($stub);
return $this;
}
/**
* @param mixed $value
* @param mixed $nextValues, ...
*
* @return InvocationMocker
*/
public function willReturn($value, ...$nextValues)
{
if (\count($nextValues) === 0) {
$stub = new Stub\ReturnStub($value);
} else {
$stub = new Stub\ConsecutiveCalls(
\array_merge([$value], $nextValues)
);
}
return $this->will($stub);
}
/**
* @param mixed $reference
*
* @return InvocationMocker
*/
public function willReturnReference(&$reference)
{
$stub = new Stub\ReturnReference($reference);
return $this->will($stub);
}
/**
* @param array $valueMap
*
* @return InvocationMocker
*/
public function willReturnMap(array $valueMap)
{
$stub = new Stub\ReturnValueMap($valueMap);
return $this->will($stub);
}
/**
* @param mixed $argumentIndex
*
* @return InvocationMocker
*/
public function willReturnArgument($argumentIndex)
{
$stub = new Stub\ReturnArgument($argumentIndex);
return $this->will($stub);
}
/**
* @param callable $callback
*
* @return InvocationMocker
*/
public function willReturnCallback($callback)
{
$stub = new Stub\ReturnCallback($callback);
return $this->will($stub);
}
/**
* @return InvocationMocker
*/
public function willReturnSelf()
{
$stub = new Stub\ReturnSelf;
return $this->will($stub);
}
/**
* @param mixed $values, ...
*
* @return InvocationMocker
*/
public function willReturnOnConsecutiveCalls(...$values)
{
$stub = new Stub\ConsecutiveCalls($values);
return $this->will($stub);
}
/**
* @param \Exception $exception
*
* @return InvocationMocker
*/
public function willThrowException(\Exception $exception)
{
$stub = new Stub\Exception($exception);
return $this->will($stub);
}
/**
* @param mixed $id
*
* @return InvocationMocker
*/
public function after($id)
{
$this->matcher->setAfterMatchBuilderId($id);
return $this;
}
/**
* @param array ...$arguments
*
* @return InvocationMocker
*
* @throws RuntimeException
*/
public function with(...$arguments)
{
$this->canDefineParameters();
$this->matcher->setParametersMatcher(new Matcher\Parameters($arguments));
return $this;
}
/**
* @param array ...$arguments
*
* @return InvocationMocker
*
* @throws RuntimeException
*/
public function withConsecutive(...$arguments)
{
$this->canDefineParameters();
$this->matcher->setParametersMatcher(new Matcher\ConsecutiveParameters($arguments));
return $this;
}
/**
* @return InvocationMocker
*
* @throws RuntimeException
*/
public function withAnyParameters()
{
$this->canDefineParameters();
$this->matcher->setParametersMatcher(new Matcher\AnyParameters);
return $this;
}
/**
* @param Constraint|string $constraint
*
* @return InvocationMocker
*
* @throws RuntimeException
*/
public function method($constraint)
{
if ($this->matcher->hasMethodNameMatcher()) {
throw new RuntimeException(
'Method name matcher is already defined, cannot redefine'
);
}
if (\is_string($constraint) && !\in_array(\strtolower($constraint), $this->configurableMethods)) {
throw new RuntimeException(
\sprintf(
'Trying to configure method "%s" which cannot be configured because it does not exist, has not been specified, is final, or is static',
$constraint
)
);
}
$this->matcher->setMethodNameMatcher(new Matcher\MethodName($constraint));
return $this;
}
/**
* Validate that a parameters matcher can be defined, throw exceptions otherwise.
*
* @throws RuntimeException
*/
private function canDefineParameters()
{
if (!$this->matcher->hasMethodNameMatcher()) {
throw new RuntimeException(
'Method name matcher is not defined, cannot define parameter ' .
'matcher without one'
);
}
if ($this->matcher->hasParametersMatcher()) {
throw new RuntimeException(
'Parameter matcher is already defined, cannot redefine'
);
}
}
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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;
/**
* Builder interface for invocation order matches.
*/
interface Match 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);
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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;
/**
* Builder interface for matcher of method names.
*/
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 $name Constraint for matching method, if a string is passed it will use the PHPUnit_Framework_Constraint_IsEqual
*
* @return ParametersMatch
*/
public function method($name);
}

View File

@@ -0,0 +1,37 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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, Match $builder);
}

View File

@@ -0,0 +1,50 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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 Match
{
/**
* 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,28 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Stub as BaseStub;
/**
* Builder interface for stubs which are actions replacing an invocation.
*/
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.
*
* @param BaseStub $stub
*
* @return Identity
*/
public function will(BaseStub $stub);
}

View File

@@ -0,0 +1,14 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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;
class BadMethodCallException extends \BadMethodCallException implements Exception
{
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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;
/**
* Interface for exceptions used by PHPUnit_MockObject.
*/
interface Exception
{
}

View File

@@ -0,0 +1,14 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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;
class RuntimeException extends \RuntimeException implements Exception
{
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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 PHPUnit_Framework_MockObject_MockObject;
interface MockObject extends PHPUnit_Framework_MockObject_MockObject
{
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,40 @@
{prologue}{class_declaration}
{
private $__phpunit_invocationMocker;
private $__phpunit_originalObject;
private $__phpunit_configurable = {configurable};
{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_getInvocationMocker()
{
if ($this->__phpunit_invocationMocker === null) {
$this->__phpunit_invocationMocker = new \PHPUnit\Framework\MockObject\InvocationMocker($this->__phpunit_configurable);
}
return $this->__phpunit_invocationMocker;
}
public function __phpunit_hasMatchers()
{
return $this->__phpunit_getInvocationMocker()->hasMatchers();
}
public function __phpunit_verify($unsetInvocationMocker = true)
{
$this->__phpunit_getInvocationMocker()->verify();
if ($unsetInvocationMocker) {
$this->__phpunit_invocationMocker = null;
}
}
}{epilogue}

View File

@@ -0,0 +1,7 @@
public function method()
{
$any = new \PHPUnit\Framework\MockObject\Matcher\AnyInvokedCount;
$expects = $this->expects($any);
return call_user_func_array(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}
$arguments = array({arguments_call});
$count = func_num_args();
if ($count > {arguments_count}) {
$_arguments = func_get_args();
for ($i = {arguments_count}; $i < $count; $i++) {
$arguments[] = $_arguments[$i];
}
}
$result = $this->__phpunit_getInvocationMocker()->invoke(
new \PHPUnit\Framework\MockObject\Invocation\ObjectInvocation(
'{class_name}', '{method_name}', $arguments, '{return_type}', $this, {clone_arguments}
)
);
return $result;
}

View File

@@ -0,0 +1,20 @@
{modifier} function {reference}{method_name}({arguments_decl}){return_delim}{return_type}
{{deprecation}
$arguments = array({arguments_call});
$count = func_num_args();
if ($count > {arguments_count}) {
$_arguments = func_get_args();
for ($i = {arguments_count}; $i < $count; $i++) {
$arguments[] = $_arguments[$i];
}
}
$this->__phpunit_getInvocationMocker()->invoke(
new \PHPUnit\Framework\MockObject\Invocation\ObjectInvocation(
'{class_name}', '{method_name}', $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,22 @@
{modifier} function {reference}{method_name}({arguments_decl}){return_delim}{return_type}
{
$arguments = array({arguments_call});
$count = func_num_args();
if ($count > {arguments_count}) {
$_arguments = func_get_args();
for ($i = {arguments_count}; $i < $count; $i++) {
$arguments[] = $_arguments[$i];
}
}
$this->__phpunit_getInvocationMocker()->invoke(
new \PHPUnit\Framework\MockObject\Invocation\ObjectInvocation(
'{class_name}', '{method_name}', $arguments, '{return_type}', $this, {clone_arguments}
)
);
return call_user_func_array(array($this->__phpunit_originalObject, "{method_name}"), $arguments);
}

View File

@@ -0,0 +1,22 @@
{modifier} function {reference}{method_name}({arguments_decl}){return_delim}{return_type}
{
$arguments = array({arguments_call});
$count = func_num_args();
if ($count > {arguments_count}) {
$_arguments = func_get_args();
for ($i = {arguments_count}; $i < $count; $i++) {
$arguments[] = $_arguments[$i];
}
}
$this->__phpunit_getInvocationMocker()->invoke(
new \PHPUnit\Framework\MockObject\Invocation\ObjectInvocation(
'{class_name}', '{method_name}', $arguments, '{return_type}', $this, {clone_arguments}
)
);
call_user_func_array(array($this->__phpunit_originalObject, "{method_name}"), $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,31 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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;
/**
* Interface for invocations.
*/
interface Invocation
{
/**
* @return mixed Mocked return value.
*/
public function generateReturnValue();
public function getClassName(): string;
public function getMethodName(): string;
public function getParameters(): array;
public function getReturnType(): string;
public function isReturnTypeNullable(): bool;
}

View File

@@ -0,0 +1,41 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Invocation;
/**
* Represents a non-static invocation.
*/
class ObjectInvocation extends StaticInvocation
{
/**
* @var object
*/
private $object;
/**
* @param string $className
* @param string $methodName
* @param array $parameters
* @param string $returnType
* @param object $object
* @param bool $cloneObjects
*/
public function __construct($className, $methodName, array $parameters, $returnType, $object, $cloneObjects = false)
{
parent::__construct($className, $methodName, $parameters, $returnType, $cloneObjects);
$this->object = $object;
}
public function getObject()
{
return $this->object;
}
}

View File

@@ -0,0 +1,255 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Invocation;
use PHPUnit\Framework\MockObject\Generator;
use PHPUnit\Framework\MockObject\Invocation;
use PHPUnit\Framework\SelfDescribing;
use ReflectionObject;
use SebastianBergmann\Exporter\Exporter;
/**
* Represents a static invocation.
*/
class StaticInvocation implements Invocation, SelfDescribing
{
/**
* @var array
*/
private static $uncloneableExtensions = [
'mysqli' => true,
'SQLite' => true,
'sqlite3' => true,
'tidy' => true,
'xmlwriter' => true,
'xsl' => true
];
/**
* @var array
*/
private static $uncloneableClasses = [
'Closure',
'COMPersistHelper',
'IteratorIterator',
'RecursiveIteratorIterator',
'SplFileObject',
'PDORow',
'ZipArchive'
];
/**
* @var string
*/
private $className;
/**
* @var string
*/
private $methodName;
/**
* @var array
*/
private $parameters;
/**
* @var string
*/
private $returnType;
/**
* @var bool
*/
private $isReturnTypeNullable = false;
/**
* @param string $className
* @param string $methodName
* @param array $parameters
* @param string $returnType
* @param bool $cloneObjects
*/
public function __construct($className, $methodName, array $parameters, $returnType, $cloneObjects = false)
{
$this->className = $className;
$this->methodName = $methodName;
$this->parameters = $parameters;
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;
}
public function getReturnType(): string
{
return $this->returnType;
}
public function isReturnTypeNullable(): bool
{
return $this->isReturnTypeNullable;
}
/**
* @return mixed Mocked return value
*
* @throws \ReflectionException
* @throws \PHPUnit\Framework\MockObject\RuntimeException
* @throws \PHPUnit\Framework\Exception
*/
public function generateReturnValue()
{
if ($this->isReturnTypeNullable) {
return;
}
switch (\strtolower($this->returnType)) {
case '':
case 'void':
return;
case 'string':
return '';
case 'float':
return 0.0;
case 'int':
return 0;
case 'bool':
return false;
case 'array':
return [];
case 'object':
return new \stdClass;
case 'callable':
case 'closure':
return function () {
};
case 'traversable':
case 'generator':
case 'iterable':
$generator = function () {
yield;
};
return $generator();
default:
$generator = new Generator;
return $generator->getMock($this->returnType, [], [], '', false);
}
}
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) : ''
);
}
/**
* @param object $original
*
* @return object
*/
private function cloneObject($original)
{
$cloneable = null;
$object = new ReflectionObject($original);
// Check the blacklist before asking PHP reflection to work around
// https://bugs.php.net/bug.php?id=53967
if ($object->isInternal() &&
isset(self::$uncloneableExtensions[$object->getExtensionName()])) {
$cloneable = false;
}
if ($cloneable === null) {
foreach (self::$uncloneableClasses as $class) {
if ($original instanceof $class) {
$cloneable = false;
break;
}
}
}
if ($cloneable === null) {
$cloneable = $object->isCloneable();
}
if ($cloneable === null && $object->hasMethod('__clone')) {
$method = $object->getMethod('__clone');
$cloneable = $method->isPublic();
}
if ($cloneable === null) {
$cloneable = true;
}
if ($cloneable) {
try {
return clone $original;
} catch (\Exception $e) {
return $original;
}
} else {
return $original;
}
}
}

View File

@@ -0,0 +1,185 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\MockObject\Builder\InvocationMocker as BuilderInvocationMocker;
use PHPUnit\Framework\MockObject\Builder\Match;
use PHPUnit\Framework\MockObject\Builder\NamespaceMatch;
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 MatcherCollection, Invokable, NamespaceMatch
{
/**
* @var MatcherInvocation[]
*/
private $matchers = [];
/**
* @var Match[]
*/
private $builderMap = [];
/**
* @var string[]
*/
private $configurableMethods = [];
/**
* @param array $configurableMethods
*/
public function __construct(array $configurableMethods)
{
$this->configurableMethods = $configurableMethods;
}
/**
* @param MatcherInvocation $matcher
*/
public function addMatcher(MatcherInvocation $matcher)
{
$this->matchers[] = $matcher;
}
public function hasMatchers()
{
foreach ($this->matchers as $matcher) {
if ($matcher->hasMatchers()) {
return true;
}
}
return false;
}
/**
* @param mixed $id
*
* @return bool|null
*/
public function lookupId($id)
{
if (isset($this->builderMap[$id])) {
return $this->builderMap[$id];
}
return;
}
/**
* @param mixed $id
* @param Match $builder
*
* @throws RuntimeException
*/
public function registerId($id, Match $builder)
{
if (isset($this->builderMap[$id])) {
throw new RuntimeException(
'Match builder with id <' . $id . '> is already registered.'
);
}
$this->builderMap[$id] = $builder;
}
/**
* @param MatcherInvocation $matcher
*
* @return BuilderInvocationMocker
*/
public function expects(MatcherInvocation $matcher)
{
return new BuilderInvocationMocker(
$this,
$matcher,
$this->configurableMethods
);
}
/**
* @param Invocation $invocation
*
* @return mixed
*
* @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 (\strtolower($invocation->getMethodName()) === '__tostring') {
return '';
}
return $invocation->generateReturnValue();
}
/**
* @param Invocation $invocation
*
* @return bool
*/
public function matches(Invocation $invocation)
{
foreach ($this->matchers as $matcher) {
if (!$matcher->matches($invocation)) {
return false;
}
}
return true;
}
/**
* @return bool
*
* @throws \PHPUnit\Framework\ExpectationFailedException
*/
public function verify()
{
foreach ($this->matchers as $matcher) {
$matcher->verify();
}
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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;
/**
* Interface for classes which can be invoked.
*
* The invocation will be taken from a mock object and passed to an object
* of this class.
*/
interface Invokable extends Verifiable
{
/**
* Invokes the invocation object $invocation so that it can be checked for
* expectations or matched against stubs.
*
* @param Invocation $invocation The invocation object passed from mock object
*
* @return object
*/
public function invoke(Invocation $invocation);
/**
* Checks if the invocation matches.
*
* @param Invocation $invocation The invocation object passed from mock object
*
* @return bool
*/
public function matches(Invocation $invocation);
}

View File

@@ -0,0 +1,321 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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 PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Matcher\AnyInvokedCount;
use PHPUnit\Framework\MockObject\Matcher\AnyParameters;
use PHPUnit\Framework\MockObject\Matcher\Invocation as MatcherInvocation;
use PHPUnit\Framework\MockObject\Matcher\InvokedCount;
use PHPUnit\Framework\MockObject\Matcher\MethodName;
use PHPUnit\Framework\MockObject\Matcher\Parameters;
use PHPUnit\Framework\TestFailure;
/**
* Main matcher which defines a full expectation using method, parameter and
* invocation matchers.
* This matcher encapsulates all the other matchers and allows the builder to
* set the specific matchers when the appropriate methods are called (once(),
* where() etc.).
*
* All properties are public so that they can easily be accessed by the builder.
*/
class Matcher implements MatcherInvocation
{
/**
* @var MatcherInvocation
*/
private $invocationMatcher;
/**
* @var mixed
*/
private $afterMatchBuilderId = null;
/**
* @var bool
*/
private $afterMatchBuilderIsInvoked = false;
/**
* @var MethodName
*/
private $methodNameMatcher = null;
/**
* @var Parameters
*/
private $parametersMatcher = null;
/**
* @var Stub
*/
private $stub = null;
/**
* @param MatcherInvocation $invocationMatcher
*/
public function __construct(MatcherInvocation $invocationMatcher)
{
$this->invocationMatcher = $invocationMatcher;
}
public function hasMatchers(): bool
{
return $this->invocationMatcher !== null && !$this->invocationMatcher instanceof AnyInvokedCount;
}
public function hasMethodNameMatcher(): bool
{
return $this->methodNameMatcher !== null;
}
public function getMethodNameMatcher(): MethodName
{
return $this->methodNameMatcher;
}
public function setMethodNameMatcher(MethodName $matcher)
{
$this->methodNameMatcher = $matcher;
}
public function hasParametersMatcher(): bool
{
return $this->parametersMatcher !== null;
}
public function getParametersMatcher(): Parameters
{
return $this->parametersMatcher;
}
public function setParametersMatcher($matcher)
{
$this->parametersMatcher = $matcher;
}
public function setStub($stub)
{
$this->stub = $stub;
}
public function setAfterMatchBuilderId($id)
{
$this->afterMatchBuilderId = $id;
}
/**
* @param Invocation $invocation
*
* @return mixed
*
* @throws \Exception
* @throws RuntimeException
* @throws ExpectationFailedException
*/
public function invoked(Invocation $invocation)
{
if ($this->invocationMatcher === null) {
throw new RuntimeException(
'No invocation matcher is set'
);
}
if ($this->methodNameMatcher === null) {
throw new RuntimeException('No method matcher is set');
}
if ($this->afterMatchBuilderId !== null) {
$builder = $invocation->getObject()
->__phpunit_getInvocationMocker()
->lookupId($this->afterMatchBuilderId);
if (!$builder) {
throw new RuntimeException(
\sprintf(
'No builder found for match builder identification <%s>',
$this->afterMatchBuilderId
)
);
}
$matcher = $builder->getMatcher();
if ($matcher && $matcher->invocationMatcher->hasBeenInvoked()) {
$this->afterMatchBuilderIsInvoked = true;
}
}
$this->invocationMatcher->invoked($invocation);
try {
if ($this->parametersMatcher !== null &&
!$this->parametersMatcher->matches($invocation)) {
$this->parametersMatcher->verify();
}
} catch (ExpectationFailedException $e) {
throw new ExpectationFailedException(
\sprintf(
"Expectation failed for %s when %s\n%s",
$this->methodNameMatcher->toString(),
$this->invocationMatcher->toString(),
$e->getMessage()
),
$e->getComparisonFailure()
);
}
if ($this->stub) {
return $this->stub->invoke($invocation);
}
return $invocation->generateReturnValue();
}
/**
* @param Invocation $invocation
*
* @return bool
*
* @throws RuntimeException
* @throws ExpectationFailedException
*/
public function matches(Invocation $invocation)
{
if ($this->afterMatchBuilderId !== null) {
$builder = $invocation->getObject()
->__phpunit_getInvocationMocker()
->lookupId($this->afterMatchBuilderId);
if (!$builder) {
throw new RuntimeException(
\sprintf(
'No builder found for match builder identification <%s>',
$this->afterMatchBuilderId
)
);
}
$matcher = $builder->getMatcher();
if (!$matcher) {
return false;
}
if (!$matcher->invocationMatcher->hasBeenInvoked()) {
return false;
}
}
if ($this->invocationMatcher === null) {
throw new RuntimeException(
'No invocation matcher is set'
);
}
if ($this->methodNameMatcher === null) {
throw new RuntimeException('No method matcher is set');
}
if (!$this->invocationMatcher->matches($invocation)) {
return false;
}
try {
if (!$this->methodNameMatcher->matches($invocation)) {
return false;
}
} catch (ExpectationFailedException $e) {
throw new ExpectationFailedException(
\sprintf(
"Expectation failed for %s when %s\n%s",
$this->methodNameMatcher->toString(),
$this->invocationMatcher->toString(),
$e->getMessage()
),
$e->getComparisonFailure()
);
}
return true;
}
/**
* @throws RuntimeException
* @throws ExpectationFailedException
*/
public function verify()
{
if ($this->invocationMatcher === null) {
throw new RuntimeException(
'No invocation matcher is set'
);
}
if ($this->methodNameMatcher === null) {
throw new RuntimeException('No method matcher is set');
}
try {
$this->invocationMatcher->verify();
if ($this->parametersMatcher === null) {
$this->parametersMatcher = new AnyParameters;
}
$invocationIsAny = $this->invocationMatcher instanceof AnyInvokedCount;
$invocationIsNever = $this->invocationMatcher instanceof InvokedCount && $this->invocationMatcher->isNever();
if (!$invocationIsAny && !$invocationIsNever) {
$this->parametersMatcher->verify();
}
} catch (ExpectationFailedException $e) {
throw new ExpectationFailedException(
\sprintf(
"Expectation failed for %s when %s.\n%s",
$this->methodNameMatcher->toString(),
$this->invocationMatcher->toString(),
TestFailure::exceptionToString($e)
)
);
}
}
/**
* @return string
*/
public function toString()
{
$list = [];
if ($this->invocationMatcher !== null) {
$list[] = $this->invocationMatcher->toString();
}
if ($this->methodNameMatcher !== null) {
$list[] = 'where ' . $this->methodNameMatcher->toString();
}
if ($this->parametersMatcher !== null) {
$list[] = 'and ' . $this->parametersMatcher->toString();
}
if ($this->afterMatchBuilderId !== null) {
$list[] = 'after ' . $this->afterMatchBuilderId;
}
if ($this->stub !== null) {
$list[] = 'will ' . $this->stub->toString();
}
return \implode(' ', $list);
}
}

View File

@@ -0,0 +1,29 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
/**
* Invocation matcher which checks if a method has been invoked zero or more
* times. This matcher will always match.
*/
class AnyInvokedCount extends InvokedRecorder
{
/**
* @return string
*/
public function toString()
{
return 'invoked zero or more times';
}
public function verify()
{
}
}

View File

@@ -0,0 +1,36 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
/**
* Invocation matcher which allows any parameters to a method.
*/
class AnyParameters extends StatelessInvocation
{
/**
* @return string
*/
public function toString()
{
return 'with any parameters';
}
/**
* @param BaseInvocation $invocation
*
* @return bool
*/
public function matches(BaseInvocation $invocation)
{
return true;
}
}

View File

@@ -0,0 +1,134 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\Constraint\IsEqual;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
/**
* Invocation matcher which looks for sets of specific parameters in the invocations.
*
* Checks the parameters of the incoming invocations, the parameter list is
* checked against the defined constraints in $parameters. If the constraint
* is met it will return true in matches().
*
* It takes a list of match groups and and increases a call index after each invocation.
* So the first invocation uses the first group of constraints, the second the next and so on.
*/
class ConsecutiveParameters extends StatelessInvocation
{
/**
* @var array
*/
private $parameterGroups = [];
/**
* @var array
*/
private $invocations = [];
/**
* @param array $parameterGroups
*
* @throws \PHPUnit\Framework\Exception
*/
public function __construct(array $parameterGroups)
{
foreach ($parameterGroups as $index => $parameters) {
foreach ($parameters as $parameter) {
if (!$parameter instanceof Constraint) {
$parameter = new IsEqual($parameter);
}
$this->parameterGroups[$index][] = $parameter;
}
}
}
/**
* @return string
*/
public function toString()
{
return 'with consecutive parameters';
}
/**
* @param BaseInvocation $invocation
*
* @return bool
*
* @throws \PHPUnit\Framework\ExpectationFailedException
*/
public function matches(BaseInvocation $invocation)
{
$this->invocations[] = $invocation;
$callIndex = \count($this->invocations) - 1;
$this->verifyInvocation($invocation, $callIndex);
return false;
}
public function verify()
{
foreach ($this->invocations as $callIndex => $invocation) {
$this->verifyInvocation($invocation, $callIndex);
}
}
/**
* Verify a single invocation
*
* @param BaseInvocation $invocation
* @param int $callIndex
*
* @throws ExpectationFailedException
*/
private function verifyInvocation(BaseInvocation $invocation, $callIndex)
{
if (isset($this->parameterGroups[$callIndex])) {
$parameters = $this->parameterGroups[$callIndex];
} else {
// no parameter assertion for this call index
return;
}
if ($invocation === null) {
throw new ExpectationFailedException(
'Mocked method does not exist.'
);
}
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()
)
);
}
}
}

View File

@@ -0,0 +1,49 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
use PHPUnit\Framework\MockObject\Verifiable;
use PHPUnit\Framework\SelfDescribing;
/**
* Interface for classes which matches an invocation based on its
* method name, argument, order or call count.
*/
interface Invocation extends SelfDescribing, Verifiable
{
/**
* Registers the invocation $invocation in the object as being invoked.
* This will only occur after matches() returns true which means the
* current invocation is the correct one.
*
* The matcher can store information from the invocation which can later
* be checked in verify(), or it can check the values directly and throw
* and exception if an expectation is not met.
*
* If the matcher is a stub it will also have a return value.
*
* @param BaseInvocation $invocation Object containing information on a mocked or stubbed method which was invoked
*
* @return mixed
*/
public function invoked(BaseInvocation $invocation);
/**
* Checks if the invocation $invocation matches the current rules. If it does
* the matcher will get the invoked() method called which should check if an
* expectation is met.
*
* @param BaseInvocation $invocation Object containing information on a mocked or stubbed method which was invoked
*
* @return bool
*/
public function matches(BaseInvocation $invocation);
}

View File

@@ -0,0 +1,89 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
/**
* Invocation matcher which checks if a method was invoked at a certain index.
*
* If the expected index number does not match the current invocation index it
* will not match which means it skips all method and parameter matching. Only
* once the index is reached will the method and parameter start matching and
* verifying.
*
* If the index is never reached it will throw an exception in index.
*/
class InvokedAtIndex implements Invocation
{
/**
* @var int
*/
private $sequenceIndex;
/**
* @var int
*/
private $currentIndex = -1;
/**
* @param int $sequenceIndex
*/
public function __construct($sequenceIndex)
{
$this->sequenceIndex = $sequenceIndex;
}
/**
* @return string
*/
public function toString()
{
return 'invoked at sequence index ' . $this->sequenceIndex;
}
/**
* @param BaseInvocation $invocation
*
* @return bool
*/
public function matches(BaseInvocation $invocation)
{
$this->currentIndex++;
return $this->currentIndex == $this->sequenceIndex;
}
/**
* @param BaseInvocation $invocation
*/
public function invoked(BaseInvocation $invocation)
{
}
/**
* 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()
{
if ($this->currentIndex < $this->sequenceIndex) {
throw new ExpectationFailedException(
\sprintf(
'The expected invocation at index %s was never reached.',
$this->sequenceIndex
)
);
}
}
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
use PHPUnit\Framework\ExpectationFailedException;
/**
* Invocation matcher which checks if a method has been invoked at least
* N times.
*/
class InvokedAtLeastCount extends InvokedRecorder
{
/**
* @var int
*/
private $requiredInvocations;
/**
* @param int $requiredInvocations
*/
public function __construct($requiredInvocations)
{
$this->requiredInvocations = $requiredInvocations;
}
/**
* @return string
*/
public function toString()
{
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()
{
$count = $this->getInvocationCount();
if ($count < $this->requiredInvocations) {
throw new ExpectationFailedException(
'Expected invocation at least ' . $this->requiredInvocations .
' times but it occurred ' . $count . ' time(s).'
);
}
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
use PHPUnit\Framework\ExpectationFailedException;
/**
* Invocation matcher which checks if a method has been invoked at least one
* time.
*
* If the number of invocations is 0 it will throw an exception in verify.
*/
class InvokedAtLeastOnce extends InvokedRecorder
{
/**
* @return string
*/
public function toString()
{
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()
{
$count = $this->getInvocationCount();
if ($count < 1) {
throw new ExpectationFailedException(
'Expected invocation at least once but it never occurred.'
);
}
}
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
use PHPUnit\Framework\ExpectationFailedException;
/**
* Invocation matcher which checks if a method has been invoked at least
* N times.
*/
class InvokedAtMostCount extends InvokedRecorder
{
/**
* @var int
*/
private $allowedInvocations;
/**
* @param int $allowedInvocations
*/
public function __construct($allowedInvocations)
{
$this->allowedInvocations = $allowedInvocations;
}
/**
* @return string
*/
public function toString()
{
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()
{
$count = $this->getInvocationCount();
if ($count > $this->allowedInvocations) {
throw new ExpectationFailedException(
'Expected invocation at most ' . $this->allowedInvocations .
' times but it occurred ' . $count . ' time(s).'
);
}
}
}

View File

@@ -0,0 +1,111 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
/**
* Invocation matcher which checks if a method has been invoked a certain amount
* of times.
* If the number of invocations exceeds the value it will immediately throw an
* exception,
* If the number is less it will later be checked in verify() and also throw an
* exception.
*/
class InvokedCount extends InvokedRecorder
{
/**
* @var int
*/
private $expectedCount;
/**
* @param int $expectedCount
*/
public function __construct($expectedCount)
{
$this->expectedCount = $expectedCount;
}
/**
* @return bool
*/
public function isNever()
{
return $this->expectedCount === 0;
}
/**
* @return string
*/
public function toString()
{
return 'invoked ' . $this->expectedCount . ' time(s)';
}
/**
* @param BaseInvocation $invocation
*
* @throws ExpectationFailedException
*/
public function invoked(BaseInvocation $invocation)
{
parent::invoked($invocation);
$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);
}
}
/**
* 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()
{
$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
)
);
}
}
}

View File

@@ -0,0 +1,68 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
/**
* Records invocations and provides convenience methods for checking them later
* on.
* This abstract class can be implemented by matchers which needs to check the
* number of times an invocation has occurred.
*/
abstract class InvokedRecorder implements Invocation
{
/**
* @var BaseInvocation[]
*/
private $invocations = [];
/**
* @return int
*/
public function getInvocationCount()
{
return \count($this->invocations);
}
/**
* @return BaseInvocation[]
*/
public function getInvocations()
{
return $this->invocations;
}
/**
* @return bool
*/
public function hasBeenInvoked()
{
return \count($this->invocations) > 0;
}
/**
* @param BaseInvocation $invocation
*/
public function invoked(BaseInvocation $invocation)
{
$this->invocations[] = $invocation;
}
/**
* @param BaseInvocation $invocation
*
* @return bool
*/
public function matches(BaseInvocation $invocation)
{
return true;
}
}

View File

@@ -0,0 +1,73 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\Constraint\IsEqual;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
use PHPUnit\Util\InvalidArgumentHelper;
/**
* Invocation matcher which looks for a specific method name in the invocations.
*
* Checks the method name all incoming invocations, the name is checked against
* the defined constraint $constraint. If the constraint is met it will return
* true in matches().
*/
class MethodName extends StatelessInvocation
{
/**
* @var Constraint
*/
private $constraint;
/**
* @param Constraint|string
*
* @throws Constraint
* @throws \PHPUnit\Framework\Exception
*/
public function __construct($constraint)
{
if (!$constraint instanceof Constraint) {
if (!\is_string($constraint)) {
throw InvalidArgumentHelper::factory(1, 'string');
}
$constraint = new IsEqual(
$constraint,
0,
10,
false,
true
);
}
$this->constraint = $constraint;
}
/**
* @return string
*/
public function toString()
{
return 'method name ' . $this->constraint->toString();
}
/**
* @param BaseInvocation $invocation
*
* @return bool
*/
public function matches(BaseInvocation $invocation)
{
return $this->constraint->evaluate($invocation->getMethodName(), '', true);
}
}

View File

@@ -0,0 +1,165 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
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;
/**
* Invocation matcher which looks for specific parameters in the invocations.
*
* Checks the parameters of all incoming invocations, the parameter list is
* checked against the defined constraints in $parameters. If the constraint
* is met it will return true in matches().
*/
class Parameters extends StatelessInvocation
{
/**
* @var Constraint[]
*/
private $parameters = [];
/**
* @var BaseInvocation
*/
private $invocation;
/**
* @var ExpectationFailedException
*/
private $parameterVerificationResult;
/**
* @param array $parameters
*
* @throws \PHPUnit\Framework\Exception
*/
public function __construct(array $parameters)
{
foreach ($parameters as $parameter) {
if (!($parameter instanceof Constraint)) {
$parameter = new IsEqual(
$parameter
);
}
$this->parameters[] = $parameter;
}
}
/**
* @return string
*/
public function toString()
{
$text = 'with parameter';
foreach ($this->parameters as $index => $parameter) {
if ($index > 0) {
$text .= ' and';
}
$text .= ' ' . $index . ' ' . $parameter->toString();
}
return $text;
}
/**
* @param BaseInvocation $invocation
*
* @return bool
*
* @throws \Exception
*/
public function matches(BaseInvocation $invocation)
{
$this->invocation = $invocation;
$this->parameterVerificationResult = null;
try {
$this->parameterVerificationResult = $this->verify();
return $this->parameterVerificationResult;
} catch (ExpectationFailedException $e) {
$this->parameterVerificationResult = $e;
throw $this->parameterVerificationResult;
}
}
/**
* Checks if the invocation $invocation matches the current rules. If it
* does the matcher will get the invoked() method called which should check
* if an expectation is met.
*
* @return bool
*
* @throws ExpectationFailedException
*/
public function verify()
{
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;
}
/**
* @return bool
*
* @throws ExpectationFailedException
*/
private function guardAgainstDuplicateEvaluationOfParameterConstraints()
{
if ($this->parameterVerificationResult instanceof \Exception) {
throw $this->parameterVerificationResult;
}
return (bool) $this->parameterVerificationResult;
}
}

View File

@@ -0,0 +1,54 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Matcher;
use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
/**
* Invocation matcher which does not care about previous state from earlier
* invocations.
*
* This abstract class can be implemented by matchers which does not care about
* state but only the current run-time value of the invocation itself.
*/
abstract class StatelessInvocation implements Invocation
{
/**
* Registers the invocation $invocation in the object as being invoked.
* This will only occur after matches() returns true which means the
* current invocation is the correct one.
*
* The matcher can store information from the invocation which can later
* be checked in verify(), or it can check the values directly and throw
* and exception if an expectation is not met.
*
* If the matcher is a stub it will also have a return value.
*
* @param BaseInvocation $invocation Object containing information on a mocked or stubbed method which was invoked
*
* @return mixed
*/
public function invoked(BaseInvocation $invocation)
{
}
/**
* Checks if the invocation $invocation matches the current rules. If it does
* the matcher will get the invoked() method called which should check if an
* expectation is met.
*
* @param Invocation $invocation Object containing information on a mocked or stubbed method which was invoked
*
* @return bool
*/
public function verify()
{
}
}

View File

@@ -0,0 +1,389 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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 PHPUnit\Framework\TestCase;
/**
* Implementation of the Builder pattern for Mock objects.
*/
class MockBuilder
{
/**
* @var TestCase
*/
private $testCase;
/**
* @var string
*/
private $type;
/**
* @var array
*/
private $methods = [];
/**
* @var array
*/
private $methodsExcept = [];
/**
* @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 = null;
/**
* @var bool
*/
private $allowMockingUnknownTypes = true;
/**
* @var Generator
*/
private $generator;
/**
* @param TestCase $testCase
* @param array|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.
*
* @return MockObject
*/
public function getMock()
{
$object = $this->generator->getMock(
$this->type,
$this->methods,
$this->constructorArgs,
$this->mockClassName,
$this->originalConstructor,
$this->originalClone,
$this->autoload,
$this->cloneArguments,
$this->callOriginalMethods,
$this->proxyTarget,
$this->allowMockingUnknownTypes
);
$this->testCase->registerMockObject($object);
return $object;
}
/**
* Creates a mock object for an abstract class using a fluent interface.
*
* @return MockObject
*/
public function getMockForAbstractClass()
{
$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.
*
* @return MockObject
*/
public function getMockForTrait()
{
$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.
*
* @param array|null $methods
*
* @return MockBuilder
*/
public function setMethods(array $methods = null)
{
$this->methods = $methods;
return $this;
}
/**
* Specifies the subset of methods to not mock. Default is to mock all of them.
*
* @param array $methods
*
* @return MockBuilder
*/
public function setMethodsExcept(array $methods = [])
{
$this->methodsExcept = $methods;
$this->setMethods(
\array_diff(
$this->generator->getClassMethods($this->type),
$this->methodsExcept
)
);
return $this;
}
/**
* Specifies the arguments for the constructor.
*
* @param array $args
*
* @return MockBuilder
*/
public function setConstructorArgs(array $args)
{
$this->constructorArgs = $args;
return $this;
}
/**
* Specifies the name for the mock class.
*
* @param string $name
*
* @return MockBuilder
*/
public function setMockClassName($name)
{
$this->mockClassName = $name;
return $this;
}
/**
* Disables the invocation of the original constructor.
*
* @return MockBuilder
*/
public function disableOriginalConstructor()
{
$this->originalConstructor = false;
return $this;
}
/**
* Enables the invocation of the original constructor.
*
* @return MockBuilder
*/
public function enableOriginalConstructor()
{
$this->originalConstructor = true;
return $this;
}
/**
* Disables the invocation of the original clone constructor.
*
* @return MockBuilder
*/
public function disableOriginalClone()
{
$this->originalClone = false;
return $this;
}
/**
* Enables the invocation of the original clone constructor.
*
* @return MockBuilder
*/
public function enableOriginalClone()
{
$this->originalClone = true;
return $this;
}
/**
* Disables the use of class autoloading while creating the mock object.
*
* @return MockBuilder
*/
public function disableAutoload()
{
$this->autoload = false;
return $this;
}
/**
* Enables the use of class autoloading while creating the mock object.
*
* @return MockBuilder
*/
public function enableAutoload()
{
$this->autoload = true;
return $this;
}
/**
* Disables the cloning of arguments passed to mocked methods.
*
* @return MockBuilder
*/
public function disableArgumentCloning()
{
$this->cloneArguments = false;
return $this;
}
/**
* Enables the cloning of arguments passed to mocked methods.
*
* @return MockBuilder
*/
public function enableArgumentCloning()
{
$this->cloneArguments = true;
return $this;
}
/**
* Enables the invocation of the original methods.
*
* @return MockBuilder
*/
public function enableProxyingToOriginalMethods()
{
$this->callOriginalMethods = true;
return $this;
}
/**
* Disables the invocation of the original methods.
*
* @return MockBuilder
*/
public function disableProxyingToOriginalMethods()
{
$this->callOriginalMethods = false;
$this->proxyTarget = null;
return $this;
}
/**
* Sets the proxy target.
*
* @param object $object
*
* @return MockBuilder
*/
public function setProxyTarget($object)
{
$this->proxyTarget = $object;
return $this;
}
/**
* @return MockBuilder
*/
public function allowMockingUnknownTypes()
{
$this->allowMockingUnknownTypes = true;
return $this;
}
/**
* @return MockBuilder
*/
public function disallowMockingUnknownTypes()
{
$this->allowMockingUnknownTypes = false;
return $this;
}
}

View File

@@ -0,0 +1,55 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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.
*/
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\MockObject\Builder\InvocationMocker;
use PHPUnit\Framework\MockObject\Matcher\Invocation;
/**
* Interface for all mock objects which are generated by
* MockBuilder.
*
* @method InvocationMocker method($constraint)
*/
interface PHPUnit_Framework_MockObject_MockObject /*extends Verifiable*/
{
/**
* Registers a new expectation in the mock object and returns the match
* object which can be infused with further details.
*
* @param Invocation $matcher
*
* @return InvocationMocker
*/
public function expects(Invocation $matcher);
/**
* @return InvocationMocker
*/
public function __phpunit_setOriginalObject($originalObject);
/**
* @return InvocationMocker
*/
public function __phpunit_getInvocationMocker();
/**
* 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 __phpunit_verify();
/**
* @return bool
*/
public function __phpunit_hasMatchers();
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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 PHPUnit\Framework\SelfDescribing;
/**
* An object that stubs the process of a normal method for a mock object.
*
* The stub object will replace the code for the stubbed method and return a
* specific value instead of the original value.
*/
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
*
* @return mixed
*/
public function invoke(Invocation $invocation);
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Stub;
use PHPUnit\Framework\MockObject\Invocation;
use PHPUnit\Framework\MockObject\Stub;
use SebastianBergmann\Exporter\Exporter;
/**
* Stubs a method by returning a user-defined stack of values.
*/
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()
{
$exporter = new Exporter;
return \sprintf(
'return user-specified value %s',
$exporter->export($this->value)
);
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Stub;
use PHPUnit\Framework\MockObject\Invocation;
use PHPUnit\Framework\MockObject\Stub;
use SebastianBergmann\Exporter\Exporter;
/**
* Stubs a method by raising a user-defined exception.
*/
class Exception implements Stub
{
private $exception;
public function __construct(\Throwable $exception)
{
$this->exception = $exception;
}
public function invoke(Invocation $invocation)
{
throw $this->exception;
}
public function toString()
{
$exporter = new Exporter;
return \sprintf(
'raise user-specified exception %s',
$exporter->export($this->exception)
);
}
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Stub;
use PHPUnit\Framework\MockObject\Matcher\Invocation;
/**
* Stubs a method by returning a user-defined value.
*/
interface MatcherCollection
{
/**
* Adds a new matcher to the collection which can be used as an expectation
* or a stub.
*
* @param Invocation $matcher Matcher for invocations to mock objects
*/
public function addMatcher(Invocation $matcher);
}

View File

@@ -0,0 +1,43 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Stub;
use PHPUnit\Framework\MockObject\Invocation;
use PHPUnit\Framework\MockObject\Stub;
/**
* Stubs a method by returning an argument that was passed to the mocked method.
*/
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];
}
return;
}
public function toString()
{
return \sprintf('return argument #%d', $this->argumentIndex);
}
}

View File

@@ -0,0 +1,52 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Stub;
use PHPUnit\Framework\MockObject\Invocation;
use PHPUnit\Framework\MockObject\Stub;
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()
{
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';
}
}

View File

@@ -0,0 +1,45 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Stub;
use PHPUnit\Framework\MockObject\Invocation;
use PHPUnit\Framework\MockObject\Stub;
use SebastianBergmann\Exporter\Exporter;
/**
* Stubs a method by returning a user-defined reference to a value.
*/
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()
{
$exporter = new Exporter;
return \sprintf(
'return user-specified reference %s',
$exporter->export($this->reference)
);
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Stub;
use PHPUnit\Framework\MockObject\Invocation;
use PHPUnit\Framework\MockObject\Invocation\ObjectInvocation;
use PHPUnit\Framework\MockObject\RuntimeException;
use PHPUnit\Framework\MockObject\Stub;
/**
* Stubs a method by returning the current object.
*/
class ReturnSelf implements Stub
{
public function invoke(Invocation $invocation)
{
if (!$invocation instanceof ObjectInvocation) {
throw new RuntimeException(
'The current object can only be returned when mocking an ' .
'object, not a static class.'
);
}
return $invocation->getObject();
}
public function toString()
{
return 'return the current object';
}
}

View File

@@ -0,0 +1,45 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Stub;
use PHPUnit\Framework\MockObject\Invocation;
use PHPUnit\Framework\MockObject\Stub;
use SebastianBergmann\Exporter\Exporter;
/**
* Stubs a method by returning a user-defined value.
*/
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()
{
$exporter = new Exporter;
return \sprintf(
'return user-specified value %s',
$exporter->export($this->value)
);
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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\Stub;
use PHPUnit\Framework\MockObject\Invocation;
use PHPUnit\Framework\MockObject\Stub;
/**
* Stubs a method by returning a value from a map.
*/
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;
}
}
return;
}
public function toString()
{
return 'return value from a map';
}
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of the phpunit-mock-objects package.
*
* (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 PHPUnit\Framework\ExpectationFailedException;
/**
* Interface for classes which must verify a given expectation.
*/
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();
}