1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-12 17:27:28 +01:00
psalm/tests/TypeCombinationTest.php

444 lines
13 KiB
PHP
Raw Normal View History

2016-06-16 02:16:40 +02:00
<?php
2016-07-26 00:37:44 +02:00
namespace Psalm\Tests;
2016-06-16 02:16:40 +02:00
use Psalm\Internal\Type\TypeCombination;
2019-03-23 19:27:54 +01:00
use Psalm\Type;
2016-06-16 02:16:40 +02:00
class TypeCombinationTest extends TestCase
2016-06-16 02:16:40 +02:00
{
2018-11-06 03:57:36 +01:00
use Traits\ValidCodeAnalysisTestTrait;
2017-01-13 20:07:23 +01:00
/**
* @dataProvider providerTestValidTypeCombination
2017-05-27 02:16:18 +02:00
*
* @param string $expected
* @param array<int, string> $types
2017-05-27 02:16:18 +02:00
*
2017-01-13 20:07:23 +01:00
* @return void
*/
public function testValidTypeCombination($expected, $types)
2016-06-16 02:16:40 +02:00
{
foreach ($types as $k => $type) {
$types[$k] = self::getAtomic($type);
$types[$k]->setFromDocblock();
}
2018-02-22 00:59:31 +01:00
/** @psalm-suppress InvalidArgument */
2017-05-27 02:05:57 +02:00
$this->assertSame(
$expected,
(string) TypeCombination::combineTypes($types)
);
2016-06-16 02:16:40 +02:00
}
2017-01-13 20:07:23 +01:00
/**
2019-03-01 21:55:20 +01:00
* @return iterable<string,array{string,assertions?:array<string,string>,error_levels?:string[]}>
*/
2018-11-06 03:57:36 +01:00
public function providerValidCodeParse()
{
return [
'multipleValuedArray' => [
'<?php
class A {}
class B {}
$var = [];
$var[] = new A();
2017-05-27 02:05:57 +02:00
$var[] = new B();',
],
'preventLiteralAndClassString' => [
'<?php
/**
* @param "array"|class-string $type_name
*/
function foo(string $type_name) : bool {
return $type_name === "array";
}',
],
];
}
/**
2019-02-23 22:22:39 +01:00
* @return array<string,array{string,array<int,string>}>
*/
public function providerTestValidTypeCombination()
{
return [
'intOrString' => [
'int|string',
[
'int',
2017-05-27 02:05:57 +02:00
'string',
],
],
'mixedOrNull' => [
'mixed|null',
[
'mixed',
'null',
],
],
2018-12-20 02:01:27 +01:00
'mixedOrEmpty' => [
'mixed',
[
'empty',
'mixed',
],
],
'mixedOrObject' => [
'mixed|object',
[
'mixed',
'object',
],
],
'mixedOrEmptyArray' => [
'array<empty, empty>|mixed',
[
'mixed',
'array<empty, empty>',
],
],
2017-12-09 21:51:38 +01:00
'falseTrueToBool' => [
'bool',
[
'false',
'true',
],
],
'trueFalseToBool' => [
'bool',
[
'true',
'false',
],
],
'trueBoolToBool' => [
'bool',
[
'true',
'bool',
],
],
'boolTrueToBool' => [
'bool',
[
'bool',
'true',
],
],
'intOrTrueOrFalseToBool' => [
'int|bool',
[
'int',
'false',
'true',
],
],
'intOrBoolOrTrueToBool' => [
'int|bool',
[
'int',
'bool',
'true',
],
],
'intOrTrueOrBoolToBool' => [
'int|bool',
[
'int',
'true',
'bool',
],
],
'arrayOfIntOrString' => [
'array<array-key, int|string>',
[
'array<int>',
2017-05-27 02:05:57 +02:00
'array<string>',
],
],
'arrayOfIntOrAlsoString' => [
'array<array-key, int>|string',
[
'array<int>',
2017-05-27 02:05:57 +02:00
'string',
],
],
'emptyArrays' => [
'array<empty, empty>',
[
'array<empty,empty>',
2017-05-27 02:05:57 +02:00
'array<empty,empty>',
],
],
'arrayStringOrEmptyArray' => [
'array<array-key, string>',
[
'array<empty>',
2017-05-27 02:05:57 +02:00
'array<string>',
],
],
'arrayMixedOrString' => [
'array<array-key, mixed|string>',
[
'array<mixed>',
2017-05-27 02:05:57 +02:00
'array<string>',
],
],
'arrayMixedOrStringKeys' => [
'array<int|string|mixed, string>',
[
'array<int|string,string>',
2017-05-27 02:05:57 +02:00
'array<mixed,string>',
],
],
'arrayMixedOrEmpty' => [
'array<array-key, mixed>',
[
'array<empty>',
2017-05-27 02:05:57 +02:00
'array<mixed>',
],
],
'arrayBigCombination' => [
'array<array-key, int|float|string>',
[
'array<int|float>',
2017-05-27 02:05:57 +02:00
'array<string>',
],
],
'arrayTraversableToIterable' => [
'iterable<array-key|mixed, mixed>',
[
'array',
'Traversable',
],
],
'arrayIterableToIterable' => [
'iterable<mixed, mixed>',
[
'array',
'iterable',
],
],
'iterableArrayToIterable' => [
'iterable<mixed, mixed>',
[
'iterable',
'array',
],
],
'traversableIterableToIterable' => [
'iterable<mixed, mixed>',
[
'Traversable',
'iterable',
],
],
'iterableTraversableToIterable' => [
'iterable<mixed, mixed>',
[
'iterable',
'Traversable',
],
],
'arrayTraversableToIterableWithParams' => [
'iterable<int, string|bool>',
[
'array<int, string>',
'Traversable<int, bool>',
],
],
'arrayIterableToIterableWithParams' => [
'iterable<int, string|bool>',
[
'array<int, string>',
'iterable<int, bool>',
],
],
'iterableArrayToIterableWithParams' => [
'iterable<int, string|bool>',
[
'iterable<int, string>',
'array<int, bool>',
],
],
'traversableIterableToIterableWithParams' => [
'iterable<int, string|bool>',
[
'Traversable<int, string>',
'iterable<int, bool>',
],
],
'iterableTraversableToIterableWithParams' => [
'iterable<int, string|bool>',
[
'iterable<int, string>',
'Traversable<int, bool>',
],
],
'arrayObjectAndParamsWithEmptyArray' => [
'array<empty, empty>|ArrayObject<int, string>',
[
'ArrayObject<int, string>',
'array<empty, empty>',
],
],
'emptyArrayWithArrayObjectAndParams' => [
'array<empty, empty>|ArrayObject<int, string>',
[
'array<empty, empty>',
'ArrayObject<int, string>',
2017-05-27 02:05:57 +02:00
],
],
'falseDestruction' => [
'bool',
[
'false',
2017-05-27 02:05:57 +02:00
'bool',
],
],
'onlyFalse' => [
'false',
[
2017-05-27 02:05:57 +02:00
'false',
],
],
'onlyTrue' => [
'true',
[
'true',
],
],
'falseFalseDestruction' => [
'false',
[
'false',
2017-05-27 02:05:57 +02:00
'false',
],
],
'aAndAOfB' => [
'A<B>|A',
[
'A',
2017-05-27 02:05:57 +02:00
'A<B>',
],
],
'combineObjectType1' => [
'array{a?:int, b?:string}',
[
'array{a:int}',
2017-05-27 02:05:57 +02:00
'array{b:string}',
],
],
'combineObjectType2' => [
'array{a:int|string, b?:string}',
[
'array{a:int}',
2017-05-27 02:05:57 +02:00
'array{a:string,b:string}',
],
],
'combineObjectTypeWithIntKeyedArray' => [
'array<int|string, string|int>',
[
'array{a:int}',
'array<int, string>',
],
],
'combineNestedObjectTypeWithObjectLikeIntKeyedArray' => [
'array{a:array<int|string, string|int>}',
[
'array{a:array{a:int}}',
'array{a:array<int, string>}',
],
],
'combineIntKeyedObjectTypeWithNestedIntKeyedArray' => [
'array<int, array<int|string, string|int>>',
[
'array<int, array{a:int}>',
'array<int, array<int, string>>',
],
],
'combineNestedObjectTypeWithNestedIntKeyedArray' => [
'array<int|string, array<int|string, string|int>>',
[
'array{a:array{a:int}}',
'array<int, array<int, string>>',
],
],
'combinePossiblyUndefinedKeys' => [
'array{a:bool, b?:mixed, d?:mixed}',
[
'array{a:false, b:mixed}',
'array{a:true, d:mixed}',
'array{a:true, d:mixed}',
],
],
'combinePossiblyUndefinedKeysAndString' => [
'array{a:string, b?:int}|string',
[
'array{a:string, b?:int}',
'string',
],
],
'traversableAorB' => [
'Traversable<mixed, A|B>',
[
'Traversable<A>',
'Traversable<B>',
],
],
'iterableAorB' => [
'iterable<mixed, A|B>',
[
'iterable<A>',
'iterable<B>',
],
],
'FooAorB' => [
'Foo<A>|Foo<B>',
[
'Foo<A>',
'Foo<B>',
],
],
'traversableOfMixed' => [
'Traversable<mixed, mixed>',
[
'Traversable',
'Traversable<mixed, mixed>',
],
],
'traversableAndIterator' => [
'Traversable&Iterator',
[
'Traversable&Iterator',
'Traversable&Iterator',
],
],
'traversableOfMixedAndIterator' => [
'Traversable<mixed, mixed>&Iterator',
[
'Traversable<mixed, mixed>&Iterator',
'Traversable<mixed, mixed>&Iterator',
],
],
'objectLikePlusArrayEqualsArray' => [
'array<string, int>',
[
'array<"a"|"b"|"c", 1|2|3>',
'array{a:1|2, b:2|3, c:1|3}',
],
],
];
}
/**
* @param string $string
2017-05-27 02:16:18 +02:00
*
* @return Type\Atomic
*/
2016-06-28 20:28:45 +02:00
private static function getAtomic($string)
{
return array_values(Type::parseString($string)->getTypes())[0];
2016-06-28 20:28:45 +02:00
}
2016-06-16 02:16:40 +02:00
}