Completed
Push — develop ( 8eb671...133594 )
by Mike
19:30 queued 09:24
created

Builder/Reflector/MethodAssemblerTest.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * This file is part of phpDocumentor.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @copyright 2010-2018 Mike van Riel<[email protected]>
9
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
10
 * @link      http://phpdoc.org
11
 */
12
13
namespace phpDocumentor\Descriptor\Builder\Reflector;
14
15
use Mockery as m;
16
use phpDocumentor\Descriptor\ArgumentDescriptor;
17
use phpDocumentor\Descriptor\ProjectDescriptorBuilder;
18
use phpDocumentor\Reflection\DocBlock;
19
use phpDocumentor\Reflection\Fqsen;
20
use phpDocumentor\Reflection\Php\Argument;
21
use phpDocumentor\Reflection\Php\Method;
22
use phpDocumentor\Reflection\Php\Visibility;
23
use phpDocumentor\Reflection\Types\String_;
24
25
class MethodAssemblerTest extends \Mockery\Adapter\Phpunit\MockeryTestCase
26
{
27
    /** @var MethodAssembler $fixture */
28
    protected $fixture;
29
30
    /** @var ArgumentAssembler|m\MockInterface */
31
    protected $argumentAssemblerMock;
32
33
    /** @var ProjectDescriptorBuilder|m\MockInterface */
34
    protected $builderMock;
35
36
    /**
37
     * Creates a new fixture to test with.
38
     */
39
    protected function setUp()
40
    {
41
        $this->builderMock = m::mock('phpDocumentor\Descriptor\ProjectDescriptorBuilder');
42
        $this->builderMock->shouldReceive('buildDescriptor')->andReturn(null);
43
44
        $this->argumentAssemblerMock = m::mock('phpDocumentor\Descriptor\Builder\Reflector\ArgumentAssembler');
45
        $this->argumentAssemblerMock->shouldReceive('getBuilder')->once()->andReturn(null);
46
        $this->argumentAssemblerMock->shouldReceive('setBuilder')->once();
47
48
        $this->fixture = new MethodAssembler($this->argumentAssemblerMock);
49
        $this->fixture->setBuilder($this->builderMock);
50
    }
51
52
    /**
53
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::__construct
54
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::create
55
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::mapReflectorToDescriptor
56
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::addArguments
57
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::addArgument
58
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::addVariadicArgument
59
     */
60
    public function testCreateMethodDescriptorFromReflector()
61
    {
62
        // Arrange
63
        $namespace = 'Namespace';
64
        $methodName = 'goodbyeWorld';
65
        $argumentName = 'variableName';
66
67
        $argument = $this->givenAnArgumentWithName($argumentName);
68
        $methodReflectorMock = $this->givenAMethodReflector(
69
            $namespace,
70
            $methodName,
71
            $argument,
72
            $this->givenADocBlockObject(true)
73
        );
74
75
        $argumentDescriptor = new ArgumentDescriptor();
76
        $argumentDescriptor->setName($argumentName);
77
78
        $this->argumentAssemblerMock->shouldReceive('create')->andReturn($argumentDescriptor);
79
80
        // Act
81
        $descriptor = $this->fixture->create($methodReflectorMock);
82
83
        // Assert
84
        $expectedFqsen = '\\' . $namespace . '::' . $methodName . '()';
85
        $this->assertSame($expectedFqsen, (string) $descriptor->getFullyQualifiedStructuralElementName());
86
        $this->assertSame($methodName, $descriptor->getName());
87
        $this->assertSame('\\' . $namespace, $descriptor->getNamespace());
88
        $this->assertSame('protected', (string) $descriptor->getVisibility());
89
        $this->assertFalse($descriptor->isFinal());
90
        $this->assertFalse($descriptor->isAbstract());
91
        $this->assertFalse($descriptor->isStatic());
92
93
        $argument = $descriptor->getArguments()->get($argumentName);
94
        $this->assertSame($argument->getName(), $argumentDescriptor->getName());
95
    }
96
97
    /**
98
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::__construct
99
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::create
100
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::mapReflectorToDescriptor
101
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::addArguments
102
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::addArgument
103
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::addVariadicArgument
104
     */
105
    public function testCreateMethodDescriptorFromReflectorWhenDocblockIsAbsent()
106
    {
107
        // Arrange
108
        $namespace = 'Namespace';
109
        $methodName = 'goodbyeWorld';
110
        $argumentName = 'waveHand';
111
112
        $argumentDescriptorMock = $this->givenAnArgumentWithName($argumentName);
113
        $methodReflectorMock = $this->givenAMethodReflector(
114
            $namespace,
115
            $methodName,
116
            $argumentDescriptorMock
117
        );
118
119
        $argumentDescriptor = new ArgumentDescriptor();
120
        $argumentDescriptor->setName($argumentName);
121
122
        $this->argumentAssemblerMock->shouldReceive('create')->andReturn($argumentDescriptor);
0 ignored issues
show
The method shouldReceive does only exist in Mockery\MockInterface, but not in phpDocumentor\Descriptor...ector\ArgumentAssembler.

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...
123
124
        // Act
125
        $descriptor = $this->fixture->create($methodReflectorMock);
126
127
        // Assert
128
        $argument = $descriptor->getArguments()->get($argumentName);
129
        $this->assertSame($argumentDescriptor, $argument);
130
    }
131
132
    /**
133
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::__construct
134
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::create
135
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::mapReflectorToDescriptor
136
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::addArguments
137
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::addArgument
138
     * @covers \phpDocumentor\Descriptor\Builder\Reflector\MethodAssembler::addVariadicArgument
139
     */
140
    public function testCreateMethodDescriptorFromReflectorWhenParamTagsAreAbsent()
141
    {
142
        // Arrange
143
        $namespace = 'Namespace';
144
        $methodName = 'goodbyeWorld';
145
        $argumentName = 'waveHand';
146
147
        $argumentDescriptorMock = $this->givenAnArgumentWithName($argumentName);
148
        $methodReflectorMock = $this->givenAMethodReflector(
149
            $namespace,
150
            $methodName,
151
            $argumentDescriptorMock,
152
            $this->givenADocBlockObject(false)
153
        );
154
155
        $argumentDescriptor = new ArgumentDescriptor();
156
        $argumentDescriptor->setName($argumentName);
157
158
        $this->argumentAssemblerMock->shouldReceive('create')->andReturn($argumentDescriptor);
0 ignored issues
show
The method shouldReceive does only exist in Mockery\MockInterface, but not in phpDocumentor\Descriptor...ector\ArgumentAssembler.

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...
159
160
        // Act
161
        $descriptor = $this->fixture->create($methodReflectorMock);
162
163
        // Assert
164
        $argument = $descriptor->getArguments()->get($argumentName);
165
        $this->assertSame($argumentDescriptor, $argument);
166
    }
167
168
    /**
169
     * Creates a sample method reflector for the tests with the given data.
170
     */
171
    protected function givenAMethodReflector(
172
        string $namespace,
173
        string $methodName,
174
        Argument $argumentMock,
175
        DocBlock $docBlockMock = null
176
    ) {
177
        $method = new Method(
178
            new Fqsen('\\' . $namespace . '::' . $methodName . '()'),
179
            new Visibility(Visibility::PROTECTED_),
180
            $docBlockMock
181
        );
182
183
        $method->addArgument($argumentMock);
184
185
        return $method;
186
    }
187
188
    /**
189
     * Generates a DocBlock object with applicable defaults for these tests.
190
     */
191
    protected function givenADocBlockObject($withTags): DocBlock
192
    {
193
        $docBlockDescription = new DocBlock\Description('This is an example description');
194
195
        $tags = [];
196
197
        if ($withTags) {
198
            $tags[] = new DocBlock\Tags\Param(
199
                'variableName',
200
                new String_(),
201
                true,
202
                new DocBlock\Description('foo')
203
            );
204
        }
205
206
        return new DocBlock('This is a example description', $docBlockDescription, $tags);
207
    }
208
209
    /**
210
     * Prepares a mock Argument with the given name.
211
     */
212
    protected function givenAnArgumentWithName(string $argumentName): Argument
213
    {
214
        return new Argument($argumentName);
215
    }
216
}
217