Skip to content
This repository was archived by the owner on Jul 8, 2023. It is now read-only.

Commit 1e80118

Browse files
committed
Partial mocks of abstract functions with return types now work as intended. Closes #212.
1 parent 8a89291 commit 1e80118

19 files changed

+225
-41
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
## Next release
44

5+
- **[FIXED]** Partial mocks of abstract functions with return types now work as
6+
intended ([#212]).
57
- **[FIXED]** Fixed regression of [#203] and [#204].
68

9+
[#212]: https://github.com/eloquent/phony/issues/212
10+
711
## 0.14.5 (2016-12-07)
812

913
- **[FIXED]** Mock handle substitution fixed for `threw()` and

src/Facade/FacadeDriver.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ protected function __construct(AssertionRecorder $assertionRecorder)
136136
$matcherFactory
137137
->addMatcherDriver(new ProphecyMatcherDriver($wildcardMatcher));
138138
$matcherFactory->addMatcherDriver(new MockeryMatcherDriver());
139-
$emptyValueFactory = new EmptyValueFactory();
139+
$emptyValueFactory = new EmptyValueFactory(
140+
$featureDetector
141+
);
140142
$generatorAnswerBuilderFactory = new GeneratorAnswerBuilderFactory(
141143
$invocableInspector,
142144
$invoker,
@@ -229,6 +231,7 @@ protected function __construct(AssertionRecorder $assertionRecorder)
229231
$handleFactory = new HandleFactory(
230232
$stubFactory,
231233
$stubVerifierFactory,
234+
$emptyValueFactory,
232235
$assertionRenderer,
233236
$assertionRecorder,
234237
$invoker

src/Mock/Handle/AbstractHandle.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Eloquent\Phony\Mock\Method\WrappedUncallableMethod;
2525
use Eloquent\Phony\Mock\Mock;
2626
use Eloquent\Phony\Spy\Spy;
27+
use Eloquent\Phony\Stub\EmptyValueFactory;
2728
use Eloquent\Phony\Stub\StubFactory;
2829
use Eloquent\Phony\Stub\StubVerifier;
2930
use Eloquent\Phony\Stub\StubVerifierFactory;
@@ -47,6 +48,7 @@ abstract class AbstractHandle implements Handle
4748
* @param Mock|null $mock The mock, or null if this is a static handle.
4849
* @param StubFactory $stubFactory The stub factory to use.
4950
* @param StubVerifierFactory $stubVerifierFactory The stub verifier factory to use.
51+
* @param EmptyValueFactory $emptyValueFactory The empty value factory to use.
5052
* @param AssertionRenderer $assertionRenderer The assertion renderer to use.
5153
* @param AssertionRecorder $assertionRecorder The assertion recorder to use.
5254
* @param Invoker $invoker The invoker to use.
@@ -60,6 +62,7 @@ public function __construct(
6062
Mock $mock = null,
6163
StubFactory $stubFactory,
6264
StubVerifierFactory $stubVerifierFactory,
65+
EmptyValueFactory $emptyValueFactory,
6366
AssertionRenderer $assertionRenderer,
6467
AssertionRecorder $assertionRecorder,
6568
Invoker $invoker
@@ -72,6 +75,7 @@ public function __construct(
7275
$this->callMagicMethod = $callMagicMethod;
7376
$this->stubFactory = $stubFactory;
7477
$this->stubVerifierFactory = $stubVerifierFactory;
78+
$this->emptyValueFactory = $emptyValueFactory;
7579
$this->assertionRenderer = $assertionRenderer;
7680
$this->assertionRecorder = $assertionRecorder;
7781
$this->invoker = $invoker;
@@ -332,21 +336,34 @@ protected function createStub($name)
332336
$magicKey = '__callstatic';
333337
}
334338

339+
if (isset($this->uncallableMethods[$magicKey])) {
340+
$isUncallable = true;
341+
$returnValue = $this->emptyValueFactory->fromFunction(
342+
$this->class->getMethod($magicKey)
343+
);
344+
} else {
345+
$isUncallable = false;
346+
$returnValue = null;
347+
}
348+
335349
$stub = $this->stubFactory->create(
336350
new WrappedMagicMethod(
337351
$name,
338352
$this->callMagicMethod,
339-
isset($this->uncallableMethods[$magicKey]),
340-
$this
353+
$isUncallable,
354+
$this,
355+
$returnValue
341356
),
342357
$mock,
343358
$this->state->defaultAnswerCallback
344359
);
345360
} elseif (isset($this->uncallableMethods[$key])) {
361+
$method = $this->class->getMethod($name);
346362
$stub = $this->stubFactory->create(
347363
new WrappedUncallableMethod(
348-
$this->class->getMethod($name),
349-
$this
364+
$method,
365+
$this,
366+
$this->emptyValueFactory->fromFunction($method)
350367
),
351368
$mock,
352369
$this->state->defaultAnswerCallback
@@ -409,6 +426,7 @@ protected function createStub($name)
409426
private $callMagicMethod;
410427
private $stubFactory;
411428
private $stubVerifierFactory;
429+
private $emptyValueFactory;
412430
private $assertionRenderer;
413431
private $assertionRecorder;
414432
private $invoker;

src/Mock/Handle/HandleFactory.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Eloquent\Phony\Mock\Exception\MockException;
2121
use Eloquent\Phony\Mock\Exception\NonMockClassException;
2222
use Eloquent\Phony\Mock\Mock;
23+
use Eloquent\Phony\Stub\EmptyValueFactory;
2324
use Eloquent\Phony\Stub\StubFactory;
2425
use Eloquent\Phony\Stub\StubVerifierFactory;
2526
use ReflectionClass;
@@ -41,6 +42,7 @@ public static function instance()
4142
self::$instance = new self(
4243
StubFactory::instance(),
4344
StubVerifierFactory::instance(),
45+
EmptyValueFactory::instance(),
4446
AssertionRenderer::instance(),
4547
ExceptionAssertionRecorder::instance(),
4648
Invoker::instance()
@@ -55,19 +57,22 @@ public static function instance()
5557
*
5658
* @param StubFactory $stubFactory The stub factory to use.
5759
* @param StubVerifierFactory $stubVerifierFactory The stub verifier factory to use.
60+
* @param EmptyValueFactory $emptyValueFactory The empty value factory to use.
5861
* @param AssertionRenderer $assertionRenderer The assertion renderer to use.
5962
* @param AssertionRecorder $assertionRecorder The assertion recorder to use.
6063
* @param Invoker $invoker The invoker to use.
6164
*/
6265
public function __construct(
6366
StubFactory $stubFactory,
6467
StubVerifierFactory $stubVerifierFactory,
68+
EmptyValueFactory $emptyValueFactory,
6569
AssertionRenderer $assertionRenderer,
6670
AssertionRecorder $assertionRecorder,
6771
Invoker $invoker
6872
) {
6973
$this->stubFactory = $stubFactory;
7074
$this->stubVerifierFactory = $stubVerifierFactory;
75+
$this->emptyValueFactory = $emptyValueFactory;
7176
$this->assertionRenderer = $assertionRenderer;
7277
$this->assertionRecorder = $assertionRecorder;
7378
$this->invoker = $invoker;
@@ -114,6 +119,7 @@ public function instanceHandle($mock, $label = null)
114119
),
115120
$this->stubFactory,
116121
$this->stubVerifierFactory,
122+
$this->emptyValueFactory,
117123
$this->assertionRenderer,
118124
$this->assertionRecorder,
119125
$this->invoker
@@ -173,6 +179,7 @@ public function staticHandle($class)
173179
),
174180
$this->stubFactory,
175181
$this->stubVerifierFactory,
182+
$this->emptyValueFactory,
176183
$this->assertionRenderer,
177184
$this->assertionRecorder,
178185
$this->invoker
@@ -186,6 +193,7 @@ public function staticHandle($class)
186193
private static $instance;
187194
private $stubFactory;
188195
private $stubVerifierFactory;
196+
private $emptyValueFactory;
189197
private $assertionRenderer;
190198
private $assertionRecorder;
191199
private $invoker;

src/Mock/Handle/InstanceHandle.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Eloquent\Phony\Call\Arguments;
1717
use Eloquent\Phony\Invocation\Invoker;
1818
use Eloquent\Phony\Mock\Mock;
19+
use Eloquent\Phony\Stub\EmptyValueFactory;
1920
use Eloquent\Phony\Stub\StubFactory;
2021
use Eloquent\Phony\Stub\StubVerifierFactory;
2122
use ReflectionClass;
@@ -34,6 +35,7 @@ class InstanceHandle extends AbstractHandle
3435
* @param stdClass $state The state.
3536
* @param StubFactory $stubFactory The stub factory to use.
3637
* @param StubVerifierFactory $stubVerifierFactory The stub verifier factory to use.
38+
* @param EmptyValueFactory $emptyValueFactory The empty value factory to use.
3739
* @param AssertionRenderer $assertionRenderer The assertion renderer to use.
3840
* @param AssertionRecorder $assertionRecorder The assertion recorder to use.
3941
* @param Invoker $invoker The invoker to use.
@@ -43,6 +45,7 @@ public function __construct(
4345
stdClass $state,
4446
StubFactory $stubFactory,
4547
StubVerifierFactory $stubVerifierFactory,
48+
EmptyValueFactory $emptyValueFactory,
4649
AssertionRenderer $assertionRenderer,
4750
AssertionRecorder $assertionRecorder,
4851
Invoker $invoker
@@ -89,6 +92,7 @@ public function __construct(
8992
$mock,
9093
$stubFactory,
9194
$stubVerifierFactory,
95+
$emptyValueFactory,
9296
$assertionRenderer,
9397
$assertionRecorder,
9498
$invoker

src/Mock/Handle/StaticHandle.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Eloquent\Phony\Assertion\AssertionRecorder;
1515
use Eloquent\Phony\Assertion\AssertionRenderer;
1616
use Eloquent\Phony\Invocation\Invoker;
17+
use Eloquent\Phony\Stub\EmptyValueFactory;
1718
use Eloquent\Phony\Stub\StubFactory;
1819
use Eloquent\Phony\Stub\StubVerifierFactory;
1920
use ReflectionClass;
@@ -32,6 +33,7 @@ class StaticHandle extends AbstractHandle
3233
* @param stdClass $state The state.
3334
* @param StubFactory $stubFactory The stub factory to use.
3435
* @param StubVerifierFactory $stubVerifierFactory The stub verifier factory to use.
36+
* @param EmptyValueFactory $emptyValueFactory The empty value factory to use.
3537
* @param AssertionRenderer $assertionRenderer The assertion renderer to use.
3638
* @param AssertionRecorder $assertionRecorder The assertion recorder to use.
3739
* @param Invoker $invoker The invoker to use.
@@ -41,6 +43,7 @@ public function __construct(
4143
stdClass $state,
4244
StubFactory $stubFactory,
4345
StubVerifierFactory $stubVerifierFactory,
46+
EmptyValueFactory $emptyValueFactory,
4447
AssertionRenderer $assertionRenderer,
4548
AssertionRecorder $assertionRecorder,
4649
Invoker $invoker
@@ -75,6 +78,7 @@ public function __construct(
7578
null,
7679
$stubFactory,
7780
$stubVerifierFactory,
81+
$emptyValueFactory,
7882
$assertionRenderer,
7983
$assertionRecorder,
8084
$invoker

src/Mock/Method/WrappedMagicMethod.php

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,20 @@ class WrappedMagicMethod extends AbstractWrappedInvocable implements
3131
* @param ReflectionMethod $callMagicMethod The _callMagic() method.
3232
* @param bool $isUncallable True if the underlying magic method is uncallable.
3333
* @param Handle $handle The handle.
34+
* @param mixed $returnValue The return value.
3435
*/
3536
public function __construct(
3637
$name,
3738
ReflectionMethod $callMagicMethod,
3839
$isUncallable,
39-
Handle $handle
40+
Handle $handle,
41+
$returnValue
4042
) {
4143
$this->name = $name;
4244
$this->callMagicMethod = $callMagicMethod;
4345
$this->isUncallable = $isUncallable;
4446
$this->handle = $handle;
47+
$this->returnValue = $returnValue;
4548

4649
if ($callMagicMethod->isStatic()) {
4750
$this->mock = null;
@@ -120,7 +123,7 @@ public function mock()
120123
public function invokeWith($arguments = array())
121124
{
122125
if ($this->isUncallable) {
123-
return;
126+
return $this->returnValue;
124127
}
125128

126129
if (!$arguments instanceof Arguments) {
@@ -131,9 +134,10 @@ public function invokeWith($arguments = array())
131134
->invoke($this->mock, $this->name, $arguments);
132135
}
133136

134-
protected $name;
135-
protected $callMagicMethod;
136-
protected $isUncallable;
137-
protected $handle;
138-
protected $mock;
137+
private $name;
138+
private $callMagicMethod;
139+
private $isUncallable;
140+
private $handle;
141+
private $mock;
142+
private $returnValue;
139143
}

src/Mock/Method/WrappedUncallableMethod.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,33 @@
1111

1212
namespace Eloquent\Phony\Mock\Method;
1313

14+
use Eloquent\Phony\Mock\Handle\Handle;
1415
use Error;
1516
use Exception;
17+
use ReflectionMethod;
1618

1719
/**
1820
* A wrapper for uncallable methods.
1921
*/
2022
class WrappedUncallableMethod extends AbstractWrappedMethod
2123
{
24+
/**
25+
* Construct a new wrapped uncallable method.
26+
*
27+
* @param ReflectionMethod $method The method.
28+
* @param Handle $handle The handle.
29+
* @param mixed $returnValue The return value.
30+
*/
31+
public function __construct(
32+
ReflectionMethod $method,
33+
Handle $handle,
34+
$returnValue
35+
) {
36+
$this->returnValue = $returnValue;
37+
38+
parent::__construct($method, $handle);
39+
}
40+
2241
/**
2342
* Invoke this object.
2443
*
@@ -31,6 +50,8 @@ class WrappedUncallableMethod extends AbstractWrappedMethod
3150
*/
3251
public function invokeWith($arguments = array())
3352
{
34-
return null; // do nothing
53+
return $this->returnValue;
3554
}
55+
56+
private $returnValue;
3657
}

src/Stub/EmptyValueFactory.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Eloquent\Phony\Stub;
1313

1414
use Eloquent\Phony\Mock\Builder\MockBuilderFactory;
15+
use Eloquent\Phony\Reflection\FeatureDetector;
16+
use ReflectionFunctionAbstract;
1517
use ReflectionType;
1618

1719
/**
@@ -27,12 +29,23 @@ class EmptyValueFactory
2729
public static function instance()
2830
{
2931
if (!self::$instance) {
30-
self::$instance = new self();
32+
self::$instance = new self(FeatureDetector::instance());
3133
}
3234

3335
return self::$instance;
3436
}
3537

38+
/**
39+
* Construct a new empty value factory.
40+
*
41+
* @param FeatureDetector $featureDetector The feature detector to use.
42+
*/
43+
public function __construct(FeatureDetector $featureDetector)
44+
{
45+
$this->isReturnTypeSupported =
46+
$featureDetector->isSupported('return.type');
47+
}
48+
3649
/**
3750
* Set the stub verifier factory.
3851
*
@@ -116,7 +129,28 @@ public function fromType(ReflectionType $type)
116129
return $this->mockBuilderFactory->create($typeName)->full();
117130
}
118131

132+
/**
133+
* Create a return value for the supplied function.
134+
*
135+
* @param ReflectionFunctionAbstract $function The function.
136+
*
137+
* @return mixed A value that can be returned by the function.
138+
*/
139+
public function fromFunction(ReflectionFunctionAbstract $function)
140+
{
141+
if (!$this->isReturnTypeSupported) {
142+
return null; // @codeCoverageIgnore
143+
}
144+
145+
if ($type = $function->getReturnType()) {
146+
return $this->fromType($type);
147+
}
148+
149+
return null;
150+
}
151+
119152
private static $instance;
120153
private $stubVerifierFactory;
121154
private $mockBuilderFactory;
155+
private $isReturnTypeSupported;
122156
}

0 commit comments

Comments
 (0)