1717use PHPUnit \Framework \Attributes \DataProvider ;
1818use PHPUnit \Framework \Attributes \Test ;
1919use PHPUnit \Framework \TestCase ;
20+ use Respect \Stringifier \Helpers \ObjectHelper ;
2021use Respect \Stringifier \Stringifiers \CallableStringifier ;
2122use Respect \Stringifier \Test \Double \FakeQuoter ;
2223use Respect \Stringifier \Test \Double \FakeStringifier ;
2324
2425use function array_sum ;
2526use function sprintf ;
2627
28+ #[CoversClass(ObjectHelper::class)]
2729#[CoversClass(CallableStringifier::class)]
2830final class CallableStringifierTest extends TestCase
2931{
@@ -32,14 +34,14 @@ final class CallableStringifierTest extends TestCase
3234 #[Test]
3335 public function itShouldNotStringifyWhenRawValueIsNotCallable (): void
3436 {
35- $ sut = new CallableStringifier (new FakeStringifier (), new FakeQuoter ());
37+ $ sut = new CallableStringifier (new FakeStringifier (), new FakeQuoter (), closureOnly: false );
3638
3739 self ::assertNull ($ sut ->stringify (1 , self ::DEPTH ));
3840 }
3941
4042 #[Test]
41- #[DataProvider('callableRawValuesProvider ' )]
42- public function itShouldStringifyWhenRawValueIsCallable (callable $ raw , string $ expectedWithoutQuotes ): void
43+ #[DataProvider('closureRawValuesProvider ' )]
44+ public function itShouldStringifyWhenRawValueIsClosure (callable $ raw , string $ expectedWithoutQuotes ): void
4345 {
4446 $ quoter = new FakeQuoter ();
4547
@@ -51,6 +53,31 @@ public function itShouldStringifyWhenRawValueIsCallable(callable $raw, string $e
5153 self ::assertEquals ($ expected , $ actual );
5254 }
5355
56+ #[Test]
57+ #[DataProvider('nonClosureCallableRawValuesProvider ' )]
58+ public function itShouldNotStringifyNonClosureCallableByDefault (callable $ raw , string $ useless ): void
59+ {
60+ $ sut = new CallableStringifier (new FakeStringifier (), new FakeQuoter ());
61+
62+ self ::assertNull ($ sut ->stringify ($ raw , self ::DEPTH ));
63+ }
64+
65+ #[Test]
66+ #[DataProvider('nonClosureCallableRawValuesProvider ' )]
67+ public function itShouldStringifyNonClosureCallableWhenClosureOnlyIsFalse (
68+ callable $ raw ,
69+ string $ expectedWithoutQuotes ,
70+ ): void {
71+ $ quoter = new FakeQuoter ();
72+
73+ $ sut = new CallableStringifier (new FakeStringifier (), $ quoter , closureOnly: false );
74+
75+ $ actual = $ sut ->stringify ($ raw , self ::DEPTH );
76+ $ expected = $ quoter ->quote ($ expectedWithoutQuotes , self ::DEPTH );
77+
78+ self ::assertEquals ($ expected , $ actual );
79+ }
80+
5481 #[Test]
5582 public function itShouldStringifyWhenRawValueIsCallableWithDefaultValues (): void
5683 {
@@ -63,7 +90,7 @@ public function itShouldStringifyWhenRawValueIsCallableWithDefaultValues(): void
6390
6491 $ actual = $ sut ->stringify ($ raw , self ::DEPTH );
6592 $ expected = $ quoter ->quote (
66- sprintf ('function (int $value = %s): int ' , $ stringifier ->stringify (1 , self ::DEPTH + 1 )),
93+ sprintf ('Closure { static fn (int $value = %s): int } ' , $ stringifier ->stringify (1 , self ::DEPTH + 1 )),
6794 self ::DEPTH ,
6895 );
6996
@@ -77,7 +104,7 @@ public function itShouldStringifyWhenRawValueIsCallableThatDoesNotHaveAnAccessib
77104
78105 $ quoter = new FakeQuoter ();
79106
80- $ sut = new CallableStringifier (new FakeStringifier (), $ quoter );
107+ $ sut = new CallableStringifier (new FakeStringifier (), $ quoter, closureOnly: false );
81108
82109 $ actual = $ sut ->stringify ($ raw , self ::DEPTH );
83110 $ expected = $ quoter ->quote (
@@ -88,40 +115,87 @@ public function itShouldStringifyWhenRawValueIsCallableThatDoesNotHaveAnAccessib
88115 self ::assertEquals ($ expected , $ actual );
89116 }
90117
91- /** @return array<int , array{0: callable, 1: string}> */
92- public static function callableRawValuesProvider (): array
118+ /** @return array<string , array{0: callable, 1: string}> */
119+ public static function closureRawValuesProvider (): array
93120 {
94121 $ var1 = 1 ;
95122 $ var2 = 2 ;
96123
97124 return [
98- [static fn () => 1 , 'function () ' ],
99- [static fn (): int => 1 , 'function (): int ' ],
100- [static fn (float $ value ): int => (int ) $ value , 'function (float $value): int ' ],
101- [static fn (float &$ value ): int => (int ) $ value , 'function (float &$value): int ' ],
102- // phpcs:ignore SlevomatCodingStandard.TypeHints.DNFTypeHintFormat
103- [static fn (?float $ value ): int => (int ) $ value , 'function (?float $value): int ' ],
104- [static fn (int $ value = self ::DEPTH ): int => $ value , 'function (int $value = self::DEPTH): int ' ],
105- [static fn (int |float $ value ): int => (int ) $ value , 'function (int|float $value): int ' ],
106- [static fn (Countable &Iterator $ value ): int => $ value ->count (), 'function (Countable&Iterator $value): int ' ],
107- [static fn (int ...$ value ): int => array_sum ($ value ), 'function (int ...$value): int ' ],
108- [
125+ 'static closure without parameters ' => [
126+ static fn () => 1 ,
127+ 'Closure { static fn() } ' ,
128+ ],
129+ 'non-static closure without parameters ' => [
130+ fn () => 1 ,
131+ 'Closure { fn() } ' ,
132+ ],
133+ 'static closure with return type ' => [
134+ static fn (): int => 1 ,
135+ 'Closure { static fn(): int } ' ,
136+ ],
137+ 'non-static closure with return type ' => [
138+ fn (): int => 1 ,
139+ 'Closure { fn(): int } ' ,
140+ ],
141+ 'static closure with typed parameter ' => [
142+ static fn (float $ value ): int => (int ) $ value ,
143+ 'Closure { static fn(float $value): int } ' ,
144+ ],
145+ 'static closure with reference parameter ' => [
146+ static fn (float &$ value ): int => (int ) $ value ,
147+ 'Closure { static fn(float &$value): int } ' ,
148+ ],
149+ 'static closure with nullable parameter ' => [
150+ static fn (float |null $ value ): int => (int ) $ value ,
151+ 'Closure { static fn(?float $value): int } ' ,
152+ ],
153+ 'static closure with constant default value ' => [
154+ static fn (int $ value = self ::DEPTH ): int => $ value ,
155+ 'Closure { static fn(int $value = self::DEPTH): int } ' ,
156+ ],
157+ 'static closure with union type parameter ' => [
158+ static fn (int |float $ value ): int => (int ) $ value ,
159+ 'Closure { static fn(int|float $value): int } ' ,
160+ ],
161+ 'static closure with intersection type parameter ' => [
162+ static fn (Countable &Iterator $ value ): int => $ value ->count (),
163+ 'Closure { static fn(Countable&Iterator $value): int } ' ,
164+ ],
165+ 'static closure with variadic parameter ' => [
166+ static fn (int ...$ value ): int => array_sum ($ value ),
167+ 'Closure { static fn(int ...$value): int } ' ,
168+ ],
169+ 'static closure with multiple parameters ' => [
109170 static fn (float $ value1 , float $ value2 ): float => $ value1 + $ value2 ,
110- 'function (float $value1, float $value2): float ' ,
171+ 'Closure { static fn (float $value1, float $value2): float } ' ,
111172 ],
112- [
173+ ' static closure with single use variable ' => [
113174 static function (int $ value ) use ($ var1 ): int {
114175 return $ value + $ var1 ;
115176 },
116- 'function (int $value) use ($var1): int ' ,
177+ 'Closure { static fn (int $value) use ($var1): int } ' ,
117178 ],
118- [
179+ ' static closure with multiple use variables ' => [
119180 static function (int $ value ) use ($ var1 , $ var2 ): int {
120181 return $ value + $ var1 + $ var2 ;
121182 },
122- 'function (int $value) use ($var1, $var2): int ' ,
183+ 'Closure { static fn (int $value) use ($var1, $var2): int } ' ,
123184 ],
124- [
185+ 'non-static closure with use variable ' => [
186+ function (int $ value ) use ($ var1 ): int {
187+ return $ value + $ var1 ;
188+ },
189+ 'Closure { fn(int $value) use ($var1): int } ' ,
190+ ],
191+ ];
192+ }
193+
194+ /** @return array<string, array{0: callable, 1: string}> */
195+ public static function nonClosureCallableRawValuesProvider (): array
196+ {
197+ return [
198+ 'invokable object ' => [
125199 new class {
126200 public function __invoke (int $ parameter ): never
127201 {
@@ -130,19 +204,22 @@ public function __invoke(int $parameter): never
130204 },
131205 'class->__invoke(int $parameter): never ' ,
132206 ],
133- [
207+ ' object method as array ' => [
134208 [new DateTime (), 'format ' ],
135209 'DateTime->format(string $format) ' ,
136210 ],
137- [
211+ ' static method as array ' => [
138212 ['DateTime ' , 'createFromImmutable ' ],
139213 'DateTime::createFromImmutable(DateTimeImmutable $object) ' ,
140214 ],
141- [
215+ ' static method as string ' => [
142216 'DateTimeImmutable::getLastErrors ' ,
143217 'DateTimeImmutable::getLastErrors() ' ,
144218 ],
145- ['chr ' , 'chr(int $codepoint): string ' ],
219+ 'function name as string ' => [
220+ 'chr ' ,
221+ 'chr(int $codepoint): string ' ,
222+ ],
146223 ];
147224 }
148225}
0 commit comments