Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 11 additions & 12 deletions src/Rules/PHPUnit/AssertSameBooleanExpectedRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Type\FalseBooleanType;
use PHPStan\Type\TrueBooleanType;
use PHPStan\Type\Constant\ConstantBooleanType;

class AssertSameBooleanExpectedRule implements \PHPStan\Rules\Rule
{
Expand Down Expand Up @@ -35,16 +34,16 @@ public function processNode(Node $node, Scope $scope): array

$leftType = $scope->getType($node->args[0]->value);

if ($leftType instanceof TrueBooleanType) {
return [
'You should use assertTrue() instead of assertSame() when expecting "true"',
];
}

if ($leftType instanceof FalseBooleanType) {
return [
'You should use assertFalse() instead of assertSame() when expecting "false"',
];
if ($leftType instanceof ConstantBooleanType) {
if ($leftType->getValue()) {
return [
'You should use assertTrue() instead of assertSame() when expecting "true"',
];
} else {
return [
'You should use assertFalse() instead of assertSame() when expecting "false"',
];
}
}

return [];
Expand Down
16 changes: 4 additions & 12 deletions src/Type/PHPUnit/CreateMockDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
Expand Down Expand Up @@ -38,26 +39,17 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
if (!isset($methodCall->args[$argumentIndex])) {
return $methodReflection->getReturnType();
}
$arg = $methodCall->args[$argumentIndex]->value;
if (!($arg instanceof \PhpParser\Node\Expr\ClassConstFetch)) {
$argType = $scope->getType($methodCall->args[$argumentIndex]->value);
if (!$argType instanceof ConstantStringType) {
return $methodReflection->getReturnType();
}

$class = $arg->class;
if (!($class instanceof \PhpParser\Node\Name)) {
return $methodReflection->getReturnType();
}

$class = (string) $class;
$class = $argType->getValue();

if ($class === 'static') {
return $methodReflection->getReturnType();
}

if ($class === 'self') {
$class = $scope->getClassReflection()->getName();
}

return TypeCombinator::intersect(
new ObjectType($class),
$methodReflection->getReturnType()
Expand Down
40 changes: 34 additions & 6 deletions tests/Rules/PHPUnit/AssertSameDifferentTypesRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,69 @@ public function testRule(): void
{
$this->analyse([__DIR__ . '/data/assert-same.php'], [
[
'Call to assertSame() with different types string and int will always result in test failure.',
'Call to assertSame() with different types string and int(1) will always result in test failure.',
10,
],
[
'Call to assertSame() with different types string and stdClass will always result in test failure.',
11,
],
[
'Call to assertSame() with different types int and string will always result in test failure.',
'Call to assertSame() with different types int(1) and string will always result in test failure.',
12,
],
[
'Call to assertSame() with different types string and int will always result in test failure.',
13,
],
[
'Call to assertSame() with different types array<int, string> and array<int, int> will always result in test failure.',
'Call to assertSame() with different types array<int(0)|int(1), string> and array<int(0)|int(1), int(1)|int(2)> will always result in test failure.',
14,
],
[
'Call to assertSame() with different types string and int will always result in test failure.',
'Call to assertSame() with different types string and int(2) will always result in test failure.',
16,
],
[
'Call to assertSame() with different types string and int will always result in test failure.',
'Call to assertSame() with different types string and int(2) will always result in test failure.',
17,
],
[
'Call to assertSame() with different types string and int will always result in test failure.',
'Call to assertSame() with different types string and int(2) will always result in test failure.',
18,
],
[
'Call to assertSame() with different types array<string> and array<int> will always result in test failure.',
39,
],
[
'Call to assertSame() with different types array<int(0), string> and array<int(0)|int(1), string> will always result in test failure.',
45,
],
[
'Call to assertSame() with different types string and string will always result in test failure.',
47,
],
[
'Call to assertSame() with different types array<int(0), string> and array<int(0)|int(1), int(1)|string> will always result in test failure.',
51,
],
[
'Call to assertSame() with different types array<int(0)|int(1)|int(2), float(3.000000)|int(2)|string> and array<int(0)|int(1), int(1)|string> will always result in test failure.',
52,
],
[
'Call to assertSame() with different types int(1) and int(2) will always result in test failure.',
53,
],
[
'Call to assertSame() with different types int(1) and int(2) will always result in test failure.',
54,
],
[
'Call to assertSame() with different types int(1) and int(2) will always result in test failure.',
55,
],
]);
}

Expand Down
125 changes: 125 additions & 0 deletions tests/Type/PHPUnit/CreateMockDynamicReturnTypeExtensionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\PHPUnit;

class CreateMockDynamicReturnTypeExtensionTest extends \PHPStan\Type\PHPUnit\ExtensionTestCase
{

public function createMockProvider(): array
{
return [
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$a',
],
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$b',
],
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$c',
],
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$d',
],
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$e',
],
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$f',
],
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$g',
],
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$h',
],
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$i',
],
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$j',
],
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$k',
],
[
'CreateMockTest\MockedClass&PHPUnit\Framework\MockObject\MockObject',
'$l',
],
[
'CreateMockTest\TestClass&PHPUnit\Framework\MockObject\MockObject',
'$m',
],
[
'CreateMockTest\TestClass&PHPUnit\Framework\MockObject\MockObject',
'$n',
],
[
'CreateMockTest\TestClass&PHPUnit\Framework\MockObject\MockObject',
'$o',
],
[
'CreateMockTest\TestClass&PHPUnit\Framework\MockObject\MockObject',
'$p',
],
[
'CreateMockTest\TestClass&PHPUnit\Framework\MockObject\MockObject',
'$q',
],
[
'CreateMockTest\TestClass&PHPUnit\Framework\MockObject\MockObject',
'$r',
],
[
'PHPUnit\Framework\MockObject\MockObject',
'$s',
],
[
'PHPUnit\Framework\MockObject\MockObject',
'$t',
],
[
'PHPUnit\Framework\MockObject\MockObject',
'$u',
],
[
'PHPUnit\Framework\MockObject\MockObject',
'$v',
],
[
'PHPUnit\Framework\MockObject\MockObject',
'$w',
],
[
'PHPUnit\Framework\MockObject\MockObject',
'$x',
],
];
}

/**
* @dataProvider createMockProvider
* @param string $description
* @param string $expression
*/
public function testCreateMock(string $description, string $expression): void
{
$this->assertTypes(
__DIR__ . '/data/TestClass.php',
$description,
$expression,
[new CreateMockDynamicReturnTypeExtension()]
);
}

}
79 changes: 79 additions & 0 deletions tests/Type/PHPUnit/ExtensionTestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\PHPUnit;

use PHPStan\Analyser\NodeScopeResolver;
use PHPStan\Analyser\Scope;
use PHPStan\Analyser\TypeSpecifier;
use PHPStan\Cache\Cache;
use PHPStan\File\FileHelper;
use PHPStan\PhpDoc\PhpDocStringResolver;
use PHPStan\Testing\TestCase;
use PHPStan\Type\FileTypeMapper;

abstract class ExtensionTestCase extends TestCase
{

protected function assertTypes(
string $file,
string $description,
string $expression,
array $dynamicMethodReturnTypeExtensions = [],
array $dynamicStaticMethodReturnTypeExtensions = [],
string $evaluatedPointExpression = 'die;'
): void
{
$this->processFile($file, function (\PhpParser\Node $node, Scope $scope) use ($description, $expression, $evaluatedPointExpression): void {
$printer = new \PhpParser\PrettyPrinter\Standard();
$printedNode = $printer->prettyPrint([$node]);
if ($printedNode === $evaluatedPointExpression) {
/** @var \PhpParser\Node\Expr $expressionNode */
$expressionNode = $this->getParser()->parseString(sprintf('<?php %s;', $expression))[0];
$type = $scope->getType($expressionNode);
$this->assertTypeDescribe(
$description,
$type->describe(),
sprintf('%s at %s', $expression, $evaluatedPointExpression)
);
}
}, $dynamicMethodReturnTypeExtensions, $dynamicStaticMethodReturnTypeExtensions);
}

protected function processFile(string $file, \Closure $callback, array $dynamicMethodReturnTypeExtensions = [], array $dynamicStaticMethodReturnTypeExtensions = []): void
{
/** @var \PHPStan\PhpDoc\PhpDocStringResolver $phpDocStringResolver */
$phpDocStringResolver = $this->getContainer()->getByType(PhpDocStringResolver::class);

$printer = new \PhpParser\PrettyPrinter\Standard();
$resolver = new NodeScopeResolver(
$this->createBroker(),
$this->getParser(),
$printer,
new FileTypeMapper($this->getParser(), $phpDocStringResolver, $this->createMock(Cache::class)),
new FileHelper('/'),
true,
true,
[]
);
$resolver->processNodes(
$this->getParser()->parseFile($file),
new Scope(
$this->createBroker($dynamicMethodReturnTypeExtensions, $dynamicStaticMethodReturnTypeExtensions),
$printer,
new TypeSpecifier($printer),
$file
),
$callback
);
}

protected function assertTypeDescribe(string $expectedDescription, string $actualDescription, string $label = ''): void
{
self::assertSame(
$expectedDescription,
$actualDescription,
$label
);
}

}
7 changes: 7 additions & 0 deletions tests/Type/PHPUnit/data/MockedClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php declare(strict_types = 1);

namespace CreateMockTest;

class MockedClass
{
}
Loading