diff --git a/composer.json b/composer.json
index 9859487..4dac58e 100644
--- a/composer.json
+++ b/composer.json
@@ -31,7 +31,7 @@
},
"require": {
"php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
- "php-db/phpdb": "^0.2.0",
+ "php-db/phpdb": "^0.3.0",
"webmozart/assert": "^1.11"
},
"require-dev": {
diff --git a/composer.lock b/composer.lock
index af94a09..4b5224b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "8e1e64115b9e15d27f9e22c4189baac6",
+ "content-hash": "373f53734a878eaeebfdde7a145eafda",
"packages": [
{
"name": "brick/varexporter",
@@ -259,22 +259,22 @@
},
{
"name": "php-db/phpdb",
- "version": "0.2.1",
+ "version": "0.3.x-dev",
"source": {
"type": "git",
"url": "https://github.com/php-db/phpdb.git",
- "reference": "d221b024cb3aea77992f41a962913918301dc92e"
+ "reference": "82ccbd942248e55b02d2467939bf6ce6f065a156"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-db/phpdb/zipball/d221b024cb3aea77992f41a962913918301dc92e",
- "reference": "d221b024cb3aea77992f41a962913918301dc92e",
+ "url": "https://api.github.com/repos/php-db/phpdb/zipball/82ccbd942248e55b02d2467939bf6ce6f065a156",
+ "reference": "82ccbd942248e55b02d2467939bf6ce6f065a156",
"shasum": ""
},
"require": {
"laminas/laminas-servicemanager": "^4.0.0",
"laminas/laminas-stdlib": "^3.20.0",
- "php": "~8.2.0 || ~8.3.0 || ~8.4.0"
+ "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
},
"conflict": {
"laminas/laminas-db": "*",
@@ -292,6 +292,7 @@
"laminas/laminas-eventmanager": "Laminas\\EventManager component",
"laminas/laminas-hydrator": "(^5.0.0) Laminas\\Hydrator component for using HydratingResultSets"
},
+ "default-branch": true,
"type": "library",
"extra": {
"laminas": {
@@ -321,7 +322,7 @@
"issues": "https://github.com/php-db/phpdb/issues",
"source": "https://github.com/php-db/phpdb"
},
- "time": "2025-10-07T08:36:48+00:00"
+ "time": "2025-11-09T08:06:35+00:00"
},
{
"name": "psr/container",
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 38effcf..57d45ca 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -18,10 +18,6 @@
-
-
+
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
new file mode 100644
index 0000000..aa4eea9
--- /dev/null
+++ b/phpstan-baseline.neon
@@ -0,0 +1,103 @@
+parameters:
+ ignoreErrors:
+ -
+ message: '#^Variable \$aliasTo on left side of \?\?\= is never defined\.$#'
+ identifier: nullCoalesce.variable
+ count: 1
+ path: src/Container/DriverInterfaceFactoryFactory.php
+
+ -
+ message: '#^Cannot call static method createFromConfig\(\) on callable\.$#'
+ identifier: staticMethod.nonObject
+ count: 1
+ path: src/Container/PdoDriverFactory.php
+
+ -
+ message: '#^Parameter \#1 \$name \(string\) of method PhpDb\\Adapter\\Sqlite\\Driver\\Pdo\\Connection\:\:getLastGeneratedValue\(\) should be compatible with parameter \$name \(null\) of method PhpDb\\Adapter\\Driver\\ConnectionInterface\:\:getLastGeneratedValue\(\)$#'
+ identifier: method.childParameterType
+ count: 2
+ path: src/Driver/Pdo/Connection.php
+
+ -
+ message: '#^Parameter \#2 \$parameters of class PhpDb\\Adapter\\Exception\\InvalidConnectionParametersException constructor expects int, array given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Driver/Pdo/Connection.php
+
+ -
+ message: '#^Parameter \#1 \$resource \(PDOStatement\) of method PhpDb\\Adapter\\Sqlite\\Driver\\Pdo\\Pdo\:\:createResult\(\) should be compatible with parameter \$resource \(resource\) of method PhpDb\\Adapter\\Driver\\DriverInterface\:\:createResult\(\)$#'
+ identifier: method.childParameterType
+ count: 3
+ path: src/Driver/Pdo/Pdo.php
+
+ -
+ message: '#^Parameter \#3 \$rowCount of method PhpDb\\Adapter\\Driver\\Pdo\\Result\:\:initialize\(\) expects int\|null, Closure\|null given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Driver/Pdo/Pdo.php
+
+ -
+ message: '#^Variable \$schemas might not be defined\.$#'
+ identifier: variable.undefined
+ count: 1
+ path: src/Metadata/Source/SqliteMetadata.php
+
+ -
+ message: '#^Method PhpDb\\Adapter\\Sqlite\\Sql\\Platform\\Ddl\\AlterTableDecorator\:\:processAddColumns\(\) should return array\ but returns array\\>\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Sql/Platform/Ddl/AlterTableDecorator.php
+
+ -
+ message: '#^Method PhpDb\\Adapter\\Sqlite\\Sql\\Platform\\Ddl\\AlterTableDecorator\:\:processChangeColumns\(\) should return array\ but returns array\\>\>\.$#'
+ identifier: return.type
+ count: 1
+ path: src/Sql/Platform/Ddl/AlterTableDecorator.php
+
+ -
+ message: '#^Offset ''paramPrefix'' does not exist on string\.$#'
+ identifier: offsetAccess.notFound
+ count: 2
+ path: src/Sql/Platform/SelectDecorator.php
+
+ -
+ message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertIsArray\(\) with array will always evaluate to true\.$#'
+ identifier: staticMethod.alreadyNarrowedType
+ count: 3
+ path: test/unit/ConfigProviderTest.php
+
+ -
+ message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertIsCallable\(\) with callable\(\)\: mixed will always evaluate to true\.$#'
+ identifier: staticMethod.alreadyNarrowedType
+ count: 1
+ path: test/unit/Container/ConnectionInterfaceFactoryFactoryTest.php
+
+ -
+ message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertIsCallable\(\) with callable\(\)\: mixed will always evaluate to true\.$#'
+ identifier: staticMethod.alreadyNarrowedType
+ count: 1
+ path: test/unit/Container/DriverInterfaceFactoryFactoryTest.php
+
+ -
+ message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertIsCallable\(\) with callable\(\)\: mixed will always evaluate to true\.$#'
+ identifier: staticMethod.alreadyNarrowedType
+ count: 1
+ path: test/unit/Container/PlatformInterfaceFactoryFactoryTest.php
+
+ -
+ message: '#^PHPDoc tag @var with type PhpDb\\Adapter\\Driver\\PdoDriverAwareInterface&PhpDb\\Adapter\\Driver\\StatementInterface is not subtype of native type PHPUnit\\Framework\\MockObject\\MockObject\.$#'
+ identifier: varTag.nativeType
+ count: 1
+ path: test/unit/Driver/Pdo/PdoTest.php
+
+ -
+ message: '#^Parameter \#1 \$callback of function set_error_handler expects \(callable\(int, string, string, int\)\: bool\)\|null, Closure\(int, string\)\: void given\.$#'
+ identifier: argument.type
+ count: 1
+ path: test/unit/Platform/SqliteTest.php
+
+ -
+ message: '#^Parameter \#1 \$callback of function set_error_handler expects \(callable\(int, string, string, int\)\: bool\)\|null, Closure\(mixed, mixed\)\: void given\.$#'
+ identifier: argument.type
+ count: 1
+ path: test/unit/Platform/SqliteTest.php
diff --git a/src/Driver/Pdo/Connection.php b/src/Driver/Pdo/Connection.php
index dd57722..a7340bb 100644
--- a/src/Driver/Pdo/Connection.php
+++ b/src/Driver/Pdo/Connection.php
@@ -27,7 +27,7 @@ class Connection extends AbstractPdoConnection
* {@inheritDoc}
*/
#[Override]
- public function getCurrentSchema(): string|bool
+ public function getCurrentSchema(): string|false
{
if (! $this->isConnected()) {
$this->connect();
diff --git a/src/Sql/Platform/Ddl/AlterTableDecorator.php b/src/Sql/Platform/Ddl/AlterTableDecorator.php
index 568efea..0b975f7 100644
--- a/src/Sql/Platform/Ddl/AlterTableDecorator.php
+++ b/src/Sql/Platform/Ddl/AlterTableDecorator.php
@@ -1,5 +1,7 @@
isConnected());
}
- /**
- * @todo Implement testBeginTransaction().
- */
- public function testBeginTransaction(): never
- {
- // Remove the following lines when you implement this test.
- $this->markTestIncomplete(
- 'This test has not been implemented yet.'
- );
- }
-
- /**
- * @todo Implement testCommit().
- */
- public function testCommit(): never
- {
- // Remove the following lines when you implement this test.
- $this->markTestIncomplete(
- 'This test has not been implemented yet.'
- );
- }
-
- /**
- * @todo Implement testRollback().
- */
- public function testRollback(): never
- {
- // Remove the following lines when you implement this test.
- $this->markTestIncomplete(
- 'This test has not been implemented yet.'
- );
- }
-
- public function testGetLastGeneratedValue(): never
- {
- $this->markTestIncomplete('Need to create a temporary sequence.');
- //$connection = new Connection($this->variables);
- //$connection->getLastGeneratedValue();
- }
-
public function testConnectReturnsConnectionWhenResourceSet(): void
{
/** @var PDO $resource */
@@ -129,4 +89,35 @@ public function testConnectReturnsConnectionWhenResourceSet(): void
unset($connection);
unset($resource);
}
+
+ // public function testBeginTransaction(): never
+ // {
+ // // Remove the following lines when you implement this test.
+ // $this->markTestIncomplete(
+ // 'This test has not been implemented yet.'
+ // );
+ // }
+
+ // public function testCommit(): never
+ // {
+ // // Remove the following lines when you implement this test.
+ // $this->markTestIncomplete(
+ // 'This test has not been implemented yet.'
+ // );
+ // }
+
+ // public function testRollback(): never
+ // {
+ // // Remove the following lines when you implement this test.
+ // $this->markTestIncomplete(
+ // 'This test has not been implemented yet.'
+ // );
+ // }
+
+ // public function testGetLastGeneratedValue(): never
+ // {
+ // $this->markTestIncomplete('Need to create a temporary sequence.');
+ // //$connection = new Connection($this->variables);
+ // //$connection->getLastGeneratedValue();
+ // }
}
diff --git a/test/unit/AdapterServiceFactoryTest.php b/test/unit/AdapterServiceFactoryTest.php
deleted file mode 100644
index 6a931f9..0000000
--- a/test/unit/AdapterServiceFactoryTest.php
+++ /dev/null
@@ -1,113 +0,0 @@
-getDependencies();
- if (array_key_exists('services', $config) && is_array($config['services'])) {
- $config['services']['config'] = $dbConfig;
- }
-
- return new ServiceManager($config);
- }
-
- #[Override]
- protected function setUp(): void
- {
- $this->factory = new AdapterServiceFactory();
- }
-
- /**
- * @throws ContainerExceptionInterface
- * @throws NotFoundExceptionInterface
- */
- public function testV3FactoryReturnsDefaultAdapter(): void
- {
- $this->expectNotToPerformAssertions();
-
- $services = $this->createServiceManager([
- 'db' => [
- 'driver' => 'Pdo_Sqlite',
- 'database' => ':memory:',
- ],
- ]);
-
- $this->factory->__invoke($services, Adapter::class);
- }
-
- /**
- * @throws ContainerExceptionInterface
- * @throws NotFoundExceptionInterface
- */
- public function testV3FactoryReturnsDefaultAdapterWithDefaultProfiler(): void
- {
- $services = $this->createServiceManager([
- 'db' => [
- 'driver' => 'Pdo_Sqlite',
- 'database' => ':memory:',
- 'profiler' => true,
- ],
- ]);
-
- $adapter = $this->factory->__invoke($services, Adapter::class);
- self::assertInstanceOf(ProfilerInterface::class, $adapter->getProfiler());
- }
-
- /**
- * @throws ContainerExceptionInterface
- * @throws NotFoundExceptionInterface
- */
- public function testV3FactoryReturnsDefaultAdapterWithProfilerClassname(): void
- {
- $services = $this->createServiceManager([
- 'db' => [
- 'driver' => 'Pdo_Sqlite',
- 'database' => ':memory:',
- 'profiler' => Profiler::class,
- ],
- ]);
-
- $adapter = $this->factory->__invoke($services, Adapter::class);
- self::assertInstanceOf(ProfilerInterface::class, $adapter->getProfiler());
- }
-
- /**
- * @throws ContainerExceptionInterface
- * @throws NotFoundExceptionInterface
- */
- public function testV3FactoryReturnsDefaultAdapterWithProfilerInstance(): void
- {
- $services = $this->createServiceManager([
- 'db' => [
- 'driver' => 'Pdo_Sqlite',
- 'database' => ':memory:',
- 'profiler' => $this->getMockBuilder(ProfilerInterface::class)->getMock(),
- ],
- ]);
-
- $adapter = $this->factory->__invoke($services, Adapter::class);
- self::assertInstanceOf(ProfilerInterface::class, $adapter->getProfiler());
- }
-}
diff --git a/test/unit/AdapterTest.php b/test/unit/AdapterTest.php
index 749fef1..e67c182 100644
--- a/test/unit/AdapterTest.php
+++ b/test/unit/AdapterTest.php
@@ -1,33 +1,27 @@
adapter->setProfiler(new Profiler\Profiler());
- self::assertSame($this->adapter, $ret);
- }
+ protected Adapter $adapter;
- #[TestDox('unit test: Test getProfiler() will store profiler')]
- public function testGetProfiler(): void
+ /**
+ * @throws Exception
+ */
+ #[Override]
+ protected function setUp(): void
{
- $this->adapter->setProfiler($profiler = new Profiler\Profiler());
- self::assertSame($profiler, $this->adapter->getProfiler());
+ $this->mockConnection = $this->createMock(AbstractPdoConnection::class);
+ $this->mockPlatform = new SqlitePlatform($this->createMock(PdoDriverInterface::class));
+ $this->mockStatement = $this->getMockBuilder(Statement::class)->getMock();
+ $this->mockResultSet = $this->getMockBuilder(ResultSetInterface::class)->getMock();
+ $resultInterface = $this->getMockBuilder(ResultInterface::class)->getMock();
+ $this->mockDriver = $this->getMockBuilder(Pdo::class)
+ ->setConstructorArgs([
+ $this->mockConnection,
+ $this->mockStatement,
+ $resultInterface,
+ ])
+ ->getMock();
- $adapter = new Adapter(['driver' => $this->mockDriver, 'profiler' => true], $this->mockPlatform);
- self::assertInstanceOf(Profiler\Profiler::class, $adapter->getProfiler());
- }
+ $this->mockDriver->method('getDatabasePlatformName')->willReturn('Sqlite');
+ $this->mockDriver->method('checkEnvironment')->willReturn(true);
+ $this->mockDriver->method('getConnection')->willReturn($this->mockConnection);
+ $this->mockDriver->method('createStatement')->willReturn($this->mockStatement);
- #[TestDox('unit test: Test createDriverFromParameters() will create proper driver type')]
- public function testCreateDriver(): void
- {
- if (extension_loaded('pdo')) {
- $adapter = new Adapter(['driver' => 'pdo_sqlite'], $this->mockPlatform);
- self::assertInstanceOf(Pdo::class, $adapter->driver);
- unset($adapter);
- }
+ $this->adapter = new Adapter(
+ $this->mockDriver,
+ $this->mockPlatform,
+ $this->mockResultSet
+ );
}
- #[TestDox('unit test: Test createPlatformFromDriver() will create proper platform from driver')]
- public function testCreatePlatform(): void
+ #[TestDox('unit test: Test setProfiler() will store profiler')]
+ public function testSetProfiler(): void
{
- $driver = clone $this->mockDriver;
- $driver->expects($this->any())->method('getDatabasePlatformName')->willReturn('Sqlite');
- $adapter = new Adapter($driver);
- self::assertInstanceOf(SqlitePlatform::class, $adapter->platform);
- unset($adapter, $driver);
+ $ret = $this->adapter->setProfiler(new Profiler\Profiler());
+ self::assertSame($this->adapter, $ret);
}
#[TestDox('unit test: Test getDriver() will return driver object')]
@@ -100,12 +97,6 @@ public function testGetPlatform(): void
self::assertSame($this->mockPlatform, $this->adapter->getPlatform());
}
- #[TestDox('unit test: Test getPlatform() returns platform object')]
- public function testGetQueryResultSetPrototype(): void
- {
- self::assertInstanceOf(ResultSetInterface::class, $this->adapter->getQueryResultSetPrototype());
- }
-
#[TestDox('unit test: Test getCurrentSchema() returns current schema from connection object')]
public function testGetCurrentSchema(): void
{
@@ -114,7 +105,7 @@ public function testGetCurrentSchema(): void
}
/**
- * @throws \Exception
+ * @throws Exception
*/
#[TestDox('unit test: Test query() in prepare mode produces a statement object')]
public function testQueryWhenPreparedProducesStatement(): void
@@ -125,29 +116,6 @@ public function testQueryWhenPreparedProducesStatement(): void
/**
* @throws Exception
- * @throws \Exception
- */
- #[Group('#210')]
- public function testProducedResultSetPrototypeIsDifferentForEachQuery(): void
- {
- $statement = $this->createMock(StatementInterface::class);
- $result = $this->createMock(ResultInterface::class);
-
- $this->mockDriver->method('createStatement')
- ->willReturn($statement);
- $this->mockStatement->method('execute')
- ->willReturn($result);
- $result->method('isQueryResult')
- ->willReturn(true);
-
- self::assertNotSame(
- $this->adapter->query('SELECT foo', []),
- $this->adapter->query('SELECT foo', [])
- );
- }
-
- /**
- * @throws \Exception
*/
#[TestDox('unit test: Test query() in prepare mode, with array of parameters, produces a result object')]
public function testQueryWhenPreparedWithParameterArrayProducesResult(): void
@@ -164,101 +132,9 @@ public function testQueryWhenPreparedWithParameterArrayProducesResult(): void
self::assertSame($result, $r);
}
- /**
- * @throws \Exception
- */
- #[TestDox('unit test: Test query() in prepare mode, with ParameterContainer, produces a result object')]
- public function testQueryWhenPreparedWithParameterContainerProducesResult(): void
- {
- $sql = 'SELECT foo';
- $parameterContainer = $this->getMockBuilder(ParameterContainer::class)->getMock();
- $result = $this->getMockBuilder(ResultInterface::class)->getMock();
- $this->mockDriver->expects($this->any())->method('createStatement')
- ->with($sql)->willReturn($this->mockStatement);
- $this->mockStatement->expects($this->any())->method('execute')->willReturn($result);
- $result->expects($this->any())->method('isQueryResult')->willReturn(true);
-
- $r = $this->adapter->query($sql, $parameterContainer);
- self::assertInstanceOf(ResultSet::class, $r);
- }
-
- /**
- * @throws \Exception
- */
- #[TestDox('unit test: Test query() in execute mode produces a driver result object')]
- public function testQueryWhenExecutedProducesAResult(): void
- {
- $sql = 'SELECT foo';
- $result = $this->getMockBuilder(ResultInterface::class)->getMock();
- $this->mockConnection->expects($this->any())->method('execute')->with($sql)->willReturn($result);
-
- $r = $this->adapter->query($sql, AdapterInterface::QUERY_MODE_EXECUTE);
- self::assertSame($result, $r);
- }
-
- /**
- * @throws \Exception
- */
- #[TestDox('unit test: Test query() in execute mode produces a resultset object')]
- public function testQueryWhenExecutedProducesAResultSetObjectWhenResultIsQuery(): void
- {
- $sql = 'SELECT foo';
-
- $result = $this->getMockBuilder(ResultInterface::class)->getMock();
- $this->mockConnection->expects($this->any())->method('execute')->with($sql)->willReturn($result);
- $result->expects($this->any())->method('isQueryResult')->willReturn(true);
-
- $r = $this->adapter->query($sql, AdapterInterface::QUERY_MODE_EXECUTE);
- self::assertInstanceOf(ResultSet::class, $r);
-
- $r = $this->adapter->query($sql, AdapterInterface::QUERY_MODE_EXECUTE, new TemporaryResultSet());
- self::assertInstanceOf(TemporaryResultSet::class, $r);
- }
-
#[TestDox('unit test: Test createStatement() produces a statement object')]
public function testCreateStatement(): void
{
self::assertSame($this->mockStatement, $this->adapter->createStatement());
}
-
- public function testMagicGet(): void
- {
- // @codingStandardsIgnoreEnd
- self::assertSame($this->mockDriver, $this->adapter->driver);
- /** @psalm-suppress UndefinedMagicPropertyFetch */
- self::assertSame($this->mockDriver, $this->adapter->DrivER);
- /** @psalm-suppress UndefinedMagicPropertyFetch */
- self::assertSame($this->mockPlatform, $this->adapter->PlatForm);
- self::assertSame($this->mockPlatform, $this->adapter->platform);
-
- $this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage('Invalid magic');
- $this->adapter->foo;
- }
-
- // @codingStandardsIgnoreStart
-
- /**
- * @throws Exception
- */
- #[Override]
- protected function setUp(): void
- {
- $this->mockConnection = $this->createMock(ConnectionInterface::class);
- $this->mockPlatform = new SqlitePlatform($this->createMock(PdoDriverInterface::class));
- $this->mockStatement = $this->getMockBuilder(Statement::class)->getMock();
- $this->mockDriver = $this->getMockBuilder(Pdo::class)
- ->setConstructorArgs([
- $this->mockConnection,
- $this->mockStatement,
- ])
- ->getMock();
-
- $this->mockDriver->method('getDatabasePlatformName')->willReturn('Sqlite');
- $this->mockDriver->method('checkEnvironment')->willReturn(true);
- $this->mockDriver->method('getConnection')->willReturn($this->mockConnection);
- $this->mockDriver->method('createStatement')->willReturn($this->mockStatement);
-
- $this->adapter = new Adapter($this->mockDriver, $this->mockPlatform);
- }
}
diff --git a/test/unit/ConfigProviderTest.php b/test/unit/ConfigProviderTest.php
index 9f1fffa..0af2103 100644
--- a/test/unit/ConfigProviderTest.php
+++ b/test/unit/ConfigProviderTest.php
@@ -19,93 +19,195 @@
use PhpDb\Adapter\Profiler\ProfilerInterface;
use PhpDb\Adapter\Sqlite\ConfigProvider;
use PhpDb\Adapter\Sqlite\Container;
-use PhpDb\Adapter\Sqlite\Driver;
-use PhpDb\Adapter\Sqlite\Metadata;
-use PhpDb\Adapter\Sqlite\Platform;
+use PhpDb\Adapter\Sqlite\Driver\Pdo\Connection;
+use PhpDb\Adapter\Sqlite\Driver\Pdo\Pdo;
+use PhpDb\Adapter\Sqlite\Metadata\Source\SqliteMetadata;
+use PhpDb\Adapter\Sqlite\Platform\Sqlite;
+use PhpDb\Container\AdapterAbstractServiceFactory;
use PhpDb\Container\AdapterManager;
+use PhpDb\Container\ConnectionInterfaceFactoryFactoryInterface;
+use PhpDb\Container\DriverInterfaceFactoryFactoryInterface;
+use PhpDb\Container\PlatformInterfaceFactoryFactoryInterface;
use PhpDb\Metadata\MetadataInterface;
use PhpDb\ResultSet;
-use PHPUnit\Framework\Attributes\CoversMethod;
-use PHPUnit\Framework\Attributes\Depends;
+use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
-#[CoversMethod(ConfigProvider::class, '__invoke')]
-#[CoversMethod(ConfigProvider::class, 'getDependencies')]
-#[CoversMethod(ConfigProvider::class, 'getAdapterManagerConfig')]
+#[CoversClass(ConfigProvider::class)]
final class ConfigProviderTest extends TestCase
{
- /** @var array>> */
- private array $config = [
- 'aliases' => [
- MetadataInterface::class => Metadata\Source\SqliteMetadata::class,
- ],
- 'factories' => [
- Metadata\Source\SqliteMetadata::class => Container\MetadataInterfaceFactory::class,
- ],
- 'delegators' => [
- AdapterManager::class => [
- Container\AdapterManagerDelegator::class,
- ],
- ],
- ];
-
- private array $adapterManagerConfig = [
- 'aliases' => [
- 'SQLite' => Driver\Pdo\Pdo::class,
- 'Sqlite' => Driver\Pdo\Pdo::class,
- 'sqlite' => Driver\Pdo\Pdo::class,
- 'pdo' => Driver\Pdo\Pdo::class,
- 'pdo_sqlite' => Driver\Pdo\Pdo::class,
- 'pdosqlite' => Driver\Pdo\Pdo::class,
- 'pdodriver' => Driver\Pdo\Pdo::class,
- ConnectionInterface::class => Driver\Pdo\Connection::class,
- PdoConnectionInterface::class => Driver\Pdo\Connection::class,
- DriverInterface::class => Driver\Pdo\Pdo::class,
- PdoDriverInterface::class => Driver\Pdo\Pdo::class,
- PlatformInterface::class => Platform\Sqlite::class,
+ private ConfigProvider $configProvider;
+
+ protected function setUp(): void
+ {
+ $this->configProvider = new ConfigProvider();
+ }
+
+ public function testInvokeReturnsExpectedStructure(): void
+ {
+ $config = ($this->configProvider)();
+
+ self::assertIsArray($config);
+ self::assertArrayHasKey('dependencies', $config);
+ self::assertArrayHasKey(AdapterManager::class, $config);
+ }
+
+ public function testGetDependenciesReturnsCorrectStructure(): void
+ {
+ $dependencies = $this->configProvider->getDependencies();
+
+ self::assertIsArray($dependencies);
+ self::assertArrayHasKey('abstract_factories', $dependencies);
+ self::assertArrayHasKey('aliases', $dependencies);
+ self::assertArrayHasKey('factories', $dependencies);
+ self::assertArrayHasKey('delegators', $dependencies);
+ }
+
+ public function testGetDependenciesContainsAbstractFactories(): void
+ {
+ $dependencies = $this->configProvider->getDependencies();
+
+ self::assertContains(
+ AdapterAbstractServiceFactory::class,
+ $dependencies['abstract_factories']
+ );
+ }
+
+ public function testGetDependenciesContainsMetadataAlias(): void
+ {
+ $dependencies = $this->configProvider->getDependencies();
+
+ self::assertArrayHasKey(MetadataInterface::class, $dependencies['aliases']);
+ self::assertSame(
+ SqliteMetadata::class,
+ $dependencies['aliases'][MetadataInterface::class]
+ );
+ }
+
+ public function testGetDependenciesContainsMetadataFactory(): void
+ {
+ $dependencies = $this->configProvider->getDependencies();
+
+ self::assertArrayHasKey(SqliteMetadata::class, $dependencies['factories']);
+ self::assertSame(
+ Container\MetadataInterfaceFactory::class,
+ $dependencies['factories'][SqliteMetadata::class]
+ );
+ }
+
+ public function testGetDependenciesContainsDelegators(): void
+ {
+ $dependencies = $this->configProvider->getDependencies();
+
+ self::assertArrayHasKey(AdapterManager::class, $dependencies['delegators']);
+ self::assertContains(
+ Container\AdapterManagerDelegator::class,
+ $dependencies['delegators'][AdapterManager::class]
+ );
+ }
+
+ public function testGetAdapterManagerConfigReturnsCorrectStructure(): void
+ {
+ $config = $this->configProvider->getAdapterManagerConfig();
+
+ self::assertIsArray($config);
+ self::assertArrayHasKey('aliases', $config);
+ self::assertArrayHasKey('factories', $config);
+ self::assertArrayHasKey('invokables', $config);
+ }
+
+ public function testGetAdapterManagerConfigContainsDriverAliases(): void
+ {
+ $config = $this->configProvider->getAdapterManagerConfig();
+
+ $expectedAliases = [
+ 'SQLite' => Pdo::class,
+ 'Sqlite' => Pdo::class,
+ 'sqlite' => Pdo::class,
+ 'pdo' => Pdo::class,
+ 'pdo_sqlite' => Pdo::class,
+ 'pdosqlite' => Pdo::class,
+ 'pdodriver' => Pdo::class,
+ ];
+
+ foreach ($expectedAliases as $alias => $target) {
+ self::assertArrayHasKey($alias, $config['aliases']);
+ self::assertSame($target, $config['aliases'][$alias]);
+ }
+ }
+
+ public function testGetAdapterManagerConfigContainsInterfaceAliases(): void
+ {
+ $config = $this->configProvider->getAdapterManagerConfig();
+
+ $expectedAliases = [
+ ConnectionInterface::class => Connection::class,
+ PdoConnectionInterface::class => Connection::class,
+ DriverInterface::class => Pdo::class,
+ PdoDriverInterface::class => Pdo::class,
+ PlatformInterface::class => Sqlite::class,
ProfilerInterface::class => Profiler::class,
ResultInterface::class => Result::class,
ResultSet\ResultSetInterface::class => ResultSet\ResultSet::class,
StatementInterface::class => Statement::class,
- ],
- 'factories' => [
- AdapterInterface::class => Container\AdapterFactory::class,
- Driver\Pdo\Connection::class => Container\PdoConnectionFactory::class,
- Driver\Pdo\Pdo::class => Container\PdoDriverFactory::class,
- Result::class => Container\PdoResultFactory::class,
- Statement::class => Container\PdoStatementFactory::class,
- Platform\Sqlite::class => Container\PlatformInterfaceFactory::class,
- //Profiler::class => InvokableFactory::class,
- ResultSet\ResultSet::class => InvokableFactory::class,
- ],
- ];
+ ];
- public function testProvidesExpectedDependencies(): ConfigProvider
+ foreach ($expectedAliases as $interface => $implementation) {
+ self::assertArrayHasKey($interface, $config['aliases']);
+ self::assertSame($implementation, $config['aliases'][$interface]);
+ }
+ }
+
+ public function testGetAdapterManagerConfigContainsFactoryFactoryAliases(): void
{
- $provider = new ConfigProvider();
- self::assertEquals($this->config, $provider->getDependencies());
+ $config = $this->configProvider->getAdapterManagerConfig();
+
+ $expectedAliases = [
+ ConnectionInterfaceFactoryFactoryInterface::class => Container\ConnectionInterfaceFactoryFactory::class,
+ DriverInterfaceFactoryFactoryInterface::class => Container\DriverInterfaceFactoryFactory::class,
+ PlatformInterfaceFactoryFactoryInterface::class => Container\PlatformInterfaceFactoryFactory::class,
+ ];
- return $provider;
+ foreach ($expectedAliases as $interface => $implementation) {
+ self::assertArrayHasKey($interface, $config['aliases']);
+ self::assertSame($implementation, $config['aliases'][$interface]);
+ }
}
- public function testProvidesExpectedAdapterManagerConfiguration(): void
+ public function testGetAdapterManagerConfigContainsFactories(): void
{
- $provider = new ConfigProvider();
- self::assertEquals(
- $this->adapterManagerConfig,
- $provider->getAdapterManagerConfig()
- );
+ $config = $this->configProvider->getAdapterManagerConfig();
+
+ $expectedFactories = [
+ AdapterInterface::class => Container\AdapterFactory::class,
+ Connection::class => Container\PdoConnectionFactory::class,
+ Pdo::class => Container\PdoDriverFactory::class,
+ Result::class => Container\PdoResultFactory::class,
+ Statement::class => Container\PdoStatementFactory::class,
+ Sqlite::class => Container\PlatformInterfaceFactory::class,
+ Profiler::class => InvokableFactory::class,
+ ResultSet\ResultSet::class => InvokableFactory::class,
+ ];
+
+ foreach ($expectedFactories as $service => $factory) {
+ self::assertArrayHasKey($service, $config['factories']);
+ self::assertSame($factory, $config['factories'][$service]);
+ }
}
- #[Depends('testProvidesExpectedDependencies')]
- public function testInvocationProvidesDependencyConfiguration(ConfigProvider $provider): void
+ public function testGetAdapterManagerConfigContainsInvokables(): void
{
- self::assertEquals(
- [
- 'dependencies' => $provider->getDependencies(),
- AdapterManager::class => $provider->getAdapterManagerConfig(),
- ],
- $provider()
- );
+ $config = $this->configProvider->getAdapterManagerConfig();
+
+ $expectedInvokables = [
+ Container\ConnectionInterfaceFactoryFactory::class,
+ Container\DriverInterfaceFactoryFactory::class,
+ Container\PlatformInterfaceFactoryFactory::class,
+ ];
+
+ foreach ($expectedInvokables as $invokable) {
+ self::assertArrayHasKey($invokable, $config['invokables']);
+ self::assertSame($invokable, $config['invokables'][$invokable]);
+ }
}
}
diff --git a/test/unit/Container/ConnectionInterfaceFactoryFactoryTest.php b/test/unit/Container/ConnectionInterfaceFactoryFactoryTest.php
new file mode 100644
index 0000000..d6cd4d6
--- /dev/null
+++ b/test/unit/Container/ConnectionInterfaceFactoryFactoryTest.php
@@ -0,0 +1,129 @@
+createMock(ContainerInterface::class);
+ $containerMock->method('get')->willReturnMap([
+ [
+ 'config',
+ [
+ 'db' => [
+ 'adapters' => [
+ 'test_adapter' => [
+ 'driver' => 'sqlite',
+ ],
+ ],
+ ],
+ AdapterManager::class => [
+ 'aliases' => [
+ 'sqlite' => Pdo::class,
+ ],
+ ],
+ ],
+ ],
+ ]);
+
+ $factoryFactory = new ConnectionInterfaceFactoryFactory();
+ $result = $factoryFactory($containerMock, 'test_adapter');
+
+ self::assertIsCallable($result);
+ }
+
+ public function testInvokeReturnsPdoConnectionFactory(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')->willReturnMap([
+ [
+ 'config',
+ [
+ 'db' => [
+ 'adapters' => [
+ 'test_adapter' => [
+ 'driver' => 'sqlite',
+ ],
+ ],
+ ],
+ AdapterManager::class => [
+ 'aliases' => [
+ 'sqlite' => Pdo::class,
+ ],
+ ],
+ ],
+ ],
+ ]);
+
+ $factoryFactory = new ConnectionInterfaceFactoryFactory();
+ $result = $factoryFactory($containerMock, 'test_adapter');
+
+ self::assertInstanceOf(PdoConnectionFactory::class, $result);
+ }
+
+ public function testInvokeThrowsExceptionWhenDriverNotConfigured(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')->willReturnMap([
+ [
+ 'config',
+ [
+ 'db' => [
+ 'adapters' => [
+ 'test_adapter' => [],
+ ],
+ ],
+ ],
+ ],
+ ]);
+
+ $factoryFactory = new ConnectionInterfaceFactoryFactory();
+
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('Named adapter "test_adapter" is not configured with a driver');
+
+ $factoryFactory($containerMock, 'test_adapter');
+ }
+
+ public function testInvokeThrowsExceptionForUnknownDriver(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')->willReturnMap([
+ [
+ 'config',
+ [
+ 'db' => [
+ 'adapters' => [
+ 'test_adapter' => [
+ 'driver' => 'unknown',
+ ],
+ ],
+ ],
+ AdapterManager::class => [
+ 'aliases' => [],
+ ],
+ ],
+ ],
+ ]);
+
+ $factoryFactory = new ConnectionInterfaceFactoryFactory();
+
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('No connection factory found for driver "unknown"');
+
+ $factoryFactory($containerMock, 'test_adapter');
+ }
+}
diff --git a/test/unit/Container/DriverInterfaceFactoryFactoryTest.php b/test/unit/Container/DriverInterfaceFactoryFactoryTest.php
new file mode 100644
index 0000000..efbfe5e
--- /dev/null
+++ b/test/unit/Container/DriverInterfaceFactoryFactoryTest.php
@@ -0,0 +1,136 @@
+createMock(ContainerInterface::class);
+ $containerMock->method('get')->willReturnMap([
+ [
+ 'config',
+ [
+ 'db' => [
+ 'adapters' => [
+ 'test_adapter' => [
+ 'driver' => 'sqlite',
+ ],
+ ],
+ ],
+ AdapterManager::class => [
+ 'aliases' => [
+ 'sqlite' => Pdo::class,
+ ],
+ 'factories' => [
+ Pdo::class => PdoDriverFactory::class,
+ ],
+ ],
+ ],
+ ],
+ ]);
+
+ $factoryFactory = new DriverInterfaceFactoryFactory();
+ $result = $factoryFactory($containerMock, 'test_adapter');
+
+ self::assertIsCallable($result);
+ }
+
+ public function testInvokeReturnsPdoDriverFactory(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')->willReturnMap([
+ [
+ 'config',
+ [
+ 'db' => [
+ 'adapters' => [
+ 'test_adapter' => [
+ 'driver' => 'sqlite',
+ ],
+ ],
+ ],
+ AdapterManager::class => [
+ 'aliases' => [
+ 'sqlite' => Pdo::class,
+ ],
+ 'factories' => [
+ Pdo::class => PdoDriverFactory::class,
+ ],
+ ],
+ ],
+ ],
+ ]);
+
+ $factoryFactory = new DriverInterfaceFactoryFactory();
+ $result = $factoryFactory($containerMock, 'test_adapter');
+
+ self::assertInstanceOf(PdoDriverFactory::class, $result);
+ }
+
+ public function testInvokeThrowsExceptionWhenDriverNotConfigured(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')->willReturnMap([
+ [
+ 'config',
+ [
+ 'db' => [
+ 'adapters' => [
+ 'test_adapter' => [],
+ ],
+ ],
+ ],
+ ],
+ ]);
+
+ $factoryFactory = new DriverInterfaceFactoryFactory();
+
+ $this->expectException(RuntimeException::class);
+ $this->expectExceptionMessage('Named adapter "test_adapter" is not configured with a driver');
+
+ $factoryFactory($containerMock, 'test_adapter');
+ }
+
+ public function testInvokeWithDriverNotInAliases(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')->willReturnMap([
+ [
+ 'config',
+ [
+ 'db' => [
+ 'adapters' => [
+ 'test_adapter' => [
+ 'driver' => Pdo::class,
+ ],
+ ],
+ ],
+ AdapterManager::class => [
+ 'aliases' => [],
+ 'factories' => [
+ Pdo::class => PdoDriverFactory::class,
+ ],
+ ],
+ ],
+ ],
+ ]);
+
+ $factoryFactory = new DriverInterfaceFactoryFactory();
+ $result = $factoryFactory($containerMock, 'test_adapter');
+
+ self::assertInstanceOf(PdoDriverFactory::class, $result);
+ }
+}
diff --git a/test/unit/Container/MetadataInterfaceFactoryTest.php b/test/unit/Container/MetadataInterfaceFactoryTest.php
new file mode 100644
index 0000000..525b84f
--- /dev/null
+++ b/test/unit/Container/MetadataInterfaceFactoryTest.php
@@ -0,0 +1,40 @@
+createMock(PdoDriverInterface::class);
+ $platformMock = $this->createMock(PlatformInterface::class);
+ $platformMock->method('getName')->willReturn('SQLite');
+ $resultSetMock = $this->createMock(ResultSetInterface::class);
+
+ $adapterMock = new Adapter($driverMock, $platformMock, $resultSetMock);
+
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')
+ ->with(AdapterInterface::class)
+ ->willReturn($adapterMock);
+
+ $factory = new MetadataInterfaceFactory();
+ $metadata = $factory($containerMock);
+
+ self::assertInstanceOf(SqliteMetadata::class, $metadata);
+ }
+}
diff --git a/test/unit/Container/PdoConnectionFactoryTest.php b/test/unit/Container/PdoConnectionFactoryTest.php
new file mode 100644
index 0000000..3a5aee7
--- /dev/null
+++ b/test/unit/Container/PdoConnectionFactoryTest.php
@@ -0,0 +1,100 @@
+createMock(ContainerInterface::class);
+ $containerMock->method('get')
+ ->with('config')
+ ->willReturn([
+ 'db' => [
+ 'connection' => [
+ 'dsn' => 'sqlite::memory:',
+ ],
+ ],
+ ]);
+
+ $factory = new PdoConnectionFactory();
+ $connection = $factory($containerMock);
+
+ self::assertInstanceOf(Connection::class, $connection);
+ }
+
+ public function testInvokeWithoutConnectionConfig(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')
+ ->with('config')
+ ->willReturn([
+ 'db' => [],
+ ]);
+
+ $factory = new PdoConnectionFactory();
+ $connection = $factory($containerMock);
+
+ self::assertInstanceOf(Connection::class, $connection);
+ }
+
+ public function testInvokeWithoutDbConfig(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')
+ ->with('config')
+ ->willReturn([]);
+
+ $factory = new PdoConnectionFactory();
+ $connection = $factory($containerMock);
+
+ self::assertInstanceOf(Connection::class, $connection);
+ }
+
+ public function testCreateFromConfigReturnsConnection(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')
+ ->with('config')
+ ->willReturn([
+ 'db' => [
+ 'adapters' => [
+ 'test_adapter' => [
+ 'connection' => [
+ 'dsn' => 'sqlite::memory:',
+ ],
+ ],
+ ],
+ ],
+ ]);
+
+ $connection = PdoConnectionFactory::createFromConfig($containerMock, 'test_adapter');
+
+ self::assertInstanceOf(Connection::class, $connection);
+ }
+
+ public function testCreateFromConfigWithoutAdapterConfig(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')
+ ->with('config')
+ ->willReturn([
+ 'db' => [
+ 'adapters' => [],
+ ],
+ ]);
+
+ $connection = PdoConnectionFactory::createFromConfig($containerMock, 'unknown_adapter');
+
+ self::assertInstanceOf(Connection::class, $connection);
+ }
+}
diff --git a/test/unit/Container/PdoDriverFactoryTest.php b/test/unit/Container/PdoDriverFactoryTest.php
new file mode 100644
index 0000000..f8e2826
--- /dev/null
+++ b/test/unit/Container/PdoDriverFactoryTest.php
@@ -0,0 +1,20 @@
+createMock(ContainerInterface::class);
+
+ $factory = new PdoResultFactory();
+ $result = $factory($containerMock);
+
+ self::assertInstanceOf(Result::class, $result);
+ }
+}
diff --git a/test/unit/Container/PdoStatementFactoryTest.php b/test/unit/Container/PdoStatementFactoryTest.php
new file mode 100644
index 0000000..4cf5309
--- /dev/null
+++ b/test/unit/Container/PdoStatementFactoryTest.php
@@ -0,0 +1,60 @@
+createMock(ContainerInterface::class);
+ $containerMock->method('get')
+ ->with('config')
+ ->willReturn([
+ 'db' => [
+ 'options' => [],
+ ],
+ ]);
+
+ $factory = new PdoStatementFactory();
+ $statement = $factory($containerMock);
+
+ self::assertInstanceOf(Statement::class, $statement);
+ }
+
+ public function testInvokeWithoutOptionsConfig(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')
+ ->with('config')
+ ->willReturn([
+ 'db' => [],
+ ]);
+
+ $factory = new PdoStatementFactory();
+ $statement = $factory($containerMock);
+
+ self::assertInstanceOf(Statement::class, $statement);
+ }
+
+ public function testInvokeWithoutDbConfig(): void
+ {
+ $containerMock = $this->createMock(ContainerInterface::class);
+ $containerMock->method('get')
+ ->with('config')
+ ->willReturn([]);
+
+ $factory = new PdoStatementFactory();
+ $statement = $factory($containerMock);
+
+ self::assertInstanceOf(Statement::class, $statement);
+ }
+}
diff --git a/test/unit/Container/PlatformInterfaceFactoryFactoryTest.php b/test/unit/Container/PlatformInterfaceFactoryFactoryTest.php
new file mode 100644
index 0000000..ec2c0b6
--- /dev/null
+++ b/test/unit/Container/PlatformInterfaceFactoryFactoryTest.php
@@ -0,0 +1,30 @@
+createMock(PdoDriverInterface::class);
+
+ $platform = PlatformInterfaceFactory::fromDriver($driverMock);
+
+ self::assertInstanceOf(Sqlite::class, $platform);
+ }
+}
diff --git a/test/unit/Driver/DatabasePlatformNameTraitTest.php b/test/unit/Driver/DatabasePlatformNameTraitTest.php
new file mode 100644
index 0000000..e49d54e
--- /dev/null
+++ b/test/unit/Driver/DatabasePlatformNameTraitTest.php
@@ -0,0 +1,53 @@
+traitObject = new class {
+ use DatabasePlatformNameTrait;
+ };
+ }
+
+ public function testGetDatabasePlatformNameWithCamelCaseFormat(): void
+ {
+ $result = $this->traitObject->getDatabasePlatformName(DriverInterface::NAME_FORMAT_CAMELCASE);
+
+ self::assertSame('Sqlite', $result);
+ }
+
+ public function testGetDatabasePlatformNameWithNaturalFormat(): void
+ {
+ $result = $this->traitObject->getDatabasePlatformName(DriverInterface::NAME_FORMAT_NATURAL);
+
+ self::assertSame('SQLite', $result);
+ }
+
+ public function testGetDatabasePlatformNameWithInvalidFormatThrowsException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Invalid name format provided');
+
+ $this->traitObject->getDatabasePlatformName('INVALID_FORMAT');
+ }
+
+ public function testGetDatabasePlatformNameDefaultsToCamelCase(): void
+ {
+ $result = $this->traitObject->getDatabasePlatformName();
+
+ self::assertSame('Sqlite', $result);
+ }
+}
diff --git a/test/unit/Driver/Pdo/ConnectionTest.php b/test/unit/Driver/Pdo/ConnectionTest.php
index 3fd2866..6eab1fb 100644
--- a/test/unit/Driver/Pdo/ConnectionTest.php
+++ b/test/unit/Driver/Pdo/ConnectionTest.php
@@ -2,11 +2,10 @@
declare(strict_types=1);
-namespace PhpDbTest\Adapter\Sqlite\Sqlite\Driver\Pdo;
+namespace PhpDbTest\Adapter\Sqlite\Driver\Pdo;
use Exception;
use Override;
-use PhpDb\Adapter\Exception\InvalidConnectionParametersException;
use PhpDb\Adapter\Sqlite\Driver\Pdo\Connection;
use PHPUnit\Framework\Attributes\CoversMethod;
use PHPUnit\Framework\Attributes\Group;
@@ -17,6 +16,8 @@
final class ConnectionTest extends TestCase
{
protected Connection $connection;
+ //protected string $dsn = 'sqlite::memory:';
+ protected string $dsn = 'sqlite::memory:';
/**
* Sets up the fixture, for example, opens a network connection.
@@ -25,7 +26,9 @@ final class ConnectionTest extends TestCase
#[Override]
protected function setUp(): void
{
- $this->connection = new Connection();
+ $this->connection = new Connection([
+ 'dsn' => $this->dsn,
+ ]);
}
/**
@@ -33,7 +36,7 @@ protected function setUp(): void
*/
public function testResource(): void
{
- $this->expectException(InvalidConnectionParametersException::class);
+ $this->expectNotToPerformAssertions();
$this->connection->getResource();
}
@@ -42,23 +45,21 @@ public function testResource(): void
*/
public function testGetDsn(): void
{
- $dsn = "sqlite::memory:";
- $this->connection->setConnectionParameters(['dsn' => $dsn]);
+ $this->connection->setConnectionParameters(['dsn' => $this->dsn]);
try {
$this->connection->connect();
} catch (Exception) {
}
$responseString = $this->connection->getDsn();
- self::assertEquals($dsn, $responseString);
+ self::assertEquals($this->dsn, $responseString);
}
#[Group('2622')]
public function testArrayOfConnectionParametersCreatesCorrectDsn(): void
{
$this->connection->setConnectionParameters([
- 'driver' => 'Pdo_Sqlite',
- 'database' => ':memory',
+ 'dsn' => 'sqlite::memory:',
]);
try {
$this->connection->connect();
@@ -69,23 +70,4 @@ public function testArrayOfConnectionParametersCreatesCorrectDsn(): void
self::assertStringStartsWith('sqlite:', $responseString);
self::assertStringContainsString('memory', $responseString);
}
-
- public function testDblibArrayOfConnectionParametersCreatesCorrectDsn(): void
- {
- $this->connection->setConnectionParameters([
- 'driver' => 'pdo_dblib',
- 'charset' => 'UTF-8',
- 'dbname' => 'foo',
- 'port' => '1433',
- 'version' => '7.3',
- ]);
- try {
- $this->connection->connect();
- } catch (Exception) {
- }
- $responseString = $this->connection->getDsn();
-
- $this->assertStringStartsWith('dblib:', $responseString);
- $this->assertStringContainsString('foo', $responseString);
- }
}
diff --git a/test/unit/Driver/Pdo/ConnectionTransactionsTest.php b/test/unit/Driver/Pdo/ConnectionTransactionsTest.php
deleted file mode 100644
index 9980060..0000000
--- a/test/unit/Driver/Pdo/ConnectionTransactionsTest.php
+++ /dev/null
@@ -1,161 +0,0 @@
-wrapper = new ConnectionWrapper();
- }
-
- public function testBeginTransactionReturnsInstanceOfConnection(): void
- {
- self::assertInstanceOf(Connection::class, $this->wrapper->beginTransaction());
- }
-
- public function testBeginTransactionSetsInTransactionAtTrue(): void
- {
- $this->wrapper->beginTransaction();
- self::assertTrue($this->wrapper->inTransaction());
- }
-
- public function testCommitReturnsInstanceOfConnection(): void
- {
- $this->wrapper->beginTransaction();
- self::assertInstanceOf(Connection::class, $this->wrapper->commit());
- }
-
- public function testCommitSetsInTransactionAtFalse(): void
- {
- $this->wrapper->beginTransaction();
- $this->wrapper->commit();
- self::assertFalse($this->wrapper->inTransaction());
- }
-
- /**
- * Standalone commit after a SET autocommit=0;
- */
- public function testCommitWithoutBeginReturnsInstanceOfConnection(): void
- {
- self::assertInstanceOf(Connection::class, $this->wrapper->commit());
- }
-
- public function testNestedTransactionsCommit(): void
- {
- $nested = 0;
-
- self::assertFalse($this->wrapper->inTransaction());
-
- // 1st transaction
- $this->wrapper->beginTransaction();
- self::assertTrue($this->wrapper->inTransaction());
- self::assertSame(++$nested, $this->wrapper->getNestedTransactionsCount());
-
- // 2nd transaction
- $this->wrapper->beginTransaction();
- self::assertTrue($this->wrapper->inTransaction());
- self::assertSame(++$nested, $this->wrapper->getNestedTransactionsCount());
-
- // 1st commit
- $this->wrapper->commit();
- self::assertTrue($this->wrapper->inTransaction());
- self::assertSame(--$nested, $this->wrapper->getNestedTransactionsCount());
-
- // 2nd commit
- $this->wrapper->commit();
- self::assertFalse($this->wrapper->inTransaction());
- self::assertSame(--$nested, $this->wrapper->getNestedTransactionsCount());
- }
-
- public function testNestedTransactionsRollback(): void
- {
- $nested = 0;
-
- self::assertFalse($this->wrapper->inTransaction());
-
- // 1st transaction
- $this->wrapper->beginTransaction();
- self::assertTrue($this->wrapper->inTransaction());
- self::assertSame(++$nested, $this->wrapper->getNestedTransactionsCount());
-
- // 2nd transaction
- $this->wrapper->beginTransaction();
- self::assertTrue($this->wrapper->inTransaction());
- self::assertSame(++$nested, $this->wrapper->getNestedTransactionsCount());
-
- // Rollback
- $this->wrapper->rollback();
- self::assertFalse($this->wrapper->inTransaction());
- self::assertSame(0, $this->wrapper->getNestedTransactionsCount());
- }
-
- public function testRollbackDisconnectedThrowsException(): void
- {
- $this->wrapper->disconnect();
-
- $this->expectException(RuntimeException::class);
- $this->expectExceptionMessage('Must be connected before you can rollback');
- $this->wrapper->rollback();
- }
-
- public function testRollbackReturnsInstanceOfConnection(): void
- {
- $this->wrapper->beginTransaction();
- self::assertInstanceOf(Connection::class, $this->wrapper->rollback());
- }
-
- public function testRollbackSetsInTransactionAtFalse(): void
- {
- $this->wrapper->beginTransaction();
- $this->wrapper->rollback();
- self::assertFalse($this->wrapper->inTransaction());
- }
-
- public function testRollbackWithoutBeginThrowsException(): void
- {
- $this->expectException(RuntimeException::class);
- $this->expectExceptionMessage('Must call beginTransaction() before you can rollback');
- $this->wrapper->rollback();
- }
-
- /**
- * Standalone commit after a SET autocommit=0;
- */
- public function testStandaloneCommit(): void
- {
- self::assertFalse($this->wrapper->inTransaction());
- self::assertSame(0, $this->wrapper->getNestedTransactionsCount());
-
- $this->wrapper->commit();
-
- self::assertFalse($this->wrapper->inTransaction());
- self::assertSame(0, $this->wrapper->getNestedTransactionsCount());
- }
-}
diff --git a/test/unit/Driver/Pdo/Feature/SqliteRowCounterTest.php b/test/unit/Driver/Pdo/Feature/SqliteRowCounterTest.php
new file mode 100644
index 0000000..97bb156
--- /dev/null
+++ b/test/unit/Driver/Pdo/Feature/SqliteRowCounterTest.php
@@ -0,0 +1,25 @@
+rowCounter = new SqliteRowCounter();
+ }
+
+ public function testRowCounterExists(): void
+ {
+ self::assertInstanceOf(SqliteRowCounter::class, $this->rowCounter);
+ }
+}
diff --git a/test/unit/Driver/Pdo/PdoTest.php b/test/unit/Driver/Pdo/PdoTest.php
index 97f7259..0237612 100644
--- a/test/unit/Driver/Pdo/PdoTest.php
+++ b/test/unit/Driver/Pdo/PdoTest.php
@@ -2,10 +2,9 @@
declare(strict_types=1);
-namespace PhpDbTest\Adapter\Sqlite\Sqlite\Driver\Pdo;
+namespace PhpDbTest\Adapter\Sqlite\Driver\Pdo;
use Override;
-use PhpDb\Adapter\Driver\Pdo\Result;
use PhpDb\Adapter\Driver\PdoDriverAwareInterface;
use PhpDb\Adapter\Driver\PdoDriverInterface;
use PhpDb\Adapter\Driver\ResultInterface;
@@ -18,7 +17,6 @@
use PHPUnit\Framework\TestCase;
#[CoversMethod(Pdo::class, 'getDatabasePlatformName')]
-#[CoversMethod(Pdo::class, 'getResultPrototype')]
final class PdoTest extends TestCase
{
protected Pdo $pdo;
@@ -30,7 +28,7 @@ final class PdoTest extends TestCase
#[Override]
protected function setUp(): void
{
- $connection = new Connection();
+ $connection = new Connection(['dsn' => ':memory:']);
/** @var StatementInterface&PdoDriverAwareInterface $statementPrototype */
$statementPrototype = $this->createMockForIntersectionOfInterfaces([
@@ -94,11 +92,4 @@ public function testFormatParameterNameWithInvalidCharacters(string $name): void
$this->expectException(RuntimeException::class);
$this->pdo->formatParameterName($name);
}
-
- public function testGetResultPrototype(): void
- {
- $resultPrototype = $this->pdo->getResultPrototype();
-
- self::assertInstanceOf(Result::class, $resultPrototype);
- }
}
diff --git a/test/unit/Driver/Pdo/ResultTest.php b/test/unit/Driver/Pdo/ResultTest.php
deleted file mode 100644
index bc0d1e6..0000000
--- a/test/unit/Driver/Pdo/ResultTest.php
+++ /dev/null
@@ -1,109 +0,0 @@
-getMockBuilder(PDOStatement::class)->getMock();
- $stub->expects($this->any())
- ->method('fetch')
- ->willReturnCallback(fn() => uniqid());
-
- $result = new Result();
- $result->initialize($stub, null);
-
- self::assertEquals($result->current(), $result->current());
- }
-
- public function testFetchModeException(): void
- {
- $result = new Result();
-
- $this->expectException(InvalidArgumentException::class);
- $result->setFetchMode(13);
- }
-
- /**
- * Tests whether the fetch mode was set properly and
- */
- public function testFetchModeAnonymousObject(): void
- {
- $stub = $this->getMockBuilder(PDOStatement::class)->getMock();
- $stub->expects($this->any())
- ->method('fetch')
- ->willReturnCallback(fn() => new stdClass());
-
- $result = new Result();
- $result->initialize($stub, null);
- $result->setFetchMode(PDO::FETCH_OBJ);
-
- self::assertEquals(5, $result->getFetchMode());
- self::assertInstanceOf(stdClass::class, $result->current());
- }
-
- /**
- * Tests whether the fetch mode has a broader range
- */
- public function testFetchModeRange(): void
- {
- $stub = $this->getMockBuilder(PDOStatement::class)->getMock();
- $stub->expects($this->any())
- ->method('fetch')
- ->willReturnCallback(fn() => new stdClass());
- $result = new Result();
- $result->initialize($stub, null);
- $result->setFetchMode(PDO::FETCH_NAMED);
- self::assertEquals(11, $result->getFetchMode());
- self::assertInstanceOf(stdClass::class, $result->current());
- }
-
- public function testMultipleRewind(): void
- {
- $data = [
- ['test' => 1],
- ['test' => 2],
- ];
- $position = 0;
-
- $stub = $this->getMockBuilder(PDOStatement::class)->getMock();
- $stub->expects($this->any())
- ->method('fetch')
- ->willReturnCallback(function () use ($data, &$position) {
- return $data[$position++];
- });
- $result = new Result();
- $result->initialize($stub, null);
-
- $result->rewind();
- $result->rewind();
-
- $this->assertEquals(0, $result->key());
- $this->assertEquals(1, $position);
- $this->assertEquals($data[0], $result->current());
-
- $result->next();
- $this->assertEquals(1, $result->key());
- $this->assertEquals(2, $position);
- $this->assertEquals($data[1], $result->current());
- }
-}
diff --git a/test/unit/Driver/Pdo/StatementTest.php b/test/unit/Driver/Pdo/StatementTest.php
deleted file mode 100644
index b107854..0000000
--- a/test/unit/Driver/Pdo/StatementTest.php
+++ /dev/null
@@ -1,84 +0,0 @@
-statement,
- $this->statement->setDriver(
- (new PdoDriverFactory())->__invoke(
- $this->createMock(ContainerInterface::class)
- )
- )
- );
- }
-
- public function testSetParameterContainer(): void
- {
- self::assertSame($this->statement, $this->statement->setParameterContainer(new ParameterContainer()));
- }
-
- /**
- * @todo Implement testGetParameterContainer().
- */
- public function testGetParameterContainer(): void
- {
- $container = new ParameterContainer();
- $this->statement->setParameterContainer($container);
- self::assertSame($container, $this->statement->getParameterContainer());
- }
-
- public function testSetSql(): void
- {
- $this->statement->setSql('SELECT 1');
- self::assertEquals('SELECT 1', $this->statement->getSql());
- }
-
- public function testGetSql(): void
- {
- $this->statement->setSql('SELECT 1');
- self::assertEquals('SELECT 1', $this->statement->getSql());
- }
-
- /**
- * Sets up the fixture, for example, opens a network connection.
- * This method is called before a test is executed.
- */
- #[Override]
- protected function setUp(): void
- {
- $this->statement = new Statement();
- }
-
- /**
- * Tears down the fixture, for example, closes a network connection.
- * This method is called after a test is executed.
- */
- protected function tearDown(): void
- {
- }
-}
diff --git a/test/unit/Platform/SqliteTest.php b/test/unit/Platform/SqliteTest.php
index ee491ef..90299e9 100644
--- a/test/unit/Platform/SqliteTest.php
+++ b/test/unit/Platform/SqliteTest.php
@@ -1,47 +1,69 @@
platform = new Sqlite(new PDO(
- dsn: "sqlite::memory:mydb.sqlite",
- ));
+ $pdoMock = $this->createMock(PDO::class);
+ $this->platform = new Sqlite($pdoMock);
+ }
+
+ public function testGetNameReturnsSqlite(): void
+ {
+ $pdoMock = $this->createMock(PDO::class);
+ $platform = new Sqlite($pdoMock);
+
+ self::assertSame('SQLite', $platform->getName());
+ }
+
+ public function testPlatformNameConstant(): void
+ {
+ self::assertSame('SQLite', Sqlite::PLATFORM_NAME);
+ }
+
+ public function testConstructWithPdo(): void
+ {
+ $pdoMock = $this->createMock(PDO::class);
+ $platform = new Sqlite($pdoMock);
+
+ self::assertInstanceOf(Sqlite::class, $platform);
+ }
+
+ public function testConstructWithPdoDriver(): void
+ {
+ $driverMock = $this->createMock(PdoDriverInterface::class);
+ $platform = new Sqlite($driverMock);
+
+ self::assertInstanceOf(Sqlite::class, $platform);
+ }
+
+ public function testGetSqlPlatformDecorator(): void
+ {
+ $pdoMock = $this->createMock(PDO::class);
+ $platform = new Sqlite($pdoMock);
+
+ $decorator = $platform->getSqlPlatformDecorator();
+
+ self::assertInstanceOf(SqlPlatformDecorator::class, $decorator);
}
public function testGetName(): void
@@ -75,9 +97,6 @@ public function testQuoteValueRaisesNoticeWithoutPlatformSupport(): void
{
$raisedNotice = false;
- /**
- * @psalm-suppress InvalidArgument
- */
set_error_handler(function (int $errno, string $errstr) use (&$raisedNotice) {
$this->assertEquals(E_USER_NOTICE, $errno);
$this->assertEquals(
@@ -183,28 +202,4 @@ public function testQuoteIdentifierInFragment(): void
)
);
}
-
- public function testCanCloseConnectionAfterQuoteValue(): void
- {
- // Creating the SQLite database file
- $filePath = __DIR__ . "/_files/sqlite.db";
- if (! file_exists($filePath)) {
- touch($filePath);
- }
-
- $driver = (new PdoDriverFactory())->__invoke(
- $this->createMock(ContainerInterface::class)
- );
-
- $this->platform->setDriver($driver);
- $this->platform->quoteValue("some; random]/ value");
- $this->platform->quoteTrustedValue("some; random]/ value");
-
- // Closing the connection so we can delete the file
- $driver->getConnection()->disconnect();
-
- @unlink($filePath);
-
- self::assertFileDoesNotExist($filePath);
- }
}
diff --git a/test/unit/Platform/_files/.gitignore b/test/unit/Platform/_files/.gitignore
deleted file mode 100644
index c96a04f..0000000
--- a/test/unit/Platform/_files/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-!.gitignore
\ No newline at end of file
diff --git a/test/unit/Sql/Platform/Ddl/AlterTableDecoratorTest.php b/test/unit/Sql/Platform/Ddl/AlterTableDecoratorTest.php
new file mode 100644
index 0000000..331c66d
--- /dev/null
+++ b/test/unit/Sql/Platform/Ddl/AlterTableDecoratorTest.php
@@ -0,0 +1,252 @@
+decorator = new AlterTableDecorator();
+ }
+
+ public function testSetSubject(): void
+ {
+ $alterTable = new AlterTable('test_table');
+ $result = $this->decorator->setSubject($alterTable);
+
+ self::assertSame($this->decorator, $result);
+
+ $reflection = new ReflectionClass($this->decorator);
+ $subjectProperty = $reflection->getProperty('subject');
+ $subject = $subjectProperty->getValue($this->decorator);
+
+ self::assertSame($alterTable, $subject);
+ }
+
+ public function testColumnOptionSortOrder(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $sortOrderProperty = $reflection->getProperty('columnOptionSortOrder');
+ $sortOrder = $sortOrderProperty->getValue($this->decorator);
+
+ self::assertIsArray($sortOrder);
+ self::assertArrayHasKey('unsigned', $sortOrder);
+ self::assertArrayHasKey('zerofill', $sortOrder);
+ self::assertArrayHasKey('identity', $sortOrder);
+ self::assertArrayHasKey('serial', $sortOrder);
+ self::assertArrayHasKey('autoincrement', $sortOrder);
+ self::assertArrayHasKey('comment', $sortOrder);
+ self::assertArrayHasKey('columnformat', $sortOrder);
+ self::assertArrayHasKey('format', $sortOrder);
+ self::assertArrayHasKey('storage', $sortOrder);
+ self::assertArrayHasKey('after', $sortOrder);
+ }
+
+ public function testColumnOptionSortOrderIncludesAfter(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $sortOrderProperty = $reflection->getProperty('columnOptionSortOrder');
+ $sortOrder = $sortOrderProperty->getValue($this->decorator);
+
+ self::assertArrayHasKey('after', $sortOrder);
+ self::assertSame(6, $sortOrder['after']);
+ }
+
+ public function testGetSqlInsertOffsets(): void
+ {
+ $sql = 'column_name VARCHAR(255) NOT NULL DEFAULT "test" UNIQUE PRIMARY REFERENCES other_table(id)';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertCount(4, $offsets);
+ self::assertIsInt($offsets[0]);
+ self::assertIsInt($offsets[1]);
+ self::assertIsInt($offsets[2]);
+ self::assertIsInt($offsets[3]);
+ }
+
+ public function testGetSqlInsertOffsetsWithNullKeyword(): void
+ {
+ $sql = 'column_name VARCHAR(255) NULL';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertGreaterThan(0, $offsets[0]);
+ }
+
+ public function testGetSqlInsertOffsetsWithDefaultKeyword(): void
+ {
+ $sql = 'column_name INTEGER DEFAULT 42';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertGreaterThan(0, $offsets[0]);
+ }
+
+ public function testGetSqlInsertOffsetsWithUniqueKeyword(): void
+ {
+ $sql = 'column_name VARCHAR(100) UNIQUE';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertGreaterThan(0, $offsets[1]);
+ }
+
+ public function testGetSqlInsertOffsetsWithPrimaryKeyword(): void
+ {
+ $sql = 'id INTEGER PRIMARY KEY';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertGreaterThan(0, $offsets[1]);
+ }
+
+ public function testGetSqlInsertOffsetsWithReferencesKeyword(): void
+ {
+ $sql = 'user_id INTEGER REFERENCES users(id)';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertGreaterThan(0, $offsets[2]);
+ }
+
+ public function testGetSqlInsertOffsetsWithoutKeywords(): void
+ {
+ $sql = 'column_name VARCHAR(255)';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ $sqlLength = strlen($sql);
+ self::assertSame($sqlLength, $offsets[0]);
+ self::assertSame($sqlLength, $offsets[1]);
+ self::assertSame($sqlLength, $offsets[2]);
+ self::assertSame($sqlLength, $offsets[3]);
+ }
+
+ public function testNormalizeColumnOption(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('normalizeColumnOption');
+
+ self::assertSame('autoincrement', $method->invoke($this->decorator, 'auto-increment'));
+ self::assertSame('autoincrement', $method->invoke($this->decorator, 'auto_increment'));
+ self::assertSame('autoincrement', $method->invoke($this->decorator, 'AUTO INCREMENT'));
+ self::assertSame('columnformat', $method->invoke($this->decorator, 'column-format'));
+ self::assertSame('zerofill', $method->invoke($this->decorator, 'ZERO_FILL'));
+ self::assertSame('after', $method->invoke($this->decorator, 'AFTER'));
+ }
+
+ public function testCompareColumnOptions(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('compareColumnOptions');
+
+ // unsigned (0) should come before zerofill (1)
+ $result = $method->invoke($this->decorator, 'unsigned', 'zerofill');
+ self::assertLessThan(0, $result);
+
+ // zerofill (1) should come before identity (2)
+ $result = $method->invoke($this->decorator, 'zerofill', 'identity');
+ self::assertLessThan(0, $result);
+
+ // identity (2) should come before comment (3)
+ $result = $method->invoke($this->decorator, 'identity', 'comment');
+ self::assertLessThan(0, $result);
+
+ // comment (3) should come before columnformat (4)
+ $result = $method->invoke($this->decorator, 'comment', 'columnformat');
+ self::assertLessThan(0, $result);
+
+ // storage (5) should come before after (6)
+ $result = $method->invoke($this->decorator, 'storage', 'after');
+ self::assertLessThan(0, $result);
+ }
+
+ public function testCompareColumnOptionsWithSameValue(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('compareColumnOptions');
+
+ $result = $method->invoke($this->decorator, 'unsigned', 'unsigned');
+ self::assertSame(0, $result);
+ }
+
+ public function testCompareColumnOptionsWithUnknownOptions(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('compareColumnOptions');
+
+ // Unknown options should be treated equally
+ $result = $method->invoke($this->decorator, 'unknown1', 'unknown2');
+ self::assertSame(0, $result);
+ }
+
+ public function testCompareColumnOptionsKnownVsUnknown(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('compareColumnOptions');
+
+ // Known option should come before unknown option
+ $result = $method->invoke($this->decorator, 'unsigned', 'unknown');
+ self::assertLessThan(0, $result);
+
+ // Unknown option should come after known option
+ $result = $method->invoke($this->decorator, 'unknown', 'unsigned');
+ self::assertGreaterThan(0, $result);
+ }
+
+ public function testCompareColumnOptionsAfterIsLast(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('compareColumnOptions');
+
+ // 'after' should come after 'storage'
+ $result = $method->invoke($this->decorator, 'storage', 'after');
+ self::assertLessThan(0, $result);
+
+ // 'after' should come after 'comment'
+ $result = $method->invoke($this->decorator, 'comment', 'after');
+ self::assertLessThan(0, $result);
+ }
+}
diff --git a/test/unit/Sql/Platform/Ddl/CreateTableDecoratorTest.php b/test/unit/Sql/Platform/Ddl/CreateTableDecoratorTest.php
new file mode 100644
index 0000000..96a3323
--- /dev/null
+++ b/test/unit/Sql/Platform/Ddl/CreateTableDecoratorTest.php
@@ -0,0 +1,226 @@
+decorator = new CreateTableDecorator();
+ }
+
+ public function testSetSubject(): void
+ {
+ $createTable = new CreateTable('test_table');
+ $result = $this->decorator->setSubject($createTable);
+
+ self::assertSame($this->decorator, $result);
+
+ $reflection = new ReflectionClass($this->decorator);
+ $subjectProperty = $reflection->getProperty('subject');
+ $subject = $subjectProperty->getValue($this->decorator);
+
+ self::assertSame($createTable, $subject);
+ }
+
+ public function testColumnOptionSortOrder(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $sortOrderProperty = $reflection->getProperty('columnOptionSortOrder');
+ $sortOrder = $sortOrderProperty->getValue($this->decorator);
+
+ self::assertIsArray($sortOrder);
+ self::assertArrayHasKey('unsigned', $sortOrder);
+ self::assertArrayHasKey('zerofill', $sortOrder);
+ self::assertArrayHasKey('identity', $sortOrder);
+ self::assertArrayHasKey('serial', $sortOrder);
+ self::assertArrayHasKey('autoincrement', $sortOrder);
+ self::assertArrayHasKey('comment', $sortOrder);
+ self::assertArrayHasKey('columnformat', $sortOrder);
+ self::assertArrayHasKey('format', $sortOrder);
+ self::assertArrayHasKey('storage', $sortOrder);
+ }
+
+ public function testGetSqlInsertOffsets(): void
+ {
+ $sql = 'column_name VARCHAR(255) NOT NULL DEFAULT "test" UNIQUE PRIMARY REFERENCES other_table(id)';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertCount(4, $offsets);
+ self::assertIsInt($offsets[0]);
+ self::assertIsInt($offsets[1]);
+ self::assertIsInt($offsets[2]);
+ self::assertIsInt($offsets[3]);
+ }
+
+ public function testGetSqlInsertOffsetsWithNullKeyword(): void
+ {
+ $sql = 'column_name VARCHAR(255) NULL';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertGreaterThan(0, $offsets[0]);
+ }
+
+ public function testGetSqlInsertOffsetsWithDefaultKeyword(): void
+ {
+ $sql = 'column_name INTEGER DEFAULT 42';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertGreaterThan(0, $offsets[0]);
+ }
+
+ public function testGetSqlInsertOffsetsWithUniqueKeyword(): void
+ {
+ $sql = 'column_name VARCHAR(100) UNIQUE';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertGreaterThan(0, $offsets[1]);
+ }
+
+ public function testGetSqlInsertOffsetsWithPrimaryKeyword(): void
+ {
+ $sql = 'id INTEGER PRIMARY KEY';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertGreaterThan(0, $offsets[1]);
+ }
+
+ public function testGetSqlInsertOffsetsWithReferencesKeyword(): void
+ {
+ $sql = 'user_id INTEGER REFERENCES users(id)';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ self::assertGreaterThan(0, $offsets[2]);
+ }
+
+ public function testGetSqlInsertOffsetsWithoutKeywords(): void
+ {
+ $sql = 'column_name VARCHAR(255)';
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('getSqlInsertOffsets');
+
+ $offsets = $method->invoke($this->decorator, $sql);
+
+ self::assertIsArray($offsets);
+ $sqlLength = strlen($sql);
+ self::assertSame($sqlLength, $offsets[0]);
+ self::assertSame($sqlLength, $offsets[1]);
+ self::assertSame($sqlLength, $offsets[2]);
+ self::assertSame($sqlLength, $offsets[3]);
+ }
+
+ public function testNormalizeColumnOption(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('normalizeColumnOption');
+
+ self::assertSame('autoincrement', $method->invoke($this->decorator, 'auto-increment'));
+ self::assertSame('autoincrement', $method->invoke($this->decorator, 'auto_increment'));
+ self::assertSame('autoincrement', $method->invoke($this->decorator, 'AUTO INCREMENT'));
+ self::assertSame('columnformat', $method->invoke($this->decorator, 'column-format'));
+ self::assertSame('zerofill', $method->invoke($this->decorator, 'ZERO_FILL'));
+ }
+
+ public function testCompareColumnOptions(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('compareColumnOptions');
+
+ // unsigned (0) should come before zerofill (1)
+ $result = $method->invoke($this->decorator, 'unsigned', 'zerofill');
+ self::assertLessThan(0, $result);
+
+ // zerofill (1) should come before identity (2)
+ $result = $method->invoke($this->decorator, 'zerofill', 'identity');
+ self::assertLessThan(0, $result);
+
+ // identity (2) should come before comment (3)
+ $result = $method->invoke($this->decorator, 'identity', 'comment');
+ self::assertLessThan(0, $result);
+
+ // comment (3) should come before columnformat (4)
+ $result = $method->invoke($this->decorator, 'comment', 'columnformat');
+ self::assertLessThan(0, $result);
+
+ // storage (5) should come after format (4)
+ $result = $method->invoke($this->decorator, 'format', 'storage');
+ self::assertLessThan(0, $result);
+ }
+
+ public function testCompareColumnOptionsWithSameValue(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('compareColumnOptions');
+
+ $result = $method->invoke($this->decorator, 'unsigned', 'unsigned');
+ self::assertSame(0, $result);
+ }
+
+ public function testCompareColumnOptionsWithUnknownOptions(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('compareColumnOptions');
+
+ // Unknown options should be treated equally
+ $result = $method->invoke($this->decorator, 'unknown1', 'unknown2');
+ self::assertSame(0, $result);
+ }
+
+ public function testCompareColumnOptionsKnownVsUnknown(): void
+ {
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('compareColumnOptions');
+
+ // Known option should come before unknown option
+ $result = $method->invoke($this->decorator, 'unsigned', 'unknown');
+ self::assertLessThan(0, $result);
+
+ // Unknown option should come after known option
+ $result = $method->invoke($this->decorator, 'unknown', 'unsigned');
+ self::assertGreaterThan(0, $result);
+ }
+}
diff --git a/test/unit/Sql/Platform/SelectDecoratorTest.php b/test/unit/Sql/Platform/SelectDecoratorTest.php
index a0fd91b..309d7ce 100644
--- a/test/unit/Sql/Platform/SelectDecoratorTest.php
+++ b/test/unit/Sql/Platform/SelectDecoratorTest.php
@@ -4,189 +4,152 @@
namespace PhpDbTest\Adapter\Sqlite\Sql\Platform;
-use PhpDb\Adapter\AdapterInterface;
use PhpDb\Adapter\Driver\DriverInterface;
-use PhpDb\Adapter\Driver\PdoDriverInterface;
-use PhpDb\Adapter\Driver\StatementInterface;
use PhpDb\Adapter\ParameterContainer;
-use PhpDb\Adapter\Sqlite\Platform\Sqlite as SqlitePlatform;
+use PhpDb\Adapter\Platform\PlatformInterface;
use PhpDb\Adapter\Sqlite\Sql\Platform\SelectDecorator;
-use PhpDb\Sql\Expression;
use PhpDb\Sql\Select;
use PHPUnit\Framework\Attributes\CoversClass;
-use PHPUnit\Framework\Attributes\DataProvider;
-use PHPUnit\Framework\Attributes\TestDox;
-use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
+use ReflectionClass;
#[CoversClass(SelectDecorator::class)]
final class SelectDecoratorTest extends TestCase
{
- protected SqlitePlatform&MockObject $platform;
- protected PdoDriverInterface&MockObject $driver;
+ private SelectDecorator $decorator;
protected function setUp(): void
{
- $this->driver = $this->getMockBuilder(PdoDriverInterface::class)
- ->getMock();
+ $this->decorator = new SelectDecorator();
+ }
+
+ public function testSetSubject(): void
+ {
+ $select = new Select();
+ $result = $this->decorator->setSubject($select);
+
+ self::assertSame($this->decorator, $result);
- $this->platform = $this->getMockBuilder(SqlitePlatform::class)
- ->onlyMethods([])
- ->setConstructorArgs([$this->driver])
- ->getMock();
+ $reflection = new ReflectionClass($this->decorator);
+ $subjectProperty = $reflection->getProperty('subject');
+ $subject = $subjectProperty->getValue($this->decorator);
- parent::setUp();
+ self::assertSame($select, $subject);
}
- public function testLimitAndOffset(): void
+ public function testProcessLimitWithoutLimitAndWithoutOffset(): void
{
- $select = new Select();
- $select->offset(5);
- $selectDecorator = new SelectDecorator();
- $selectDecorator->setSubject($select);
- $sqlString = $selectDecorator->getSqlString($this->platform);
- self::assertEquals('SELECT * LIMIT 18446744073709551615 OFFSET 5', $sqlString);
+ $platformMock = $this->createMock(PlatformInterface::class);
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('processLimit');
+
+ $result = $method->invoke($this->decorator, $platformMock);
+
+ self::assertNull($result);
}
- #[DataProvider('dataProviderUnionSyntaxFromCombine')]
- #[TestDox('integration test: Testing SelectDecorator will use Select an internal state to prepare a proper combine
-statement')]
- public function testPrepareStatementPreparesUnionSyntaxFromCombine(
- Select $select,
- string $expectedSql,
- array $expectedParams
- ): void {
- $driver = $this->getMockBuilder(DriverInterface::class)->getMock();
- $driver->expects($this->any())->method('formatParameterName')->willReturn('?');
-
- // test
- $adapter = $this->getMockBuilder(AdapterInterface::class)
- ->onlyMethods([])
- ->setConstructorArgs([
- $driver,
- $this->platform,
- ])
- ->getMock();
+ public function testProcessLimitWithLimit(): void
+ {
+ $this->decorator->limit(10);
- $parameterContainer = new ParameterContainer();
- $statement = $this->getMockBuilder(StatementInterface::class)->getMock();
- $statement->expects($this->any())->method('getParameterContainer')
- ->willReturn($parameterContainer);
+ $platformMock = $this->createMock(PlatformInterface::class);
- $statement->expects($this->once())->method('setSql')->with($expectedSql);
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('processLimit');
- $selectDecorator = new SelectDecorator();
- $selectDecorator->setSubject($select);
- $selectDecorator->prepareStatement($adapter, $statement);
+ $result = $method->invoke($this->decorator, $platformMock);
- self::assertEquals($expectedParams, $parameterContainer->getNamedArray());
+ self::assertSame([10], $result);
}
- #[DataProvider('dataProviderUnionSyntaxFromCombine')]
- #[TestDox('integration test: Testing SelectDecorator will use Select an internal state to prepare a proper combine
-statement')]
- public function testGetSqlStringPreparesUnionSyntaxFromCombine(
- Select $select,
- string $expectedSql
- ): void {
+ public function testProcessLimitWithLimitAndParameterContainer(): void
+ {
+ $this->decorator->limit(15);
+
+ $platformMock = $this->createMock(PlatformInterface::class);
+ $driverMock = $this->createMock(DriverInterface::class);
+ $driverMock->expects(self::once())
+ ->method('formatParameterName')
+ ->with('limit')
+ ->willReturn(':limit');
+
$parameterContainer = new ParameterContainer();
- $statement = $this->getMockBuilder(StatementInterface::class)->getMock();
- $statement->expects($this->any())->method('getParameterContainer')
- ->willReturn($parameterContainer);
- $selectDecorator = new SelectDecorator();
- $selectDecorator->setSubject($select);
- self::assertEquals($expectedSql, $selectDecorator->getSqlString($this->platform));
+ $reflection = new ReflectionClass($this->decorator);
+ $processInfoProperty = $reflection->getProperty('processInfo');
+ $processInfoProperty->setValue($this->decorator, ['paramPrefix' => '']);
+
+ $method = $reflection->getMethod('processLimit');
+ $result = $method->invoke($this->decorator, $platformMock, $driverMock, $parameterContainer);
+
+ self::assertSame([':limit'], $result);
+ self::assertTrue($parameterContainer->offsetExists('limit'));
+ self::assertSame(15, $parameterContainer->offsetGet('limit'));
+ }
+
+ public function testProcessLimitWithoutLimitButWithOffset(): void
+ {
+ $this->decorator->offset(5);
+
+ $platformMock = $this->createMock(PlatformInterface::class);
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('processLimit');
+
+ $result = $method->invoke($this->decorator, $platformMock);
+
+ self::assertSame([''], $result);
}
- /**
- * Create a data provider for union syntax that would come from combine
- *
- * @psalm-return array,
- * 3: string
- * }>
- */
- public static function dataProviderUnionSyntaxFromCombine(): array
+ public function testProcessOffsetWithoutOffset(): void
{
- $select0 = new Select();
- $select0->from('foo');
- $select1 = clone $select0;
- $select0->combine($select1);
-
- $expectedPrepareSql0 = '( SELECT "foo".* FROM "foo" ) UNION ( SELECT "foo".* FROM "foo" )';
- $expectedParams0 = [];
- $expectedSql0 = '( SELECT "foo".* FROM "foo" ) UNION ( SELECT "foo".* FROM "foo" )';
-
- // nested single limit & offset in field param
- $nestedSelect0 = new Select();
- $nestedSelect0->from('foo1')
- ->columns([
- 'cnt' => new Expression('count(foo1.id)'),
- ])->limit(100)->offset(500);
-
- $select3 = new Select();
- $select3->from('foo')
- ->columns([
- 'res' => $nestedSelect0,
- ])
- ->limit(10)->offset(50);
-
- $expectedPrepareSql3 =
- 'SELECT (SELECT count(foo1.id) AS "cnt" FROM "foo1" LIMIT ? OFFSET ?) AS "res"'
- . ' FROM "foo" LIMIT ? OFFSET ?';
- $expectedParams3 = [
- 'subselect1limit' => 100,
- 'subselect1offset' => 500,
- 'limit' => 10,
- 'offset' => 50,
- ];
- $expectedSql3 = 'SELECT (SELECT count(foo1.id) AS "cnt"'
- . ' FROM "foo1" LIMIT 100 OFFSET 500) AS "res"'
- . ' FROM "foo" LIMIT 10 OFFSET 50';
- // multiple nested query
- $nestedSelect0 = new Select();
- $nestedSelect0->from('foo1')
- ->columns([
- 'cnt' => new Expression('count(foo1.id)'),
- ])->limit(100)->offset(500);
-
- $nestedSelect1 = new Select();
- $nestedSelect1->from('foo2')
- ->columns([
- 'cnt' => new Expression('count(foo2.id)'),
- ])->limit(50)->offset(101);
-
- $select4 = new Select();
- $select4->from('foo')
- ->columns([
- 'res' => $nestedSelect0,
- 'res0' => $nestedSelect1,
- ])
- ->limit(10)->offset(5);
-
- $expectedPrepareSql4 =
- 'SELECT (SELECT count(foo1.id) AS "cnt" FROM "foo1" LIMIT ? OFFSET ?) AS "res",'
- . ' (SELECT count(foo2.id) AS "cnt" FROM "foo2" LIMIT ? OFFSET ?) AS "res0"'
- . ' FROM "foo" LIMIT ? OFFSET ?';
- $expectedParams4 = [
- 'subselect1limit' => 100,
- 'subselect1offset' => 500,
- 'subselect2limit' => 50,
- 'subselect2offset' => 101,
- 'limit' => 10,
- 'offset' => 5,
- ];
- $expectedSql4 = 'SELECT (SELECT count(foo1.id) AS "cnt" FROM "foo1" LIMIT 100 OFFSET 500) AS "res",'
- . ' (SELECT count(foo2.id) AS "cnt" FROM "foo2" LIMIT 50 OFFSET 101) AS "res0"'
- . ' FROM "foo" LIMIT 10 OFFSET 5';
-
- return [
- [$select0, $expectedPrepareSql0, $expectedParams0, $expectedSql0],
- [$select3, $expectedPrepareSql3, $expectedParams3, $expectedSql3],
- [$select4, $expectedPrepareSql4, $expectedParams4, $expectedSql4],
- ];
+ $platformMock = $this->createMock(PlatformInterface::class);
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('processOffset');
+
+ $result = $method->invoke($this->decorator, $platformMock);
+
+ self::assertNull($result);
+ }
+
+ public function testProcessOffsetWithOffset(): void
+ {
+ $this->decorator->offset(20);
+
+ $platformMock = $this->createMock(PlatformInterface::class);
+
+ $reflection = new ReflectionClass($this->decorator);
+ $method = $reflection->getMethod('processOffset');
+
+ $result = $method->invoke($this->decorator, $platformMock);
+
+ self::assertSame([20], $result);
+ }
+
+ public function testProcessOffsetWithOffsetAndParameterContainer(): void
+ {
+ $this->decorator->offset(25);
+
+ $platformMock = $this->createMock(PlatformInterface::class);
+ $driverMock = $this->createMock(DriverInterface::class);
+ $driverMock->expects(self::once())
+ ->method('formatParameterName')
+ ->with('offset')
+ ->willReturn(':offset');
+
+ $parameterContainer = new ParameterContainer();
+
+ $reflection = new ReflectionClass($this->decorator);
+ $processInfoProperty = $reflection->getProperty('processInfo');
+ $processInfoProperty->setValue($this->decorator, ['paramPrefix' => '']);
+
+ $method = $reflection->getMethod('processOffset');
+ $result = $method->invoke($this->decorator, $platformMock, $driverMock, $parameterContainer);
+
+ self::assertSame([':offset'], $result);
+ self::assertTrue($parameterContainer->offsetExists('offset'));
+ self::assertSame(25, $parameterContainer->offsetGet('offset'));
}
}
diff --git a/test/unit/Sql/Platform/SqliteTest.php b/test/unit/Sql/Platform/SqliteTest.php
index 61feae8..b3676ef 100644
--- a/test/unit/Sql/Platform/SqliteTest.php
+++ b/test/unit/Sql/Platform/SqliteTest.php
@@ -1,29 +1,62 @@
platform = new Sqlite();
+ }
+
+ public function testConstructorSetsTypeDecorators(): void
+ {
+ self::assertInstanceOf(Sqlite::class, $this->platform);
+ }
+
+ public function testSelectDecoratorIsRegistered(): void
+ {
+ $reflection = new ReflectionClass($this->platform);
+ $decoratorsProperty = $reflection->getProperty('decorators');
+ $decorators = $decoratorsProperty->getValue($this->platform);
+
+ self::assertArrayHasKey(Select::class, $decorators);
+ self::assertInstanceOf(SelectDecorator::class, $decorators[Select::class]);
+ }
+
+ public function testCreateTableDecoratorIsRegistered(): void
+ {
+ $reflection = new ReflectionClass($this->platform);
+ $decoratorsProperty = $reflection->getProperty('decorators');
+ $decorators = $decoratorsProperty->getValue($this->platform);
+
+ self::assertArrayHasKey(CreateTable::class, $decorators);
+ self::assertInstanceOf(CreateTableDecorator::class, $decorators[CreateTable::class]);
+ }
+
+ public function testAlterTableDecoratorIsRegistered(): void
{
- $mysql = new Sqlite();
- $decorators = $mysql->getDecorators();
+ $reflection = new ReflectionClass($this->platform);
+ $decoratorsProperty = $reflection->getProperty('decorators');
+ $decorators = $decoratorsProperty->getValue($this->platform);
- $type = key($decorators);
- $decorator = current($decorators);
- self::assertEquals(Select::class, $type);
- self::assertInstanceOf(SelectDecorator::class, $decorator);
+ self::assertArrayHasKey(AlterTable::class, $decorators);
+ self::assertInstanceOf(AlterTableDecorator::class, $decorators[AlterTable::class]);
}
}
diff --git a/test/unit/TestAsset/ConnectionWrapper.php b/test/unit/TestAsset/ConnectionWrapper.php
deleted file mode 100644
index 16547d8..0000000
--- a/test/unit/TestAsset/ConnectionWrapper.php
+++ /dev/null
@@ -1,23 +0,0 @@
-resource = new PdoStubDriver('foo', 'bar', 'baz');
- }
-
- public function getNestedTransactionsCount(): int
- {
- return $this->nestedTransactionsCount;
- }
-}
diff --git a/test/unit/TestAsset/PdoStubDriver.php b/test/unit/TestAsset/PdoStubDriver.php
deleted file mode 100644
index 1979cb2..0000000
--- a/test/unit/TestAsset/PdoStubDriver.php
+++ /dev/null
@@ -1,31 +0,0 @@
-