Completed
Pull Request — master (#266)
by Marco
04:32
created

testCanCreateAndRegisterCallbackWithVariadicNotation()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 33
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 2 Features 0
Metric Value
dl 0
loc 33
rs 8.8571
c 3
b 2
f 0
cc 2
eloc 17
nc 2
nop 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A AccessInterceptorValueHolderFunctionalTest::testWillForwardVariadicArguments() 0 22 1
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license.
17
 */
18
19
namespace ProxyManagerTest\Functional;
20
21
use PHPUnit_Framework_TestCase;
22
use ProxyManager\Factory\AccessInterceptorValueHolderFactory;
23
use ProxyManager\Generator\ClassGenerator;
24
use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
25
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
26
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolderGenerator;
27
use ProxyManagerTestAsset\BaseClass;
28
use ProxyManagerTestAsset\BaseInterface;
29
use ProxyManagerTestAsset\ClassWithCounterConstructor;
30
use ProxyManagerTestAsset\ClassWithDynamicArgumentsMethod;
31
use ProxyManagerTestAsset\ClassWithMethodWithByRefVariadicFunction;
32
use ProxyManagerTestAsset\ClassWithMethodWithVariadicFunction;
33
use ProxyManagerTestAsset\ClassWithPublicArrayProperty;
34
use ProxyManagerTestAsset\ClassWithPublicProperties;
35
use ProxyManagerTestAsset\ClassWithSelfHint;
36
use ReflectionClass;
37
use stdClass;
38
39
/**
40
 * Tests for {@see \ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator} produced objects
41
 *
42
 * @author Marco Pivetta <[email protected]>
43
 * @license MIT
44
 *
45
 * @group Functional
46
 * @coversNothing
47
 */
48
class AccessInterceptorValueHolderFunctionalTest extends PHPUnit_Framework_TestCase
49
{
50
    /**
51
     * @dataProvider getProxyMethods
52
     *
53
     * @param string  $className
54
     * @param object  $instance
55
     * @param string  $method
56
     * @param mixed[] $params
57
     * @param mixed   $expectedValue
58
     */
59
    public function testMethodCalls($className, $instance, $method, $params, $expectedValue)
60
    {
61
        $proxyName = $this->generateProxy($className);
62
63
        /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */
64
        $proxy     = $proxyName::staticProxyConstructor($instance);
65
66
        $this->assertSame($instance, $proxy->getWrappedValueHolderValue());
67
        $this->assertSame($expectedValue, call_user_func_array([$proxy, $method], $params));
68
69
        /* @var $listener callable|\PHPUnit_Framework_MockObject_MockObject */
70
        $listener = $this->getMock(stdClass::class, ['__invoke']);
71
        $listener
72
            ->expects($this->once())
73
            ->method('__invoke')
74
            ->with($proxy, $instance, $method, $params, false);
75
76
        $proxy->setMethodPrefixInterceptor(
1 ignored issue
show
Bug introduced by
The method setMethodPrefixInterceptor does only exist in ProxyManager\Proxy\AccessInterceptorInterface, but not in ProxyManager\Proxy\ValueHolderInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
77
            $method,
78
            function ($proxy, $instance, $method, $params, & $returnEarly) use ($listener) {
79
                $listener($proxy, $instance, $method, $params, $returnEarly);
80
            }
81
        );
82
83
        $this->assertSame($expectedValue, call_user_func_array([$proxy, $method], $params));
84
85
        $random = uniqid();
86
87
        $proxy->setMethodPrefixInterceptor(
1 ignored issue
show
Bug introduced by
The method setMethodPrefixInterceptor does only exist in ProxyManager\Proxy\AccessInterceptorInterface, but not in ProxyManager\Proxy\ValueHolderInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
88
            $method,
89
            function ($proxy, $instance, $method, $params, & $returnEarly) use ($random) {
90
                $returnEarly = true;
91
92
                return $random;
93
            }
94
        );
95
96
        $this->assertSame($random, call_user_func_array([$proxy, $method], $params));
97
    }
98
99
    /**
100
     * @dataProvider getProxyMethods
101
     *
102
     * @param string  $className
103
     * @param object  $instance
104
     * @param string  $method
105
     * @param mixed[] $params
106
     * @param mixed   $expectedValue
107
     */
108
    public function testMethodCallsWithSuffixListener($className, $instance, $method, $params, $expectedValue)
109
    {
110
        $proxyName = $this->generateProxy($className);
111
112
        /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */
113
        $proxy    = $proxyName::staticProxyConstructor($instance);
114
        /* @var $listener callable|\PHPUnit_Framework_MockObject_MockObject */
115
        $listener = $this->getMock(stdClass::class, ['__invoke']);
116
        $listener
117
            ->expects($this->once())
118
            ->method('__invoke')
119
            ->with($proxy, $instance, $method, $params, $expectedValue, false);
120
121
        $proxy->setMethodSuffixInterceptor(
1 ignored issue
show
Bug introduced by
The method setMethodSuffixInterceptor does only exist in ProxyManager\Proxy\AccessInterceptorInterface, but not in ProxyManager\Proxy\ValueHolderInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
122
            $method,
123
            function ($proxy, $instance, $method, $params, $returnValue, & $returnEarly) use ($listener) {
124
                $listener($proxy, $instance, $method, $params, $returnValue, $returnEarly);
125
            }
126
        );
127
128
        $this->assertSame($expectedValue, call_user_func_array([$proxy, $method], $params));
129
130
        $random = uniqid();
131
132
        $proxy->setMethodSuffixInterceptor(
1 ignored issue
show
Bug introduced by
The method setMethodSuffixInterceptor does only exist in ProxyManager\Proxy\AccessInterceptorInterface, but not in ProxyManager\Proxy\ValueHolderInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
133
            $method,
134
            function ($proxy, $instance, $method, $params, $returnValue, & $returnEarly) use ($random) {
135
                $returnEarly = true;
136
137
                return $random;
138
            }
139
        );
140
141
        $this->assertSame($random, call_user_func_array([$proxy, $method], $params));
142
    }
143
144
    /**
145
     * @dataProvider getProxyMethods
146
     *
147
     * @param string  $className
148
     * @param object  $instance
149
     * @param string  $method
150
     * @param mixed[] $params
151
     * @param mixed   $expectedValue
152
     */
153
    public function testMethodCallsAfterUnSerialization($className, $instance, $method, $params, $expectedValue)
154
    {
155
        $proxyName = $this->generateProxy($className);
156
        /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */
157
        $proxy     = unserialize(serialize($proxyName::staticProxyConstructor($instance)));
158
159
        $this->assertSame($expectedValue, call_user_func_array([$proxy, $method], $params));
160
        $this->assertEquals($instance, $proxy->getWrappedValueHolderValue());
1 ignored issue
show
Bug introduced by
The method getWrappedValueHolderValue does only exist in ProxyManager\Proxy\ValueHolderInterface, but not in ProxyManager\Proxy\AccessInterceptorInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
161
    }
162
163
    /**
164
     * @dataProvider getProxyMethods
165
     *
166
     * @param string  $className
167
     * @param object  $instance
168
     * @param string  $method
169
     * @param mixed[] $params
170
     * @param mixed   $expectedValue
171
     */
172
    public function testMethodCallsAfterCloning($className, $instance, $method, $params, $expectedValue)
173
    {
174
        $proxyName = $this->generateProxy($className);
175
176
        /* @var $proxy \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface */
177
        $proxy     = $proxyName::staticProxyConstructor($instance);
178
        $cloned    = clone $proxy;
179
180
        $this->assertNotSame($proxy->getWrappedValueHolderValue(), $cloned->getWrappedValueHolderValue());
181
        $this->assertSame($expectedValue, call_user_func_array([$cloned, $method], $params));
182
        $this->assertEquals($instance, $cloned->getWrappedValueHolderValue());
183
    }
184
185
    /**
186
     * @dataProvider getPropertyAccessProxies
187
     *
188
     * @param object                                                                                  $instance
189
     * @param \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface $proxy
190
     * @param string                                                                                  $publicProperty
191
     * @param mixed                                                                                   $propertyValue
192
     */
193
    public function testPropertyReadAccess($instance, $proxy, $publicProperty, $propertyValue)
194
    {
195
        $this->assertSame($propertyValue, $proxy->$publicProperty);
196
        $this->assertEquals($instance, $proxy->getWrappedValueHolderValue());
1 ignored issue
show
Bug introduced by
The method getWrappedValueHolderValue does only exist in ProxyManager\Proxy\ValueHolderInterface, but not in ProxyManager\Proxy\AccessInterceptorInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
197
    }
198
199
    /**
200
     * @dataProvider getPropertyAccessProxies
201
     *
202
     * @param object                                                                                  $instance
203
     * @param \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface $proxy
204
     * @param string                                                                                  $publicProperty
205
     */
206
    public function testPropertyWriteAccess($instance, $proxy, $publicProperty)
207
    {
208
        $newValue               = uniqid();
209
        $proxy->$publicProperty = $newValue;
210
211
        $this->assertSame($newValue, $proxy->$publicProperty);
212
        $this->assertSame($newValue, $proxy->getWrappedValueHolderValue()->$publicProperty);
213
    }
214
215
    /**
216
     * @dataProvider getPropertyAccessProxies
217
     *
218
     * @param object                                                                                  $instance
219
     * @param \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface $proxy
220
     * @param string                                                                                  $publicProperty
221
     */
222
    public function testPropertyExistence($instance, $proxy, $publicProperty)
223
    {
224
        $this->assertSame(isset($instance->$publicProperty), isset($proxy->$publicProperty));
225
        $this->assertEquals($instance, $proxy->getWrappedValueHolderValue());
1 ignored issue
show
Bug introduced by
The method getWrappedValueHolderValue does only exist in ProxyManager\Proxy\ValueHolderInterface, but not in ProxyManager\Proxy\AccessInterceptorInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
226
227
        $proxy->getWrappedValueHolderValue()->$publicProperty = null;
228
        $this->assertFalse(isset($proxy->$publicProperty));
229
    }
230
231
    /**
232
     * @dataProvider getPropertyAccessProxies
233
     *
234
     * @param object                                                                                  $instance
235
     * @param \ProxyManager\Proxy\AccessInterceptorInterface|\ProxyManager\Proxy\ValueHolderInterface $proxy
236
     * @param string                                                                                  $publicProperty
237
     */
238
    public function testPropertyUnset($instance, $proxy, $publicProperty)
239
    {
240
        $instance = $proxy->getWrappedValueHolderValue() ? $proxy->getWrappedValueHolderValue() : $instance;
241
        unset($proxy->$publicProperty);
242
243
        $this->assertFalse(isset($instance->$publicProperty));
244
        $this->assertFalse(isset($proxy->$publicProperty));
245
    }
246
247
    /**
248
     * Verifies that accessing a public property containing an array behaves like in a normal context
249
     */
250
    public function testCanWriteToArrayKeysInPublicProperty()
251
    {
252
        $instance    = new ClassWithPublicArrayProperty();
253
        $className   = get_class($instance);
254
        $proxyName   = $this->generateProxy($className);
255
        /* @var $proxy ClassWithPublicArrayProperty */
256
        $proxy       = $proxyName::staticProxyConstructor($instance);
257
258
        $proxy->arrayProperty['foo'] = 'bar';
259
260
        $this->assertSame('bar', $proxy->arrayProperty['foo']);
261
262
        $proxy->arrayProperty = ['tab' => 'taz'];
263
264
        $this->assertSame(['tab' => 'taz'], $proxy->arrayProperty);
265
    }
266
267
    /**
268
     * Verifies that public properties retrieved via `__get` don't get modified in the object state
269
     */
270
    public function testWillNotModifyRetrievedPublicProperties()
271
    {
272
        $instance    = new ClassWithPublicProperties();
273
        $className   = get_class($instance);
274
        $proxyName   = $this->generateProxy($className);
275
        /* @var $proxy ClassWithPublicProperties */
276
        $proxy       = $proxyName::staticProxyConstructor($instance);
277
        $variable    = $proxy->property0;
278
279
        $this->assertSame('property0', $variable);
280
281
        $variable = 'foo';
282
283
        $this->assertSame('property0', $proxy->property0);
284
        $this->assertSame('foo', $variable);
285
    }
286
287
    /**
288
     * Verifies that public properties references retrieved via `__get` modify in the object state
289
     */
290
    public function testWillModifyByRefRetrievedPublicProperties()
291
    {
292
        $instance    = new ClassWithPublicProperties();
293
        $className   = get_class($instance);
294
        $proxyName   = $this->generateProxy($className);
295
        /* @var $proxy ClassWithPublicProperties */
296
        $proxy       = $proxyName::staticProxyConstructor($instance);
297
        $variable    = & $proxy->property0;
298
299
        $this->assertSame('property0', $variable);
300
301
        $variable = 'foo';
302
303
        $this->assertSame('foo', $proxy->property0);
304
        $this->assertSame('foo', $variable);
305
    }
306
307
    /**
308
     * @group 115
309
     * @group 175
310
     */
311
    public function testWillBehaveLikeObjectWithNormalConstructor()
312
    {
313
        $instance = new ClassWithCounterConstructor(10);
314
315
        $this->assertSame(10, $instance->amount, 'Verifying that test asset works as expected');
316
        $this->assertSame(10, $instance->getAmount(), 'Verifying that test asset works as expected');
317
        $instance->__construct(3);
318
        $this->assertSame(13, $instance->amount, 'Verifying that test asset works as expected');
319
        $this->assertSame(13, $instance->getAmount(), 'Verifying that test asset works as expected');
320
321
        $proxyName = $this->generateProxy(get_class($instance));
322
323
        /* @var $proxy ClassWithCounterConstructor */
324
        $proxy = new $proxyName(15);
325
326
        $this->assertSame(15, $proxy->amount, 'Verifying that the proxy constructor works as expected');
327
        $this->assertSame(15, $proxy->getAmount(), 'Verifying that the proxy constructor works as expected');
328
        $proxy->__construct(5);
329
        $this->assertSame(20, $proxy->amount, 'Verifying that the proxy constructor works as expected');
330
        $this->assertSame(20, $proxy->getAmount(), 'Verifying that the proxy constructor works as expected');
331
    }
332
333
    public function testWillForwardVariadicArguments()
334
    {
335
        $factory       = new AccessInterceptorValueHolderFactory();
336
        $targetObject  = new ClassWithMethodWithVariadicFunction();
337
338
        /* @var $object ClassWithMethodWithVariadicFunction */
339
        $object = $factory->createProxy(
340
            $targetObject,
341
            [
342
                function ($paratemers) {
0 ignored issues
show
Unused Code introduced by
The parameter $paratemers is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
343
                    return 'Foo Baz';
344
                },
345
            ]
346
        );
347
348
        $this->assertNull($object->bar);
349
        $this->assertNull($object->baz);
350
351
        $object->foo('Ocramius', 'Malukenho', 'Danizord');
352
        $this->assertSame('Ocramius', $object->bar);
353
        $this->assertSame(['Malukenho', 'Danizord'], $object->baz);
354
    }
355
356
    /**
357
     * @group 265
358
     */
359
    public function testWillForwardVariadicByRefArguments()
360
    {
361
        $factory       = new AccessInterceptorValueHolderFactory();
362
        $targetObject  = new ClassWithMethodWithByRefVariadicFunction();
363
364
        /* @var $object ClassWithMethodWithByRefVariadicFunction */
365
        $object = $factory->createProxy(
366
            $targetObject,
367
            [
368
                function ($paratemers) {
0 ignored issues
show
Unused Code introduced by
The parameter $paratemers is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
369
                    return 'Foo Baz';
370
                },
371
            ]
372
        );
373
374
        $arguments = ['Ocramius', 'Malukenho', 'Danizord'];
375
376
        self::assertSame(
377
            ['Ocramius', 'changed', 'Danizord'],
378
            (new ClassWithMethodWithByRefVariadicFunction())->tuz(...$arguments),
379
            'Verifying that the implementation of the test asset is correct before proceeding'
380
        );
381
        self::assertSame(['Ocramius', 'changed', 'Danizord'], $object->tuz(...$arguments));
382
        self::assertSame(['Ocramius', 'changed', 'Danizord'], $arguments, 'By-ref arguments were changed');
383
    }
384
385
    /**
386
     * This test documents a known limitation: `func_get_args()` (and similars) don't work in proxied APIs.
387
     * If you manage to make this test pass, then please do send a patch
388
     *
389
     * @group 265
390
     */
391
    public function testWillNotForwardDynamicArguments()
392
    {
393
        $proxyName = $this->generateProxy(ClassWithDynamicArgumentsMethod::class);
394
395
        /* @var $object ClassWithDynamicArgumentsMethod */
396
        $object = $proxyName::staticProxyConstructor(new ClassWithDynamicArgumentsMethod());
397
398
        self::assertSame(['a', 'b'], (new ClassWithDynamicArgumentsMethod())->dynamicArgumentsMethod('a', 'b'));
399
400
        $this->setExpectedException(\PHPUnit_Framework_ExpectationFailedException::class);
401
402
        self::assertSame(['a', 'b'], $object->dynamicArgumentsMethod('a', 'b'));
403
    }
404
405
    /**
406
     * Generates a proxy for the given class name, and retrieves its class name
407
     *
408
     * @param string $parentClassName
409
     *
410
     * @return string
411
     */
412
    private function generateProxy($parentClassName)
413
    {
414
        $generatedClassName = __NAMESPACE__ . '\\' . UniqueIdentifierGenerator::getIdentifier('Foo');
415
        $generator          = new AccessInterceptorValueHolderGenerator();
416
        $generatedClass     = new ClassGenerator($generatedClassName);
417
        $strategy           = new EvaluatingGeneratorStrategy();
418
419
        $generator->generate(new ReflectionClass($parentClassName), $generatedClass);
420
        $strategy->generate($generatedClass);
421
422
        return $generatedClassName;
423
    }
424
425
    /**
426
     * Generates a list of object | invoked method | parameters | expected result
427
     *
428
     * @return array
429
     */
430
    public function getProxyMethods()
431
    {
432
        $selfHintParam = new ClassWithSelfHint();
433
434
        return [
435
            [
436
                BaseClass::class,
437
                new BaseClass(),
438
                'publicMethod',
439
                [],
440
                'publicMethodDefault'
441
            ],
442
            [
443
                BaseClass::class,
444
                new BaseClass(),
445
                'publicTypeHintedMethod',
446
                ['param' => new stdClass()],
447
                'publicTypeHintedMethodDefault'
448
            ],
449
            [
450
                BaseClass::class,
451
                new BaseClass(),
452
                'publicByReferenceMethod',
453
                [],
454
                'publicByReferenceMethodDefault'
455
            ],
456
            [
457
                BaseInterface::class,
458
                new BaseClass(),
459
                'publicMethod',
460
                [],
461
                'publicMethodDefault'
462
            ],
463
            [
464
                ClassWithSelfHint::class,
465
                new ClassWithSelfHint(),
466
                'selfHintMethod',
467
                ['parameter' => $selfHintParam],
468
                $selfHintParam
469
            ],
470
        ];
471
    }
472
473
    /**
474
     * Generates proxies and instances with a public property to feed to the property accessor methods
475
     *
476
     * @return array
477
     */
478
    public function getPropertyAccessProxies()
479
    {
480
        $instance1  = new BaseClass();
481
        $proxyName1 = $this->generateProxy(get_class($instance1));
482
        $instance2  = new BaseClass();
483
        $proxyName2 = $this->generateProxy(get_class($instance2));
484
485
        return [
486
            [
487
                $instance1,
488
                $proxyName1::staticProxyConstructor($instance1),
489
                'publicProperty',
490
                'publicPropertyDefault',
491
            ],
492
            [
493
                $instance2,
494
                unserialize(serialize($proxyName2::staticProxyConstructor($instance2))),
495
                'publicProperty',
496
                'publicPropertyDefault',
497
            ],
498
        ];
499
    }
500
}
501