2019-10-13 07:59:52 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
2019-03-23 15:43:12 +01:00
|
|
|
|
|
|
|
namespace Rector\PhpSpecToPHPUnit;
|
|
|
|
|
|
|
|
use PhpParser\Node;
|
|
|
|
use PhpParser\Node\Expr\Variable;
|
|
|
|
use PhpParser\Node\Param;
|
|
|
|
use PhpParser\Node\Stmt\Class_;
|
|
|
|
use PhpParser\Node\Stmt\ClassMethod;
|
2020-02-06 22:48:18 +01:00
|
|
|
use Rector\Core\Exception\ShouldNotHappenException;
|
2020-02-09 23:47:00 +01:00
|
|
|
use Rector\NodeNameResolver\NodeNameResolver;
|
2019-04-13 11:20:27 +02:00
|
|
|
use Rector\NodeTypeResolver\Node\AttributeKey;
|
2021-01-16 22:45:18 +01:00
|
|
|
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
|
2019-03-23 15:43:12 +01:00
|
|
|
|
|
|
|
final class PhpSpecMockCollector
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var mixed[]
|
|
|
|
*/
|
|
|
|
private $mocks = [];
|
|
|
|
|
|
|
|
/**
|
2020-02-01 17:04:38 +01:00
|
|
|
* @var mixed[]
|
2019-03-23 15:43:12 +01:00
|
|
|
*/
|
2020-02-01 17:04:38 +01:00
|
|
|
private $mocksWithsTypes = [];
|
2019-03-23 15:43:12 +01:00
|
|
|
|
|
|
|
/**
|
2020-02-01 17:04:38 +01:00
|
|
|
* @var mixed[]
|
2019-03-23 15:43:12 +01:00
|
|
|
*/
|
2020-02-01 17:04:38 +01:00
|
|
|
private $propertyMocksByClass = [];
|
2019-03-23 15:43:12 +01:00
|
|
|
|
|
|
|
/**
|
2020-02-09 12:31:31 +01:00
|
|
|
* @var NodeNameResolver
|
2019-03-23 15:43:12 +01:00
|
|
|
*/
|
2020-02-09 12:31:31 +01:00
|
|
|
private $nodeNameResolver;
|
2019-03-23 15:43:12 +01:00
|
|
|
|
2019-03-26 15:43:47 +01:00
|
|
|
/**
|
2021-01-16 22:45:18 +01:00
|
|
|
* @var SimpleCallableNodeTraverser
|
2019-03-26 15:43:47 +01:00
|
|
|
*/
|
2021-01-16 22:45:18 +01:00
|
|
|
private $simpleCallableNodeTraverser;
|
2019-03-26 15:43:47 +01:00
|
|
|
|
2021-01-16 22:45:18 +01:00
|
|
|
public function __construct(
|
|
|
|
SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
|
|
|
|
NodeNameResolver $nodeNameResolver
|
|
|
|
) {
|
2020-02-09 12:31:31 +01:00
|
|
|
$this->nodeNameResolver = $nodeNameResolver;
|
2021-01-16 22:45:18 +01:00
|
|
|
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
|
2019-03-23 15:43:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return mixed[]
|
|
|
|
*/
|
|
|
|
public function resolveClassMocksFromParam(Class_ $class): array
|
|
|
|
{
|
2020-02-09 12:31:31 +01:00
|
|
|
$className = $this->nodeNameResolver->getName($class);
|
2019-03-23 15:43:12 +01:00
|
|
|
|
|
|
|
if (isset($this->mocks[$className])) {
|
|
|
|
return $this->mocks[$className];
|
|
|
|
}
|
|
|
|
|
2021-01-16 22:45:18 +01:00
|
|
|
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($class, function (Node $node): void {
|
2019-03-23 15:43:12 +01:00
|
|
|
if (! $node instanceof ClassMethod) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! $node->isPublic()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($node->params as $param) {
|
|
|
|
$this->addMockFromParam($param);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// set default value if none was found
|
|
|
|
if (! isset($this->mocks[$className])) {
|
|
|
|
$this->mocks[$className] = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->mocks[$className];
|
|
|
|
}
|
|
|
|
|
|
|
|
public function isVariableMockInProperty(Variable $variable): bool
|
|
|
|
{
|
2020-02-09 12:31:31 +01:00
|
|
|
$variableName = $this->nodeNameResolver->getName($variable);
|
2019-04-13 11:20:27 +02:00
|
|
|
$className = $variable->getAttribute(AttributeKey::CLASS_NAME);
|
2019-03-23 15:43:12 +01:00
|
|
|
|
2019-03-26 15:43:47 +01:00
|
|
|
return in_array($variableName, $this->propertyMocksByClass[$className] ?? [], true);
|
2019-03-23 15:43:12 +01:00
|
|
|
}
|
|
|
|
|
2020-06-29 23:19:37 +02:00
|
|
|
public function getTypeForClassAndVariable(Class_ $class, string $variable): string
|
2019-03-23 15:43:12 +01:00
|
|
|
{
|
2020-06-29 23:19:37 +02:00
|
|
|
$className = $this->nodeNameResolver->getName($class);
|
2019-03-23 15:43:12 +01:00
|
|
|
|
2019-03-24 12:58:37 +01:00
|
|
|
if (! isset($this->mocksWithsTypes[$className][$variable])) {
|
2019-09-21 13:03:30 +02:00
|
|
|
throw new ShouldNotHappenException();
|
2019-03-24 12:58:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $this->mocksWithsTypes[$className][$variable];
|
2019-03-23 15:43:12 +01:00
|
|
|
}
|
|
|
|
|
2019-03-26 15:43:47 +01:00
|
|
|
public function addPropertyMock(string $class, string $property): void
|
|
|
|
{
|
|
|
|
$this->propertyMocksByClass[$class][] = $property;
|
|
|
|
}
|
|
|
|
|
2019-03-23 15:43:12 +01:00
|
|
|
private function addMockFromParam(Param $param): void
|
|
|
|
{
|
2020-02-09 12:31:31 +01:00
|
|
|
$variable = $this->nodeNameResolver->getName($param->var);
|
2019-03-23 15:43:12 +01:00
|
|
|
|
|
|
|
/** @var string $class */
|
2019-04-13 11:20:27 +02:00
|
|
|
$class = $param->getAttribute(AttributeKey::CLASS_NAME);
|
2019-03-23 15:43:12 +01:00
|
|
|
|
2019-04-13 11:20:27 +02:00
|
|
|
$this->mocks[$class][$variable][] = $param->getAttribute(AttributeKey::METHOD_NAME);
|
2019-03-23 15:43:12 +01:00
|
|
|
|
|
|
|
if ($param->type === null) {
|
2019-09-21 13:03:30 +02:00
|
|
|
throw new ShouldNotHappenException();
|
2019-03-23 15:43:12 +01:00
|
|
|
}
|
|
|
|
|
2020-05-13 22:43:48 +02:00
|
|
|
$paramType = (string) ($param->type->getAttribute(AttributeKey::ORIGINAL_NAME) ?: $param->type);
|
2019-03-23 15:43:12 +01:00
|
|
|
$this->mocksWithsTypes[$class][$variable] = $paramType;
|
|
|
|
}
|
|
|
|
}
|