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

MagicUnsetTest   A

Complexity

Total Complexity 3

Size/Duplication

Total Lines 151
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 3
lcom 1
cbo 1
dl 0
loc 151
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\MagicUnset;
10
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\PrivatePropertiesMap;
11
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\ProtectedPropertiesMap;
12
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
13
use ProxyManagerTestAsset\ClassWithMagicMethods;
14
use ProxyManagerTestAsset\ProxyGenerator\LazyLoading\MethodGenerator\ClassWithTwoPublicProperties;
15
use ReflectionClass;
16
use Zend\Code\Generator\MethodGenerator;
17
use Zend\Code\Generator\PropertyGenerator;
18
19
/**
20
 * Tests for {@see \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicUnset}
21
 *
22
 * @group Coverage
23
 */
24
final class MagicUnsetTest extends TestCase
25
{
26
    /** @var PropertyGenerator&MockObject */
27
    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...
28
29
    /** @var MethodGenerator&MockObject */
30
    private MethodGenerator $initMethod;
31
32
    /** @var PublicPropertiesMap&MockObject */
33
    private PublicPropertiesMap $publicProperties;
34
35
    /** @var ProtectedPropertiesMap&MockObject */
36
    private ProtectedPropertiesMap $protectedProperties;
37
38
    /** @var PrivatePropertiesMap&MockObject */
39
    private PrivatePropertiesMap $privateProperties;
40
41
    private string $expectedCode = <<<'PHP'
42
$this->foo && $this->baz('__unset', array('name' => $name));
43
44
if (isset(self::$bar[$name])) {
45
    unset($this->$name);
46
47
    return;
48
}
49
50
if (isset(self::$baz[$name])) {
51
    // check protected property access via compatible class
52
    $callers      = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
53
    $caller       = isset($callers[1]) ? $callers[1] : [];
54
    $object       = isset($caller['object']) ? $caller['object'] : '';
55
    $expectedType = self::$baz[$name];
56
57
    if ($object instanceof $expectedType) {
58
        unset($this->$name);
59
60
        return;
61
    }
62
63
    $class = isset($caller['class']) ? $caller['class'] : '';
64
65
    if ($class === $expectedType || is_subclass_of($class, $expectedType) || $class === 'ReflectionProperty') {
66
        unset($this->$name);
67
68
        return;
69
    }
70
} elseif (isset(self::$tab[$name])) {
71
    // check private property access via same class
72
    $callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
73
    $caller  = isset($callers[1]) ? $callers[1] : [];
74
    $class   = isset($caller['class']) ? $caller['class'] : '';
75
76
    static $accessorCache = [];
77
78
    if (isset(self::$tab[$name][$class])) {
79
        $cacheKey = $class . '#' . $name;
80
        $accessor = isset($accessorCache[$cacheKey])
81
            ? $accessorCache[$cacheKey]
82
            : $accessorCache[$cacheKey] = \Closure::bind(function ($instance) use ($name) {
83
                unset($instance->$name);
84
            }, null, $class);
85
86
        return $accessor($this);
87
    }
88
89
    if ('ReflectionProperty' === $class) {
90
        $tmpClass = key(self::$tab[$name]);
91
        $cacheKey = $tmpClass . '#' . $name;
92
        $accessor = isset($accessorCache[$cacheKey])
93
            ? $accessorCache[$cacheKey]
94
            : $accessorCache[$cacheKey] = \Closure::bind(function ($instance) use ($name) {
95
                unset($instance->$name);
96
            }, null, $tmpClass);
97
98
        return $accessor($this);
99
    }
100
}
101
%A
102
PHP;
103
104
    /**
105
     * {@inheritDoc}
106
     */
107
    protected function setUp() : void
108
    {
109
        $this->initializer         = $this->createMock(PropertyGenerator::class);
110
        $this->initMethod          = $this->createMock(MethodGenerator::class);
111
        $this->publicProperties    = $this
112
            ->getMockBuilder(PublicPropertiesMap::class)
113
            ->disableOriginalConstructor()
114
            ->getMock();
115
        $this->protectedProperties = $this
116
            ->getMockBuilder(ProtectedPropertiesMap::class)
117
            ->disableOriginalConstructor()
118
            ->getMock();
119
        $this->privateProperties   = $this
120
            ->getMockBuilder(PrivatePropertiesMap::class)
121
            ->disableOriginalConstructor()
122
            ->getMock();
123
124
        $this->initializer->method('getName')->willReturn('foo');
125
        $this->initMethod->method('getName')->willReturn('baz');
126
        $this->publicProperties->method('isEmpty')->willReturn(false);
127
        $this->publicProperties->method('getName')->willReturn('bar');
128
        $this->protectedProperties->method('getName')->willReturn('baz');
129
        $this->privateProperties->method('getName')->willReturn('tab');
130
    }
131
132
    /**
133
     * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicUnset::__construct
134
     */
135
    public function testBodyStructure() : void
136
    {
137
        $magicIsset = new MagicUnset(
138
            new ReflectionClass(ClassWithTwoPublicProperties::class),
139
            $this->initializer,
140
            $this->initMethod,
141
            $this->publicProperties,
142
            $this->protectedProperties,
143
            $this->privateProperties
144
        );
145
146
        self::assertSame('__unset', $magicIsset->getName());
147
        self::assertCount(1, $magicIsset->getParameters());
148
        self::assertStringMatchesFormat($this->expectedCode, $magicIsset->getBody());
149
    }
150
151
    /**
152
     * @covers \ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicUnset::__construct
153
     */
154
    public function testBodyStructureWithOverriddenMagicGet() : void
155
    {
156
        $magicIsset = new MagicUnset(
157
            new ReflectionClass(ClassWithMagicMethods::class),
158
            $this->initializer,
159
            $this->initMethod,
160
            $this->publicProperties,
161
            $this->protectedProperties,
162
            $this->privateProperties
163
        );
164
165
        self::assertSame('__unset', $magicIsset->getName());
166
        self::assertCount(1, $magicIsset->getParameters());
167
168
        $body = $magicIsset->getBody();
169
170
        self::assertStringMatchesFormat($this->expectedCode, $body);
171
        self::assertStringMatchesFormat('%Areturn parent::__unset($name);', $body);
172
    }
173
}
174