@@ -37,14 +37,14 @@ final class CallableStringifierTest extends TestCase
3737 #[Test]
3838 public function itShouldNotStringifyWhenRawValueIsNotCallable (): void
3939 {
40- $ sut = new CallableStringifier (new FakeStringifier (), new FakeQuoter ());
40+ $ sut = new CallableStringifier (new FakeStringifier (), new FakeQuoter (), closureOnly: false );
4141
4242 self ::assertNull ($ sut ->stringify (1 , self ::DEPTH ));
4343 }
4444
4545 #[Test]
46- #[DataProvider('callableRawValuesProvider ' )]
47- public function itShouldStringifyWhenRawValueIsCallable (callable $ raw , string $ expectedWithoutQuotes ): void
46+ #[DataProvider('closureRawValuesProvider ' )]
47+ public function itShouldStringifyWhenRawValueIsClosure (callable $ raw , string $ expectedWithoutQuotes ): void
4848 {
4949 $ quoter = new FakeQuoter ();
5050
@@ -56,6 +56,31 @@ public function itShouldStringifyWhenRawValueIsCallable(callable $raw, string $e
5656 self ::assertEquals ($ expected , $ actual );
5757 }
5858
59+ #[Test]
60+ #[DataProvider('nonClosureCallableRawValuesProvider ' )]
61+ public function itShouldNotStringifyNonClosureCallableByDefault (callable $ raw , string $ _ ): void
62+ {
63+ $ sut = new CallableStringifier (new FakeStringifier (), new FakeQuoter ());
64+
65+ self ::assertNull ($ sut ->stringify ($ raw , self ::DEPTH ));
66+ }
67+
68+ #[Test]
69+ #[DataProvider('nonClosureCallableRawValuesProvider ' )]
70+ public function itShouldStringifyNonClosureCallableWhenClosureOnlyIsFalse (
71+ callable $ raw ,
72+ string $ expectedWithoutQuotes ,
73+ ): void {
74+ $ quoter = new FakeQuoter ();
75+
76+ $ sut = new CallableStringifier (new FakeStringifier (), $ quoter , closureOnly: false );
77+
78+ $ actual = $ sut ->stringify ($ raw , self ::DEPTH );
79+ $ expected = $ quoter ->quote ($ expectedWithoutQuotes , self ::DEPTH );
80+
81+ self ::assertEquals ($ expected , $ actual );
82+ }
83+
5984 #[Test]
6085 public function itShouldStringifyWhenRawValueIsCallableWithDefaultValues (): void
6186 {
@@ -68,7 +93,7 @@ public function itShouldStringifyWhenRawValueIsCallableWithDefaultValues(): void
6893
6994 $ actual = $ sut ->stringify ($ raw , self ::DEPTH );
7095 $ expected = $ quoter ->quote (
71- sprintf ('function (int $value = %s): int ' , $ stringifier ->stringify (1 , self ::DEPTH + 1 )),
96+ sprintf ('Closure { static fn (int $value = %s): int } ' , $ stringifier ->stringify (1 , self ::DEPTH + 1 )),
7297 self ::DEPTH
7398 );
7499
@@ -86,7 +111,7 @@ public function itShouldStringifyWhenRawValueIsCallableThatDoesNotHaveAnAccessib
86111
87112 $ quoter = new FakeQuoter ();
88113
89- $ sut = new CallableStringifier (new FakeStringifier (), $ quoter );
114+ $ sut = new CallableStringifier (new FakeStringifier (), $ quoter, closureOnly: false );
90115
91116 $ actual = $ sut ->stringify ($ raw , self ::DEPTH );
92117 $ expected = $ quoter ->quote (
@@ -98,40 +123,90 @@ public function itShouldStringifyWhenRawValueIsCallableThatDoesNotHaveAnAccessib
98123 }
99124
100125 /**
101- * @return array<int , array{0: callable, 1: string}>
126+ * @return array<string , array{0: callable, 1: string}>
102127 */
103- public static function callableRawValuesProvider (): array
128+ public static function closureRawValuesProvider (): array
104129 {
105130 $ var1 = 1 ;
106131 $ var2 = 2 ;
107132
108133 return [
109- [static fn () => 1 , 'function () ' ],
110- [static fn (): int => 1 , 'function (): int ' ],
111- [static fn (float $ value ): int => (int ) $ value , 'function (float $value): int ' ],
112- [static fn (float &$ value ): int => (int ) $ value , 'function (float &$value): int ' ],
113- [static fn (?float $ value ): int => (int ) $ value , 'function (?float $value): int ' ],
114- [static fn (int $ value = self ::DEPTH ): int => $ value , 'function (int $value = self::DEPTH): int ' ],
115- [static fn (int |float $ value ): int => (int ) $ value , 'function (int|float $value): int ' ],
116- [static fn (Countable &Iterator $ value ): int => $ value ->count (), 'function (Countable&Iterator $value): int ' ],
117- [static fn (int ...$ value ): int => array_sum ($ value ), 'function (int ...$value): int ' ],
118- [
134+ 'static closure without parameters ' => [
135+ static fn () => 1 ,
136+ 'Closure { static fn() } ' ,
137+ ],
138+ 'non-static closure without parameters ' => [
139+ fn () => 1 ,
140+ 'Closure { fn() } ' ,
141+ ],
142+ 'static closure with return type ' => [
143+ static fn (): int => 1 ,
144+ 'Closure { static fn(): int } ' ,
145+ ],
146+ 'non-static closure with return type ' => [
147+ fn (): int => 1 ,
148+ 'Closure { fn(): int } ' ,
149+ ],
150+ 'static closure with typed parameter ' => [
151+ static fn (float $ value ): int => (int ) $ value ,
152+ 'Closure { static fn(float $value): int } ' ,
153+ ],
154+ 'static closure with reference parameter ' => [
155+ static fn (float &$ value ): int => (int ) $ value ,
156+ 'Closure { static fn(float &$value): int } ' ,
157+ ],
158+ 'static closure with nullable parameter ' => [
159+ static fn (?float $ value ): int => (int ) $ value ,
160+ 'Closure { static fn(?float $value): int } ' ,
161+ ],
162+ 'static closure with constant default value ' => [
163+ static fn (int $ value = self ::DEPTH ): int => $ value ,
164+ 'Closure { static fn(int $value = self::DEPTH): int } ' ,
165+ ],
166+ 'static closure with union type parameter ' => [
167+ static fn (int |float $ value ): int => (int ) $ value ,
168+ 'Closure { static fn(int|float $value): int } ' ,
169+ ],
170+ 'static closure with intersection type parameter ' => [
171+ static fn (Countable &Iterator $ value ): int => $ value ->count (),
172+ 'Closure { static fn(Countable&Iterator $value): int } ' ,
173+ ],
174+ 'static closure with variadic parameter ' => [
175+ static fn (int ...$ value ): int => array_sum ($ value ),
176+ 'Closure { static fn(int ...$value): int } ' ,
177+ ],
178+ 'static closure with multiple parameters ' => [
119179 static fn (float $ value1 , float $ value2 ): float => $ value1 + $ value2 ,
120- 'function (float $value1, float $value2): float ' ,
180+ 'Closure { static fn (float $value1, float $value2): float } ' ,
121181 ],
122- [
182+ ' static closure with single use variable ' => [
123183 static function (int $ value ) use ($ var1 ): int {
124184 return $ value + $ var1 ;
125185 },
126- 'function (int $value) use ($var1): int ' ,
186+ 'Closure { static fn (int $value) use ($var1): int } ' ,
127187 ],
128- [
188+ ' static closure with multiple use variables ' => [
129189 static function (int $ value ) use ($ var1 , $ var2 ): int {
130190 return $ value + $ var1 + $ var2 ;
131191 },
132- 'function (int $value) use ($var1, $var2): int ' ,
192+ 'Closure { static fn(int $value) use ($var1, $var2): int } ' ,
193+ ],
194+ 'non-static closure with use variable ' => [
195+ function (int $ value ) use ($ var1 ): int {
196+ return $ value + $ var1 ;
197+ },
198+ 'Closure { fn(int $value) use ($var1): int } ' ,
133199 ],
134- [
200+ ];
201+ }
202+
203+ /**
204+ * @return array<string, array{0: callable, 1: string}>
205+ */
206+ public static function nonClosureCallableRawValuesProvider (): array
207+ {
208+ return [
209+ 'invokable object ' => [
135210 new class {
136211 public function __invoke (int $ parameter ): never
137212 {
@@ -140,19 +215,22 @@ public function __invoke(int $parameter): never
140215 },
141216 'class->__invoke(int $parameter): never ' ,
142217 ],
143- [
218+ ' object method as array ' => [
144219 [new DateTime (), 'format ' ],
145220 'DateTime->format(string $format) ' ,
146221 ],
147- [
222+ ' static method as array ' => [
148223 ['DateTime ' , 'createFromImmutable ' ],
149224 'DateTime::createFromImmutable(DateTimeImmutable $object) ' ,
150225 ],
151- [
226+ ' static method as string ' => [
152227 'DateTimeImmutable::getLastErrors ' ,
153228 'DateTimeImmutable::getLastErrors() ' ,
154229 ],
155- ['chr ' , 'chr(int $codepoint): string ' ],
230+ 'function name as string ' => [
231+ 'chr ' ,
232+ 'chr(int $codepoint): string ' ,
233+ ],
156234 ];
157235 }
158236}
0 commit comments