Completed
Push — master ( 3be072...ba2d3a )
by Marco
231:32 queued 209:55
created

MagicGetTest   A

Complexity

Total Complexity 3

Size/Duplication

Total Lines 159
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 3
lcom 1
cbo 1
dl 0
loc 159
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ProxyManagerTest\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
6
7
use PHPUnit\Framework\MockObject\MockObject;
8
use PHPUnit\Framework\TestCase;
9
use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicGet;
10
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\InitializationTracker;
11
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\PrivatePropertiesMap;
12
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\ProtectedPropertiesMap;
13
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
14
use ProxyManagerTestAsset\BaseClass;
15
use ProxyManagerTestAsset\ClassWithMagicMethods;
16
use ReflectionClass;
17
use Zend\Code\Generator\MethodGenerator;
18
use Zend\Code\Generator\PropertyGenerator;
19
20
/**
21
 * Tests for {@see \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicGet}
22
 *
23
 * @group Coverage
24
 */
25
final class MagicGetTest extends TestCase
26
{
27
    /** @var PropertyGenerator&MockObject */
28
    private PropertyGenerator $initializer;
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_STRING, expecting T_FUNCTION or T_CONST
Loading history...
29
30
    /** @var MethodGenerator&MockObject */
31
    private MethodGenerator $initMethod;
32
33
    /** @var PublicPropertiesMap&MockObject */
34
    private PublicPropertiesMap $publicProperties;
35
36
    /** @var ProtectedPropertiesMap&MockObject */
37
    private ProtectedPropertiesMap $protectedProperties;
38
39
    /** @var PrivatePropertiesMap&MockObject */
40
    private PrivatePropertiesMap $privateProperties;
41
42
    /** @var InitializationTracker&MockObject */
43
    private InitializationTracker $initializationTracker;
44
45
    /** @var string */
46
    private string $expectedCode = <<<'PHP'
47
$this->foo && ! $this->init && $this->baz('__get', array('name' => $name));
48
49
if (isset(self::$bar[$name])) {
50
    return $this->$name;
51
}
52
53
if (isset(self::$baz[$name])) {
54
    if ($this->init) {
55
        return $this->$name;
56
    }
57
58
    // check protected property access via compatible class
59
    $callers      = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
60
    $caller       = isset($callers[1]) ? $callers[1] : [];
61
    $object       = isset($caller['object']) ? $caller['object'] : '';
62
    $expectedType = self::$baz[$name];
63
64
    if ($object instanceof $expectedType) {
65
        return $this->$name;
66
    }
67
68
    $class = isset($caller['class']) ? $caller['class'] : '';
69
70
    if ($class === $expectedType || is_subclass_of($class, $expectedType) || $class === 'ReflectionProperty') {
71
        return $this->$name;
72
    }
73
} elseif (isset(self::$tab[$name])) {
74
    // check private property access via same class
75
    $callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
76
    $caller  = isset($callers[1]) ? $callers[1] : [];
77
    $class   = isset($caller['class']) ? $caller['class'] : '';
78
79
    static $accessorCache = [];
80
81
    if (isset(self::$tab[$name][$class])) {
82
        $cacheKey = $class . '#' . $name;
83
        $accessor = isset($accessorCache[$cacheKey])
84
            ? $accessorCache[$cacheKey]
85
            : $accessorCache[$cacheKey] = \Closure::bind(function & ($instance) use ($name) {
86
                return $instance->$name;
87
            }, null, $class);
88
89
        return $accessor($this);
90
    }
91
92
    if ($this->init || 'ReflectionProperty' === $class) {
93
        $tmpClass = key(self::$tab[$name]);
94
        $cacheKey = $tmpClass . '#' . $name;
95
        $accessor = isset($accessorCache[$cacheKey])
96
            ? $accessorCache[$cacheKey]
97
            : $accessorCache[$cacheKey] = \Closure::bind(function & ($instance) use ($name) {
98
                return $instance->$name;
99
            }, null, $tmpClass);
100
101
        return $accessor($this);
102
    }
103
}
104
105
%a
106
PHP;
107
108
    /**
109
     * {@inheritDoc}
110
     */
111
    protected function setUp() : void
112
    {
113
        $this->initializer           = $this->createMock(PropertyGenerator::class);
114
        $this->initMethod            = $this->createMock(MethodGenerator::class);
115
        $this->publicProperties      = $this
116
            ->getMockBuilder(PublicPropertiesMap::class)
117
            ->disableOriginalConstructor()
118
            ->getMock();
119
        $this->protectedProperties   = $this
120
            ->getMockBuilder(ProtectedPropertiesMap::class)
121
            ->disableOriginalConstructor()
122
            ->getMock();
123
        $this->privateProperties     = $this
124
            ->getMockBuilder(PrivatePropertiesMap::class)
125
            ->disableOriginalConstructor()
126
            ->getMock();
127
        $this->initializationTracker = $this
128
            ->getMockBuilder(InitializationTracker::class)
129
            ->disableOriginalConstructor()
130
            ->getMock();
131
132
        $this->initializer->method('getName')->willReturn('foo');
133
        $this->initMethod->method('getName')->willReturn('baz');
134
        $this->publicProperties->method('isEmpty')->willReturn(false);
135
        $this->publicProperties->method('getName')->willReturn('bar');
136
        $this->protectedProperties->method('getName')->willReturn('baz');
137
        $this->privateProperties->method('getName')->willReturn('tab');
138
        $this->initializationTracker->method('getName')->willReturn('init');
139
    }
140
141
    /**
142
     * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicGet
143
     */
144
    public function testBodyStructure() : void
145
    {
146
        $magicGet = new MagicGet(
147
            new ReflectionClass(BaseClass::class),
148
            $this->initializer,
149
            $this->initMethod,
150
            $this->publicProperties,
151
            $this->protectedProperties,
152
            $this->privateProperties,
153
            $this->initializationTracker
154
        );
155
156
        self::assertSame('__get', $magicGet->getName());
157
        self::assertCount(1, $magicGet->getParameters());
158
159
        self::assertStringMatchesFormat($this->expectedCode, $magicGet->getBody());
160
    }
161
162
    /**
163
     * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicGet
164
     */
165
    public function testBodyStructureWithOverriddenMagicGet() : void
166
    {
167
        $magicGet = new MagicGet(
168
            new ReflectionClass(ClassWithMagicMethods::class),
169
            $this->initializer,
170
            $this->initMethod,
171
            $this->publicProperties,
172
            $this->protectedProperties,
173
            $this->privateProperties,
174
            $this->initializationTracker
175
        );
176
177
        self::assertSame('__get', $magicGet->getName());
178
        self::assertCount(1, $magicGet->getParameters());
179
180
        self::assertStringMatchesFormat($this->expectedCode, $magicGet->getBody());
181
        self::assertStringMatchesFormat('%Areturn parent::__get($name);', $magicGet->getBody());
182
    }
183
}
184