Skip to content

Commit bf24250

Browse files
committed
WIP assertSuperType
1 parent 361b5b7 commit bf24250

4 files changed

Lines changed: 165 additions & 0 deletions

File tree

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
"classmap": [
1515
"tests/objects"
1616
],
17+
"files": [
18+
"tests/functions.php"
19+
],
1720
"psr-4": {
1821
"Vojtechdobes\\Tests\\": "tests/cases/"
1922
}

phpstan-baseline.neon

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ parameters:
2424
count: 3
2525
path: tests/cases/DatabaseSpecificTypeInferenceSharedBase.php
2626

27+
-
28+
message: '#^Calling PHPStan\\File\\SystemAgnosticSimpleRelativePathHelper\:\:getRelativePath\(\) is not covered by backward compatibility promise\. The method might change in a minor PHPStan version\.$#'
29+
identifier: phpstanApi.method
30+
count: 4
31+
path: tests/cases/DatabaseSpecificTypeInferenceTest.php
32+
33+
-
34+
message: '#^Creating new PHPStan\\File\\SystemAgnosticSimpleRelativePathHelper is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#'
35+
identifier: phpstanApi.constructor
36+
count: 1
37+
path: tests/cases/DatabaseSpecificTypeInferenceTest.php
38+
2739
-
2840
message: '#^Parameter \#1 \$sql of method Dibi\\Connection\<null\>\:\:nativeQuery\(\) expects literal\-string, non\-empty\-string given\.$#'
2941
identifier: argument.type
@@ -35,3 +47,9 @@ parameters:
3547
identifier: argument.type
3648
count: 1
3749
path: tests/cases/SchemaTest.php
50+
51+
-
52+
message: '#^Declaring PHPStan namespace is not allowed in 3rd party packages\.$#'
53+
identifier: phpstanApi.phpstanNamespace
54+
count: 1
55+
path: tests/functions.php

tests/cases/DatabaseSpecificTypeInferenceTest.php

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

55
use PHPStan;
66
use PHPUnit;
7+
use PhpParser;
78

89

910
final class DatabaseSpecificTypeInferenceTest extends PHPStan\Testing\TypeInferenceTestCase
@@ -38,4 +39,130 @@ public static function getAdditionalConfigFiles(): array
3839
return [__DIR__ . '/DatabaseSpecificTypeInferenceTest.extension.neon'];
3940
}
4041

42+
43+
44+
/**
45+
* @api
46+
* @param mixed ...$args
47+
*/
48+
public function assertFileAsserts(
49+
string $assertType,
50+
string $file,
51+
...$args,
52+
): void
53+
{
54+
parent::assertFileAsserts($assertType, $file, ...$args);
55+
56+
if ($assertType === 'superType') {
57+
$expected = $args[0];
58+
$actual = $args[1];
59+
$isCorrect = $args[2];
60+
61+
$failureMessage = sprintf('Expected subtype of %s, got type %s in %s on line %d.', $expected, $actual, $file, $args[3]);
62+
63+
self::assertTrue(
64+
$isCorrect,
65+
$failureMessage,
66+
);
67+
}
68+
}
69+
70+
71+
72+
/**
73+
* @api
74+
* @return array<string, mixed[]>
75+
*/
76+
public static function gatherAssertTypes(string $file): array
77+
{
78+
$parentAsserts = parent::gatherAssertTypes($file);
79+
80+
$fileHelper = self::getContainer()->getByType(PHPStan\File\FileHelper::class);
81+
82+
$relativePathHelper = new PHPStan\File\SystemAgnosticSimpleRelativePathHelper($fileHelper);
83+
$typeStringResolver = self::getContainer()->getByType(PHPStan\PhpDoc\TypeStringResolver::class);
84+
85+
$file = $fileHelper->normalizePath($file);
86+
87+
$asserts = [];
88+
self::processFile($file, static function (PhpParser\Node $node, PHPStan\Analyser\Scope $scope) use (& $asserts, $file, $relativePathHelper, $typeStringResolver): void {
89+
if (!$node instanceof PhpParser\Node\Expr\FuncCall) {
90+
return;
91+
}
92+
93+
$nameNode = $node->name;
94+
95+
if (!$nameNode instanceof PhpParser\Node\Name) {
96+
return;
97+
}
98+
99+
$functionName = $nameNode->toString();
100+
101+
if (in_array(strtolower($functionName), ['assertsupertype'], true)) {
102+
self::fail(sprintf(
103+
'Missing use statement for %s() in %s on line %d.',
104+
$functionName,
105+
$relativePathHelper->getRelativePath($file),
106+
$node->getStartLine(),
107+
));
108+
} elseif ($functionName === 'PHPStan\\Testing\\assertSuperType') {
109+
$expectedType = $scope->getType($node->getArgs()[0]->value);
110+
$expectedTypeStrings = $expectedType->getConstantStrings();
111+
112+
if (count($expectedTypeStrings) !== 1) {
113+
self::fail(sprintf(
114+
'Expected super type must be a literal string, %s given in %s on line %d.',
115+
$expectedType->describe(PHPStan\Type\VerbosityLevel::precise()),
116+
$relativePathHelper->getRelativePath($file),
117+
$node->getStartLine(),
118+
));
119+
}
120+
121+
$actualType = $scope->getType($node->getArgs()[1]->value);
122+
$isCorrect = $typeStringResolver->resolve($expectedTypeStrings[0]->getValue())->isSuperTypeOf($actualType)->yes();
123+
124+
$assert = ['superType', $file, $expectedTypeStrings[0]->getValue(), $actualType->describe(PHPStan\Type\VerbosityLevel::precise()), $isCorrect, $node->getStartLine()];
125+
} else {
126+
$correctFunction = null;
127+
128+
$assertFunctions = [
129+
'assertSuperType' => 'PHPStan\\Testing\\assertSuperType',
130+
];
131+
132+
foreach ($assertFunctions as $assertFn => $fqFunctionName) {
133+
if (stripos($functionName, $assertFn) === false) {
134+
continue;
135+
}
136+
137+
$correctFunction = $fqFunctionName;
138+
}
139+
140+
if ($correctFunction === null) {
141+
return;
142+
}
143+
144+
self::fail(sprintf(
145+
'Function %s imported with wrong namespace %s called in %s on line %d.',
146+
$correctFunction,
147+
$functionName,
148+
$relativePathHelper->getRelativePath($file),
149+
$node->getStartLine(),
150+
));
151+
}
152+
153+
if (count($node->getArgs()) !== 2) {
154+
self::fail(sprintf(
155+
'ERROR: Wrong %s() call in %s on line %d.',
156+
$functionName,
157+
$relativePathHelper->getRelativePath($file),
158+
$node->getStartLine(),
159+
));
160+
}
161+
162+
$asserts[$file . ':' . $node->getStartLine()] = $assert;
163+
});
164+
165+
return array_merge($parentAsserts, $asserts);
166+
}
167+
41168
}

tests/functions.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace PHPStan\Testing;
4+
5+
/**
6+
* Asserts a super type of a value.
7+
*
8+
* @phpstan-pure
9+
* @param mixed $value
10+
* @return mixed
11+
*
12+
* @throws void
13+
*/
14+
function assertSuperType(string $superType, $value) // phpcs:ignore
15+
{
16+
return null;
17+
}

0 commit comments

Comments
 (0)