1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 04:45:20 +01:00
psalm/tests/TypeParseTest.php

536 lines
12 KiB
PHP
Raw Normal View History

<?php
namespace Psalm\Tests;
2016-11-02 07:29:00 +01:00
use Psalm\Type;
class TypeParseTest extends TestCase
{
/**
* @return void
*/
public function setUp()
{
//pae::setUp();
}
2018-03-22 22:55:36 +01:00
/**
* @return void
*/
public function testThisToStatic()
{
$this->assertSame('static', (string) Type::parseString('$this'));
}
/**
* @return void
*/
public function testThisToStaticUnion()
{
$this->assertSame('static|A', (string) Type::parseString('$this|A'));
}
2017-01-13 20:07:23 +01:00
/**
* @return void
*/
public function testIntOrString()
{
2017-05-27 02:05:57 +02:00
$this->assertSame('int|string', (string) Type::parseString('int|string'));
}
2018-03-23 03:28:06 +01:00
/**
* @return void
*/
public function testBracketedIntOrString()
{
$this->assertSame('int|string', (string) Type::parseString('(int|string)'));
}
2018-03-21 01:19:26 +01:00
/**
* @return void
*/
public function testBoolOrIntOrString()
{
$this->assertSame('bool|int|string', (string) Type::parseString('bool|int|string'));
}
2017-11-20 06:32:40 +01:00
/**
* @return void
*/
public function testNullable()
{
$this->assertSame('null|string', (string) Type::parseString('?string'));
}
2017-01-13 20:07:23 +01:00
/**
* @return void
*/
public function testArray()
{
2017-05-27 02:05:57 +02:00
$this->assertSame('array<int, int>', (string) Type::parseString('array<int, int>'));
$this->assertSame('array<int, string>', (string) Type::parseString('array<int, string>'));
$this->assertSame('array<int, static>', (string) Type::parseString('array<int, static>'));
2018-03-21 01:19:26 +01:00
}
/**
* @return void
*/
public function testArrayWithSingleArg()
{
$this->assertSame('array<mixed, int>', (string) Type::parseString('array<int>'));
}
/**
* @return void
*/
public function testArrayWithNestedSingleArg()
{
$this->assertSame('array<mixed, array<mixed, int>>', (string) Type::parseString('array<array<int>>'));
}
/**
* @return void
*/
public function testArrayWithUnion()
{
2017-05-27 02:05:57 +02:00
$this->assertSame('array<int|string, string>', (string) Type::parseString('array<int|string, string>'));
}
2017-01-13 20:07:23 +01:00
/**
* @return void
*/
public function testGeneric()
{
2017-05-27 02:05:57 +02:00
$this->assertSame('B<int>', (string) Type::parseString('B<int>'));
}
/**
* @return void
*/
public function testIntersection()
{
$this->assertSame('I1&I2', (string) Type::parseString('I1&I2'));
}
2018-03-22 22:55:36 +01:00
/**
* @return void
*/
public function testIntersectionOrNull()
{
$this->assertSame('I1&I2|null', (string) Type::parseString('I1&I2|null'));
}
/**
* @return void
*/
public function testNullOrIntersection()
{
$this->assertSame('null|I1&I2', (string) Type::parseString('null|I1&I2'));
}
/**
* @return void
*/
public function testInteratorAndTraversable()
{
$this->assertSame('Iterator<int>&Traversable', (string) Type::parseString('Iterator<int>&Traversable'));
}
/**
* @return void
*/
public function testTraversableAndIteratorOrNull()
{
$this->assertSame(
'Traversable&Iterator<int>|null',
(string) Type::parseString('Traversable&Iterator<int>|null')
);
}
2017-01-13 20:07:23 +01:00
/**
* @return void
*/
2018-03-21 01:19:26 +01:00
public function testPhpDocSimpleArray()
2016-10-30 02:57:03 +02:00
{
2017-05-27 02:05:57 +02:00
$this->assertSame('array<mixed, A>', (string) Type::parseString('A[]'));
2018-03-21 01:19:26 +01:00
}
/**
* @return void
*/
public function testPhpDocUnionArray()
{
2017-05-27 02:05:57 +02:00
$this->assertSame('array<mixed, A|B>', (string) Type::parseString('(A|B)[]'));
2018-03-21 01:19:26 +01:00
}
/**
* @return void
*/
public function testPhpDocMultiDimensionalArray()
{
2017-05-27 02:05:57 +02:00
$this->assertSame('array<mixed, array<mixed, A>>', (string) Type::parseString('A[][]'));
2018-03-21 01:19:26 +01:00
}
/**
* @return void
*/
public function testPhpDocMultidimensionalUnionArray()
{
2017-05-27 02:05:57 +02:00
$this->assertSame('array<mixed, array<mixed, A|B>>', (string) Type::parseString('(A|B)[][]'));
2018-03-21 01:19:26 +01:00
}
/**
* @return void
*/
public function testPhpDocObjectLikeArray()
{
$this->assertSame(
'array<mixed, array{b:bool, d:string}>',
(string) Type::parseString('array{b:bool,d:string}[]')
);
}
2018-03-21 01:19:26 +01:00
/**
* @return void
*/
public function testPhpDocUnionOfArrays()
{
2017-05-27 02:05:57 +02:00
$this->assertSame('array<mixed, A|B>', (string) Type::parseString('A[]|B[]'));
2018-03-21 01:19:26 +01:00
}
/**
* @return void
*/
public function testPhpDocUnionOfArraysOrObject()
{
2017-05-27 02:05:57 +02:00
$this->assertSame('array<mixed, A|B>|C', (string) Type::parseString('A[]|B[]|C'));
2016-10-30 02:57:03 +02:00
}
/**
* @return void
*/
public function testPsalmOnlyAtomic()
{
$this->assertSame('class-string', (string) Type::parseString('class-string'));
}
2017-10-12 20:02:06 +02:00
/**
* @expectedException \Psalm\Exception\TypeParseTreeException
*
* @return void
*/
public function testInvalidType()
{
Type::parseString('array(A)');
}
2018-03-23 03:28:06 +01:00
/**
* @expectedException \Psalm\Exception\TypeParseTreeException
*
* @return void
*/
public function testBracketedUnionAndIntersection()
{
Type::parseString('(A|B)&C');
}
2017-01-13 20:07:23 +01:00
/**
* @return void
*/
2018-03-21 01:19:26 +01:00
public function testObjectLikeWithSimpleArgs()
{
2017-05-27 02:05:57 +02:00
$this->assertSame('array{a:int, b:string}', (string) Type::parseString('array{a:int, b:string}'));
2018-03-21 01:19:26 +01:00
}
/**
* @return void
*/
public function testObjectLikeWithUnionArgs()
{
2017-05-27 02:05:57 +02:00
$this->assertSame(
2016-11-13 17:24:25 +01:00
'array{a:int|string, b:string}',
2016-11-02 07:29:00 +01:00
(string) Type::parseString('array{a:int|string, b:string}')
);
2018-03-21 01:19:26 +01:00
}
2016-11-02 07:29:00 +01:00
2018-03-21 01:19:26 +01:00
/**
* @return void
*/
public function testObjectLikeWithGenericArgs()
{
2017-05-27 02:05:57 +02:00
$this->assertSame(
2016-11-13 17:24:25 +01:00
'array{a:array<int, string|int>, b:string}',
2016-11-02 07:29:00 +01:00
(string) Type::parseString('array{a:array<int, string|int>, b:string}')
);
2018-03-21 01:19:26 +01:00
}
2018-03-21 01:19:26 +01:00
/**
* @return void
*/
public function testObjectLikeWithIntKeysAndUnionArgs()
{
$this->assertSame(
'array{0:stdClass|null}',
(string)Type::parseString('array{stdClass|null}')
);
2018-03-21 01:19:26 +01:00
}
2018-03-21 01:19:26 +01:00
/**
* @return void
*/
public function testObjectLikeWithIntKeysAndGenericArgs()
{
$this->assertSame(
'array{0:array<mixed, mixed>}',
(string)Type::parseString('array{array}')
);
$this->assertSame(
'array{0:array<int, string>}',
(string)Type::parseString('array{array<int, string>}')
);
}
/**
* @return void
*/
public function testObjectLikeOptional()
{
$this->assertSame(
'array{a:int, b?:int}',
(string)Type::parseString('array{a:int, b?:int}')
);
}
/**
* @return void
*/
public function testCallable()
{
$this->assertSame(
2018-04-08 18:57:56 +02:00
'callable(int, string):void',
(string)Type::parseString('callable(int, string) : void')
);
}
2018-03-28 16:53:19 +02:00
/**
* @return void
*/
public function testEmptyCallable()
{
$this->assertSame(
2018-04-08 18:57:56 +02:00
'callable():void',
2018-03-28 16:53:19 +02:00
(string)Type::parseString('callable() : void')
);
}
/**
* @return void
*/
public function testCallableWithUnionLastType()
{
$this->assertSame(
2018-04-08 18:57:56 +02:00
'callable(int, int|string):void',
(string)Type::parseString('callable(int, int|string) : void')
);
}
/**
* @return void
*/
public function testCallableWithVariadic()
{
$this->assertSame(
2018-04-08 18:57:56 +02:00
'callable(int, string...):void',
(string)Type::parseString('callable(int, string...) : void')
);
}
/**
* @return void
*/
public function testCallableThatReturnsACallable()
{
$this->assertSame(
'callable():callable():string',
(string)Type::parseString('callable() : callable() : string')
);
}
2018-04-19 01:04:06 +02:00
/**
* @return void
*/
2018-04-19 01:00:08 +02:00
public function testCallableOrInt()
{
$this->assertSame(
'callable(string):void|int',
(string)Type::parseString('callable(string):void|int')
);
}
/**
* @expectedException \Psalm\Exception\TypeParseTreeException
*
* @return void
*/
public function testCallableWithBadVariadic()
{
Type::parseString('callable(int, ...string) : void');
}
2018-04-16 00:16:31 +02:00
/**
* @expectedException \Psalm\Exception\TypeParseTreeException
*
* @return void
*/
public function testCallableWithTrailingColon()
{
Type::parseString('callable(int):');
}
/**
* @expectedException \Psalm\Exception\TypeParseTreeException
*
* @return void
*/
public function testCallableWithAnotherBadVariadic()
{
Type::parseString('callable(int, string..) : void');
}
/**
* @expectedException \Psalm\Exception\TypeParseTreeException
*
* @return void
*/
public function testCallableWithVariadicAndDefault()
{
Type::parseString('callable(int, string...=) : void');
}
/**
* @expectedException \Psalm\Exception\TypeParseTreeException
*
* @return void
*/
public function testBadVariadic()
{
Type::parseString('string...');
}
2018-03-27 20:43:39 +02:00
/**
* @expectedException \Psalm\Exception\TypeParseTreeException
*
* @return void
*/
public function testBadFullStop()
{
Type::parseString('string.');
}
2018-04-05 20:11:57 +02:00
/**
* @expectedException \Psalm\Exception\TypeParseTreeException
*
* @return void
*/
public function testBadSemicolon()
{
Type::parseString('string;');
}
2018-03-29 08:20:19 +02:00
/**
* @expectedException \Psalm\Exception\TypeParseTreeException
*
* @return void
*/
public function testDoubleBar()
{
Type::parseString('PDO||Closure|numeric');
}
/**
* @return void
*/
public function testCallableWithDefault()
{
$this->assertSame(
2018-04-08 18:57:56 +02:00
'callable(int, string=):void',
(string)Type::parseString('callable(int, string=) : void')
);
}
/**
* @return void
*/
public function testCallableWithoutReturn()
{
$this->assertSame(
'callable(int, string)',
(string)Type::parseString('callable(int, string)')
);
}
2018-04-19 01:00:08 +02:00
/**
* @return void
*/
public function testVeryLargeType()
{
$very_large_type = 'array{a:Closure():(array<mixed, mixed>|null), b?:Closure():array<mixed, mixed>, c?:Closure():array<mixed, mixed>, d?:Closure():array<mixed, mixed>, e?:Closure():(array{f:null|string, g:null|string, h:null|string, i:string, j:mixed, k:mixed, l:mixed, m:mixed, n:bool, o?:array{0:string}}|null), p?:Closure():(array{f:null|string, g:null|string, h:null|string, q:string, i:string, j:mixed, k:mixed, l:mixed, m:mixed, n:bool, o?:array{0:string}}|null), r?:Closure():(array<mixed, mixed>|null), s:array<mixed, mixed>}|null';
$this->assertSame(
$very_large_type,
(string) Type::parseString($very_large_type)
);
}
2018-04-19 01:00:08 +02:00
/**
* @dataProvider providerTestValidCallMapType
*
2018-04-19 01:04:06 +02:00
* @param string $return_type
* @param string $param_type_1
* @param string $param_type_2
* @param string $param_type_3
* @param string $param_type_4
2018-04-19 01:00:08 +02:00
*
* @return void
*/
public function testValidCallMapType(
$return_type,
$param_type_1 = '',
$param_type_2 = '',
$param_type_3 = '',
$param_type_4 = ''
) {
if ($return_type && $return_type !== 'void') {
\Psalm\Type::parseString($return_type);
}
if ($param_type_1 && $param_type_1 !== 'mixed') {
if (strpos($param_type_1, 'oci-') !== false) {
return;
}
\Psalm\Type::parseString($param_type_1);
}
if ($param_type_2 && $param_type_2 !== 'mixed') {
\Psalm\Type::parseString($param_type_2);
}
if ($param_type_3 && $param_type_3 !== 'mixed') {
\Psalm\Type::parseString($param_type_3);
}
if ($param_type_4 && $param_type_4 !== 'mixed') {
\Psalm\Type::parseString($param_type_4);
}
}
/**
2018-04-19 01:04:06 +02:00
* @return array<string, array<int|string, string>>
2018-04-19 01:00:08 +02:00
*/
public function providerTestValidCallMapType()
{
return \Psalm\Codebase\CallMap::getCallMap();
}
}