4
4
5
5
namespace Test \Unit \Eboreum \Caster \Formatter \Object_ ;
6
6
7
+ use ArrayIterator ;
7
8
use Eboreum \Caster \Caster ;
8
9
use Eboreum \Caster \Formatter \Object_ \ClosureFormatter ;
10
+ use Iterator ;
9
11
use PHPUnit \Framework \TestCase ;
12
+ use Traversable ;
10
13
11
14
class ClosureFormatterTest extends TestCase
12
15
{
@@ -25,7 +28,7 @@ public function testFormatReturnsNullWhenObjectIsNotQualified(): void
25
28
/**
26
29
* @dataProvider dataProvider_testFormatWorks
27
30
*/
28
- public function testFormatWorks (string $ message , \ Closure $ closure , string $ expectedArguments ): void
31
+ public function testFormatWorks (string $ message , string $ expected , \ Closure $ closure ): void
29
32
{
30
33
$ caster = Caster::create ();
31
34
$ closureFormatter = new ClosureFormatter ();
@@ -34,95 +37,141 @@ public function testFormatWorks(string $message, \Closure $closure, string $expe
34
37
$ formatted = $ closureFormatter ->format ($ caster , $ closure );
35
38
$ this ->assertIsString ($ formatted );
36
39
assert (is_string ($ formatted )); // Make phpstan happy
37
- $ this ->assertMatchesRegularExpression (
38
- sprintf (
39
- implode ('' , [
40
- '/ ' ,
41
- '^ ' ,
42
- '\\\\Closure\(%s\) ' ,
43
- '$ ' ,
44
- '/ ' ,
45
- ]),
46
- preg_quote ($ expectedArguments , '/ ' ),
47
- ),
48
- $ formatted ,
49
- $ message ,
50
- );
40
+ $ this ->assertSame ($ expected , $ formatted , $ message );
51
41
}
52
42
53
43
/**
54
- * @return array<int, array{string, \Closure, string }>
44
+ * @return array<int, array{string, string, \Closure }>
55
45
*/
56
46
public function dataProvider_testFormatWorks (): array
57
47
{
58
48
return [
59
49
[
60
- '\Closure with no arguments. ' ,
50
+ '\Closure with no arguments and no return type. ' ,
51
+ '\\Closure() ' ,
61
52
static function () {},
62
- '' ,
63
53
],
64
54
[
65
- '\Closure with 1 argument. No default value. ' ,
55
+ '\Closure with 1 argument. No default value. No return type. ' ,
56
+ '\\Closure(int $a) ' ,
66
57
static function (int $ a ) {},
67
- 'int $a ' ,
68
58
],
69
59
[
70
- '\Closure with 1 argument. With default value. ' ,
60
+ '\Closure with 1 argument. With default value. No return type. ' ,
61
+ '\\Closure(int $a = 42) ' ,
71
62
static function (int $ a = 42 ) {},
72
- 'int $a = 42 ' ,
73
63
],
74
64
[
75
- '\Closure with 1 argument. With default value being a global constant. ' ,
65
+ '\Closure with 1 argument. With default value being a global constant. No return type. ' ,
66
+ '\\Closure(int $a = PHP_INT_MAX) ' ,
76
67
static function (int $ a = \PHP_INT_MAX ) {},
77
- 'int $a = PHP_INT_MAX ' ,
78
68
],
79
69
[
80
- '\Closure with 1 argument. With default value being a constant with a `self` reference. ' ,
70
+ implode ('' , [
71
+ '\Closure with 1 argument. With default value being a constant with a `self` reference. No return ' ,
72
+ ' type. ' ,
73
+ ]),
74
+ '\\Closure(int $a = self::A_CONSTANT) ' ,
81
75
static function (int $ a = self ::A_CONSTANT ) {},
82
- 'int $a = self::A_CONSTANT ' ,
83
76
],
84
77
[
85
- '\Closure with 1 argument. With default value being a constant with a class name reference. ' ,
86
- static function (int $ a = ClosureFormatterTest::A_CONSTANT ) {},
78
+ implode ('' , [
79
+ '\Closure with 1 argument. With default value being a constant with a class name reference. No ' ,
80
+ ' return type. ' ,
81
+ ]),
87
82
sprintf (
88
- 'int $a = \\%s::A_CONSTANT ' ,
83
+ '\\ Closure( int $a = \\%s::A_CONSTANT) ' ,
89
84
ClosureFormatterTest::class,
90
85
),
86
+ static function (int $ a = ClosureFormatterTest::A_CONSTANT ) {},
91
87
],
92
88
[
93
- '\Closure with 3 arguments. No default values. ' ,
89
+ '\Closure with 3 arguments. No default values. No return type. ' ,
90
+ '\\Closure(int $a, string $b, bool $c) ' ,
94
91
static function (int $ a , string $ b , bool $ c ) {},
95
- 'int $a, string $b, bool $c ' ,
96
92
],
97
93
[
98
- '\Closure with 3 arguments. With 3 default values. ' ,
94
+ '\Closure with 3 arguments. With 3 default values. No return type. ' ,
95
+ '\\Closure(int $a = 42, string $b = "foo", bool $c = true) ' ,
99
96
static function (int $ a = 42 , string $ b = 'foo ' , bool $ c = true ) {},
100
- 'int $a = 42, string $b = "foo", bool $c = true ' ,
101
97
],
102
98
[
103
- '\Closure with 1 typed variadic argument. ' ,
99
+ '\Closure with 1 typed variadic argument. No return type. ' ,
100
+ '\\Closure(int ...$a) ' ,
104
101
static function (int ...$ a ) {},
105
- 'int ...$a ' ,
106
102
],
107
103
[
108
- '\Closure with 1 typed variadic argument being nullable. ' ,
104
+ '\Closure with 1 typed variadic argument being nullable. No return type. ' ,
105
+ '\\Closure(?int ...$a) ' ,
109
106
static function (?int ...$ a ) {},
110
- '?int ...$a ' ,
111
107
],
112
108
[
113
- '\Closure with 1 typed argument passed by reference. ' ,
109
+ '\Closure with 1 typed argument passed by reference. No return type. ' ,
110
+ '\\Closure(int &$a) ' ,
114
111
static function (int &$ a ) {},
115
- 'int &$a ' ,
116
112
],
117
113
[
118
- '\Closure with 1 typed argument passed by reference being nullable. ' ,
114
+ '\Closure with 1 typed argument passed by reference being nullable. No return type. ' ,
115
+ '\\Closure(?int &$a) ' ,
119
116
static function (?int &$ a ) {},
120
- '?int &$a ' ,
117
+ ],
118
+ [
119
+ '\Closure with no arguments Return type "int". ' ,
120
+ '\\Closure(): int ' ,
121
+ static function (): int {
122
+ return 1 ; // phpstan love
123
+ },
124
+ ],
125
+ [
126
+ '\Closure with no arguments Return type "static". ' ,
127
+ '\\Closure(): static ' ,
128
+ function (): static {
129
+ return $ this ; // phpstan love
130
+ },
131
+ ],
132
+ [
133
+ '\Closure with no arguments Return type "?int". ' ,
134
+ '\\Closure(): ?int ' ,
135
+ static function (): ?int {
136
+ return rand (0 , 1 ) === 1 ? 1 : null ; // phpstan love
137
+ },
138
+ ],
139
+ [
140
+ '\Closure with no arguments Return type "int|null" (union). Must get shorted to "?int". ' ,
141
+ '\\Closure(): ?int ' ,
142
+ static function (): int |null {
143
+ return rand (0 , 1 ) === 1 ? 1 : null ; // phpstan love
144
+ },
145
+ ],
146
+ [
147
+ '\Closure with no arguments Return type "int|float|string". Must get normalized to "string|int|float". ' ,
148
+ '\\Closure(): string|int|float ' ,
149
+ static function (): int |float |string {
150
+ // phpstan love
151
+
152
+ switch (rand (0 , 2 )) {
153
+ case 0 :
154
+ return 3.14 ;
155
+ case 1 :
156
+ return 42 ;
157
+ }
158
+
159
+ return 'foo ' ;
160
+ },
161
+ ],
162
+ [
163
+ '\Closure with no arguments Return type "Traversable&Iterator" (intersection). ' ,
164
+ '\\Closure(): Traversable&Iterator ' ,
165
+ static function (): Traversable &Iterator {
166
+ return new ArrayIterator ([]); // phpstan love
167
+ },
121
168
],
122
169
[
123
170
'The big one. ' ,
124
- static function ($ a , &$ b , int $ c , bool $ d , \stdClass $ e , array $ f = ['lala ' ], ?string ...$ z ) {},
125
- '$a, &$b, int $c, bool $d, \\stdClass $e, array $f = [0 => "lala"], ?string ...$z ' ,
171
+ '\\Closure($a, &$b, int $c, bool $d, \\stdClass $e, array $f = [0 => "lala"], ?string ...$z): int ' ,
172
+ static function ($ a , &$ b , int $ c , bool $ d , \stdClass $ e , array $ f = ['lala ' ], ?string ...$ z ): int {
173
+ return 1 ; // phpstan love
174
+ },
126
175
],
127
176
];
128
177
}
0 commit comments