Completed
Push — develop ( dcb0ff...425513 )
by Sergei
23s queued 13s
created

AbstractDriverTest   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 183
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 16
eloc 73
dl 0
loc 183
rs 10
c 0
b 0
f 0

10 Methods

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