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