packages/deriver/tests/Unit/Deriver/Evaluator/Call/Provider/DispatchProviderTest.php

1<?php
2
3declare (strict_types=1);
4
5namespace Tests\Unit\Deriver\Evaluator\Call\Provider;
6
7use Deriver\Deriver\Evaluator\Call\Provider\DispatchDecision;
8use Deriver\Deriver\Evaluator\Call\Provider\DispatchProvider;
9use Deriver\Deriver\Evaluator\Call\Provider\DispatchRequest;
10use Deriver\Deriver\Evaluator\Call\Provider\DispatchTarget;
11use Deriver\Deriver\Evaluator\Call\Provider\Provider;
12use Deriver\Deriver\Evaluator\Request\EntryPoint;
13use Deriver\Deriver\Evaluator\TargetProfile;
14use Deriver\Deriver\Evaluator\Term;
15use Deriver\Deriver\Evaluator\TermKind;
16use Deriver\Deriver\Providers\DeclarationProvider;
17use Deriver\Deriver\Providers\EntryPointProvider;
18use Deriver\Deriver\Providers\EnvironmentProvider;
19use Deriver\Deriver\Sources\Source;
20use Deriver\Deriver\Sources\SourceRef;
21use Deriver\Deriver\Sources\Sources;
22use Override;
23use PHPUnit\Framework\Attributes\CoversClass;
24use PHPUnit\Framework\Attributes\Small;
25use PHPUnit\Framework\Attributes\UsesClass;
26use PHPUnit\Framework\TestCase;
27
28/**
29 * @covers \Deriver\Deriver\Evaluator\Call\Provider\DispatchProvider
30 */
31#[CoversClass(DispatchProvider::class)]
32#[UsesClass(DeclarationProvider::class)]
33#[UsesClass(DispatchDecision::class)]
34#[UsesClass(DispatchRequest::class)]
35#[UsesClass(DispatchTarget::class)]
36#[UsesClass(EntryPointProvider::class)]
37#[UsesClass(EnvironmentProvider::class)]
38#[UsesClass(Provider::class)]
39#[UsesClass(TargetProfile::class)]
40#[UsesClass(SourceRef::class)]
41#[UsesClass(Term::class)]
42#[Small]
43final class DispatchProviderTest extends TestCase
44{
45    public function testResolveSeparatesExhaustiveBindingsFromUnmatchedCalls(): void
46    {
47        $source = new SourceRef('s', 'f.php', 0, 1);
48        $receiver = Term::parameter('service', 'Contract');
49        $request = new DispatchRequest($receiver, 'label', false, $source, new TargetProfile());
50        $decision = (new class () implements DeclarationProvider, DispatchProvider, EnvironmentProvider, EntryPointProvider {
51            /**
52             * @return string Provider identity
53             */
54            #[Override]
55            public function id(): string
56            {
57                return 'example.container';
58            }
59            /**
60             * @return string Captured export version
61             */
62            #[Override]
63            public function version(): string
64            {
65                return '1';
66            }
67            /**
68             * @return Sources Explicit generated declaration and semantics
69             */
70            #[Override]
71            public function declarations(): Sources
72            {
73                return new Sources([new Source('generated/service.php', '<?php class GeneratedService{public function label(){return "service";}}')]);
74            }
75            /**
76             * @param DispatchRequest $request Evaluated call metadata
77             * @return DispatchDecision Exported binding, with explicit completeness
78             */
79            #[Override]
80            public function resolve(DispatchRequest $request): DispatchDecision
81            {
82                if ($request->method !== 'label' || ($request->receiver->attributes['type'] ?? '') !== 'Contract') {
83                    return new DispatchDecision();
84                }
85                return new DispatchDecision([new DispatchTarget('GeneratedService::label', new Term(TermKind::Object, 'container:shared-service', attributes: ['class' => 'GeneratedService']))], true, ['container:export-complete']);
86            }
87            /**
88             * @return array<string, Term> Captured settings
89             */
90            #[Override]
91            public function environment(): array
92            {
93                return ['APP_NAME' => Term::constant('captured')];
94            }
95            /**
96             * @return list<EntryPoint> Declared lifecycle entries
97             */
98            #[Override]
99            public function entries(): array
100            {
101                return [new EntryPoint('entry')];
102            }
103        })->resolve($request);
104        self::assertTrue($decision->exhaustive);
105        self::assertSame('GeneratedService::label', $decision->targets[0]->symbol);
106    }
107}
108