Completed
Pull Request — master (#25)
by Robbie
03:50 queued 42s
created

ExtensionsCommandTest   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 102
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 7
lcom 1
cbo 4
dl 0
loc 102
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getTestCommand() 0 4 1
A testExecute() 0 13 1
A testConfigure() 0 4 1
A testGetHeaders() 0 4 1
A headerProvider() 0 7 1
A testGetRows() 0 4 1
A rowsProvider() 0 19 1
1
<?php
2
3
namespace SilverLeague\Console\Tests\Command\Object;
4
5
use SilverLeague\Console\Tests\Command\AbstractCommandTest;
6
use Symfony\Component\Console\Tester\CommandTester;
7
8
/**
9
 * @coversDefaultClass \SilverLeague\Console\Command\Object\ExtensionsCommand
10
 * @package silverstripe-console
11
 * @author  Robbie Averill <[email protected]>
12
 */
13
class ExtensionsCommandTest extends AbstractCommandTest
14
{
15
    /**
16
     * {@inheritDoc}
17
     */
18
    public function getTestCommand()
19
    {
20
        return 'object:extensions';
21
    }
22
23
    /**
24
     * Ensure that the Injector's class resolution is returned for a given Object
25
     *
26
     * @covers ::execute
27
     */
28
    public function testExecute()
29
    {
30
        $tester = new CommandTester($this->command);
31
        $tester->execute(
32
            [
33
                'command' => $this->command->getName(),
34
                'object'  => "SilverStripe\Forms\GridField\GridFieldDetailForm"
35
            ]
36
        );
37
38
        $output = $tester->getDisplay();
39
        $this->assertContains("SilverStripe\ORM\Versioning\VersionedGridFieldDetailForm", $output);
40
    }
41
42
    /**
43
     * Ensure that the InputArgument for the object is added
44
     *
45
     * @covers ::configure
46
     */
47
    public function testConfigure()
48
    {
49
        $this->assertTrue($this->command->getDefinition()->hasArgument('object'));
50
    }
51
52
    /**
53
     * Ensure that extra headers are added for CMS pages
54
     *
55
     * @covers ::getHeaders
56
     * @dataProvider headerProvider
57
     *
58
     * @param bool     $isCms
59
     * @param string[] $expected
60
     */
61
    public function testGetHeaders($isCms, $expected)
62
    {
63
        $this->assertSame($expected, $this->command->getHeaders($isCms));
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SilverLeague\Console\Command\SilverStripeCommand as the method getHeaders() does only exist in the following sub-classes of SilverLeague\Console\Command\SilverStripeCommand: SilverLeague\Console\Com...bject\ExtensionsCommand. 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...
64
    }
65
66
    /**
67
     * @return string[]
68
     */
69
    public function headerProvider()
70
    {
71
        return [
72
            [true, ['Class name', 'Added DB fields', 'Updates CMS fields']],
73
            [false, ['Class name', 'Added DB fields']]
74
        ];
75
    }
76
77
    /**
78
     * Ensure that extra headers are added for CMS pages
79
     *
80
     * @covers ::getRows
81
     * @dataProvider rowsProvider
82
     *
83
     * @param bool     $isCms
84
     * @param array    $extensions
85
     * @param string[] $expected
86
     */
87
    public function testGetRows($isCms, $extensions, $expected)
88
    {
89
        $this->assertSame($expected, $this->command->getRows($isCms, $extensions));
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SilverLeague\Console\Command\SilverStripeCommand as the method getRows() does only exist in the following sub-classes of SilverLeague\Console\Command\SilverStripeCommand: SilverLeague\Console\Com...bject\ExtensionsCommand. 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...
90
    }
91
92
    /**
93
     * @return array[]
94
     */
95
    public function rowsProvider()
96
    {
97
        $extensions = [
98
            "SilverStripe\Assets\AssetControlExtension"
99
        ];
100
101
        return [
102
            [
103
                false,
104
                $extensions,
105
                [array_merge($extensions, [0])]
106
            ],
107
            [
108
                true,
109
                $extensions,
110
                [array_merge($extensions, [0, 'Yes'])]
111
            ]
112
        ];
113
    }
114
}
115