From 86d3d3fb969965b488b941da39a26cf4bf9fb96f Mon Sep 17 00:00:00 2001 From: Wilfried JOnker Date: Thu, 13 Mar 2025 19:34:34 +0100 Subject: [PATCH] Enable SQLite for Unit Testing and Improve ODBC Compatibility - Added support for running unit tests using SQLite by introducing `mockDb2UsingSqlite` config option. - Refactored DSN handling with a `buildDsn` method for better maintainability. - Fixed issues with ODBC connection handling, improving compatibility with PHP 8.4. - Updated tests to dynamically determine the DSN based on the configuration. This makes it easier to run tests without an IBM i system and allows for automated testing across multiple PHP versions. --- ToolkitApi/Toolkit.php | 4 ++-- UNITTEST.md | 23 +++++++++++++++++++++++ tests/config/db.config.php.dist | 1 + tests/functional/ToolkitTest.php | 25 +++++++++++++++++++++---- 4 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 UNITTEST.md diff --git a/ToolkitApi/Toolkit.php b/ToolkitApi/Toolkit.php index 180bbb9..db1a0ef 100644 --- a/ToolkitApi/Toolkit.php +++ b/ToolkitApi/Toolkit.php @@ -158,7 +158,7 @@ public function __construct($databaseNameOrResource, $userOrI5NamingFlag = '0', } // stop any types that are not valid for first parameter. Invalid values may cause toolkit to try to create another database connection. - if (!is_string($databaseNameOrResource) && !is_resource($databaseNameOrResource) && ((!is_object($databaseNameOrResource) || (is_object($databaseNameOrResource) && get_class($databaseNameOrResource) !== PDO::class)))) { + if (!is_string($databaseNameOrResource) && !is_resource($databaseNameOrResource) && ((!is_object($databaseNameOrResource) || (is_object($databaseNameOrResource) && !in_array(get_class($databaseNameOrResource), [PDO::class, \Odbc\Connection::class], true))))) { // initialize generic message $this->error = "\nFailed to connect. databaseNameOrResource " . var_export($databaseNameOrResource, true) . " not valid."; @@ -224,7 +224,7 @@ public function __construct($databaseNameOrResource, $userOrI5NamingFlag = '0', if ($this->isDebug()) { $this->debugLog("Re-using existing db connection with schema separator: $schemaSep"); } - } elseif ($transportType === 'odbc' && $isResource) { + } elseif ($transportType === 'odbc' && ($isResource || $databaseNameOrResource instanceof \Odbc\Connection)) { $conn = $databaseNameOrResource; $this->_i5NamingFlag = $userOrI5NamingFlag; $schemaSep = ($this->_i5NamingFlag) ? '/' : '.'; diff --git a/UNITTEST.md b/UNITTEST.md new file mode 100644 index 0000000..cb41cfe --- /dev/null +++ b/UNITTEST.md @@ -0,0 +1,23 @@ +### Running Unit Tests with SQLite + +1. **Install dependencies**: + ```sh + composer install + ``` + +2. **Install required packages on Debian**: + ```sh + apt install php-pdo php-pdo-sqlite php-odbc libsqliteodbc sqlite3 + ``` + +3. **Enable SQLite mocking**: + - Open `tests/config/db.config.php` + - Set: + ```php + 'mockDb2UsingSqlite' => true, + ``` + +4. **Run the tests**: + ```sh + vendor/bin/phpunit + ``` \ No newline at end of file diff --git a/tests/config/db.config.php.dist b/tests/config/db.config.php.dist index 59cb4fd..d89c898 100644 --- a/tests/config/db.config.php.dist +++ b/tests/config/db.config.php.dist @@ -1,6 +1,7 @@ [ + 'mockDb2UsingSqlite' => false, 'odbc' => [ 'dsn' => 'DSN=*LOCAL;', 'username' => 'MYUSER', diff --git a/tests/functional/ToolkitTest.php b/tests/functional/ToolkitTest.php index d8e9152..385336c 100644 --- a/tests/functional/ToolkitTest.php +++ b/tests/functional/ToolkitTest.php @@ -21,10 +21,16 @@ final class ToolkitTest extends TestCase */ private $toolkitOptions; + /** + * @var bool + */ + private $mockDb2UsingSqlite; + public function setUp(): void { $config = getConfig(); + $this->mockDb2UsingSqlite = $config['db']['mockDb2UsingSqlite'] ?? false; $this->connectionOptions = $config['db']['odbc']; $this->toolkitOptions = $config['toolkit']; } @@ -35,7 +41,7 @@ public function setUp(): void public function testCanPassPdoOdbcObjectToToolkit() { $pdo = new \PDO( - 'odbc:' . $this->connectionOptions['dsn'], + $this->buildDsn('pdo'), $this->connectionOptions['username'], $this->connectionOptions['password'], [ @@ -44,7 +50,7 @@ public function testCanPassPdoOdbcObjectToToolkit() 'quote_identifiers' => $this->connectionOptions['platform_options']['quote_identifiers'], ] ] - ); +); $toolkit = new Toolkit($pdo, null, null, 'pdo'); $toolkit->setOptions($this->toolkitOptions); @@ -57,7 +63,7 @@ public function testCanPassPdoOdbcObjectToToolkit() */ public function testCanPassOdbcResourceToToolkit() { - $connection = odbc_connect($this->connectionOptions['dsn'], $this->connectionOptions['username'], $this->connectionOptions['password']); + $connection = odbc_connect($this->buildDsn('odbc'), $this->connectionOptions['username'], $this->connectionOptions['password']); if (!$connection) { throw new \Exception('Connection failed'); @@ -74,7 +80,7 @@ public function testCanPassOdbcResourceToToolkit() public function testCanPassOdbcConnectionParametersToToolkit() { $toolkit = new Toolkit( - $this->connectionOptions['dsn'], + $this->buildDsn('odbc'), $this->connectionOptions['username'], $this->connectionOptions['password'], 'odbc' @@ -83,4 +89,15 @@ public function testCanPassOdbcConnectionParametersToToolkit() $this->assertInstanceOf(Toolkit::class, $toolkit); } + + /** + * Builds the appropriate DSN based on configuration. + */ + private function buildDsn(string $type = 'pdo'): string + { + if ($this->mockDb2UsingSqlite) { + return ($type === 'pdo') ? 'sqlite::memory:' : 'Driver=SQLite3;Database=:memory:'; + } + return ($type === 'pdo') ? 'odbc:' . $this->connectionOptions['dsn'] : $this->connectionOptions['dsn']; + } }