doctrine /
dbal
| 1 | <?php |
||
| 2 | |||
| 3 | declare(strict_types=1); |
||
| 4 | |||
| 5 | namespace Doctrine\DBAL\Tests\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 PHPUnit\Framework\MockObject\MockObject; |
||
| 33 | use PHPUnit\Framework\TestCase; |
||
| 34 | use ReflectionProperty; |
||
| 35 | use function array_merge; |
||
| 36 | use function get_class; |
||
| 37 | use function sprintf; |
||
| 38 | |||
| 39 | abstract class AbstractDriverTest extends TestCase |
||
| 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 | self::markTestSkipped('This test is only intended for exception converter drivers.'); |
||
| 80 | } |
||
| 81 | |||
| 82 | $driverException = $this->getMockBuilder(DriverExceptionInterface::class) |
||
| 83 | ->setConstructorArgs([$message, $errorCode]) |
||
| 84 | ->getMock(); |
||
| 85 | $driverException->method('getSQLState') |
||
| 86 | ->willReturn($sqlState); |
||
| 87 | |||
| 88 | $dbalMessage = 'DBAL exception message'; |
||
| 89 | $dbalException = $this->driver->convertException($dbalMessage, $driverException); |
||
| 90 | |||
| 91 | self::assertInstanceOf($expectedClass, $dbalException); |
||
| 92 | |||
| 93 | self::assertSame($driverException->getCode(), $dbalException->getCode()); |
||
| 94 | self::assertSame($driverException->getSQLState(), $dbalException->getSQLState()); |
||
| 95 | self::assertSame($driverException, $dbalException->getPrevious()); |
||
| 96 | self::assertSame($dbalMessage, $dbalException->getMessage()); |
||
| 97 | } |
||
| 98 | |||
| 99 | public function testCreatesDatabasePlatformForVersion() : void |
||
| 100 | { |
||
| 101 | if (! $this->driver instanceof VersionAwarePlatformDriver) { |
||
| 102 | self::markTestSkipped('This test is only intended for version aware platform drivers.'); |
||
| 103 | } |
||
| 104 | |||
| 105 | $data = $this->getDatabasePlatformsForVersions(); |
||
| 106 | |||
| 107 | self::assertNotEmpty( |
||
| 108 | $data, |
||
| 109 | sprintf( |
||
| 110 | 'No test data found for test %s. You have to return test data from %s.', |
||
| 111 | static::class . '::' . __FUNCTION__, |
||
| 112 | static::class . '::getDatabasePlatformsForVersions' |
||
| 113 | ) |
||
| 114 | ); |
||
| 115 | |||
| 116 | foreach ($data as $item) { |
||
| 117 | $generatedVersion = get_class($this->driver->createDatabasePlatformForVersion($item[0])); |
||
| 118 | |||
| 119 | self::assertSame( |
||
| 120 | $item[1], |
||
| 121 | $generatedVersion, |
||
| 122 | sprintf( |
||
| 123 | 'Expected platform for version "%s" should be "%s", "%s" given', |
||
| 124 | $item[0], |
||
| 125 | $item[1], |
||
| 126 | $generatedVersion |
||
| 127 | ) |
||
| 128 | ); |
||
| 129 | } |
||
| 130 | } |
||
| 131 | |||
| 132 | public function testThrowsExceptionOnCreatingDatabasePlatformsForInvalidVersion() : void |
||
| 133 | { |
||
| 134 | if (! $this->driver instanceof VersionAwarePlatformDriver) { |
||
| 135 | self::markTestSkipped('This test is only intended for version aware platform drivers.'); |
||
| 136 | } |
||
| 137 | |||
| 138 | $this->expectException(DBALException::class); |
||
| 139 | $this->driver->createDatabasePlatformForVersion('foo'); |
||
| 140 | } |
||
| 141 | |||
| 142 | public function testReturnsDatabasePlatform() : void |
||
| 143 | { |
||
| 144 | self::assertEquals($this->createPlatform(), $this->driver->getDatabasePlatform()); |
||
| 145 | } |
||
| 146 | |||
| 147 | public function testReturnsSchemaManager() : void |
||
| 148 | { |
||
| 149 | $connection = $this->getConnectionMock(); |
||
| 150 | $schemaManager = $this->driver->getSchemaManager($connection); |
||
| 151 | |||
| 152 | self::assertEquals($this->createSchemaManager($connection), $schemaManager); |
||
| 153 | |||
| 154 | $re = new ReflectionProperty($schemaManager, '_conn'); |
||
| 155 | $re->setAccessible(true); |
||
| 156 | |||
| 157 | self::assertSame($connection, $re->getValue($schemaManager)); |
||
| 158 | } |
||
| 159 | |||
| 160 | /** |
||
| 161 | * Factory method for creating the driver instance under test. |
||
| 162 | */ |
||
| 163 | abstract protected function createDriver() : Driver; |
||
| 164 | |||
| 165 | /** |
||
| 166 | * Factory method for creating the the platform instance return by the driver under test. |
||
| 167 | * |
||
| 168 | * The platform instance returned by this method must be the same as returned by |
||
| 169 | * the driver's getDatabasePlatform() method. |
||
| 170 | */ |
||
| 171 | abstract protected function createPlatform() : AbstractPlatform; |
||
| 172 | |||
| 173 | /** |
||
| 174 | * Factory method for creating the the schema manager instance return by the driver under test. |
||
| 175 | * |
||
| 176 | * The schema manager instance returned by this method must be the same as returned by |
||
| 177 | * the driver's getSchemaManager() method. |
||
| 178 | * |
||
| 179 | * @param Connection $connection The underlying connection to use. |
||
| 180 | */ |
||
| 181 | abstract protected function createSchemaManager(Connection $connection) : AbstractSchemaManager; |
||
| 182 | |||
| 183 | /** |
||
| 184 | * @return Connection&MockObject |
||
| 185 | */ |
||
| 186 | protected function getConnectionMock() : Connection |
||
| 187 | { |
||
| 188 | return $this->getMockBuilder(Connection::class) |
||
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
Loading history...
|
|||
| 189 | ->disableOriginalConstructor() |
||
| 190 | ->getMock(); |
||
| 191 | } |
||
| 192 | |||
| 193 | /** |
||
| 194 | * @return array<int, array<int, string>> |
||
| 195 | */ |
||
| 196 | protected function getDatabasePlatformsForVersions() : array |
||
| 197 | { |
||
| 198 | return []; |
||
| 199 | } |
||
| 200 | |||
| 201 | /** |
||
| 202 | * @return mixed[][] |
||
| 203 | */ |
||
| 204 | public static function exceptionConversionProvider() : iterable |
||
| 205 | { |
||
| 206 | foreach (static::getExceptionConversionData() as $expectedClass => $items) { |
||
| 207 | foreach ($items as $item) { |
||
| 208 | yield array_merge([$expectedClass], $item); |
||
|
0 ignored issues
–
show
|
|||
| 209 | } |
||
| 210 | } |
||
| 211 | |||
| 212 | yield [self::EXCEPTION_DRIVER, 1, 'HY000', 'The message']; |
||
| 213 | } |
||
| 214 | |||
| 215 | /** |
||
| 216 | * @return array<string,mixed[][]> |
||
| 217 | */ |
||
| 218 | protected static function getExceptionConversionData() : array |
||
| 219 | { |
||
| 220 | return []; |
||
| 221 | } |
||
| 222 | } |
||
| 223 |