Failed Conditions
Push — master ( 4d0d2a...06d1d8 )
by Marco
22s queued 16s
created

php$0 ➔ exceptionConversionProvider()   A

Complexity

Conditions 3

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
cc 3
1
<?php
2
3
namespace Doctrine\Tests\DBAL\Driver;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\DBALException;
7
use Doctrine\DBAL\Driver;
8
use Doctrine\DBAL\Driver\DriverException as DriverExceptionInterface;
9
use Doctrine\DBAL\Driver\ExceptionConverterDriver;
10
use Doctrine\DBAL\Exception\ConnectionException;
11
use Doctrine\DBAL\Exception\ConstraintViolationException;
12
use Doctrine\DBAL\Exception\DatabaseObjectExistsException;
13
use Doctrine\DBAL\Exception\DatabaseObjectNotFoundException;
14
use Doctrine\DBAL\Exception\DeadlockException;
15
use Doctrine\DBAL\Exception\DriverException;
16
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
17
use Doctrine\DBAL\Exception\InvalidFieldNameException;
18
use Doctrine\DBAL\Exception\LockWaitTimeoutException;
19
use Doctrine\DBAL\Exception\NonUniqueFieldNameException;
20
use Doctrine\DBAL\Exception\NotNullConstraintViolationException;
21
use Doctrine\DBAL\Exception\ReadOnlyException;
22
use Doctrine\DBAL\Exception\ServerException;
23
use Doctrine\DBAL\Exception\SyntaxErrorException;
24
use Doctrine\DBAL\Exception\TableExistsException;
25
use Doctrine\DBAL\Exception\TableNotFoundException;
26
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
27
use Doctrine\DBAL\Platforms\AbstractPlatform;
28
use Doctrine\DBAL\Schema\AbstractSchemaManager;
29
use Doctrine\DBAL\VersionAwarePlatformDriver;
30
use Doctrine\Tests\DbalTestCase;
31
use Exception;
32
use ReflectionProperty;
33
use function array_merge;
34
use function get_class;
35
use function sprintf;
36
37
abstract class AbstractDriverTest extends DbalTestCase
38
{
39
    public const EXCEPTION_CONNECTION                       = ConnectionException::class;
40
    public const EXCEPTION_CONSTRAINT_VIOLATION             = ConstraintViolationException::class;
41
    public const EXCEPTION_DATABASE_OBJECT_EXISTS           = DatabaseObjectExistsException::class;
42
    public const EXCEPTION_DATABASE_OBJECT_NOT_FOUND        = DatabaseObjectNotFoundException::class;
43
    public const EXCEPTION_DRIVER                           = DriverException::class;
44
    public const EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION = ForeignKeyConstraintViolationException::class;
45
    public const EXCEPTION_INVALID_FIELD_NAME               = InvalidFieldNameException::class;
46
    public const EXCEPTION_NON_UNIQUE_FIELD_NAME            = NonUniqueFieldNameException::class;
47
    public const EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION    = NotNullConstraintViolationException::class;
48
    public const EXCEPTION_READ_ONLY                        = ReadOnlyException::class;
49
    public const EXCEPTION_SERVER                           = ServerException::class;
50
    public const EXCEPTION_SYNTAX_ERROR                     = SyntaxErrorException::class;
51
    public const EXCEPTION_TABLE_EXISTS                     = TableExistsException::class;
52
    public const EXCEPTION_TABLE_NOT_FOUND                  = TableNotFoundException::class;
53
    public const EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION      = UniqueConstraintViolationException::class;
54
    public const EXCEPTION_DEADLOCK                         = DeadlockException::class;
55
    public const EXCEPTION_LOCK_WAIT_TIMEOUT                = LockWaitTimeoutException::class;
56
57
    /**
58
     * The driver mock under test.
59
     *
60
     * @var Driver
61
     */
62
    protected $driver;
63
64
    protected function setUp() : void
65
    {
66
        parent::setUp();
67
68
        $this->driver = $this->createDriver();
69
    }
70
71
    /**
72
     * @dataProvider exceptionConversionProvider
73
     */
74
    public function testConvertsException($errorCode, $sqlState, $message, string $expectedClass) : void
75
    {
76
        if (! $this->driver instanceof ExceptionConverterDriver) {
77
            $this->markTestSkipped('This test is only intended for exception converter drivers.');
78
        }
79
80
        $driverException = new class ($errorCode, $sqlState, $message)
81
            extends Exception
82
            implements DriverExceptionInterface
83
        {
84
            /** @var mixed */
85
            private $errorCode;
86
87
            /** @var mixed */
88
            private $sqlState;
89
90
            public function __construct($errorCode, $sqlState, $message)
91
            {
92
                parent::__construct($message);
93
94
                $this->errorCode = $errorCode;
95
                $this->sqlState  = $sqlState;
96
            }
97
98
            /**
99
             * {@inheritDoc}
100
             */
101
            public function getErrorCode()
102
            {
103
                return $this->errorCode;
104
            }
105
106
            /**
107
             * {@inheritDoc}
108
             */
109
            public function getSQLState()
110
            {
111
                return $this->sqlState;
112
            }
113
        };
114
115
        $dbalMessage   = 'DBAL exception message';
116
        $dbalException = $this->driver->convertException($dbalMessage, $driverException);
117
118
        self::assertInstanceOf($expectedClass, $dbalException);
119
120
        self::assertSame($driverException->getErrorCode(), $dbalException->getErrorCode());
121
        self::assertSame($driverException->getSQLState(), $dbalException->getSQLState());
122
        self::assertSame($driverException, $dbalException->getPrevious());
123
        self::assertSame($dbalMessage, $dbalException->getMessage());
124
    }
125
126
    public function testCreatesDatabasePlatformForVersion()
127
    {
128
        if (! $this->driver instanceof VersionAwarePlatformDriver) {
129
            $this->markTestSkipped('This test is only intended for version aware platform drivers.');
130
        }
131
132
        $data = $this->getDatabasePlatformsForVersions();
133
134
        self::assertNotEmpty(
135
            $data,
136
            sprintf(
137
                'No test data found for test %s. You have to return test data from %s.',
138
                static::class . '::' . __FUNCTION__,
139
                static::class . '::getDatabasePlatformsForVersions'
140
            )
141
        );
142
143
        foreach ($data as $item) {
144
            $generatedVersion = get_class($this->driver->createDatabasePlatformForVersion($item[0]));
145
146
            self::assertSame(
147
                $item[1],
148
                $generatedVersion,
149
                sprintf(
150
                    'Expected platform for version "%s" should be "%s", "%s" given',
151
                    $item[0],
152
                    $item[1],
153
                    $generatedVersion
154
                )
155
            );
156
        }
157
    }
158
159
    public function testThrowsExceptionOnCreatingDatabasePlatformsForInvalidVersion()
160
    {
161
        if (! $this->driver instanceof VersionAwarePlatformDriver) {
162
            $this->markTestSkipped('This test is only intended for version aware platform drivers.');
163
        }
164
165
        $this->expectException(DBALException::class);
166
        $this->driver->createDatabasePlatformForVersion('foo');
167
    }
168
169
    public function testReturnsDatabaseName()
170
    {
171
        $params = [
172
            'user'     => 'foo',
173
            'password' => 'bar',
174
            'dbname'   => 'baz',
175
        ];
176
177
        $connection = $this->getConnectionMock();
178
179
        $connection->expects($this->once())
180
            ->method('getParams')
181
            ->will($this->returnValue($params));
182
183
        self::assertSame($params['dbname'], $this->driver->getDatabase($connection));
184
    }
185
186
    public function testReturnsDatabasePlatform()
187
    {
188
        self::assertEquals($this->createPlatform(), $this->driver->getDatabasePlatform());
189
    }
190
191
    public function testReturnsSchemaManager()
192
    {
193
        $connection    = $this->getConnectionMock();
194
        $schemaManager = $this->driver->getSchemaManager($connection);
195
196
        self::assertEquals($this->createSchemaManager($connection), $schemaManager);
197
198
        $re = new ReflectionProperty($schemaManager, '_conn');
199
        $re->setAccessible(true);
200
201
        self::assertSame($connection, $re->getValue($schemaManager));
202
    }
203
204
    /**
205
     * Factory method for creating the driver instance under test.
206
     *
207
     * @return Driver
208
     */
209
    abstract protected function createDriver();
210
211
    /**
212
     * Factory method for creating the the platform instance return by the driver under test.
213
     *
214
     * The platform instance returned by this method must be the same as returned by
215
     * the driver's getDatabasePlatform() method.
216
     *
217
     * @return AbstractPlatform
218
     */
219
    abstract protected function createPlatform();
220
221
    /**
222
     * Factory method for creating the the schema manager instance return by the driver under test.
223
     *
224
     * The schema manager instance returned by this method must be the same as returned by
225
     * the driver's getSchemaManager() method.
226
     *
227
     * @param Connection $connection The underlying connection to use.
228
     *
229
     * @return AbstractSchemaManager
230
     */
231
    abstract protected function createSchemaManager(Connection $connection);
232
233
    protected function getConnectionMock()
234
    {
235
        return $this->getMockBuilder(Connection::class)
236
            ->disableOriginalConstructor()
237
            ->getMock();
238
    }
239
240
    protected function getDatabasePlatformsForVersions()
241
    {
242
        return [];
243
    }
244
245
    /**
246
     * @return mixed[][]
247
     */
248
    public static function exceptionConversionProvider() : iterable
249
    {
250
        foreach (static::getExceptionConversionData() as $expectedClass => $items) {
251
            foreach ($items as $item) {
252
                yield array_merge($item, [$expectedClass]);
0 ignored issues
show
Bug Best Practice introduced by
The expression yield array_merge($item, array($expectedClass)) returns the type Generator which is incompatible with the documented return type array<mixed,array<mixed,mixed>>.
Loading history...
253
            }
254
        }
255
256
        yield ['foo', 'bar', 'baz', self::EXCEPTION_DRIVER];
257
    }
258
259
    /**
260
     * @return array<string,mixed[][]>
261
     */
262
    protected static function getExceptionConversionData() : array
263
    {
264
        return [];
265
    }
266
}
267