Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 425904d

Browse files
Support for createMockForIntersectionOfInterfaces
1 parent 202afe9 commit 425904d

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

‎extension.neon‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ services:
4747
class: PHPStan\Type\PHPUnit\MockBuilderDynamicReturnTypeExtension
4848
tags:
4949
- phpstan.broker.dynamicMethodReturnTypeExtension
50+
-
51+
class: PHPStan\Type\PHPUnit\MockForIntersectionDynamicReturnTypeExtension
52+
tags:
53+
- phpstan.broker.dynamicMethodReturnTypeExtension
5054
-
5155
class: PHPStan\Rules\PHPUnit\CoversHelper
5256
-
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\PHPUnit;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Type\DynamicMethodReturnTypeExtension;
9+
use PHPStan\Type\ObjectType;
10+
use PHPStan\Type\Type;
11+
use PHPStan\Type\TypeCombinator;
12+
use PHPUnit\Framework\MockObject\MockObject;
13+
use PHPUnit\Framework\MockObject\Stub;
14+
use PHPUnit\Framework\TestCase;
15+
use function in_array;
16+
17+
class MockForIntersectionDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
18+
{
19+
20+
public function getClass(): string
21+
{
22+
return TestCase::class;
23+
}
24+
25+
public function isMethodSupported(MethodReflection $methodReflection): bool
26+
{
27+
return in_array(
28+
$methodReflection->getName(),
29+
[
30+
'createMockForIntersectionOfInterfaces',
31+
'createStubForIntersectionOfInterfaces',
32+
],
33+
true,
34+
);
35+
}
36+
37+
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type
38+
{
39+
$args = $methodCall->getArgs();
40+
if (!isset($args[0])) {
41+
return null;
42+
}
43+
44+
$interfaces = $scope->getType($args[0]->value);
45+
$constantArrays = $interfaces->getConstantArrays();
46+
if (count($constantArrays) !== 1) {
47+
return null;
48+
}
49+
50+
$constantArray = $constantArrays[0];
51+
if (count($constantArray->getOptionalKeys()) > 0) {
52+
return null;
53+
}
54+
55+
$result = [];
56+
if ($methodReflection->getName() === 'createMockForIntersectionOfInterfaces') {
57+
$result[] = new ObjectType(MockObject::class);
58+
} else {
59+
$result[] = new ObjectType(Stub::class);
60+
}
61+
62+
63+
foreach ($constantArray->getValueTypes() as $valueType) {
64+
if (!$valueType->isClassString()->yes()) {
65+
return null;
66+
}
67+
68+
$values = $valueType->getConstantScalarValues();
69+
if (count($values) !== 1) {
70+
return null;
71+
}
72+
73+
$result[] = new ObjectType($values[0]);
74+
}
75+
76+
return TypeCombinator::intersect(...$result);
77+
}
78+
79+
}

‎tests/Rules/PHPUnit/MockMethodCallRuleTest.php‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PHPStan\Rules\Rule;
66
use PHPStan\Testing\RuleTestCase;
7+
use PHPUnit\Framework\TestCase;
78
use const PHP_VERSION_ID;
89

910
/**
@@ -34,6 +35,17 @@ public function testRule(): void
3435
],
3536
];
3637

38+
if (method_exists(TestCase::class, 'createMockForIntersectionOfInterfaces')) {
39+
$expectedErrors[] = [
40+
'Trying to mock an undefined method bazMethod() on class MockMethodCall\FooInterface&MockMethodCall\BarInterface.',
41+
49,
42+
];
43+
$expectedErrors[] = [
44+
'Trying to mock an undefined method bazMethod() on class MockMethodCall\FooInterface&MockMethodCall\BarInterface.',
45+
57,
46+
];
47+
}
48+
3749
$this->analyse([__DIR__ . '/data/mock-method-call.php'], $expectedErrors);
3850
}
3951

‎tests/Rules/PHPUnit/data/mock-method-call.php‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ public function testMockObject(\PHPUnit\Framework\MockObject\MockObject $mock)
4141
$mock->method('doFoo');
4242
}
4343

44+
public function testMockForIntersection()
45+
{
46+
$mock = $this->createMockForIntersectionOfInterfaces([FooInterface::class, BarInterface::class]);
47+
$mock->method('fooMethod');
48+
$mock->method('barMethod');
49+
$mock->method('bazMethod');
50+
}
51+
52+
public function testStubForIntersection()
53+
{
54+
$stub = $this->createStubForIntersectionOfInterfaces([FooInterface::class, BarInterface::class]);
55+
$stub->method('fooMethod');
56+
$stub->method('barMethod');
57+
$stub->method('bazMethod');
58+
}
59+
4460
}
4561

4662
class Bar {
@@ -71,3 +87,11 @@ public function testMockFinalClass()
7187
}
7288

7389
}
90+
91+
interface FooInterface {
92+
public function fooMethod(): int;
93+
}
94+
95+
interface BarInterface {
96+
public function barMethod(): string;
97+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /