Skip to content

Commit

Permalink
testFileAsserts - testing variable certainty support
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jun 20, 2020
1 parent 14b17a8 commit 1567d0f
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 19 deletions.
78 changes: 59 additions & 19 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10027,23 +10027,35 @@ public function dataArrayTypehintWithoutNullInPhpDoc(): array
* @dataProvider dataMixedTypehint
* @dataProvider dataVariadics
* @dataProvider dataArrayTypehintWithoutNullInPhpDoc
* @param ConstantStringType $expectedType
* @param Type $actualType
* @param string $assertType
* @param string $file
* @param mixed ...$args
*/
public function testFileAsserts(
string $assertType,
string $file,
ConstantStringType $expectedType,
Type $actualType,
int $line
...$args
): void
{
$expected = $expectedType->getValue();
$actual = $actualType->describe(VerbosityLevel::precise());
$this->assertSame(
$expected,
$actual,
sprintf('Expected type %s, got type %s in %s on line %d.', $expected, $actual, $file, $line)
);
if ($assertType === 'type') {
$expectedType = $args[0];
$expected = $expectedType->getValue();
$actualType = $args[1];
$actual = $actualType->describe(VerbosityLevel::precise());
$this->assertSame(
$expected,
$actual,
sprintf('Expected type %s, got type %s in %s on line %d.', $expected, $actual, $file, $args[2])
);
} elseif ($assertType === 'variableCertainty') {
$expectedCertainty = $args[0];
$actualCertainty = $args[1];
$variableName = $args[2];
$this->assertTrue(
$expectedCertainty->equals($actualCertainty),
sprintf('Expected %s, actual certainty of variable $%s is %s', $expectedCertainty->describe(), $variableName, $actualCertainty->describe())
);
}
}

/**
Expand All @@ -10052,8 +10064,8 @@ public function testFileAsserts(
*/
private function gatherAssertTypes(string $file): array
{
$types = [];
$this->processFile($file, function (Node $node, Scope $scope) use (&$types, $file): void {
$asserts = [];
$this->processFile($file, function (Node $node, Scope $scope) use (&$asserts, $file): void {
if (!$node instanceof Node\Expr\FuncCall) {
return;
}
Expand All @@ -10065,29 +10077,57 @@ private function gatherAssertTypes(string $file): array

$functionName = $nameNode->toString();
if ($functionName === 'PHPStan\\Analyser\\assertType') {
$assertTypeFunctionName = 'PHPStan\\Analyser\\assertType';
$expectedType = $scope->getType($node->args[0]->value);
$actualType = $scope->getType($node->args[1]->value);
$assert = ['type', $file, $expectedType, $actualType, $node->getLine()];
} elseif ($functionName === 'PHPStan\\Analyser\\assertNativeType') {
$assertTypeFunctionName = 'PHPStan\\Analyser\\assertNativeType';
$expectedType = $scope->getNativeType($node->args[0]->value);
$actualType = $scope->getNativeType($node->args[1]->value);
$assert = ['type', $file, $expectedType, $actualType, $node->getLine()];
} elseif ($functionName === 'PHPStan\\Analyser\\assertVariableCertainty') {
$certainty = $node->args[0]->value;
if (!$certainty instanceof StaticCall) {
$this->fail(sprintf('First argument of %s() must be TrinaryLogic call', $functionName));
}
if (!$certainty->class instanceof Node\Name) {
$this->fail(sprintf('ERROR: Invalid TrinaryLogic call.'));
}

if ($certainty->class->toString() !== 'PHPStan\\TrinaryLogic') {
$this->fail(sprintf('ERROR: Invalid TrinaryLogic call.'));
}

if (!$certainty->name instanceof Node\Identifier) {
$this->fail(sprintf('ERROR: Invalid TrinaryLogic call.'));
}

$expectedertaintyValue = TrinaryLogic::{$certainty->name->toString()}();
$variable = $node->args[1]->value;
if (!$variable instanceof Node\Expr\Variable) {
$this->fail(sprintf('ERROR: Invalid assertVariableCertainty call.'));
}
if (!is_string($variable->name)) {
$this->fail(sprintf('ERROR: Invalid assertVariableCertainty call.'));
}

$actualCertaintyValue = $scope->hasVariableType($variable->name);
$assert = ['variableCertainty', $file, $expectedertaintyValue, $actualCertaintyValue, $variable->name];
} else {
return;
}

if (count($node->args) !== 2) {
$this->fail(sprintf(
'ERROR: Wrong %s() call on line %d.',
$assertTypeFunctionName,
$functionName,
$node->getLine()
));
}

$types[$file . ':' . $node->getLine()] = [$file, $expectedType, $actualType, $node->getLine()];
$asserts[$file . ':' . $node->getLine()] = $assert;
});

return $types;
return $asserts;
}

public function dataInferPrivatePropertyTypeFromConstructor(): array
Expand Down
9 changes: 9 additions & 0 deletions tests/PHPStan/Analyser/data/root-scope-maybe-defined.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
<?php

use PHPStan\TrinaryLogic;

\PHPStan\Analyser\assertType('mixed', $foo);
\PHPStan\Analyser\assertVariableCertainty(TrinaryLogic::createMaybe(), $foo);

$bar = 'str';
\PHPStan\Analyser\assertVariableCertainty(TrinaryLogic::createYes(), $bar);
\PHPStan\Analyser\assertVariableCertainty(TrinaryLogic::createMaybe(), $baz);

\PHPStan\Analyser\assertType('\'str\'', $bar);

Expand All @@ -12,3 +17,7 @@
}

\PHPStan\Analyser\assertType('mixed', $baz);

function () {
\PHPStan\Analyser\assertVariableCertainty(TrinaryLogic::createNo(), $foo);
};
10 changes: 10 additions & 0 deletions tests/PHPStan/Analyser/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace PHPStan\Analyser;

use PHPStan\TrinaryLogic;

/**
* Asserts the static type of a value.
*
Expand All @@ -24,3 +26,11 @@ function assertType(string $type, $value): void // phpcs:ignore
function assertNativeType(string $type, $value): void // phpcs:ignore
{
}

/**
* @param TrinaryLogic $certainty
* @param mixed $variable
*/
function assertVariableCertainty(TrinaryLogic $certainty, $variable): void // phpcs:ignore
{
}

0 comments on commit 1567d0f

Please sign in to comment.