packages/deriver/tests/Unit/Deriver/Evaluator/Execution/Transfer/PropertyLookupTest.php

1<?php
2
3declare (strict_types=1);
4
5namespace Tests\Unit\Deriver\Evaluator\Execution\Transfer;
6
7use Deriver\Deriver\Evaluator\Execution\Transfer\PropertyLookup;
8use Deriver\Deriver\Evaluator\TargetProfile;
9use Deriver\Deriver\Lowerer\Declaration\CallableIdentity;
10use Deriver\Deriver\Lowerer\Declaration\CallableSource;
11use Deriver\Deriver\Lowerer\Declaration\ConstantSignatures;
12use Deriver\Deriver\Lowerer\Declaration\Index;
13use Deriver\Deriver\Lowerer\Declaration\Indexer;
14use Deriver\Deriver\Lowerer\Declaration\Metadata\ClassDeclaration;
15use Deriver\Deriver\Lowerer\Declaration\Metadata\PropertyDeclaration;
16use Deriver\Deriver\Lowerer\Declaration\Traits\Composition;
17use Deriver\Deriver\Lowerer\Hierarchy\Builtins;
18use Deriver\Deriver\Lowerer\Hierarchy\Dispatch;
19use Deriver\Deriver\Lowerer\Lowerer;
20use Deriver\Deriver\Parser\Node\File;
21use Deriver\Deriver\Parser\Parser;
22use Deriver\Deriver\Parser\ParserConfig;
23use Deriver\Deriver\Parser\TargetSyntax;
24use Deriver\Deriver\Resolver\AssignmentPatterns;
25use Deriver\Deriver\Resolver\ClassScope;
26use Deriver\Deriver\Resolver\ExpressionValidation;
27use Deriver\Deriver\Resolver\MagicContext;
28use Deriver\Deriver\Resolver\Resolver;
29use Deriver\Deriver\Sources\LineMap;
30use Deriver\Deriver\Sources\Path;
31use Deriver\Deriver\Sources\Source;
32use Deriver\Deriver\Sources\Sources;
33use Deriver\Exception\ParserException;
34use Deriver\Exception\ResolutionException;
35use PHPUnit\Framework\Attributes\CoversClass;
36use PHPUnit\Framework\Attributes\Small;
37use PHPUnit\Framework\Attributes\UsesClass;
38use PHPUnit\Framework\TestCase;
39
40/**
41 * @covers \Deriver\Deriver\Evaluator\Execution\Transfer\PropertyLookup
42 */
43#[UsesClass(Resolver::class)]
44#[UsesClass(ExpressionValidation::class)]
45#[UsesClass(ResolutionException::class)]
46#[UsesClass(ParserConfig::class)]
47#[UsesClass(ParserException::class)]
48#[CoversClass(PropertyLookup::class)]
49#[UsesClass(CallableIdentity::class)]
50#[UsesClass(ClassDeclaration::class)]
51#[UsesClass(PropertyDeclaration::class)]
52#[UsesClass(Builtins::class)]
53#[UsesClass(Dispatch::class)]
54#[UsesClass(Sources::class)]
55#[UsesClass(Path::class)]
56#[UsesClass(Source::class)]
57#[UsesClass(TargetProfile::class)]
58#[UsesClass(Parser::class)]
59#[UsesClass(File::class)]
60#[UsesClass(Lowerer::class)]
61#[UsesClass(ConstantSignatures::class)]
62#[UsesClass(CallableSource::class)]
63#[UsesClass(Indexer::class)]
64#[UsesClass(Index::class)]
65#[UsesClass(Composition::class)]
66#[UsesClass(LineMap::class)]
67#[UsesClass(MagicContext::class)]
68#[UsesClass(AssignmentPatterns::class)]
69#[UsesClass(ClassScope::class)]
70#[UsesClass(TargetSyntax::class)]
71#[Small]
72final class PropertyLookupTest extends TestCase
73{
74    public function testFindPrefersTheLexicalPrivateSlotInASubclass(): void
75    {
76        $source = '<?php class A{private $x;}class B extends A{public $x;}';
77        $snapshotId = 'test';
78        $input = new Sources([new Source('fixture.php', $source)]);
79        $profile = new TargetProfile();
80        $parser = new Parser(new ParserConfig($profile->version));
81        $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));
82        $program = new Index($snapshotId, $trees);
83        $lookup = new PropertyLookup($program);
84        self::assertSame('A', $lookup->find('B', 'A', 'x')?->className);
85        self::assertSame('B', $lookup->find('B', '', 'x')?->className);
86    }
87    public function testAccessibleAllowsProtectedAccessFromRelatedClasses(): void
88    {
89        $source = '<?php class A{protected $x;}class B extends A{}';
90        $snapshotId = 'test';
91        $input = new Sources([new Source('fixture.php', $source)]);
92        $profile = new TargetProfile();
93        $parser = new Parser(new ParserConfig($profile->version));
94        $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));
95        $program = new Index($snapshotId, $trees);
96        $lookup = new PropertyLookup($program);
97        $property = $lookup->find('B', '', 'x');
98        self::assertTrue($lookup->accessible($property, 'B'));
99        self::assertFalse($lookup->accessible($property, 'Unrelated'));
100    }
101}
102