-
Notifications
You must be signed in to change notification settings - Fork 568
Expand file tree
/
Copy pathObjectShapeTypeTest.php
More file actions
159 lines (135 loc) · 4.74 KB
/
ObjectShapeTypeTest.php
File metadata and controls
159 lines (135 loc) · 4.74 KB
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<?php declare(strict_types = 1);
namespace PHPStan\Type;
use PHPStan\Testing\PHPStanTestCase;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPUnit\Framework\Attributes\DataProvider;
use function sprintf;
class ObjectShapeTypeTest extends PHPStanTestCase
{
public static function dataIsSuperTypeOf(): iterable
{
// Same properties, same types
yield [
new ObjectShapeType(['foo' => new IntegerType()], []),
new ObjectShapeType(['foo' => new IntegerType()], []),
TrinaryLogic::createYes(),
];
// Wider property type is supertype
yield [
new ObjectShapeType(['foo' => new IntegerType()], []),
new ObjectShapeType(['foo' => new ConstantIntegerType(1)], []),
TrinaryLogic::createYes(),
];
// Narrower property type is maybe supertype
yield [
new ObjectShapeType(['foo' => new ConstantIntegerType(1)], []),
new ObjectShapeType(['foo' => new IntegerType()], []),
TrinaryLogic::createMaybe(),
];
// Incompatible property types
yield [
new ObjectShapeType(['foo' => new IntegerType()], []),
new ObjectShapeType(['foo' => new StringType()], []),
TrinaryLogic::createNo(),
];
// Disjoint properties - object shapes are open types
yield [
new ObjectShapeType(['foo' => new IntegerType()], []),
new ObjectShapeType(['bar' => new StringType()], []),
TrinaryLogic::createMaybe(),
];
yield [
new ObjectShapeType(['bar' => new StringType()], []),
new ObjectShapeType(['foo' => new IntegerType()], []),
TrinaryLogic::createMaybe(),
];
// Required vs optional: optional is supertype of required
yield [
new ObjectShapeType(['foo' => new IntegerType()], ['foo']),
new ObjectShapeType(['foo' => new IntegerType()], []),
TrinaryLogic::createYes(),
];
// Required vs optional: required is maybe supertype of optional
yield [
new ObjectShapeType(['foo' => new IntegerType()], []),
new ObjectShapeType(['foo' => new IntegerType()], ['foo']),
TrinaryLogic::createMaybe(),
];
// Wider type with required property
yield [
new ObjectShapeType(['foo' => TypeCombinator::union(new IntegerType(), new NullType())], []),
new ObjectShapeType(['foo' => new IntegerType()], []),
TrinaryLogic::createYes(),
];
// Narrower type checking wider
yield [
new ObjectShapeType(['foo' => new IntegerType()], []),
new ObjectShapeType(['foo' => TypeCombinator::union(new IntegerType(), new NullType())], []),
TrinaryLogic::createMaybe(),
];
// Optional wider type vs required narrower
yield [
new ObjectShapeType(['foo' => TypeCombinator::union(new IntegerType(), new NullType())], ['foo']),
new ObjectShapeType(['foo' => new IntegerType()], []),
TrinaryLogic::createYes(),
];
// Required narrower vs optional wider
yield [
new ObjectShapeType(['foo' => new IntegerType()], []),
new ObjectShapeType(['foo' => TypeCombinator::union(new IntegerType(), new NullType())], ['foo']),
TrinaryLogic::createMaybe(),
];
// Disjoint with optional property
yield [
new ObjectShapeType(['foo' => new IntegerType()], []),
new ObjectShapeType(['bar' => new IntegerType()], ['bar']),
TrinaryLogic::createMaybe(),
];
yield [
new ObjectShapeType(['bar' => new IntegerType()], ['bar']),
new ObjectShapeType(['foo' => new IntegerType()], []),
TrinaryLogic::createMaybe(),
];
// Optional property with incompatible types
yield [
new ObjectShapeType(['foo' => new IntegerType()], []),
new ObjectShapeType(['foo' => new StringType()], ['foo']),
TrinaryLogic::createMaybe(),
];
// Superset has extra required property - maybe because shapes are open
yield [
new ObjectShapeType(['foo' => new IntegerType(), 'bar' => new StringType()], []),
new ObjectShapeType(['foo' => new IntegerType()], []),
TrinaryLogic::createMaybe(),
];
// Subset is supertype
yield [
new ObjectShapeType(['foo' => new IntegerType()], []),
new ObjectShapeType(['foo' => new IntegerType(), 'bar' => new StringType()], []),
TrinaryLogic::createYes(),
];
// Empty shape is supertype of any shape
yield [
new ObjectShapeType([], []),
new ObjectShapeType(['foo' => new IntegerType()], []),
TrinaryLogic::createYes(),
];
// Any shape is maybe supertype of empty shape
yield [
new ObjectShapeType(['foo' => new IntegerType()], []),
new ObjectShapeType([], []),
TrinaryLogic::createMaybe(),
];
}
#[DataProvider('dataIsSuperTypeOf')]
public function testIsSuperTypeOf(ObjectShapeType $type, Type $otherType, TrinaryLogic $expectedResult): void
{
$actualResult = $type->isSuperTypeOf($otherType);
$this->assertSame(
$expectedResult->describe(),
$actualResult->describe(),
sprintf('%s -> isSuperTypeOf(%s)', $type->describe(VerbosityLevel::precise()), $otherType->describe(VerbosityLevel::precise())),
);
}
}