1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 04:45:20 +01:00
psalm/tests/JsonOutputTest.php
Daniil Gentili 1986c8b4a8
Add support for strict arrays, fix type alias intersection, fix array_is_list assertion on non-lists (#8395)
* Immutable CodeLocation

* Remove excess clones

* Remove external clones

* Remove leftover clones

* Fix final clone issue

* Immutable storages

* Refactoring

* Fixes

* Fixes

* Fix

* Fix

* Fixes

* Simplify

* Fixes

* Fix

* Fixes

* Update

* Fix

* Cache global types

* Fix

* Update

* Update

* Fixes

* Fixes

* Refactor

* Fixes

* Fix

* Fix

* More caching

* Fix

* Fix

* Update

* Update

* Fix

* Fixes

* Update

* Refactor

* Update

* Fixes

* Break one more test

* Fix

* FIx

* Fix

* Fix

* Fix

* Fix

* Improve performance and readability

* Equivalent logic

* Fixes

* Revert

* Revert "Revert"

This reverts commit f9175100c8452c80559234200663fd4c4f4dd889.

* Fix

* Fix reference bug

* Make default TypeVisitor immutable

* Bugfix

* Remove clones

* Partial refactoring

* Refactoring

* Fixes

* Fix

* Fixes

* Fixes

* cs-fix

* Fix final bugs

* Add test

* Misc fixes

* Update

* Fixes

* Experiment with removing different property

* revert "Experiment with removing different property"

This reverts commit ac1156e077fc4ea633530d51096d27b6e88bfdf9.

* Uniform naming

* Uniform naming

* Hack hotfix

* Clean up $_FILES ref #8621

* Undo hack, try fixing properly

* Helper method

* Remove redundant call

* Partially fix bugs

* Cleanup

* Change defaults

* Fix bug

* Fix (?, hope this doesn't break anything else)

* cs-fix

* Review fixes

* Bugfix

* Bugfix

* Improve logic

* Add support for list{} and callable-list{} types, properly implement array_is_list assertions (fixes #8389)

* Default to sealed arrays

* Fix array_merge bug

* Fixes

* Fix

* Sealed type checks

* Properly infer properties-of and get_object_vars on final classes

* Fix array_map zipping

* Fix tests

* Fixes

* Fixes

* Fix more stuff

* Recursively resolve type aliases

* Fix typo

* Fixes

* Fix array_is_list assertion on keyed array

* Add BC docs

* Fixes

* fix

* Update

* Update

* Update

* Update

* Seal arrays with count assertions

* Fix #8528

* Fix

* Update

* Improve sealed array foreach logic

* get_object_vars on template properties

* Fix sealed array assertion reconciler logic

* Improved reconciler

* Add tests

* Single source of truth for test types

* Fix tests

* Fixup tests

* Fixup tests

* Fixup tests

* Update

* Fix tests

* Fix tests

* Final fixes

* Fixes

* Use list syntax only when needed

* Fix tests

* Cs-fix

* Update docs

* Update docs

* Update docs

* Update docs

* Update docs

* Document missing types

* Update docs

* Improve class-string-map docs

* Update

* Update

* I love working on psalm :)

* Keep arrays unsealed by default

* Fixup tests

* Fix syntax mistake

* cs-fix

* Fix typo

* Re-import missing types

* Keep strict types only in return types

* argc/argv fixes

* argc/argv fixes

* Fix test

* Comment-out valinor code, pinging @romm pls merge https://github.com/CuyZ/Valinor/pull/246 so we can add valinor to the psalm docs :)
2022-11-05 22:34:42 +01:00

154 lines
5.2 KiB
PHP

<?php
namespace Psalm\Tests;
use Psalm\Context;
use Psalm\Internal\Analyzer\ProjectAnalyzer;
use Psalm\Internal\Provider\FakeFileProvider;
use Psalm\Internal\Provider\Providers;
use Psalm\Internal\RuntimeCaches;
use Psalm\IssueBuffer;
use Psalm\Report;
use Psalm\Report\ReportOptions;
use Psalm\Tests\Internal\Provider\FakeParserCacheProvider;
use function substr;
class JsonOutputTest extends TestCase
{
public function setUp(): void
{
// `TestCase::setUp()` creates its own ProjectAnalyzer and Config instance, but we don't want to do that in this
// case, so don't run a `parent::setUp()` call here.
RuntimeCaches::clearAll();
$this->file_provider = new FakeFileProvider();
$config = new TestConfig();
$config->throw_exception = false;
$stdout_report_options = new ReportOptions();
$stdout_report_options->format = Report::TYPE_JSON;
$this->project_analyzer = new ProjectAnalyzer(
$config,
new Providers(
$this->file_provider,
new FakeParserCacheProvider()
),
$stdout_report_options
);
$this->project_analyzer->getCodebase()->reportUnusedCode();
}
/**
* @dataProvider providerTestJsonOutputErrors
*/
public function testJsonOutputErrors(
string $code,
int $error_count,
string $message,
int $line_number,
string $error
): void {
$this->addFile('somefile.php', $code);
$this->analyzeFile('somefile.php', new Context());
$all_issue_data = IssueBuffer::getIssuesData()['somefile.php'];
$this->assertCount($error_count, $all_issue_data);
$issue_data = $all_issue_data[0];
$this->assertSame('somefile.php', $issue_data->file_path);
$this->assertSame('error', $issue_data->severity);
$this->assertSame($message, $issue_data->message);
$this->assertSame($line_number, $issue_data->line_from);
$this->assertSame(
$error,
substr($code, $issue_data->from, $issue_data->to - $issue_data->from)
);
}
/**
* @return array<string,strict-array{code:string,error_count:int,message:string,line:int,error:string}>
*/
public function providerTestJsonOutputErrors(): array
{
return [
'returnTypeError' => [
'code' => '<?php
function fooFoo(int $a): string {
return $a + 1;
}',
'error_count' => 2,
'message' => "The inferred type 'int' does not match the declared return type 'string' for fooFoo",
'line' => 3,
'error' => '$a + 1',
],
'undefinedVar' => [
'code' => '<?php
function fooFoo(int $a): int {
return $b + 1;
}',
'error_count' => 5,
'message' => 'Cannot find referenced variable $b',
'line' => 3,
'error' => '$b',
],
'unknownParamClass' => [
'code' => '<?php
function fooFoo(Badger\Bodger $a): Badger\Bodger {
return $a;
}',
'error_count' => 3,
'message' => 'Class, interface or enum named Badger\\Bodger does not exist',
'line' => 2,
'error' => 'Badger\\Bodger',
],
'missingReturnType' => [
'code' => '<?php
function fooFoo() {
return "hello";
}',
'error_count' => 1,
'message' => "Method fooFoo does not have a return type, expecting 'hello'",
'line' => 2,
'error' => 'fooFoo',
],
'wrongMultilineReturnType' => [
'code' => '<?php
/**
* @return int
*/
function fooFoo() {
return "hello";
}',
'error_count' => 2,
'message' => "The inferred type ''hello'' does not match the declared return type 'int' for fooFoo",
'line' => 6,
'error' => '"hello"',
],
'assertCancelsMixedAssignment' => [
'code' => '<?php
$a = $_GET["hello"];
assert(is_string($a));
if (is_string($a)) {}',
'error_count' => 1,
'message' => 'Docblock-defined type string for $a is always string',
'line' => 4,
'error' => 'is_string($a)',
],
'singleIssueForTypeDifference' => [
'code' => '<?php
function fooFoo(?string $a, ?string $b): void {
if ($a || $b) {
if ($a || $b) {}
}
}',
'error_count' => 1,
'message' => 'Operand of type non-falsy-string is always truthy',
'line' => 4,
'error' => '$b',
],
];
}
}