RegisterMenuPassTest::testProcess()   C
last analyzed

Complexity

Conditions 8
Paths 1

Size

Total Lines 28
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 22
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the Lug package.
5
 *
6
 * (c) Eric GELOEN <[email protected]>
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Lug\Bundle\UiBundle\Tests\DependencyInjection\Compiler;
13
14
use Knp\Menu\ItemInterface;
15
use Lug\Bundle\UiBundle\DependencyInjection\Compiler\RegisterMenuPass;
16
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
17
use Symfony\Component\DependencyInjection\ContainerBuilder;
18
use Symfony\Component\DependencyInjection\Definition;
19
use Symfony\Component\DependencyInjection\Reference;
20
21
/**
22
 * @author GeLo <[email protected]>
23
 */
24
class RegisterMenuPassTest extends \PHPUnit_Framework_TestCase
25
{
26
    /**
27
     * @var RegisterMenuPass
28
     */
29
    private $compiler;
30
31
    /**
32
     * {@inheritdoc}
33
     */
34
    protected function setUp()
35
    {
36
        $this->compiler = new RegisterMenuPass();
37
    }
38
39
    public function testInheritance()
40
    {
41
        $this->assertInstanceOf(CompilerPassInterface::class, $this->compiler);
42
    }
43
44
    public function testProcess()
45
    {
46
        $container = $this->createContainerBuilderMock();
47
        $container
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in Symfony\Component\Depend...ection\ContainerBuilder.

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...
48
            ->expects($this->once())
49
            ->method('findTaggedServiceIds')
50
            ->with($this->identicalTo('lug.menu.builder'))
51
            ->will($this->returnValue([$service = 'my.service' => [['alias' => $alias = 'my.alias']]]));
52
53
        $container
54
            ->expects($this->once())
55
            ->method('setDefinition')
56
            ->with(
57
                $this->identicalTo($service.'.menu'),
58
                $this->callback(function (Definition $definition) use ($service, $alias) {
59
                    return $definition->getClass() === ItemInterface::class
60
                        && $definition->getTag('knp_menu.menu') === [['alias' => $alias]]
61
                        && is_array($factory = $definition->getFactory())
62
                        && isset($factory[0])
63
                        && $factory[0] instanceof Reference
64
                        && (string) $factory[0] === $service
65
                        && isset($factory[1])
66
                        && $factory[1] === 'create';
67
                })
68
            );
69
70
        $this->compiler->process($container);
0 ignored issues
show
Bug introduced by
It seems like $container defined by $this->createContainerBuilderMock() on line 46 can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, Lug\Bundle\UiBundle\Depe...sterMenuPass::process() does only seem to accept object<Symfony\Component...ction\ContainerBuilder>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
71
    }
72
73
    /**
74
     * @expectedException \Lug\Bundle\UiBundle\Exception\TagAttributeNotFoundException
75
     * @expectedExceptionMessage The attribute "alias" could not be found for the tag "lug.menu.builder" on the "my.service" service.
76
     */
77
    public function testProcessWithoutAlias()
78
    {
79
        $container = $this->createContainerBuilderMock();
80
        $container
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in Symfony\Component\Depend...ection\ContainerBuilder.

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...
81
            ->expects($this->once())
82
            ->method('findTaggedServiceIds')
83
            ->with($this->identicalTo('lug.menu.builder'))
84
            ->will($this->returnValue([$service = 'my.service' => [[]]]));
85
86
        $this->compiler->process($container);
0 ignored issues
show
Bug introduced by
It seems like $container defined by $this->createContainerBuilderMock() on line 79 can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, Lug\Bundle\UiBundle\Depe...sterMenuPass::process() does only seem to accept object<Symfony\Component...ction\ContainerBuilder>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
87
    }
88
89
    /**
90
     * @return \PHPUnit_Framework_MockObject_MockObject|ContainerBuilder
91
     */
92
    private function createContainerBuilderMock()
93
    {
94
        return $this->getMockBuilder(ContainerBuilder::class)
95
            ->setMethods(['findTaggedServiceIds', 'setDefinition'])
96
            ->getMock();
97
    }
98
}
99