Passed
Push — master ( 047d0e...5cefa4 )
by Marco
06:53
created

AbstractDriverTest.php$0 ➔ getSQLState()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
1
<?php
2
3
namespace Doctrine\Tests\DBAL\Driver;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Driver\DriverException;
7
use Doctrine\DBAL\Driver\ExceptionConverterDriver;
8
use Doctrine\DBAL\VersionAwarePlatformDriver;
9
use Doctrine\Tests\DbalTestCase;
10
use Throwable;
11
12
abstract class AbstractDriverTest extends DbalTestCase
13
{
14
    const EXCEPTION_CONNECTION = 'Doctrine\DBAL\Exception\ConnectionException';
15
    const EXCEPTION_CONSTRAINT_VIOLATION = 'Doctrine\DBAL\Exception\ConstraintViolationException';
16
    const EXCEPTION_DATABASE_OBJECT_EXISTS = 'Doctrine\DBAL\Exception\DatabaseObjectExistsException';
17
    const EXCEPTION_DATABASE_OBJECT_NOT_FOUND = 'Doctrine\DBAL\Exception\DatabaseObjectNotFoundException';
18
    const EXCEPTION_DRIVER = 'Doctrine\DBAL\Exception\DriverException';
19
    const EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION = 'Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException';
20
    const EXCEPTION_INVALID_FIELD_NAME = 'Doctrine\DBAL\Exception\InvalidFieldNameException';
21
    const EXCEPTION_NON_UNIQUE_FIELD_NAME = 'Doctrine\DBAL\Exception\NonUniqueFieldNameException';
22
    const EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION = 'Doctrine\DBAL\Exception\NotNullConstraintViolationException';
23
    const EXCEPTION_READ_ONLY = 'Doctrine\DBAL\Exception\ReadOnlyException';
24
    const EXCEPTION_SERVER = 'Doctrine\DBAL\Exception\ServerException';
25
    const EXCEPTION_SYNTAX_ERROR = 'Doctrine\DBAL\Exception\SyntaxErrorException';
26
    const EXCEPTION_TABLE_EXISTS = 'Doctrine\DBAL\Exception\TableExistsException';
27
    const EXCEPTION_TABLE_NOT_FOUND = 'Doctrine\DBAL\Exception\TableNotFoundException';
28
    const EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION = 'Doctrine\DBAL\Exception\UniqueConstraintViolationException';
29
    const EXCEPTION_DEADLOCK = 'Doctrine\DBAL\Exception\DeadlockException';
30
    const EXCEPTION_LOCK_WAIT_TIMEOUT = 'Doctrine\DBAL\Exception\LockWaitTimeoutException';
31
32
    /**
33
     * The driver mock under test.
34
     *
35
     * @var \Doctrine\DBAL\Driver
36
     */
37
    protected $driver;
38
39
    protected function setUp()
40
    {
41
        parent::setUp();
42
43
        $this->driver = $this->createDriver();
44
    }
45
46
    public function testConvertsException()
47
    {
48
        if ( ! $this->driver instanceof ExceptionConverterDriver) {
49
            $this->markTestSkipped('This test is only intended for exception converter drivers.');
50
        }
51
52
        $data = $this->getExceptionConversions();
53
54
        if (empty($data)) {
55
            $this->fail(
56
                sprintf(
57
                    'No test data found for test %s. You have to return test data from %s.',
58
                    get_class($this) . '::' . __FUNCTION__,
59
                    get_class($this) . '::getExceptionConversionData'
60
                )
61
            );
62
        }
63
64
        $driverException = new class extends \Exception implements DriverException
65
        {
66
            public function __construct()
67
            {
68
                parent::__construct('baz');
69
            }
70
71
            /**
72
             * {@inheritDoc}
73
             */
74
            public function getErrorCode()
75
            {
76
                return 'foo';
77
            }
78
79
            /**
80
             * {@inheritDoc}
81
             */
82
            public function getSQLState()
83
            {
84
                return 'bar';
85
            }
86
        };
87
88
        $data[] = array($driverException, self::EXCEPTION_DRIVER);
89
90
        $message = 'DBAL exception message';
91
92
        foreach ($data as $item) {
93
            /** @var $driverException \Doctrine\DBAL\Driver\DriverException */
94
            list($driverException, $convertedExceptionClassName) = $item;
95
96
            $convertedException = $this->driver->convertException($message, $driverException);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\DBAL\Driver as the method convertException() does only exist in the following implementations of said interface: Doctrine\DBAL\Driver\AbstractMySQLDriver, Doctrine\DBAL\Driver\AbstractOracleDriver, Doctrine\DBAL\Driver\AbstractPostgreSQLDriver, Doctrine\DBAL\Driver\AbstractSQLAnywhereDriver, Doctrine\DBAL\Driver\AbstractSQLiteDriver, Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver, Doctrine\DBAL\Driver\Mysqli\Driver, Doctrine\DBAL\Driver\OCI8\Driver, Doctrine\DBAL\Driver\PDOMySql\Driver, Doctrine\DBAL\Driver\PDOOracle\Driver, Doctrine\DBAL\Driver\PDOPgSql\Driver, Doctrine\DBAL\Driver\PDOSqlite\Driver, Doctrine\DBAL\Driver\SQLAnywhere\Driver.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
97
98
            $this->assertSame($convertedExceptionClassName, get_class($convertedException));
99
100
            $this->assertSame($driverException->getErrorCode(), $convertedException->getErrorCode());
101
            $this->assertSame($driverException->getSQLState(), $convertedException->getSQLState());
102
            $this->assertSame($message, $convertedException->getMessage());
103
        }
104
    }
105
106
    public function testCreatesDatabasePlatformForVersion()
107
    {
108
        if ( ! $this->driver instanceof VersionAwarePlatformDriver) {
109
            $this->markTestSkipped('This test is only intended for version aware platform drivers.');
110
        }
111
112
        $data = $this->getDatabasePlatformsForVersions();
113
114
        if (empty($data)) {
115
            $this->fail(
116
                sprintf(
117
                    'No test data found for test %s. You have to return test data from %s.',
118
                    get_class($this) . '::' . __FUNCTION__,
119
                    get_class($this) . '::getDatabasePlatformsForVersions'
120
                )
121
            );
122
        }
123
124
        foreach ($data as $item) {
125
            $this->assertSame($item[1], get_class($this->driver->createDatabasePlatformForVersion($item[0])));
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\DBAL\Driver as the method createDatabasePlatformForVersion() does only exist in the following implementations of said interface: Doctrine\DBAL\Driver\AbstractMySQLDriver, Doctrine\DBAL\Driver\AbstractPostgreSQLDriver, Doctrine\DBAL\Driver\AbstractSQLAnywhereDriver, Doctrine\DBAL\Driver\AbstractSQLServerDriver, Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver, Doctrine\DBAL\Driver\Mysqli\Driver, Doctrine\DBAL\Driver\PDOMySql\Driver, Doctrine\DBAL\Driver\PDOPgSql\Driver, Doctrine\DBAL\Driver\PDOSqlsrv\Driver, Doctrine\DBAL\Driver\SQLAnywhere\Driver, Doctrine\DBAL\Driver\SQLSrv\Driver.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
126
        }
127
    }
128
129
    /**
130
     * @expectedException \Doctrine\DBAL\DBALException
131
     */
132
    public function testThrowsExceptionOnCreatingDatabasePlatformsForInvalidVersion()
133
    {
134
        if ( ! $this->driver instanceof VersionAwarePlatformDriver) {
135
            $this->markTestSkipped('This test is only intended for version aware platform drivers.');
136
        }
137
138
        $this->driver->createDatabasePlatformForVersion('foo');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\DBAL\Driver as the method createDatabasePlatformForVersion() does only exist in the following implementations of said interface: Doctrine\DBAL\Driver\AbstractMySQLDriver, Doctrine\DBAL\Driver\AbstractPostgreSQLDriver, Doctrine\DBAL\Driver\AbstractSQLAnywhereDriver, Doctrine\DBAL\Driver\AbstractSQLServerDriver, Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver, Doctrine\DBAL\Driver\Mysqli\Driver, Doctrine\DBAL\Driver\PDOMySql\Driver, Doctrine\DBAL\Driver\PDOPgSql\Driver, Doctrine\DBAL\Driver\PDOSqlsrv\Driver, Doctrine\DBAL\Driver\SQLAnywhere\Driver, Doctrine\DBAL\Driver\SQLSrv\Driver.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
139
    }
140
141 View Code Duplication
    public function testReturnsDatabaseName()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
142
    {
143
        $params = array(
144
            'user'     => 'foo',
145
            'password' => 'bar',
146
            'dbname'   => 'baz',
147
        );
148
149
        $connection = $this->getConnectionMock();
150
151
        $connection->expects($this->once())
152
            ->method('getParams')
153
            ->will($this->returnValue($params));
154
155
        $this->assertSame($params['dbname'], $this->driver->getDatabase($connection));
156
    }
157
158
    public function testReturnsDatabasePlatform()
159
    {
160
        $this->assertEquals($this->createPlatform(), $this->driver->getDatabasePlatform());
161
    }
162
163
    public function testReturnsSchemaManager()
164
    {
165
        $connection    = $this->getConnectionMock();
166
        $schemaManager = $this->driver->getSchemaManager($connection);
167
168
        $this->assertEquals($this->createSchemaManager($connection), $schemaManager);
169
        $this->assertAttributeSame($connection, '_conn', $schemaManager);
170
    }
171
172
    /**
173
     * Factory method for creating the driver instance under test.
174
     *
175
     * @return \Doctrine\DBAL\Driver
176
     */
177
    abstract protected function createDriver();
178
179
    /**
180
     * Factory method for creating the the platform instance return by the driver under test.
181
     *
182
     * The platform instance returned by this method must be the same as returned by
183
     * the driver's getDatabasePlatform() method.
184
     *
185
     * @return \Doctrine\DBAL\Platforms\AbstractPlatform
186
     */
187
    abstract protected function createPlatform();
188
189
    /**
190
     * Factory method for creating the the schema manager instance return by the driver under test.
191
     *
192
     * The schema manager instance returned by this method must be the same as returned by
193
     * the driver's getSchemaManager() method.
194
     *
195
     * @param Connection $connection The underlying connection to use.
196
     *
197
     * @return \Doctrine\DBAL\Schema\AbstractSchemaManager
198
     */
199
    abstract protected function createSchemaManager(Connection $connection);
200
201
    protected function getConnectionMock()
202
    {
203
        return $this->getMockBuilder('Doctrine\DBAL\Connection')
204
            ->disableOriginalConstructor()
205
            ->getMock();
206
    }
207
208
    protected function getDatabasePlatformsForVersions()
209
    {
210
        return array();
211
    }
212
213
    protected function getExceptionConversionData()
214
    {
215
        return array();
216
    }
217
218
    private function getExceptionConversions()
219
    {
220
        $data = array();
221
222
        foreach ($this->getExceptionConversionData() as $convertedExceptionClassName => $errors) {
223
            foreach ($errors as $error) {
224 View Code Duplication
                $driverException = new class ($error[0], $error[1], $error[2])
0 ignored issues
show
Duplication introduced by
This class seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
225
                    extends \Exception
226
                    implements DriverException
227
                {
228
                    /**
229
                     * @var mixed
230
                     */
231
                    private $errorCode;
232
233
                    /**
234
                     * @var mixed
235
                     */
236
                    private $sqlState;
237
238
                    public function __construct($errorCode, $sqlState, $message)
239
                    {
240
                        parent::__construct($message);
241
242
                        $this->errorCode = $errorCode;
243
                        $this->sqlState  = $sqlState;
244
                    }
245
246
                    /**
247
                     * {@inheritDoc}
248
                     */
249
                    public function getErrorCode()
250
                    {
251
                        return $this->errorCode;
252
                    }
253
254
                    /**
255
                     * {@inheritDoc}
256
                     */
257
                    public function getSQLState()
258
                    {
259
                        return $this->sqlState;
260
                    }
261
                };
262
263
                $data[] = array($driverException, $convertedExceptionClassName);
264
            }
265
        }
266
267
        return $data;
268
    }
269
}
270