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