1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00
psalm/tests/Php71Test.php
Matthew Brown 17edb2bbe6
Add better understanding of arrays with keyed integer offsets (#400)
* Add tests for keyed integer assignemnt

* First pass to get keyed integer assignment working

* Fix array assignment to object-like with different key type

* Improve treatment of objectlikes for callable and iterable comparisons

* Fix array assignment to strings and addition

* Convert expression to CNF

* Do better at merging property types

* Fix array_rand key type
2017-12-18 18:47:17 -05:00

280 lines
8.4 KiB
PHP

<?php
namespace Psalm\Tests;
class Php71Test extends TestCase
{
use Traits\FileCheckerInvalidCodeParseTestTrait;
use Traits\FileCheckerValidCodeParseTestTrait;
/**
* @return array
*/
public function providerFileCheckerValidCodeParse()
{
return [
'nullableReturnType' => [
'<?php
function a(): ?string
{
return rand(0, 10) ? "elePHPant" : null;
}
$a = a();',
'assertions' => [
'$a' => 'string|null',
],
],
'nullableReturnTypeInDocblock' => [
'<?php
/** @return ?string */
function a() {
return rand(0, 10) ? "elePHPant" : null;
}
$a = a();',
'assertions' => [
'$a' => 'null|string',
],
],
'nullableArgument' => [
'<?php
function test(?string $name) : ?string
{
return $name;
}
test("elePHPant");
test(null);',
],
'protectedClassConst' => [
'<?php
class A
{
protected const IS_PROTECTED = 1;
}
class B extends A
{
function fooFoo() : int {
return A::IS_PROTECTED;
}
}',
],
'privateClassConst' => [
'<?php
class A
{
private const IS_PRIVATE = 1;
function fooFoo() : int {
return A::IS_PRIVATE;
}
}',
],
'publicClassConstFetch' => [
'<?php
class A
{
public const IS_PUBLIC = 1;
const IS_ALSO_PUBLIC = 2;
}
class B extends A
{
function fooFoo() : int {
echo A::IS_PUBLIC;
return A::IS_ALSO_PUBLIC;
}
}
echo A::IS_PUBLIC;
echo A::IS_ALSO_PUBLIC;',
],
'arrayDestructuring' => [
'<?php
$data = [
[1, "Tom"],
[2, "Fred"],
];
// list() style
list($id1, $name1) = $data[0];
// [] style
[$id2, $name2] = $data[1];',
'assertions' => [
'$id1' => 'int',
'$name1' => 'string',
'$id2' => 'int',
'$name2' => 'string',
],
],
'arrayDestructuringInForeach' => [
'<?php
$data = [
[1, "Tom"],
[2, "Fred"],
];
// [] style
foreach ($data as [$id, $name]) {
echo $id;
echo $name;
}',
],
'arrayDestructuringWithKeys' => [
'<?php
$data = [
["id" => 1, "name" => "Tom"],
["id" => 2, "name" => "Fred"],
];
// list() style
list("id" => $id1, "name" => $name1) = $data[0];
// [] style
["id" => $id2, "name" => $name2] = $data[1];',
'assertions' => [
'$id1' => 'int',
'$name1' => 'string',
'$id2' => 'int',
'$name2' => 'string',
],
],
'arrayListDestructuringInForeachWithKeys' => [
'<?php
$data = [
["id" => 1, "name" => "Tom"],
["id" => 2, "name" => "Fred"],
];
$last_id = null;
$last_name = null;
// list() style
foreach ($data as list("id" => $id, "name" => $name)) {
$last_id = $id;
$last_name = $name;
}',
'assertions' => [
'$last_id' => 'null|int',
'$last_name' => 'null|string',
],
],
'arrayDestructuringInForeachWithKeys' => [
'<?php
$data = [
["id" => 1, "name" => "Tom"],
["id" => 2, "name" => "Fred"],
];
$last_id = null;
$last_name = null;
// [] style
foreach ($data as ["id" => $id, "name" => $name]) {
$last_id = $id;
$last_name = $name;
}',
'assertions' => [
'$last_id' => 'null|int',
'$last_name' => 'null|string',
],
],
'iterableArg' => [
'<?php
/**
* @param iterable<int, int> $iter
*/
function iterator(iterable $iter) : void
{
foreach ($iter as $val) {
//
}
}
iterator([1, 2, 3, 4]);
iterator(new SplFixedArray(5));',
],
'traversableObject' => [
'<?php
class IteratorObj implements Iterator {
function rewind() : void {}
/** @return mixed */
function current() { return null; }
function key() : int { return 0; }
function next() : void {}
function valid() : bool { return false; }
}
function foo(\Traversable $t) : void {
}
foo(new IteratorObj);',
],
];
}
/**
* @return array
*/
public function providerFileCheckerInvalidCodeParse()
{
return [
'invalidPrivateClassConstFetch' => [
'<?php
class A
{
private const IS_PRIVATE = 1;
}
echo A::IS_PRIVATE;',
'error_message' => 'InaccessibleClassConstant',
],
'invalidPrivateClassConstFetchFromSubclass' => [
'<?php
class A
{
private const IS_PRIVATE = 1;
}
class B extends A
{
function fooFoo() : int {
return A::IS_PRIVATE;
}
}',
'error_message' => 'InaccessibleClassConstant',
],
'invalidProtectedClassConstFetch' => [
'<?php
class A
{
protected const IS_PROTECTED = 1;
}
echo A::IS_PROTECTED;',
'error_message' => 'InaccessibleClassConstant',
],
'invalidIterableArg' => [
'<?php
/**
* @param iterable<string> $iter
*/
function iterator(iterable $iter) : void
{
foreach ($iter as $val) {
//
}
}
class A {
}
iterator(new A());',
'error_message' => 'InvalidArgument',
],
];
}
}