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