packages/deriver/tests/Unit/Deriver/Lowerer/LiteralArrayLoweringTest.php
1<?php
2
3declare (strict_types=1);
4
5namespace Tests\Unit\Deriver\Lowerer;
6
7use Deriver\Deriver\Evaluator\TargetProfile;
8use Deriver\Deriver\Lowerer\Declaration\Index;
9use Deriver\Deriver\Lowerer\LiteralArrayLowering;
10use Deriver\Deriver\Lowerer\LoweringScope;
11use Deriver\Deriver\Parser\Node\File;
12use Deriver\Deriver\Parser\Parser;
13use Deriver\Deriver\Parser\ParserConfig;
14use Deriver\Deriver\Resolver\Resolver;
15use Deriver\Deriver\Sources\Path;
16use Deriver\Deriver\Sources\Source;
17use Deriver\Deriver\Sources\Sources;
18use PhpParser\Node\Expr\ConstFetch;
19use PhpParser\Node\Expr\UnaryMinus;
20use PhpParser\Node\Expr\Variable;
21use PhpParser\Node\Name;
22use PhpParser\Node\Scalar\Int_;
23use PHPUnit\Framework\Attributes\CoversNothing;
24use PHPUnit\Framework\Attributes\Small;
25use PHPUnit\Framework\TestCase;
26
27#[CoversNothing]
28#[Small]
29final class LiteralArrayLoweringTest extends TestCase
30{
31 public function testLowerKeepsScalarObservationsAndFallsBackForReferences(): void
32 {
33 $source = '<?php function target(){return [1,2,"x"]; }';
34 $snapshotId = 'test';
35 $input = new Sources([new Source('fixture.php', $source)]);
36 $profile = new TargetProfile();
37 $parser = new Parser(new ParserConfig($profile->version));
38 $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));
39 $index = new Index($snapshotId, $trees);
40 $body = $index->callable('target');
41 self::assertNotNull($body);
42 self::assertCount(4, $body->blocks[0]->instructions);
43 $constant = $body->blocks[0]->instructions[3]->constant;
44 self::assertNotNull($constant);
45 self::assertSame([1, 2, 'x'], array_map(static fn ($element) => $element->literal, $constant->operands));
46 self::assertCount(4, $body->blocks[0]->instructions);
47 $source2 = '<?php function target(&$x){return [&$x,1];}';
48 $snapshotId1 = 'test';
49 $input1 = new Sources([new Source('fixture.php', $source2)]);
50 $profile1 = new TargetProfile();
51 $parser1 = new Parser(new ParserConfig($profile1->version));
52 $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));
53 $other = (new Index($snapshotId1, $trees1))->callable('target');
54 self::assertNotNull($other);
55 self::assertContains('array-set', array_column($other->blocks[0]->instructions, 'operation'));
56 }
57 public function testLiteralNeverEvaluatesApplicationConstants(): void
58 {
59 $source = '<?php';
60 $snapshotId = 'test';
61 $input = new Sources([new Source('fixture.php', $source)]);
62 $profile = new TargetProfile();
63 $parser = new Parser(new ParserConfig($profile->version));
64 $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));
65 $index = new Index($snapshotId, $trees);
66 $lowering = new LoweringScope($index->builder('fixture.php'), $index, 'target');
67 $literal = new LiteralArrayLowering($lowering);
68 self::assertNull($literal->literal(new ConstFetch(new Name('APP_SECRET'))));
69 self::assertNull($literal->literal(new Variable('x')));
70 }
71 public function testObserveRetainsTheSignedExpressionAndItsOperand(): void
72 {
73 $source = '<?php';
74 $snapshotId = 'test';
75 $input = new Sources([new Source('fixture.php', $source)]);
76 $profile = new TargetProfile();
77 $parser = new Parser(new ParserConfig($profile->version));
78 $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));
79 $index = new Index($snapshotId, $trees);
80 $lowering = new LoweringScope($index->builder('fixture.php'), $index, 'target');
81 $literal = new LiteralArrayLowering($lowering);
82 $literal->observe(new UnaryMinus(new Int_(3)));
83 $blocks = $lowering->graph->finish();
84 self::assertSame([3, -3], array_map(static fn ($instruction) => $instruction->constant?->native(), $blocks[0]->instructions));
85 }
86}
87