packages/deriver/tests/Unit/Deriver/Evaluator/Execution/Operation/PartialFormattingTest.php
1<?php
2
3declare (strict_types=1);
4
5namespace Tests\Unit\Deriver\Evaluator\Execution\Operation;
6
7use Deriver\Deriver\Contributions;
8use Deriver\Deriver\DeriverConfig;
9use Deriver\Deriver\Evaluator\Call\Evaluators;
10use Deriver\Deriver\Evaluator\Call\Registrations;
11use Deriver\Deriver\Evaluator\EvaluatorConfig;
12use Deriver\Deriver\Evaluator\Evidence\Frontier;
13use Deriver\Deriver\Evaluator\Execution\Completion\Alternative;
14use Deriver\Deriver\Evaluator\Execution\EvaluatorConfig as ExecutionEvaluatorConfig;
15use Deriver\Deriver\Evaluator\Request\ReturnQuery;
16use Deriver\Deriver\Evaluator\TargetProfile;
17use Deriver\Deriver\Evaluator\Term;
18use Deriver\Deriver\Evaluator\TermKind;
19use Deriver\Deriver\Execution\QueryExecution;
20use Deriver\Deriver\Lowerer\Declaration\Index;
21use Deriver\Deriver\MicroEvaluatorConversion;
22use Deriver\Deriver\Parser\Node\File;
23use Deriver\Deriver\Parser\Parser;
24use Deriver\Deriver\Parser\ParserConfig;
25use Deriver\Deriver\Providers\ProviderExpansion;
26use Deriver\Deriver\Resolver\Resolver;
27use Deriver\Deriver\SnapshotIdentity;
28use Deriver\Deriver\Sources\Path;
29use Deriver\Deriver\Sources\Source;
30use Deriver\Deriver\Sources\Sources;
31use PHPUnit\Framework\Attributes\CoversNothing;
32use PHPUnit\Framework\Attributes\Small;
33use PHPUnit\Framework\TestCase;
34
35#[CoversNothing]
36#[Small]
37final class PartialFormattingTest extends TestCase
38{
39 public function testApplyKeepsTheFormattedKnownPrefixBeforeAnExplicitResidual(): void
40 {
41 $source = '<?php function target(string $f){return sprintf("SELECT %s FROM t WHERE ".$f,"id");}';
42 $symbol = 'target';
43 $input = new Sources([new Source('fixture.php', $source)]);
44 $configuration = new DeriverConfig();
45 $contributions = new Contributions();
46 $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
47 $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
48 $contributions1 = $providers->contributions;
49 $evaluators = new Evaluators(new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $configuration->standardEvaluators);
50 $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
51 $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
52 $snapshotId = $identity->id;
53 $input1 = $providers->input;
54 $parser = new Parser(new ParserConfig($target->version));
55 $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($input1, false));
56 $program = new Index($snapshotId, $trees);
57 $result = (new QueryExecution($program, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program->diagnostics()))))->derive(new ReturnQuery($symbol));
58 self::assertCount(1, $result->normalOutcomes);
59 $value = $result->normalOutcomes[0]->values['return'];
60 self::assertSame(TermKind::Concat, $value->kind);
61 self::assertSame('SELECT id FROM t WHERE ', $value->operands[0]->native());
62 self::assertSame(['UNSUPPORTED_EVALUATOR_CASE'], array_column($result->frontiers, 'code'));
63 self::assertSame('sprintf', $result->frontiers[0]->operation);
64 self::assertTrue($result->exceptionalOutcomes[0]->exception->attributes['uncertain'] ?? false);
65 }
66 public function testApplyFormatsVectorArgumentsInValueOrder(): void
67 {
68 $source = '<?php function target(string $f){return vsprintf(\'%2$s %1$s \'.$f,["a"=>"x","b"=>"y"]);}';
69 $symbol = 'target';
70 $input = new Sources([new Source('fixture.php', $source)]);
71 $configuration = new DeriverConfig();
72 $contributions = new Contributions();
73 $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
74 $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
75 $contributions1 = $providers->contributions;
76 $evaluators = new Evaluators(new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $configuration->standardEvaluators);
77 $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
78 $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
79 $snapshotId = $identity->id;
80 $input1 = $providers->input;
81 $parser = new Parser(new ParserConfig($target->version));
82 $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($input1, false));
83 $program = new Index($snapshotId, $trees);
84 $result = (new QueryExecution($program, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program->diagnostics()))))->derive(new ReturnQuery($symbol));
85 self::assertSame('y x ', $result->normalOutcomes[0]->values['return']->operands[0]->native());
86 }
87 public function testApplyLeavesUndecidablePrefixesToTheOrdinaryModel(): void
88 {
89 $source = '<?php function target(string $f){return sprintf("%s %s ".$f,"id");}';
90 $symbol = 'target';
91 $input = new Sources([new Source('fixture.php', $source)]);
92 $configuration = new DeriverConfig();
93 $contributions = new Contributions();
94 $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
95 $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
96 $contributions1 = $providers->contributions;
97 $evaluators = new Evaluators(new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $configuration->standardEvaluators);
98 $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
99 $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
100 $snapshotId = $identity->id;
101 $input1 = $providers->input;
102 $parser = new Parser(new ParserConfig($target->version));
103 $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($input1, false));
104 $program = new Index($snapshotId, $trees);
105 $result = (new QueryExecution($program, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program->diagnostics()))))->derive(new ReturnQuery($symbol));
106 $values = array_map(static fn (Alternative $outcome) => $outcome->values['return'], $result->normalOutcomes);
107 self::assertSame(['opaque'], array_values(array_unique(array_map(static fn ($value): string => $value->kind->value, $values))));
108 self::assertSame(['UNSUPPORTED_EVALUATOR_CASE'], array_column($result->frontiers, 'code'));
109 }
110 public function testApplyDoesNotChangeCompletelyKnownFormats(): void
111 {
112 $source = '<?php function target(){$f=" %s";return sprintf("%s".$f,"a","b");}';
113 $symbol = 'target';
114 $input = new Sources([new Source('fixture.php', $source)]);
115 $configuration = new DeriverConfig();
116 $contributions = new Contributions();
117 $target = new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision);
118 $providers = new ProviderExpansion($input, array_map(Term::fromNative(...), $configuration->environment), $contributions);
119 $contributions1 = $providers->contributions;
120 $evaluators = new Evaluators(new TargetProfile($configuration->phpVersion, $configuration->integerBits, $configuration->floatPrecision), new Registrations($contributions1->evaluators, $contributions1->providers, $contributions1->domains, $contributions1->intrinsics, $contributions1->stateSlots), $configuration->standardEvaluators);
121 $settings = new EvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators, array_map((new MicroEvaluatorConversion())->convert(...), $configuration->evaluators));
122 $identity = new SnapshotIdentity($providers->input, $settings, $evaluators, $providers->manifest);
123 $snapshotId = $identity->id;
124 $input1 = $providers->input;
125 $parser = new Parser(new ParserConfig($target->version));
126 $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($input1, false));
127 $program = new Index($snapshotId, $trees);
128 $result = (new QueryExecution($program, new ExecutionEvaluatorConfig($target, $providers->environment, $configuration->standardEvaluators), $evaluators, $identity->snapshot(array_map(Frontier::fromDiagnostic(...), $program->diagnostics()))))->derive(new ReturnQuery($symbol));
129 self::assertSame('a b', $result->normalOutcomes[0]->values['return']->native());
130 self::assertSame([], $result->frontiers);
131 }
132}
133