packages/deriver/tests/Unit/Deriver/Candidate/CandidateCollectionTest.php

1<?php
2
3declare (strict_types=1);
4
5namespace Tests\Unit\Deriver\Candidate;
6
7use Deriver\Deriver\Candidate\CandidateCollection;
8use Deriver\Deriver\Candidate\CandidateStatus;
9use Deriver\Deriver\Candidate\ResultRef;
10use Deriver\Deriver\Contributions;
11use Deriver\Deriver\DeriverConfig;
12use Deriver\Deriver\Evaluator\Call\Evaluators;
13use Deriver\Deriver\Evaluator\Call\Registrations;
14use Deriver\Deriver\Evaluator\EvaluatorConfig;
15use Deriver\Deriver\Evaluator\Evidence\Frontier;
16use Deriver\Deriver\Evaluator\Index\DefinitionIndex;
17use Deriver\Deriver\Evaluator\Request\Budget;
18use Deriver\Deriver\Evaluator\Request\ReturnQuery;
19use Deriver\Deriver\Evaluator\TargetProfile;
20use Deriver\Deriver\Evaluator\Term;
21use Deriver\Deriver\Lowerer\Declaration\Index;
22use Deriver\Deriver\MicroEvaluatorConversion;
23use Deriver\Deriver\Parser\Node\File;
24use Deriver\Deriver\Parser\Parser;
25use Deriver\Deriver\Parser\ParserConfig;
26use Deriver\Deriver\Providers\ProviderExpansion;
27use Deriver\Deriver\Publication\CandidateQuery;
28use Deriver\Deriver\Resolver\Resolver;
29use Deriver\Deriver\SnapshotIdentity;
30use Deriver\Deriver\Sources\Path;
31use Deriver\Deriver\Sources\Source;
32use Deriver\Deriver\Sources\Sources;
33use OutOfBoundsException;
34use PHPUnit\Framework\Attributes\CoversNothing;
35use PHPUnit\Framework\Attributes\DataProvider;
36use PHPUnit\Framework\TestCase;
37use RuntimeException;
38
39#[CoversNothing]
40final class CandidateCollectionTest extends TestCase
41{
42    public function testOffsetGetReturnsTheSameCandidatesAsIteration(): void
43    {
44        $source = 'function target($x){return $x?35:65;}';
45        $configuration = new DeriverConfig();
46        $budget = new Budget();
47        $contributions = new Contributions();
48        $prepared1Input = new Sources([new Source('candidate.php', '<?php ' . $source)]);
49        $prepared1Configuration = $configuration;
50        $prepared1Contributions = $contributions;
51        $prepared1Target = new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision);
52        $prepared1Providers = new ProviderExpansion($prepared1Input, array_map(Term::fromNative(...), $prepared1Configuration->environment), $prepared1Contributions);
53        $contributions1 = $prepared1Providers->contributions;
54        $prepared1Evaluators = new Evaluators(new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $prepared1Configuration->standardEvaluators);
55        $prepared1Settings = new EvaluatorConfig($prepared1Target, $prepared1Providers->environment, $prepared1Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration->evaluators));
56        $prepared1Identity = new SnapshotIdentity($prepared1Providers->input, $prepared1Settings, $prepared1Evaluators, $prepared1Providers->manifest);
57        $snapshotId = $prepared1Identity->id;
58        $input = $prepared1Providers->input;
59        $parser = new Parser(new ParserConfig($prepared1Target->version));
60        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input, false));
61        $prepared1Program = new Index($snapshotId, $trees);
62        $prepared1Snapshot = $prepared1Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program->diagnostics()));
63        $collection = (new CandidateQuery(new DefinitionIndex($prepared1Program), $prepared1Settings, $prepared1Evaluators, $prepared1Snapshot))->derive(new ReturnQuery('target', budget: $budget));
64        self::assertSame(35, $collection[0]->result);
65        self::assertSame(65, $collection[1]->result);
66        self::assertSame([$collection[0], $collection[1]], iterator_to_array($collection));
67        self::assertArrayNotHasKey('candidates', get_object_vars($collection));
68    }
69    #[DataProvider('providerMissingOffsets')]
70    public function testOffsetGetRejectsMissingAndNonIntegerOffsets(int|string|null $offset): void
71    {
72        $source = 'function target(){return 42;}';
73        $configuration = new DeriverConfig();
74        $budget = new Budget();
75        $contributions = new Contributions();
76        $prepared1Input = new Sources([new Source('candidate.php', '<?php ' . $source)]);
77        $prepared1Configuration = $configuration;
78        $prepared1Contributions = $contributions;
79        $prepared1Target = new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision);
80        $prepared1Providers = new ProviderExpansion($prepared1Input, array_map(Term::fromNative(...), $prepared1Configuration->environment), $prepared1Contributions);
81        $contributions1 = $prepared1Providers->contributions;
82        $prepared1Evaluators = new Evaluators(new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $prepared1Configuration->standardEvaluators);
83        $prepared1Settings = new EvaluatorConfig($prepared1Target, $prepared1Providers->environment, $prepared1Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration->evaluators));
84        $prepared1Identity = new SnapshotIdentity($prepared1Providers->input, $prepared1Settings, $prepared1Evaluators, $prepared1Providers->manifest);
85        $snapshotId = $prepared1Identity->id;
86        $input = $prepared1Providers->input;
87        $parser = new Parser(new ParserConfig($prepared1Target->version));
88        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input, false));
89        $prepared1Program = new Index($snapshotId, $trees);
90        $prepared1Snapshot = $prepared1Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program->diagnostics()));
91        $collection = (new CandidateQuery(new DefinitionIndex($prepared1Program), $prepared1Settings, $prepared1Evaluators, $prepared1Snapshot))->derive(new ReturnQuery('target', budget: $budget));
92        self::assertFalse($collection->offsetExists($offset));
93        $this->expectException(OutOfBoundsException::class);
94        $collection->offsetGet($offset);
95    }
96    /**
97     * @return iterable<string, array{int|string|null}>
98     */
99    public static function providerMissingOffsets(): iterable
100    {
101        yield 'negative' => [-1];
102        yield 'past the end' => [1];
103        yield 'numeric string' => ['0'];
104        yield 'string' => ['missing'];
105        yield 'null' => [null];
106    }
107    public function testOffsetGetRejectsAnEmptyCollection(): void
108    {
109        $collection = new CandidateCollection([], new ResultRef('empty'));
110        self::assertCount(0, $collection);
111        self::assertFalse(isset($collection[0]));
112        self::assertNull($collection[0] ?? null);
113        $this->expectException(OutOfBoundsException::class);
114        $collection[0];
115    }
116    public function testOffsetExistsIncludesCandidatesWithNullValues(): void
117    {
118        $source = 'function target(){return null;}';
119        $configuration = new DeriverConfig();
120        $budget = new Budget();
121        $contributions = new Contributions();
122        $prepared1Input = new Sources([new Source('candidate.php', '<?php ' . $source)]);
123        $prepared1Configuration = $configuration;
124        $prepared1Contributions = $contributions;
125        $prepared1Target = new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision);
126        $prepared1Providers = new ProviderExpansion($prepared1Input, array_map(Term::fromNative(...), $prepared1Configuration->environment), $prepared1Contributions);
127        $contributions1 = $prepared1Providers->contributions;
128        $prepared1Evaluators = new Evaluators(new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $prepared1Configuration->standardEvaluators);
129        $prepared1Settings = new EvaluatorConfig($prepared1Target, $prepared1Providers->environment, $prepared1Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration->evaluators));
130        $prepared1Identity = new SnapshotIdentity($prepared1Providers->input, $prepared1Settings, $prepared1Evaluators, $prepared1Providers->manifest);
131        $snapshotId = $prepared1Identity->id;
132        $input = $prepared1Providers->input;
133        $parser = new Parser(new ParserConfig($prepared1Target->version));
134        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input, false));
135        $prepared1Program = new Index($snapshotId, $trees);
136        $prepared1Snapshot = $prepared1Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program->diagnostics()));
137        $collection = (new CandidateQuery(new DefinitionIndex($prepared1Program), $prepared1Settings, $prepared1Evaluators, $prepared1Snapshot))->derive(new ReturnQuery('target', budget: $budget));
138        $candidate = $collection[0] ?? null;
139        self::assertNotNull($candidate);
140        self::assertSame($collection[0], $candidate);
141        self::assertTrue(isset($collection[0]));
142        self::assertNull($candidate->result);
143        self::assertFalse(isset($collection[1]));
144        self::assertNull($collection[1] ?? null);
145    }
146    public function testOffsetSetRejectsReplacement(): void
147    {
148        $source = 'function target(){return 42;}';
149        $configuration = new DeriverConfig();
150        $budget = new Budget();
151        $contributions = new Contributions();
152        $prepared1Input = new Sources([new Source('candidate.php', '<?php ' . $source)]);
153        $prepared1Configuration = $configuration;
154        $prepared1Contributions = $contributions;
155        $prepared1Target = new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision);
156        $prepared1Providers = new ProviderExpansion($prepared1Input, array_map(Term::fromNative(...), $prepared1Configuration->environment), $prepared1Contributions);
157        $contributions1 = $prepared1Providers->contributions;
158        $prepared1Evaluators = new Evaluators(new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $prepared1Configuration->standardEvaluators);
159        $prepared1Settings = new EvaluatorConfig($prepared1Target, $prepared1Providers->environment, $prepared1Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration->evaluators));
160        $prepared1Identity = new SnapshotIdentity($prepared1Providers->input, $prepared1Settings, $prepared1Evaluators, $prepared1Providers->manifest);
161        $snapshotId = $prepared1Identity->id;
162        $input = $prepared1Providers->input;
163        $parser = new Parser(new ParserConfig($prepared1Target->version));
164        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input, false));
165        $prepared1Program = new Index($snapshotId, $trees);
166        $prepared1Snapshot = $prepared1Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program->diagnostics()));
167        $collection = (new CandidateQuery(new DefinitionIndex($prepared1Program), $prepared1Settings, $prepared1Evaluators, $prepared1Snapshot))->derive(new ReturnQuery('target', budget: $budget));
168        $original = $collection[0];
169        $source2 = 'function target(){return 7;}';
170        $configuration1 = new DeriverConfig();
171        $budget1 = new Budget();
172        $contributions2 = new Contributions();
173        $prepared1Input1 = new Sources([new Source('candidate.php', '<?php ' . $source2)]);
174        $prepared1Configuration1 = $configuration1;
175        $prepared1Contributions1 = $contributions2;
176        $prepared1Target1 = new TargetProfile($prepared1Configuration1->phpVersion, $prepared1Configuration1->integerBits, $prepared1Configuration1->floatPrecision);
177        $prepared1Providers1 = new ProviderExpansion($prepared1Input1, array_map(Term::fromNative(...), $prepared1Configuration1->environment), $prepared1Contributions1);
178        $contributions3 = $prepared1Providers1->contributions;
179        $prepared1Evaluators1 = new Evaluators(new TargetProfile($prepared1Configuration1->phpVersion, $prepared1Configuration1->integerBits, $prepared1Configuration1->floatPrecision), new Registrations($contributions3->evaluators, $contributions3->providers, $contributions3->domains, $contributions3->intrinsics, $contributions3->stateSlots), $prepared1Configuration1->standardEvaluators);
180        $prepared1Settings1 = new EvaluatorConfig($prepared1Target1, $prepared1Providers1->environment, $prepared1Configuration1->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration1->evaluators));
181        $prepared1Identity1 = new SnapshotIdentity($prepared1Providers1->input, $prepared1Settings1, $prepared1Evaluators1, $prepared1Providers1->manifest);
182        $snapshotId1 = $prepared1Identity1->id;
183        $input1 = $prepared1Providers1->input;
184        $parser1 = new Parser(new ParserConfig($prepared1Target1->version));
185        $trees1 = array_map(static fn (Source $source3): File => (new Resolver())->resolve($parser1->parse(new Source(Path::normalize($source3->path), $source3->contents, $source3->declarationsOnly))), iterator_to_array($input1, false));
186        $prepared1Program1 = new Index($snapshotId1, $trees1);
187        $prepared1Snapshot1 = $prepared1Identity1->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program1->diagnostics()));
188        $replacement = (new CandidateQuery(new DefinitionIndex($prepared1Program1), $prepared1Settings1, $prepared1Evaluators1, $prepared1Snapshot1))->derive(new ReturnQuery('target', budget: $budget1))[0];
189        $this->expectException(RuntimeException::class);
190        try {
191            $collection[0] = $replacement;
192        } finally {
193            self::assertCount(1, $collection);
194            self::assertSame($original, $collection[0]);
195        }
196    }
197    public function testOffsetSetRejectsAppend(): void
198    {
199        $source = 'function target(){return 42;}';
200        $configuration = new DeriverConfig();
201        $budget = new Budget();
202        $contributions = new Contributions();
203        $prepared1Input = new Sources([new Source('candidate.php', '<?php ' . $source)]);
204        $prepared1Configuration = $configuration;
205        $prepared1Contributions = $contributions;
206        $prepared1Target = new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision);
207        $prepared1Providers = new ProviderExpansion($prepared1Input, array_map(Term::fromNative(...), $prepared1Configuration->environment), $prepared1Contributions);
208        $contributions1 = $prepared1Providers->contributions;
209        $prepared1Evaluators = new Evaluators(new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $prepared1Configuration->standardEvaluators);
210        $prepared1Settings = new EvaluatorConfig($prepared1Target, $prepared1Providers->environment, $prepared1Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration->evaluators));
211        $prepared1Identity = new SnapshotIdentity($prepared1Providers->input, $prepared1Settings, $prepared1Evaluators, $prepared1Providers->manifest);
212        $snapshotId = $prepared1Identity->id;
213        $input = $prepared1Providers->input;
214        $parser = new Parser(new ParserConfig($prepared1Target->version));
215        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input, false));
216        $prepared1Program = new Index($snapshotId, $trees);
217        $prepared1Snapshot = $prepared1Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program->diagnostics()));
218        $collection = (new CandidateQuery(new DefinitionIndex($prepared1Program), $prepared1Settings, $prepared1Evaluators, $prepared1Snapshot))->derive(new ReturnQuery('target', budget: $budget));
219        $this->expectException(RuntimeException::class);
220        try {
221            $collection[] = $collection[0];
222        } finally {
223            self::assertCount(1, $collection);
224            self::assertFalse(isset($collection[1]));
225        }
226    }
227    public function testOffsetUnsetRejectsRemoval(): void
228    {
229        $source = 'function target(){return 42;}';
230        $configuration = new DeriverConfig();
231        $budget = new Budget();
232        $contributions = new Contributions();
233        $prepared1Input = new Sources([new Source('candidate.php', '<?php ' . $source)]);
234        $prepared1Configuration = $configuration;
235        $prepared1Contributions = $contributions;
236        $prepared1Target = new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision);
237        $prepared1Providers = new ProviderExpansion($prepared1Input, array_map(Term::fromNative(...), $prepared1Configuration->environment), $prepared1Contributions);
238        $contributions1 = $prepared1Providers->contributions;
239        $prepared1Evaluators = new Evaluators(new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $prepared1Configuration->standardEvaluators);
240        $prepared1Settings = new EvaluatorConfig($prepared1Target, $prepared1Providers->environment, $prepared1Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration->evaluators));
241        $prepared1Identity = new SnapshotIdentity($prepared1Providers->input, $prepared1Settings, $prepared1Evaluators, $prepared1Providers->manifest);
242        $snapshotId = $prepared1Identity->id;
243        $input = $prepared1Providers->input;
244        $parser = new Parser(new ParserConfig($prepared1Target->version));
245        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input, false));
246        $prepared1Program = new Index($snapshotId, $trees);
247        $prepared1Snapshot = $prepared1Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program->diagnostics()));
248        $collection = (new CandidateQuery(new DefinitionIndex($prepared1Program), $prepared1Settings, $prepared1Evaluators, $prepared1Snapshot))->derive(new ReturnQuery('target', budget: $budget));
249        $original = $collection[0];
250        $this->expectException(RuntimeException::class);
251        try {
252            unset($collection[0]);
253        } finally {
254            self::assertCount(1, $collection);
255            self::assertSame($original, $collection[0]);
256        }
257    }
258    public function testGetIteratorCannotChangeTheCollection(): void
259    {
260        $source = 'function target(){return 42;}';
261        $configuration = new DeriverConfig();
262        $budget = new Budget();
263        $contributions = new Contributions();
264        $prepared1Input = new Sources([new Source('candidate.php', '<?php ' . $source)]);
265        $prepared1Configuration = $configuration;
266        $prepared1Contributions = $contributions;
267        $prepared1Target = new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision);
268        $prepared1Providers = new ProviderExpansion($prepared1Input, array_map(Term::fromNative(...), $prepared1Configuration->environment), $prepared1Contributions);
269        $contributions1 = $prepared1Providers->contributions;
270        $prepared1Evaluators = new Evaluators(new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $prepared1Configuration->standardEvaluators);
271        $prepared1Settings = new EvaluatorConfig($prepared1Target, $prepared1Providers->environment, $prepared1Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration->evaluators));
272        $prepared1Identity = new SnapshotIdentity($prepared1Providers->input, $prepared1Settings, $prepared1Evaluators, $prepared1Providers->manifest);
273        $snapshotId = $prepared1Identity->id;
274        $input = $prepared1Providers->input;
275        $parser = new Parser(new ParserConfig($prepared1Target->version));
276        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input, false));
277        $prepared1Program = new Index($snapshotId, $trees);
278        $prepared1Snapshot = $prepared1Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program->diagnostics()));
279        $collection = (new CandidateQuery(new DefinitionIndex($prepared1Program), $prepared1Settings, $prepared1Evaluators, $prepared1Snapshot))->derive(new ReturnQuery('target', budget: $budget));
280        $original = $collection[0];
281        $iterator = $collection->getIterator();
282        unset($iterator[0]);
283        self::assertCount(1, $collection);
284        self::assertSame($original, $collection[0]);
285    }
286    public function testCountIncludesPartialCandidates(): void
287    {
288        $source = 'function target($x){return $x;}';
289        $configuration = new DeriverConfig();
290        $budget = new Budget();
291        $contributions = new Contributions();
292        $prepared1Input = new Sources([new Source('candidate.php', '<?php ' . $source)]);
293        $prepared1Configuration = $configuration;
294        $prepared1Contributions = $contributions;
295        $prepared1Target = new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision);
296        $prepared1Providers = new ProviderExpansion($prepared1Input, array_map(Term::fromNative(...), $prepared1Configuration->environment), $prepared1Contributions);
297        $contributions1 = $prepared1Providers->contributions;
298        $prepared1Evaluators = new Evaluators(new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $prepared1Configuration->standardEvaluators);
299        $prepared1Settings = new EvaluatorConfig($prepared1Target, $prepared1Providers->environment, $prepared1Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration->evaluators));
300        $prepared1Identity = new SnapshotIdentity($prepared1Providers->input, $prepared1Settings, $prepared1Evaluators, $prepared1Providers->manifest);
301        $snapshotId = $prepared1Identity->id;
302        $input = $prepared1Providers->input;
303        $parser = new Parser(new ParserConfig($prepared1Target->version));
304        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input, false));
305        $prepared1Program = new Index($snapshotId, $trees);
306        $prepared1Snapshot = $prepared1Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program->diagnostics()));
307        self::assertSame(1, (new CandidateQuery(new DefinitionIndex($prepared1Program), $prepared1Settings, $prepared1Evaluators, $prepared1Snapshot))->derive(new ReturnQuery('target', budget: $budget))->count());
308    }
309    public function testGetIteratorReturnsCandidateRecords(): void
310    {
311        $source = 'function target(){return 42;}';
312        $configuration = new DeriverConfig();
313        $budget = new Budget();
314        $contributions = new Contributions();
315        $prepared1Input = new Sources([new Source('candidate.php', '<?php ' . $source)]);
316        $prepared1Configuration = $configuration;
317        $prepared1Contributions = $contributions;
318        $prepared1Target = new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision);
319        $prepared1Providers = new ProviderExpansion($prepared1Input, array_map(Term::fromNative(...), $prepared1Configuration->environment), $prepared1Contributions);
320        $contributions1 = $prepared1Providers->contributions;
321        $prepared1Evaluators = new Evaluators(new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $prepared1Configuration->standardEvaluators);
322        $prepared1Settings = new EvaluatorConfig($prepared1Target, $prepared1Providers->environment, $prepared1Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration->evaluators));
323        $prepared1Identity = new SnapshotIdentity($prepared1Providers->input, $prepared1Settings, $prepared1Evaluators, $prepared1Providers->manifest);
324        $snapshotId = $prepared1Identity->id;
325        $input = $prepared1Providers->input;
326        $parser = new Parser(new ParserConfig($prepared1Target->version));
327        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input, false));
328        $prepared1Program = new Index($snapshotId, $trees);
329        $prepared1Snapshot = $prepared1Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program->diagnostics()));
330        $candidate = (new CandidateQuery(new DefinitionIndex($prepared1Program), $prepared1Settings, $prepared1Evaluators, $prepared1Snapshot))->derive(new ReturnQuery('target', budget: $budget))->getIterator()[0];
331        self::assertNotNull($candidate);
332        self::assertSame(CandidateStatus::Analyzed, $candidate->type);
333    }
334    public function testForCallerRetainsSameContextAmbiguity(): void
335    {
336        $source = 'function target($x){return $x?35:65;}function caller($x){return target($x);}';
337        $configuration = new DeriverConfig();
338        $budget = new Budget();
339        $contributions = new Contributions();
340        $prepared1Input = new Sources([new Source('candidate.php', '<?php ' . $source)]);
341        $prepared1Configuration = $configuration;
342        $prepared1Contributions = $contributions;
343        $prepared1Target = new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision);
344        $prepared1Providers = new ProviderExpansion($prepared1Input, array_map(Term::fromNative(...), $prepared1Configuration->environment), $prepared1Contributions);
345        $contributions1 = $prepared1Providers->contributions;
346        $prepared1Evaluators = new Evaluators(new TargetProfile($prepared1Configuration->phpVersion, $prepared1Configuration->integerBits, $prepared1Configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $prepared1Configuration->standardEvaluators);
347        $prepared1Settings = new EvaluatorConfig($prepared1Target, $prepared1Providers->environment, $prepared1Configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $prepared1Configuration->evaluators));
348        $prepared1Identity = new SnapshotIdentity($prepared1Providers->input, $prepared1Settings, $prepared1Evaluators, $prepared1Providers->manifest);
349        $snapshotId = $prepared1Identity->id;
350        $input = $prepared1Providers->input;
351        $parser = new Parser(new ParserConfig($prepared1Target->version));
352        $trees = array_map(static fn (Source $source1): File => (new Resolver())->resolve($parser->parse(new Source(Path::normalize($source1->path), $source1->contents, $source1->declarationsOnly))), iterator_to_array($input, false));
353        $prepared1Program = new Index($snapshotId, $trees);
354        $prepared1Snapshot = $prepared1Identity->snapshot(array_map(Frontier::fromDiagnostic(...), $prepared1Program->diagnostics()));
355        $result = (new CandidateQuery(new DefinitionIndex($prepared1Program), $prepared1Settings, $prepared1Evaluators, $prepared1Snapshot))->derive(new ReturnQuery('target', budget: $budget));
356        self::assertCount(2, $result->forCaller('caller'));
357    }
358}
359