Skip to content

Commit

Permalink
Merge branch '10.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastianbergmann committed Jun 17, 2023
2 parents 3c86e7e + d8a4acc commit 2de18a2
Show file tree
Hide file tree
Showing 21 changed files with 1,995 additions and 1,362 deletions.
12 changes: 6 additions & 6 deletions .psalm/baseline.xml
Expand Up @@ -195,12 +195,6 @@
<code><![CDATA[$client->__getFunctions()]]></code>
</PossiblyNullArgument>
</file>
<file src="src/Framework/MockObject/Invocation.php">
<ArgumentTypeCoercion>
<code><![CDATA[$this->returnType]]></code>
<code>$types</code>
</ArgumentTypeCoercion>
</file>
<file src="src/Framework/MockObject/Matcher.php">
<InvalidNullableReturnType>
<code>MethodName</code>
Expand Down Expand Up @@ -248,6 +242,12 @@
<code><![CDATA[strpos($parameterAsString, '<optional> ')]]></code>
</PossiblyFalseOperand>
</file>
<file src="src/Framework/MockObject/ReturnValueGenerator.php">
<ArgumentTypeCoercion>
<code>$returnType</code>
<code>$types</code>
</ArgumentTypeCoercion>
</file>
<file src="src/Framework/MockObject/Rule/Parameters.php">
<PropertyNotSetInConstructor>
<code>$parameterVerificationResult</code>
Expand Down
3 changes: 2 additions & 1 deletion src/Event/Events/Test/Outcome/Errored.php
Expand Up @@ -11,6 +11,7 @@

use const PHP_EOL;
use function sprintf;
use function trim;
use PHPUnit\Event\Code;
use PHPUnit\Event\Code\Throwable;
use PHPUnit\Event\Event;
Expand Down Expand Up @@ -51,7 +52,7 @@ public function throwable(): Throwable

public function asString(): string
{
$message = $this->throwable->message();
$message = trim($this->throwable->message());

if (!empty($message)) {
$message = PHP_EOL . $message;
Expand Down
3 changes: 2 additions & 1 deletion src/Event/Events/Test/Outcome/Failed.php
Expand Up @@ -11,6 +11,7 @@

use const PHP_EOL;
use function sprintf;
use function trim;
use PHPUnit\Event\Code;
use PHPUnit\Event\Code\ComparisonFailure;
use PHPUnit\Event\Code\Throwable;
Expand Down Expand Up @@ -74,7 +75,7 @@ public function comparisonFailure(): ComparisonFailure

public function asString(): string
{
$message = $this->throwable->message();
$message = trim($this->throwable->message());

if (!empty($message)) {
$message = PHP_EOL . $message;
Expand Down
3 changes: 2 additions & 1 deletion src/Event/Events/Test/Outcome/MarkedIncomplete.php
Expand Up @@ -11,6 +11,7 @@

use const PHP_EOL;
use function sprintf;
use function trim;
use PHPUnit\Event\Code;
use PHPUnit\Event\Code\Throwable;
use PHPUnit\Event\Event;
Expand Down Expand Up @@ -51,7 +52,7 @@ public function throwable(): Throwable

public function asString(): string
{
$message = $this->throwable->message();
$message = trim($this->throwable->message());

if (!empty($message)) {
$message = PHP_EOL . $message;
Expand Down
172 changes: 16 additions & 156 deletions src/Framework/MockObject/Invocation.php
Expand Up @@ -10,36 +10,40 @@
namespace PHPUnit\Framework\MockObject;

use function array_map;
use function explode;
use function implode;
use function in_array;
use function interface_exists;
use function is_object;
use function sprintf;
use function str_contains;
use function str_starts_with;
use function strtolower;
use function substr;
use PHPUnit\Framework\SelfDescribing;
use PHPUnit\Util\Cloner;
use ReflectionClass;
use SebastianBergmann\Exporter\Exporter;
use stdClass;
use Throwable;

/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class Invocation implements SelfDescribing
{
/**
* @psalm-var class-string
*/
private readonly string $className;

/**
* @psalm-var non-empty-string
*/
private readonly string $methodName;
private array $parameters;
private readonly string $returnType;
private bool $isReturnTypeNullable = false;
private readonly bool $proxiedCall;
private readonly object $object;

/**
* @psalm-param class-string $className
* @psalm-param non-empty-string $methodName
*/
public function __construct(string $className, string $methodName, array $parameters, string $returnType, object $object, bool $cloneObjects = false, bool $proxiedCall = false)
{
$this->className = $className;
Expand Down Expand Up @@ -94,141 +98,11 @@ public function generateReturnValue(): mixed
return null;
}

$intersection = false;
$union = false;
$unionContainsIntersections = false;

if (str_contains($this->returnType, '|')) {
$types = explode('|', $this->returnType);
$union = true;

if (str_contains($this->returnType, '(')) {
$unionContainsIntersections = true;
}
} elseif (str_contains($this->returnType, '&')) {
$types = explode('&', $this->returnType);
$intersection = true;
} else {
$types = [$this->returnType];
}

$types = array_map('strtolower', $types);

if (!$intersection && !$unionContainsIntersections) {
if (in_array('', $types, true) ||
in_array('null', $types, true) ||
in_array('mixed', $types, true) ||
in_array('void', $types, true)) {
return null;
}

if (in_array('true', $types, true)) {
return true;
}

if (in_array('false', $types, true) ||
in_array('bool', $types, true)) {
return false;
}

if (in_array('float', $types, true)) {
return 0.0;
}

if (in_array('int', $types, true)) {
return 0;
}

if (in_array('string', $types, true)) {
return '';
}

if (in_array('array', $types, true)) {
return [];
}

if (in_array('static', $types, true)) {
try {
return (new ReflectionClass($this->object::class))->newInstanceWithoutConstructor();
} catch (\ReflectionException $e) {
throw new ReflectionException(
$e->getMessage(),
$e->getCode(),
$e,
);
}
}

if (in_array('object', $types, true)) {
return new stdClass;
}

if (in_array('callable', $types, true) ||
in_array('closure', $types, true)) {
return static function (): void
{
};
}

if (in_array('traversable', $types, true) ||
in_array('generator', $types, true) ||
in_array('iterable', $types, true)) {
$generator = static function (): \Generator
{
yield from [];
};

return $generator();
}

if (!$union) {
try {
return (new Generator)->getMock($this->returnType, [], [], '', false);
} catch (Throwable $t) {
if ($t instanceof Exception) {
throw $t;
}

throw new RuntimeException(
$t->getMessage(),
(int) $t->getCode(),
$t,
);
}
}
}

if ($intersection && $this->onlyInterfaces($types)) {
try {
return (new Generator)->getMockForInterfaces($types);
} catch (Throwable $t) {
throw new RuntimeException(
sprintf(
'Return value for %s::%s() cannot be generated: %s',
$this->className,
$this->methodName,
$t->getMessage(),
),
(int) $t->getCode(),
);
}
}

$reason = '';

if ($union) {
$reason = ' because the declared return type is a union';
} elseif ($intersection) {
$reason = ' because the declared return type is an intersection';
}

throw new RuntimeException(
sprintf(
'Return value for %s::%s() cannot be generated%s, please configure a return value for this method',
$this->className,
$this->methodName,
$reason,
),
return (new ReturnValueGenerator)->generate(
$this->className,
$this->methodName,
$this->object::class,
$this->returnType,
);
}

Expand All @@ -255,18 +129,4 @@ public function object(): object
{
return $this->object;
}

/**
* @psalm-param non-empty-list<string> $types
*/
private function onlyInterfaces(array $types): bool
{
foreach ($types as $type) {
if (!interface_exists($type)) {
return false;
}
}

return true;
}
}
6 changes: 3 additions & 3 deletions src/Framework/MockObject/MockObject.php
Expand Up @@ -9,11 +9,11 @@
*/
namespace PHPUnit\Framework\MockObject;

use PHPUnit\Framework\MockObject\Builder\InvocationMocker as BuilderInvocationMocker;
use PHPUnit\Framework\MockObject\Builder\InvocationMocker;
use PHPUnit\Framework\MockObject\Rule\InvocationOrder;

/**
* @method BuilderInvocationMocker method($constraint)
* @method InvocationMocker method($constraint)
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
*/
Expand All @@ -23,5 +23,5 @@ public function __phpunit_setOriginalObject(object $originalObject): void;

public function __phpunit_verify(bool $unsetInvocationMocker = true): void;

public function expects(InvocationOrder $invocationRule): BuilderInvocationMocker;
public function expects(InvocationOrder $invocationRule): InvocationMocker;
}

0 comments on commit 2de18a2

Please sign in to comment.