Skip to content

Commit

Permalink
Merge pull request #38 from facile-it/hotfix/properties-stub
Browse files Browse the repository at this point in the history
Fix property stubs
  • Loading branch information
xzhayon authored Jul 14, 2017
2 parents 32fd8dc + 02233ec commit 690881b
Show file tree
Hide file tree
Showing 21 changed files with 460 additions and 130 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,22 @@ Moka::prophecy(FooInterface::class)
->willReturn($something);
```

**Warning:** this workaround cannot be used with methods having the same name as a previously stubbed property:

```php
Moka::prophecy(FooInterface::class, 'foo')->stub([
'$someName' => true
]);

var_dump(Moka::prophecy('foo')->someName);
// bool(true)

Moka::prophecy('foo')
->someName->set(new AnyValuesToken())
->willReturn($something);
// throws \Exception
```

## Plugin development

If you feel a genius and want to create your own mock generator (or add support for an existing one), just implement `Moka\Plugin\PluginInterface` and the relative `Moka\Strategy\MockingStrategyInterface`:
Expand Down
3 changes: 2 additions & 1 deletion src/Moka/Factory/StubFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Moka\Exception\InvalidArgumentException;
use Moka\Stub\MethodStub;
use Moka\Stub\PropertyStub;
use Moka\Stub\StubHelper;
use Moka\Stub\StubInterface;
use Moka\Stub\StubSet;

Expand All @@ -26,7 +27,7 @@ public static function fromArray(array $namesWithValues): StubSet
$stubSet = new StubSet();
foreach ($namesWithValues as $name => $value) {
try {
$stub = StubInterface::PREFIX_PROPERTY === $name[0]
$stub = StubHelper::isPropertyName($name)
? new PropertyStub($name, $value)
: new MethodStub($name, $value);

Expand Down
14 changes: 5 additions & 9 deletions src/Moka/Generator/Template/ClassTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*/
class ClassTemplate implements TemplateInterface
{
const UNSAFE_METHODS = ['__construct', '__destruct', '__call', '__clone'];
const UNSAFE_METHODS = ['__construct', '__destruct', '__call', '__get', '__clone'];

const TEMPLATE_FQCN = 'Moka_%s_%s';

Expand All @@ -28,8 +28,6 @@ public function __construct()
%s
}
%s
public function __call(%s $name, %s $arguments)
{
return $this->doCall($name, $arguments);
Expand All @@ -39,6 +37,8 @@ public function __get(%s $name)
{
return $this->doGet($name);
}
%s
};
return "%s";
Expand Down Expand Up @@ -66,20 +66,16 @@ protected static function doGenerate(\ReflectionClass $class): string

$methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
$methodsCode = [];
$methodNames = array_map(function (\ReflectionMethod $method) {
return $method->name;
}, $methods);

$callParametersTypes = array_fill(0, 2, '');
$getNameType = '';

foreach ($properties as $property) {
if (!in_array($property->name, $methodNames)) {
if ($property->isStatic()) {
continue;
}

$propertiesCode[] = PropertyTemplate::generate($property);

$constructorCode[] = PropertyInitializationTemplate::generate($property);
}

Expand Down Expand Up @@ -120,10 +116,10 @@ protected static function doGenerate(\ReflectionClass $class): string
ProxyTrait::class,
implode(PHP_EOL, $propertiesCode),
implode(PHP_EOL, $constructorCode),
implode(PHP_EOL, $methodsCode),
$callNameType ?: '',
$callArgumentsType ?: '',
$getNameType,
implode(PHP_EOL, $methodsCode),
$proxyClassName
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
class PropertyInitializationTemplate implements TemplateInterface
{
const TEMPLATE = '
%s%s = function () {
return $this->doGet("%s");
};
unset(%s%s);
';

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Moka/Plugin/Phake/Matcher/FirstStubMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public function doArgumentsMatch(array &$arguments)
*/
public function __toString()
{
return '';
return get_class($this);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Moka/Plugin/Prophecy/Token/AbstractPriorityToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ public function isLast()
*/
public function __toString()
{
return '';
return get_class($this);
}
}
4 changes: 2 additions & 2 deletions src/Moka/Proxy/ProxyInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
interface ProxyInterface
{
/**
* @param array $methodsWithValues
* @param array $namesWithValues
* @return ProxyInterface
*
* @throws InvalidArgumentException
* @throws MockNotCreatedException
*/
public function stub(array $methodsWithValues): ProxyInterface;
public function stub(array $namesWithValues): ProxyInterface;
}
25 changes: 25 additions & 0 deletions src/Moka/Proxy/ProxyTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Moka\Exception\InvalidArgumentException;
use Moka\Exception\MockNotCreatedException;
use Moka\Strategy\MockingStrategyInterface;
use Moka\Stub\StubHelper;

/**
* Trait ProxyTrait
Expand All @@ -23,6 +24,16 @@ trait ProxyTrait
*/
private $__moka_mockingStrategy;

/**
* @var array
*/
private $__moka_properties = [];

/**
* @var array
*/
private $__moka_methods = [];

/**
* @return object
*/
Expand Down Expand Up @@ -62,6 +73,16 @@ public function __moka_setMockingStrategy(MockingStrategyInterface $mockingStrat
*/
public function stub(array $namesWithValues): ProxyInterface
{
foreach ($namesWithValues as $name => $value) {
if (StubHelper::isPropertyName($name)) {
$this->__moka_properties[] = StubHelper::stripName($name);
}

if (StubHelper::isMethodName($name)) {
$this->__moka_methods[] = StubHelper::stripName($name);
}
}

/** @var $this ProxyInterface */
$this->__moka_mockingStrategy->decorate($this->__moka_mock, $namesWithValues);

Expand Down Expand Up @@ -94,6 +115,10 @@ protected function doGet(string $name)
return null;
}

if (in_array($name, $this->__moka_properties)) {
return $this->__moka_mockingStrategy->get($this->__moka_mock)->$name;
}

return $this->__moka_mockingStrategy->call($this->__moka_mock, $name);
}
}
13 changes: 1 addition & 12 deletions src/Moka/Stub/AbstractStub.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
*/
abstract class AbstractStub implements StubInterface
{
const REGEX_NAME = '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/';

/**
* @var string
*/
Expand All @@ -32,16 +30,7 @@ abstract class AbstractStub implements StubInterface
*/
public function __construct(string $name, $value)
{
if (!preg_match(self::REGEX_NAME, $name)) {
throw new InvalidArgumentException(
sprintf(
'Name must be a valid variable or method name, "%s" given',
$name
)
);
}

$this->name = $name;
$this->name = StubHelper::stripName($name);
$this->value = $value;
}

Expand Down
15 changes: 15 additions & 0 deletions src/Moka/Stub/MethodStub.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,25 @@

namespace Moka\Stub;

use Moka\Exception\InvalidArgumentException;

/**
* Class MethodStub
* @package Moka\Stub
*/
class MethodStub extends AbstractStub
{
/**
* MethodStub constructor.
* @param string $name
* @param mixed $value
*
* @throws InvalidArgumentException
*/
public function __construct(string $name, $value)
{
StubHelper::validateMethodName($name);

parent::__construct($name, $value);
}
}
12 changes: 2 additions & 10 deletions src/Moka/Stub/PropertyStub.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,8 @@ class PropertyStub extends AbstractStub
*/
public function __construct(string $name, $value)
{
if (static::PREFIX_PROPERTY !== $name[0]) {
throw new InvalidArgumentException(
sprintf(
'Name must be prefixed by "%s", "%s" given',
StubInterface::PREFIX_PROPERTY,
$name
)
);
}
StubHelper::validatePropertyName($name);

parent::__construct(substr($name, 1), $value);
parent::__construct($name, $value);
}
}
Loading

0 comments on commit 690881b

Please sign in to comment.