55namespace Constructo \Test \Core \Reflect ;
66
77use Constructo \Contract \Reflect \TypesFactory ;
8+ use Constructo \Core \Reflect \Introspection \Introspector ;
89use Constructo \Core \Reflect \Reflector ;
910use Constructo \Factory \DefaultSpecsFactory ;
1011use Constructo \Factory \SchemaFactory ;
1314use Constructo \Support \Reflective \Notation ;
1415use Constructo \Test \Stub \Domain \Entity \Command \GameCommand ;
1516use Constructo \Test \Stub \Domain \Entity \Command \PersonCommand ;
17+ use Constructo \Test \Stub \Domain \Entity \EmptyClass ;
1618use Constructo \Test \Stub \Reflector \Sample ;
1719use PHPUnit \Framework \TestCase ;
1820
@@ -26,6 +28,7 @@ protected function setUp(): void
2628 {
2729 $ types = new Types ();
2830 $ cache = new Cache ();
31+ $ introspector = new Introspector ();
2932 $ notation = Notation::SNAKE ;
3033
3134 $ typesFactory = $ this ->createMock (TypesFactory::class);
@@ -73,7 +76,7 @@ protected function setUp(): void
7376 $ schemaFactory = new SchemaFactory ($ specsFactory );
7477
7578
76- $ this ->reflector = new Reflector ($ schemaFactory , $ types , $ cache , $ notation );
79+ $ this ->reflector = new Reflector ($ schemaFactory , $ types , $ cache , $ introspector , $ notation );
7780 }
7881
7982 public function testReflectSampleClassCreatesSchemaWithAllFields (): void
@@ -228,6 +231,9 @@ public function testExtractCompleteJsonSchemaStructure(): void
228231 "optional_object_field.published_at" : [ "sometimes", "date" ],
229232 "optional_object_field.data" : [ "sometimes", "array" ],
230233 "optional_object_field.features" : [ "sometimes", "array" ],
234+ "optional_object_field.features.*.name" : [ "sometimes", "string" ],
235+ "optional_object_field.features.*.description" : [ "sometimes", "string" ],
236+ "optional_object_field.features.*.enabled" : [ "sometimes", "boolean" ],
231237 "default_enum_field" : [ "sometimes", "required", "integer", "in:1,2,3" ],
232238 "processed_nullable_field" : [ "sometimes", "nullable", "string" ]
233239 } ' ;
@@ -248,7 +254,7 @@ public function testReflectorReturnsCorrectRulesForGameCommand(): void
248254 "features": [ "required", "array" ],
249255 "features.*.name": [ "required", "string" ],
250256 "features.*.description": [ "required", "string" ],
251- "features.*.enabled": [ "required", "bool " ]
257+ "features.*.enabled": [ "required", "boolean " ]
252258 } ' ;
253259 $ expected = json_decode ($ json , true );
254260 $ this ->assertEquals ($ expected , $ rules );
@@ -273,4 +279,26 @@ public function testReflectReturnsCorrectRulesForPersonCommand(): void
273279 $ expected = json_decode ($ json , true );
274280 $ this ->assertEquals ($ expected , $ rules );
275281 }
282+
283+ public function testReflectClassWithEmptySourceReturnsEarly (): void
284+ {
285+ // Create a stub class that has EmptyClass as a field source
286+ $ stubClass = new class (new EmptyClass ()) {
287+ public function __construct (
288+ public EmptyClass $ emptyField ,
289+ ) {
290+ }
291+ };
292+
293+ $ schema = $ this ->reflector ->reflect ($ stubClass ::class);
294+ $ rules = $ schema ->rules ();
295+
296+ // Should have the field but no nested rules since EmptyClass has no parameters
297+ $ this ->assertArrayHasKey ('empty_field ' , $ rules );
298+ $ this ->assertEquals (['required ' , 'array ' ], $ rules ['empty_field ' ]);
299+
300+ // Should not have any nested rules for empty_field since EmptyClass has no constructor parameters
301+ $ nestedKeys = array_filter (array_keys ($ rules ), fn ($ key ) => str_starts_with ($ key , 'empty_field. ' ));
302+ $ this ->assertEmpty ($ nestedKeys );
303+ }
276304}
0 commit comments