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

MagicSetTest   A

Complexity

Total Complexity 3

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

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