@@ -84,6 +84,45 @@ final public function someMethod(): string
8484 self ::assertSame ('test ' , $ result ->someMethod ());
8585 }
8686
87+ #[TestDox('Test that `decorate` method returns service as-is when class itself is final ' )]
88+ public function testThatDecoratorReturnsTheSameInstanceForFinalClass (): void
89+ {
90+ $ service = new FinalTestService ();
91+
92+ $ stopWatch = $ this ->getMockBuilder (Stopwatch::class)->disableOriginalConstructor ()->getMock ();
93+
94+ $ decorator = new StopwatchDecorator ($ stopWatch , new NullLogger ());
95+
96+ $ result = $ decorator ->decorate ($ service );
97+
98+ // Since the class is final, it should return the same instance
99+ self ::assertSame ($ service , $ result );
100+ self ::assertSame ('final-test ' , $ result ->testMethod ());
101+ }
102+
103+ #[TestDox('Test that decorator handles parameters with internal class default values ' )]
104+ public function testThatDecoratorHandlesInternalClassDefaultValues (): void
105+ {
106+ $ service = new ServiceWithInternalDefaults ();
107+
108+ $ stopWatch = $ this ->getMockBuilder (Stopwatch::class)->disableOriginalConstructor ()->getMock ();
109+
110+ $ stopWatch
111+ ->expects ($ this ->once ())
112+ ->method ('start ' );
113+
114+ $ stopWatch
115+ ->expects ($ this ->once ())
116+ ->method ('stop ' );
117+
118+ $ decorator = new StopwatchDecorator ($ stopWatch , new NullLogger ());
119+
120+ $ result = $ decorator ->decorate ($ service );
121+
122+ // The decorated service should work with methods that have internal class default values
123+ self ::assertSame ('test ' , $ result ->methodWithInternalDefault ());
124+ }
125+
87126 /**
88127 * @throws Throwable
89128 */
@@ -164,3 +203,39 @@ public static function dataProviderTestThatDecorateMethodReturnsExpected(): Gene
164203 yield [stdClass::class, new stdClass ()];
165204 }
166205}
206+
207+ /**
208+ * Helper final class for testing
209+ */
210+ final class FinalTestService
211+ {
212+ public function testMethod (): string
213+ {
214+ return 'final-test ' ;
215+ }
216+ }
217+
218+ /**
219+ * Helper class for testing internal class default values
220+ * Extends an internal class to potentially trigger reflection edge cases
221+ */
222+ class ServiceWithInternalDefaults extends \SplFileInfo
223+ {
224+ public function __construct ()
225+ {
226+ parent ::__construct (__FILE__ );
227+ }
228+
229+ /**
230+ * Method with parameter that has complex default values
231+ * This is for testing the catch block in getDefaultValueString when the decorator
232+ * tries to get the default value via reflection for certain edge cases
233+ *
234+ * @param array<string, mixed> $options
235+ */
236+ public function methodWithInternalDefault (array $ options = []): string
237+ {
238+ return 'test ' ;
239+ }
240+ }
241+
0 commit comments