Completed
Push — master ( e0017c...6b1304 )
by Tom
14s queued 11s
created

Form/Element/ObjectRadioTest.php (3 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
declare(strict_types=1);
4
5
namespace DoctrineModuleTest\Form\Element;
6
7
use DoctrineModule\Form\Element\ObjectRadio;
8
use function get_class;
9
10
/**
11
 * Tests for the ObjectRadio element
12
 *
13
 * @covers \DoctrineModule\Form\Element\ObjectRadio
14
 */
15
class ObjectRadioTest extends ProxyAwareElementTestCase
16
{
17
    /** @var ObjectRadio */
18
    protected $element;
19
20
    /**
21
     * {@inheritDoc}.
22
     */
23
    protected function setUp() : void
24
    {
25
        parent::setUp();
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class DoctrineModuleTest\Form\...oxyAwareElementTestCase as the method setUp() does only exist in the following sub-classes of DoctrineModuleTest\Form\...oxyAwareElementTestCase: DoctrineModuleTest\Form\...ObjectMultiCheckboxTest, DoctrineModuleTest\Form\Element\ObjectRadioTest, DoctrineModuleTest\Form\Element\ObjectSelectTest. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
26
        $this->element = new ObjectRadio();
27
    }
28
29
    public function testGetValueOptionsDoesntCauseInfiniteLoopIfProxyReturnsEmptyArrayAndValidatorIsInitialized() : void
30
    {
31
        $element = $this->createPartialMock(get_class($this->element), ['setValueOptions']);
32
33
        $options = [];
34
35
        $proxy = $this->createMock('DoctrineModule\Form\Element\Proxy');
36
        $proxy->expects($this->exactly(2))
37
            ->method('getValueOptions')
38
            ->will($this->returnValue($options));
39
40
        $element->expects($this->never())
41
            ->method('setValueOptions');
42
43
        $this->setProxyViaReflection($proxy, $element);
0 ignored issues
show
$proxy is of type null, but the function expects a object<PHPUnit\Framework\MockObject\MockObject>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
44
        $element->getInputSpecification();
45
        $this->assertEquals($options, $element->getValueOptions());
46
    }
47
48
    public function testGetValueOptionsDoesntInvokeProxyIfOptionsNotEmpty() : void
49
    {
50
        $options = ['foo' => 'bar'];
51
52
        $proxy = $this->createMock('DoctrineModule\Form\Element\Proxy');
53
        $proxy->expects($this->once())
54
            ->method('getValueOptions')
55
            ->will($this->returnValue($options));
56
57
        $this->setProxyViaReflection($proxy);
0 ignored issues
show
$proxy is of type null, but the function expects a object<PHPUnit\Framework\MockObject\MockObject>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
58
59
        $this->assertEquals($options, $this->element->getValueOptions());
60
        $this->assertEquals($options, $this->element->getValueOptions());
61
    }
62
63
    public function testOptionsCanBeSetSingle() : void
64
    {
65
        $proxy = $this->createMock('DoctrineModule\Form\Element\Proxy');
66
        $proxy->expects($this->once())->method('setOptions')->with(['is_method' => true]);
67
68
        $this->setProxyViaReflection($proxy);
69
70
        $this->element->setOption('is_method', true);
71
    }
72
}
73