forked from vimeo/psalm
/
TypeComparatorTest.php
136 lines (122 loc) · 3.63 KB
/
TypeComparatorTest.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<?php
namespace Psalm\Tests;
use Psalm\Internal\Analyzer\ProjectAnalyzer;
use Psalm\Internal\Provider\FakeFileProvider;
use Psalm\Internal\Provider\Providers;
use Psalm\Internal\RuntimeCaches;
use Psalm\Internal\Type\Comparator\UnionTypeComparator;
use Psalm\Internal\Type\TypeTokenizer;
use Psalm\Tests\Internal\Provider\FakeParserCacheProvider;
use Psalm\Type;
use function array_diff_key;
use function array_keys;
use function array_map;
class TypeComparatorTest extends TestCase
{
public function setUp(): void
{
RuntimeCaches::clearAll();
$this->file_provider = new FakeFileProvider();
$config = new TestConfig();
$providers = new Providers(
$this->file_provider,
new FakeParserCacheProvider()
);
$this->project_analyzer = new ProjectAnalyzer(
$config,
$providers
);
}
/**
* @dataProvider getAllBasicTypes
*/
public function testTypeAcceptsItself(string $type_string): void
{
$type_1 = Type::parseString($type_string);
$type_2 = Type::parseString($type_string);
$this->assertTrue(
UnionTypeComparator::isContainedBy(
$this->project_analyzer->getCodebase(),
$type_1,
$type_2
)
);
}
/**
* @return array<array{string}>
*/
public function getAllBasicTypes(): array
{
// these types are not valid without generics attached
$basic_generic_types = [
'key-of' => true,
'arraylike-object' => true,
'value-of' => true,
'class-string-map' => true,
'int-mask-of' => true,
'int-mask' => true,
'pure-Closure' => true,
];
$basic_types = array_diff_key(
TypeTokenizer::PSALM_RESERVED_WORDS,
$basic_generic_types,
[
'open-resource' => true, // unverifiable
'non-empty-countable' => true, // bit weird, maybe a bug?
]
);
return array_map(
function ($type) {
return [$type];
},
array_keys($basic_types)
);
}
/**
* @dataProvider getAllowedChildTypes
*/
public function testTypeAcceptsType(string $parent_type_string, string $child_type_string): void
{
$parent_type = Type::parseString($parent_type_string);
$child_type = Type::parseString($child_type_string);
$this->assertTrue(
UnionTypeComparator::isContainedBy(
$this->project_analyzer->getCodebase(),
$child_type,
$parent_type
)
);
}
/**
* @return array<array{string, string}>
*/
public function getAllowedChildTypes(): array
{
return [
'iterableAcceptsArray' => [
'iterable',
'array',
],
'listAcceptsEmptyArray' => [
'list',
'array<never, never>',
],
'arrayAcceptsEmptyArray' => [
'array',
'array<never, never>',
],
'arrayOptionalKeyed1AcceptsEmptyArray' => [
'array{foo?: string}',
'array<never, never>',
],
'arrayOptionalKeyed2AcceptsEmptyArray' => [
'array{foo?: string}&array<string, mixed>',
'array<never, never>',
],
'Lowercase-stringAndCallable-string' => [
'lowercase-string',
'callable-string',
],
];
}
}