77use TypePHP \Tests \Fixtures \Domain \Cat ;
88use TypePHP \Tests \Fixtures \Domain \Dog ;
99use TypePHP \Tests \Fixtures \Generics \ChildComboService ;
10+ use TypePHP \Tests \Fixtures \Generics \ChildSingleAbstractService ;
1011use TypePHP \Tests \Fixtures \Generics \ChildWithoutTemplateDocblock ;
12+ use TypePHP \Tests \Fixtures \Generics \DeepGenericChildService ;
1113use TypePHP \TypePHP ;
1214
1315describe ('Inherited Interface Template Discovery during Instance Pre-binding ' , function () {
14- test ('binds generic union template when child class inherits template from interface without declaring it locally ' , function () {
15- /** @var ChildWithoutTemplateDocblock<Dog|Cat> $container */
16- $ container = new ChildWithoutTemplateDocblock ();
16+ describe ('Interface Template Inheritance ' , function () {
17+ test ('binds generic union template when child class inherits template from interface without declaring it locally ' , function () {
18+ /** @var ChildWithoutTemplateDocblock<Dog|Cat> $container */
19+ $ container = new ChildWithoutTemplateDocblock ();
1720
18- $ container ->push (new Dog ());
21+ $ container ->push (new Dog ());
1922
20- expect ($ container ->push (new Cat ()))->toBeTrue ();
21- expect (TypePHP::getGenericType ($ container ))->toBe ('( ' . Dog::class . ' | ' . Cat::class . ') ' );
23+ expect ($ container ->push (new Cat ()))->toBeTrue ();
24+ expect (TypePHP::getGenericType ($ container ))->toBe ('( ' . Dog::class . ' | ' . Cat::class . ') ' );
25+ });
26+
27+ test ('throws TypeError when item violates pre-bound union template on child inheriting interface ' , function () {
28+ /** @var ChildWithoutTemplateDocblock<Dog|Cat> $container */
29+ $ container = new ChildWithoutTemplateDocblock ();
30+
31+ expect (fn () => $ container ->push (new Car ()))
32+ ->toThrow (TypeError::class, 'must be of type ( ' . Dog::class . ' | ' . Cat::class . ') ' );
33+ });
34+ });
35+
36+ describe ('Single Abstract Class Generic Inheritance ' , function () {
37+ test ('pre-binds template inherited from single abstract parent without child docblock ' , function () {
38+ /** @var ChildSingleAbstractService<Dog|Cat> $service */
39+ $ service = new ChildSingleAbstractService ();
40+
41+ expect ($ service ->setItem (new Dog ()))->toBeTrue ();
42+ expect ($ service ->setItem (new Cat ()))->toBeTrue ();
43+
44+ expect (fn () => $ service ->setItem (new Car ()))
45+ ->toThrow (TypeError::class, 'must be of type ( ' . Dog::class . ' | ' . Cat::class . ') ' );
46+ });
2247 });
2348
24- test ('throws TypeError when item violates pre-bound union template on child inheriting interface ' , function () {
25- /** @var ChildWithoutTemplateDocblock<Dog|Cat> $container */
26- $ container = new ChildWithoutTemplateDocblock ();
49+ describe ('Multi-Nested Deep Generic Inheritance (Root -> Mid -> Child) ' , function () {
50+ test ('pre-binds template inherited across 3-tier deep abstract inheritance chain without child docblock ' , function () {
51+ /** @var DeepGenericChildService<positive-int> $service */
52+ $ service = new DeepGenericChildService ();
2753
28- expect (fn () => $ container ->push (new Car ()))
29- ->toThrow (TypeError::class, 'must be of type ( ' . Dog::class . ' | ' . Cat::class . ') ' )
30- ;
54+ expect ($ service ->processElement (100 ))->toBeTrue ();
55+
56+ expect (fn () => $ service ->processElement (-50 ))
57+ ->toThrow (TypeError::class, 'must be of type positive-int ' );
58+ });
3159 });
3260
3361 describe ('Abstract Class + Interface + Trait Combo Hierarchy ' , function () {
3765
3866 expect ($ service ->processData (42 ))->toBeTrue ();
3967 expect (fn () => $ service ->processData (-5 ))
40- ->toThrow (TypeError::class, 'must be of type positive-int ' )
41- ;
68+ ->toThrow (TypeError::class, 'must be of type positive-int ' );
4269
4370 expect ($ service ->setKey ('valid_key ' ))->toBeTrue ();
4471 expect (fn () => $ service ->setKey ('' ))
45- ->toThrow (TypeError::class, 'must be of type non-empty-string ' )
46- ;
47-
72+ ->toThrow (TypeError::class, 'must be of type non-empty-string ' );
73+
4874 expect ($ service ->setVal (new Dog ()))->toBeTrue ();
4975 expect ($ service ->setVal (new Cat ()))->toBeTrue ();
5076 expect (fn () => $ service ->setVal (new Car ()))
51- ->toThrow (TypeError::class, 'must be of type ( ' . Dog::class . ' | ' . Cat::class . ') ' )
52- ;
77+ ->toThrow (TypeError::class, 'must be of type ( ' . Dog::class . ' | ' . Cat::class . ') ' );
5378 });
5479 });
55- });
80+ });
0 commit comments