From 853ffd0f8df3ede4eeb9f9e2f59f1989b078ff8e Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Fri, 11 Jul 2025 11:24:27 +0200 Subject: [PATCH 01/11] Raise requirements to PHP 8.3, update dependencies --- composer.json | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index a89c35e3..7c8841b5 100644 --- a/composer.json +++ b/composer.json @@ -6,18 +6,18 @@ "homepage": "https://github.com/joomla-framework/database", "license": "GPL-2.0-or-later", "require": { - "php": "^8.1.0", - "joomla/event": "^3.0", + "php": "^8.3.0", + "joomla/event": "dev-4.x-dev", "symfony/deprecation-contracts": "^2|^3" }, "require-dev": { - "joomla/archive": "^3.0", - "joomla/console": "^3.0", - "joomla/di": "^3.0", - "joomla/filesystem": "^3.0", - "joomla/registry": "^3.0", - "joomla/test": "^3.0", - "phpunit/phpunit": "^9.5.28", + "joomla/archive": "dev-4.x-dev", + "joomla/console": "dev-4.x-dev", + "joomla/di": "dev-4.x-dev", + "joomla/filesystem": "dev-4.x-dev", + "joomla/registry": "dev-4.x-dev", + "joomla/test": "dev-4.x-dev", + "phpunit/phpunit": "^12.2.6", "psr/log": "^1.1", "symfony/phpunit-bridge": "^5.0", "squizlabs/php_codesniffer": "~3.7.2", @@ -49,7 +49,8 @@ "extra": { "branch-alias": { "dev-2.0-dev": "2.0-dev", - "dev-3.x-dev": "3.0-dev" + "dev-3.x-dev": "3.0-dev", + "dev-4.x-dev": "4.0-dev" } } } From 569819448c3645309df63c7fe551d478937a877c Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Fri, 11 Jul 2025 11:30:58 +0200 Subject: [PATCH 02/11] Update documentation --- README.md | 8 ++++---- SECURITY.md | 3 ++- docs/index.md | 1 + docs/v2-to-v3-update.md | 12 ++++++++++++ docs/v3-to-v4-update.md | 10 +++++++++- 5 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 docs/v2-to-v3-update.md diff --git a/README.md b/README.md index 0d3cfe2d..2aa1f7ee 100644 --- a/README.md +++ b/README.md @@ -173,12 +173,12 @@ This is the log file: ## Installation via Composer -Add `"joomla/database": "~3.0"` to the require block in your composer.json and then run `composer install`. +Add `"joomla/database": "~4.0"` to the require block in your composer.json and then run `composer install`. ```json { "require": { - "joomla/database": "~3.0" + "joomla/database": "~4.0" } } ``` @@ -186,11 +186,11 @@ Add `"joomla/database": "~3.0"` to the require block in your composer.json and t Alternatively, you can simply run the following from the command line: ```sh -composer require joomla/database "~3.0" +composer require joomla/database "~4.0" ``` If you want to include the test sources, use ```sh -composer require --prefer-source joomla/database "~3.0" +composer require --prefer-source joomla/database "~4.0" ``` diff --git a/SECURITY.md b/SECURITY.md index ed9f30a8..0ea4e4f4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,8 @@ These versions are currently being supported with security updates: | Version | Supported | -| ------- | ------------------ | +|---------| ------------------ | +| 4.x.x | :white_check_mark: | | 3.x.x | :white_check_mark: | | 2.0.x | :white_check_mark: | | 1.8.x | :x: | diff --git a/docs/index.md b/docs/index.md index c716e331..656c20a5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,4 @@ * [Overview](overview.md) * [Updating from v1 to v2](v1-to-v2-update.md) +* [Updating from v2 to v3](v2-to-v3-update.md) * [Updating from v3 to v4](v3-to-v4-update.md) diff --git a/docs/v2-to-v3-update.md b/docs/v2-to-v3-update.md new file mode 100644 index 00000000..214dfe09 --- /dev/null +++ b/docs/v2-to-v3-update.md @@ -0,0 +1,12 @@ +## Updating from v2 to v3 + +The following changes were made to the Database package between v2 and v3. + +### Minimum supported PHP version raised + +All Framework packages now require PHP 8.1 or newer. + +### `DatabaseDriver::getQuery(true)` has been deprecated + +`DatabaseDriver::getQuery()` with the parameter set to `true` returns a new `DatabaseQuery` object, while the unset parameter or set to `false` returns the last query set. +This parameter has been deprecated and will be removed in 5.0. `DatabaseDriver::getQuery()` will only return the last set query in the future and instead you should use `DatabaseDriver::createQuery()`. diff --git a/docs/v3-to-v4-update.md b/docs/v3-to-v4-update.md index 1fecf5c9..d8bcb537 100644 --- a/docs/v3-to-v4-update.md +++ b/docs/v3-to-v4-update.md @@ -4,7 +4,7 @@ The following changes were made to the Database package between v3 and v4. ### Minimum supported PHP version raised -All Framework packages now require PHP 8.1 or newer. +All Framework packages now require PHP 8.3 or newer. ### Minimum supported database versions raised @@ -22,3 +22,11 @@ The deprecated method `quoteNameStr` has been removed. Use `quoteNameString` ins `DatabaseInterface` adds a `createQuery` method for creating query objects. Use `createQuery()` instead of `getQuery(true)`. If you have a custom query class update your adapter's `createQuery()` method to return your custom query class. + +### Removed deprecated `LimitableInterface` and `PreparableInterface` + +The interfaces `Joomla\Database\Query\LimitableInterface` and `Joomla\Database\Query\PreparableInterface` have been removed and its signatures added to the `QueryInterface`. All objects implementing one of these interfaces need to implement the `QueryInterface` instead. + +### Removed deprecated `DatabaseQuery::castAsChar()` + +The deprecated method `DatabaseQuery::castAsChar()` as been removed. Use `$query->castAs('CHAR', $value)` instead. From 8a1de00c639d9feecef21ca9755c2a52ad42ef46 Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Fri, 11 Jul 2025 11:31:26 +0200 Subject: [PATCH 03/11] Remove deprecated interfaces and update QueryInterface --- src/Query/LimitableInterface.php | 61 ------------ src/Query/PreparableInterface.php | 75 --------------- src/QueryInterface.php | 150 +++++++++++++++++++++++++++++- 3 files changed, 147 insertions(+), 139 deletions(-) delete mode 100644 src/Query/LimitableInterface.php delete mode 100644 src/Query/PreparableInterface.php diff --git a/src/Query/LimitableInterface.php b/src/Query/LimitableInterface.php deleted file mode 100644 index 2932b31e..00000000 --- a/src/Query/LimitableInterface.php +++ /dev/null @@ -1,61 +0,0 @@ -setLimit(100, 0); (retrieve 100 rows, starting at first record) - * $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th record) - * - * @param integer $limit The limit for the result set - * @param integer $offset The offset for the result set - * - * @return $this - * - * @since 1.0 - */ - public function setLimit($limit = 0, $offset = 0); -} diff --git a/src/Query/PreparableInterface.php b/src/Query/PreparableInterface.php deleted file mode 100644 index 125d4325..00000000 --- a/src/Query/PreparableInterface.php +++ /dev/null @@ -1,75 +0,0 @@ -innerJoin('b', 'b.id = a.id')->innerJoin('c', 'c.id = b.id'); + * + * @param string $table The name of table. + * @param string $condition The join condition. + * + * @return $this + * + * @since 4.0 + */ + public function innerJoin($table, $condition = null); + + /** + * Add an OUTER JOIN clause to the query. + * + * Usage: + * $query->outerJoin('b', 'b.id = a.id')->leftJoin('c', 'c.id = b.id'); + * + * @param string $table The name of table. + * @param string $condition The join condition. + * + * @return $this + * + * @since 4.0 + */ + public function outerJoin($table, $condition = null); + + /** + * Add a LEFT JOIN clause to the query. + * + * Usage: + * $query->leftJoin('b', 'b.id = a.id')->leftJoin('c', 'c.id = b.id'); + * + * @param string $table The name of table. + * @param string $condition The join condition. + * + * @return $this + * + * @since 4.0 + */ + public function leftJoin($table, $condition = null); + + /** + * Add a RIGHT JOIN clause to the query. + * + * Usage: + * $query->rightJoin('b', 'b.id = a.id')->rightJoin('c', 'c.id = b.id'); + * + * @param string $table The name of table. + * @param string $condition The join condition. + * + * @return $this + * + * @since 4.0 + */ + public function rightJoin($table, $condition = null); + /** * Get the length of a string in bytes. * @@ -537,6 +595,21 @@ public function selectRowNumber($orderBy, $orderColumnAlias); */ public function set($conditions, $glue = ','); + /** + * Allows a direct query to be provided to the database driver's setQuery() method, but still allow queries + * to have bounded variables. + * + * Usage: + * $query->setQuery('select * from #__users'); + * + * @param DatabaseQuery|string $sql A SQL query string or DatabaseQuery object + * + * @return $this + * + * @since 4.0 + */ + public function setQuery($sql); + /** * Add a table name to the UPDATE clause of the query. * @@ -722,4 +795,75 @@ public function querySet($query); * @since 2.0.0 */ public function toQuerySet(); + + /** + * Method to add a variable to an internal array that will be bound to a prepared SQL statement before query execution. + * + * @param array|string|integer $key The key that will be used in your SQL query to reference the value. Usually of + * the form ':key', but can also be an integer. + * @param mixed $value The value that will be bound. It can be an array, in this case it has to be + * same length of $key; The value is passed by reference to support output + * parameters such as those possible with stored procedures. + * @param array|string $dataType Constant corresponding to a SQL datatype. It can be an array, in this case it + * has to be same length of $key + * @param integer $length The length of the variable. Usually required for OUTPUT parameters. + * @param array $driverOptions Optional driver options to be used. + * + * @return $this + * + * @since 4.0 + */ + public function bind($key, &$value, $dataType = ParameterType::STRING, $length = 0, $driverOptions = []); + + /** + * Method to unbind a bound variable. + * + * @param array|string|integer $key The key or array of keys to unbind. + * + * @return $this + * + * @since 4.0.0 + */ + public function unbind($key); + + /** + * Retrieves the bound parameters array when key is null and returns it by reference. If a key is provided then that item is returned. + * + * @param mixed $key The bounded variable key to retrieve. + * + * @return mixed + * + * @since 4.0 + */ + public function &getBounded($key = null); + + /** + * Method to modify a query already in string format with the needed additions to make the query limited to a particular number of + * results, or start at a particular offset. + * + * @param string $query The query in string format + * @param integer $limit The limit for the result set + * @param integer $offset The offset for the result set + * + * @return string + * + * @since 4.0 + */ + public function processLimit($query, $limit, $offset = 0); + + /** + * Sets the offset and limit for the result set, if the database driver supports it. + * + * Usage: + * $query->setLimit(100, 0); (retrieve 100 rows, starting at first record) + * $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th record) + * + * @param integer $limit The limit for the result set + * @param integer $offset The offset for the result set + * + * @return $this + * + * @since 4.0 + */ + public function setLimit($limit = 0, $offset = 0); } From b855c6f5598e0f42dcdd8f87db3ad34866db43ee Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Fri, 11 Jul 2025 11:32:22 +0200 Subject: [PATCH 04/11] Remove deprecated DatabaseQuery::castAsChar() --- src/DatabaseQuery.php | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/DatabaseQuery.php b/src/DatabaseQuery.php index b288c4df..e7866ab5 100644 --- a/src/DatabaseQuery.php +++ b/src/DatabaseQuery.php @@ -558,26 +558,6 @@ public function castAs(string $type, string $value, ?string $length = null) } } - /** - * Casts a value to a char. - * - * Ensure that the value is properly quoted before passing to the method. - * - * Usage: - * $query->select($query->castAsChar('a')); - * - * @param string $value The value to cast as a char. - * - * @return string SQL statement to cast the value as a char type. - * - * @since 1.0 - * @deprecated 3.0 Use $query->castAs('CHAR', $value) - */ - public function castAsChar($value) - { - return $this->castAs('CHAR', $value); - } - /** * Gets the number of characters in a string. * From d20f06d7b5d8e0bc9c72047229c37427be904776 Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Fri, 11 Jul 2025 11:32:44 +0200 Subject: [PATCH 05/11] Update unittests to phpunit 12 --- Tests/DatabaseExporterTest.php | 100 +++++++------- Tests/DatabaseFactoryTest.php | 188 ++++++++++++++++----------- Tests/DatabaseImporterTest.php | 49 ++++--- Tests/DatabaseQueryTest.php | 136 +++++++++---------- Tests/Pgsql/PgsqlQueryTest.php | 8 -- Tests/Query/QueryElementTest.php | 182 +++++++++++++------------- Tests/Sqlsrv/SqlsrvQueryTest.php | 8 -- Tests/Stubs/TestDatabaseExporter.php | 28 ++++ Tests/Stubs/TestDatabaseImporter.php | 32 +++++ Tests/Stubs/TestDatabaseQuery.php | 22 ++++ 10 files changed, 428 insertions(+), 325 deletions(-) create mode 100644 Tests/Stubs/TestDatabaseExporter.php create mode 100644 Tests/Stubs/TestDatabaseImporter.php create mode 100644 Tests/Stubs/TestDatabaseQuery.php diff --git a/Tests/DatabaseExporterTest.php b/Tests/DatabaseExporterTest.php index 3d11e5e3..e2bb22a9 100644 --- a/Tests/DatabaseExporterTest.php +++ b/Tests/DatabaseExporterTest.php @@ -8,8 +8,12 @@ namespace Joomla\Database\Tests; use Joomla\Database\DatabaseExporter; +use Joomla\Database\DatabaseImporter; use Joomla\Database\DatabaseInterface; +use Joomla\Database\Tests\Stubs\TestDatabaseExporter; +use Joomla\Database\Tests\Stubs\TestDatabaseImporter; use Joomla\Test\TestHelper; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -18,21 +22,39 @@ */ class DatabaseExporterTest extends TestCase { + /** + * Importer object + * + * @var DatabaseExporter + */ + private $exporter; + + /** + * Sets up the fixture. + * + * This method is called before a test is executed. + * + * @return void + */ + protected function setUp(): void + { + parent::setUp(); + + $this->exporter = new TestDatabaseExporter(); + } + /** * @testdox The exporter is correctly configured when instantiated */ public function testInstantiation() { - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); - $expected = (object) [ 'withStructure' => true, 'withData' => false, ]; - $this->assertEquals($expected, TestHelper::getValue($exporter, 'options')); - $this->assertSame('xml', TestHelper::getValue($exporter, 'asFormat')); + $this->assertEquals($expected, TestHelper::getValue($this->exporter, 'options')); + $this->assertSame('xml', TestHelper::getValue($this->exporter, 'asFormat')); } /** @@ -40,34 +62,33 @@ public function testInstantiation() */ public function testAsXml() { - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); - - $this->assertSame($exporter, $exporter->asXml(), 'The exporter supports method chaining'); + $this->assertSame($this->exporter, $this->exporter->asXml(), 'The exporter supports method chaining'); - $this->assertSame('xml', TestHelper::getValue($exporter, 'asFormat')); + $this->assertSame('xml', TestHelper::getValue($this->exporter, 'asFormat')); } /** * Data provider for from test cases * - * @return \Generator + * @return array */ - public function dataFrom(): \Generator + public static function dataFrom(): array { - yield 'single table' => [ - '#__dbtest', - false, - ]; - - yield 'multiple tables' => [ - ['#__content', '#__dbtest'], - false, - ]; - - yield 'incorrect table data type' => [ - new \stdClass(), - true, + return [ + 'single table' => [ + '#__dbtest', + false, + ], + + 'multiple tables' => [ + ['#__content', '#__dbtest'], + false, + ], + + 'incorrect table data type' => [ + new \stdClass(), + true, + ], ]; } @@ -76,21 +97,17 @@ public function dataFrom(): \Generator * * @param string[]|string $from The name of a single table, or an array of the table names to export. * @param boolean $shouldRaiseException Flag indicating the exporter should raise an exception for an unsupported data type - * - * @dataProvider dataFrom */ + #[DataProvider('dataFrom')] public function testFrom($from, bool $shouldRaiseException) { if ($shouldRaiseException) { $this->expectException(\InvalidArgumentException::class); } - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); - - $this->assertSame($exporter, $exporter->from($from), 'The exporter supports method chaining'); + $this->assertSame($this->exporter, $this->exporter->from($from), 'The exporter supports method chaining'); - $this->assertSame((array) $from, TestHelper::getValue($exporter, 'from')); + $this->assertSame((array) $from, TestHelper::getValue($this->exporter, 'from')); } /** @@ -98,13 +115,10 @@ public function testFrom($from, bool $shouldRaiseException) */ public function testSetDbo() { - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); - /** @var DatabaseInterface|MockObject $db */ $db = $this->createMock(DatabaseInterface::class); - $this->assertSame($exporter, $exporter->setDbo($db), 'The exporter supports method chaining'); + $this->assertSame($this->exporter, $this->exporter->setDbo($db), 'The exporter supports method chaining'); } /** @@ -112,12 +126,9 @@ public function testSetDbo() */ public function testWithStructure() { - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); + $this->assertSame($this->exporter, $this->exporter->withStructure(false), 'The exporter supports method chaining'); - $this->assertSame($exporter, $exporter->withStructure(false), 'The exporter supports method chaining'); - - $options = TestHelper::getValue($exporter, 'options'); + $options = TestHelper::getValue($this->exporter, 'options'); $this->assertFalse($options->withStructure); } @@ -127,12 +138,9 @@ public function testWithStructure() */ public function testWithData() { - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); - - $this->assertSame($exporter, $exporter->withData(true), 'The exporter supports method chaining'); + $this->assertSame($this->exporter, $this->exporter->withData(true), 'The exporter supports method chaining'); - $options = TestHelper::getValue($exporter, 'options'); + $options = TestHelper::getValue($this->exporter, 'options'); $this->assertTrue($options->withData); } diff --git a/Tests/DatabaseFactoryTest.php b/Tests/DatabaseFactoryTest.php index 17433bef..4fbfd714 100644 --- a/Tests/DatabaseFactoryTest.php +++ b/Tests/DatabaseFactoryTest.php @@ -18,6 +18,7 @@ use Joomla\Database\QueryInterface; use Joomla\Database\StatementInterface; use Joomla\Test\TestHelper; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; /** @@ -49,18 +50,20 @@ protected function setUp(): void /** * Data provider for driver test cases * - * @return \Generator + * @return array */ - public function dataGetDriver(): \Generator + public static function dataGetDriver(): array { - yield 'supported driver' => [ - 'mysqli', - false, - ]; + return [ + 'supported driver' => [ + 'mysqli', + false, + ], - yield 'unsupported exporter' => [ - 'mariadb', - true, + 'unsupported exporter' => [ + 'mariadb', + true, + ], ]; } @@ -69,9 +72,8 @@ public function dataGetDriver(): \Generator * * @param string $adapter The type of adapter to create * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter - * - * @dataProvider dataGetDriver */ + #[DataProvider('dataGetDriver')] public function testGetDriver(string $adapter, bool $shouldRaiseException) { if ($shouldRaiseException) { @@ -87,26 +89,28 @@ public function testGetDriver(string $adapter, bool $shouldRaiseException) /** * Data provider for exporter test cases * - * @return \Generator + * @return array */ - public function dataGetExporter(): \Generator + public static function dataGetExporter(): array { - yield 'exporter without database driver' => [ - 'mysqli', - false, - null, - ]; + return [ + 'exporter without database driver' => [ + 'mysqli', + false, + false, + ], - yield 'exporter with database driver' => [ - 'mysqli', - false, - $this->createMock(MysqliDriver::class), - ]; + 'exporter with database driver' => [ + 'mysqli', + false, + true, + ], - yield 'unsupported exporter' => [ - 'mariadb', - true, - null, + 'unsupported exporter' => [ + 'mariadb', + true, + false, + ], ]; } @@ -116,15 +120,20 @@ public function dataGetExporter(): \Generator * @param string $adapter The type of adapter to create * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter * @param DatabaseDriver|null $databaseDriver The optional database driver to be injected into the exporter - * - * @dataProvider dataGetExporter */ - public function testGetExporter(string $adapter, bool $shouldRaiseException, ?DatabaseDriver $databaseDriver) + #[DataProvider('dataGetExporter')] + public function testGetExporter(string $adapter, bool $shouldRaiseException, bool $createDb) { if ($shouldRaiseException) { $this->expectException(UnsupportedAdapterException::class); } + $databaseDriver = null; + + if ($createDb) { + $databaseDriver = $this->createMock(MysqliDriver::class); + } + $exporter = $this->factory->getExporter($adapter, $databaseDriver); $this->assertInstanceOf( @@ -143,44 +152,51 @@ public function testGetExporter(string $adapter, bool $shouldRaiseException, ?Da /** * Data provider for importer test cases * - * @return \Generator + * @return array */ - public function dataGetImporter(): \Generator + public static function dataGetImporter(): array { - yield 'importer without database driver' => [ - 'mysqli', - false, - null, - ]; + return [ + 'importer without database driver' => [ + 'mysqli', + false, + false, + ], - yield 'importer with database driver' => [ - 'mysqli', - false, - $this->createMock(MysqliDriver::class), - ]; + 'importer with database driver' => [ + 'mysqli', + false, + true, + ], - yield 'unsupported importer' => [ - 'mariadb', - true, - null, + 'unsupported importer' => [ + 'mariadb', + true, + false, + ], ]; } /** * @testdox The factory builds a database importer correctly * - * @param string $adapter The type of adapter to create - * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter - * @param DatabaseDriver|null $databaseDriver The optional database driver to be injected into the importer - * - * @dataProvider dataGetImporter + * @param string $adapter The type of adapter to create + * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter + * @param boolean $createDb The optional database driver to be injected into the importer */ - public function testGetImporter(string $adapter, bool $shouldRaiseException, ?DatabaseDriver $databaseDriver) + #[DataProvider('dataGetImporter')] + public function testGetImporter(string $adapter, bool $shouldRaiseException, bool $createDb) { if ($shouldRaiseException) { $this->expectException(UnsupportedAdapterException::class); } + $databaseDriver = null; + + if ($createDb) { + $databaseDriver = $this->createMock(MysqliDriver::class); + } + $importer = $this->factory->getImporter($adapter, $databaseDriver); $this->assertInstanceOf( @@ -199,26 +215,33 @@ public function testGetImporter(string $adapter, bool $shouldRaiseException, ?Da /** * Data provider for iterator test cases * - * @return \Generator + * @return array */ - public function dataGetIterator(): \Generator + public static function dataGetIterator(): array { - yield 'driver without custom iterator' => [ - 'mysqli', - $this->createMock(StatementInterface::class), + return [ + 'driver without custom iterator' => [ + 'mysqli', + true, + ], ]; } /** * @testdox The factory builds a database iterator correctly * - * @param string $adapter The type of adapter to create - * @param StatementInterface $statement Statement holding the result set to be iterated. - * - * @dataProvider dataGetIterator + * @param string $adapter The type of adapter to create + * @param bool $createStatement Statement holding the result set to be iterated. */ - public function testGetIterator(string $adapter, StatementInterface $statement) + #[DataProvider('dataGetIterator')] + public function testGetIterator(string $adapter, bool $createStatement) { + $statement = null; + + if ($createStatement) { + $statement = $this->createMock(StatementInterface::class); + } + $this->assertInstanceOf( DatabaseIterator::class, $this->factory->getIterator($adapter, $statement) @@ -228,38 +251,45 @@ public function testGetIterator(string $adapter, StatementInterface $statement) /** * Data provider for query test cases * - * @return \Generator + * @return array */ - public function dataGetQuery(): \Generator + public static function dataGetQuery(): array { - yield 'supported query' => [ - 'mysqli', - false, - $this->createMock(MysqliDriver::class), - ]; + return [ + 'supported query' => [ + 'mysqli', + false, + true, + ], - yield 'unsupported query' => [ - 'mariadb', - true, - null, + 'unsupported query' => [ + 'mariadb', + true, + false, + ], ]; } /** * @testdox The factory builds a database query object correctly * - * @param string $adapter The type of adapter to create - * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter - * @param DatabaseDriver|null $databaseDriver The optional database driver to be injected into the importer - * - * @dataProvider dataGetQuery + * @param string $adapter The type of adapter to create + * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter + * @param boolean $createDb The optional database driver to be injected into the importer */ - public function testGetQuery(string $adapter, bool $shouldRaiseException, ?DatabaseDriver $databaseDriver) + #[DataProvider('dataGetQuery')] + public function testGetQuery(string $adapter, bool $shouldRaiseException, bool $createDb) { if ($shouldRaiseException) { $this->expectException(UnsupportedAdapterException::class); } + $databaseDriver = null; + + if ($createDb) { + $databaseDriver = $this->createMock(MysqliDriver::class); + } + $this->assertInstanceOf( QueryInterface::class, $this->factory->getQuery($adapter, $databaseDriver) diff --git a/Tests/DatabaseImporterTest.php b/Tests/DatabaseImporterTest.php index 8a6a4ef4..c3e36916 100644 --- a/Tests/DatabaseImporterTest.php +++ b/Tests/DatabaseImporterTest.php @@ -9,6 +9,8 @@ use Joomla\Database\DatabaseImporter; use Joomla\Database\DatabaseInterface; +use Joomla\Database\Tests\Stubs\TestDatabaseImporter; +use Joomla\Database\Tests\Stubs\TestDatabaseQuery; use Joomla\Test\TestHelper; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -18,20 +20,38 @@ */ class DatabaseImporterTest extends TestCase { + /** + * Importer object + * + * @var DatabaseImporter + */ + private $importer; + + /** + * Sets up the fixture. + * + * This method is called before a test is executed. + * + * @return void + */ + protected function setUp(): void + { + parent::setUp(); + + $this->importer = new TestDatabaseImporter(); + } + /** * @testdox The importer is correctly configured when instantiated */ public function testInstantiation() { - /** @var DatabaseImporter|MockObject $importer */ - $importer = $this->getMockForAbstractClass(DatabaseImporter::class); - $expected = (object) [ 'withStructure' => true, ]; - $this->assertEquals($expected, TestHelper::getValue($importer, 'options')); - $this->assertSame('xml', TestHelper::getValue($importer, 'asFormat')); + $this->assertEquals($expected, TestHelper::getValue($this->importer, 'options')); + $this->assertSame('xml', TestHelper::getValue($this->importer, 'asFormat')); } /** @@ -39,12 +59,9 @@ public function testInstantiation() */ public function testAsXml() { - /** @var DatabaseImporter|MockObject $importer */ - $importer = $this->getMockForAbstractClass(DatabaseImporter::class); + $this->assertSame($this->importer, $this->importer->asXml(), 'The importer supports method chaining'); - $this->assertSame($importer, $importer->asXml(), 'The importer supports method chaining'); - - $this->assertSame('xml', TestHelper::getValue($importer, 'asFormat')); + $this->assertSame('xml', TestHelper::getValue($this->importer, 'asFormat')); } /** @@ -52,13 +69,10 @@ public function testAsXml() */ public function testSetDbo() { - /** @var DatabaseImporter|MockObject $importer */ - $importer = $this->getMockForAbstractClass(DatabaseImporter::class); - /** @var DatabaseInterface|MockObject $db */ $db = $this->createMock(DatabaseInterface::class); - $this->assertSame($importer, $importer->setDbo($db), 'The importer supports method chaining'); + $this->assertSame($this->importer, $this->importer->setDbo($db), 'The importer supports method chaining'); } /** @@ -66,12 +80,9 @@ public function testSetDbo() */ public function testWithStructure() { - /** @var DatabaseImporter|MockObject $importer */ - $importer = $this->getMockForAbstractClass(DatabaseImporter::class); - - $this->assertSame($importer, $importer->withStructure(false), 'The importer supports method chaining'); + $this->assertSame($this->importer, $this->importer->withStructure(false), 'The importer supports method chaining'); - $options = TestHelper::getValue($importer, 'options'); + $options = TestHelper::getValue($this->importer, 'options'); $this->assertFalse($options->withStructure); } diff --git a/Tests/DatabaseQueryTest.php b/Tests/DatabaseQueryTest.php index f225e1ad..e29402af 100644 --- a/Tests/DatabaseQueryTest.php +++ b/Tests/DatabaseQueryTest.php @@ -11,6 +11,8 @@ use Joomla\Database\Exception\QueryTypeAlreadyDefinedException; use Joomla\Database\Exception\UnknownTypeException; use Joomla\Database\ParameterType; +use Joomla\Database\Tests\Stubs\TestDatabaseQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -45,10 +47,7 @@ protected function setUp(): void parent::setUp(); $this->db = $this->createMock(DatabaseInterface::class); - $this->query = $this->getMockForAbstractClass( - DatabaseQuery::class, - [$this->db] - ); + $this->query = new TestDatabaseQuery($this->db); } /** @@ -77,14 +76,6 @@ public function testCallChangeQueryType() ->call('foo'); } - /** - * @testdox A string is cast as a character string for the driver - */ - public function testCastAsChar() - { - $this->assertSame('foo', $this->query->castAsChar('foo')); - } - /** * @testdox A string is cast as a character string for the driver */ @@ -113,12 +104,14 @@ public function testCastAsWithUnknownType() /** * Data provider for character length test cases * - * @return \Generator + * @return array */ - public function dataCharLength(): \Generator + public static function dataCharLength(): array { - yield 'field without comparison' => ['a.title', null, null, 'CHAR_LENGTH(a.title)']; - yield 'field with comparison' => ['a.title', '!=', '0', 'CHAR_LENGTH(a.title) != 0']; + return [ + 'field without comparison' => ['a.title', null, null, 'CHAR_LENGTH(a.title)'], + 'field with comparison' => ['a.title', '!=', '0', 'CHAR_LENGTH(a.title) != 0'], + ]; } /** @@ -128,9 +121,8 @@ public function dataCharLength(): \Generator * @param string|null $operator Comparison operator between charLength integer value and $condition * @param string|null $condition Integer value to compare charLength with. * @param string $expected The expected query string. - * - * @dataProvider dataCharLength */ + #[DataProvider('dataCharLength')] public function testCharLength(string $field, ?string $operator, ?string $condition, string $expected) { $this->assertSame( @@ -156,12 +148,14 @@ public function testColumns() /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, 'CONCATENATE(foo || bar)']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "CONCATENATE(foo || ' and ' || bar)"]; + return [ + 'values without separator' => [['foo', 'bar'], null, 'CONCATENATE(foo || bar)'], + 'values with separator' => [['foo', 'bar'], ' and ', "CONCATENATE(foo || ' and ' || bar)"], + ]; } /** @@ -170,9 +164,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) @@ -201,12 +194,14 @@ public function testCurrentTimestamp() /** * Data provider for dateAdd test cases * - * @return \Generator + * @return array */ - public function dataDateAdd(): \Generator + public static function dataDateAdd(): array { - yield 'date with positive interval' => ["'2019-10-13'", '1', 'DAY', "DATE_ADD('2019-10-13', INTERVAL 1 DAY)"]; - yield 'date with negative interval' => ["'2019-10-13'", '-1', 'DAY', "DATE_ADD('2019-10-13', INTERVAL -1 DAY)"]; + return [ + 'date with positive interval' => ["'2019-10-13'", '1', 'DAY', "DATE_ADD('2019-10-13', INTERVAL 1 DAY)"], + 'date with negative interval' => ["'2019-10-13'", '-1', 'DAY', "DATE_ADD('2019-10-13', INTERVAL -1 DAY)"], + ]; } /** @@ -216,9 +211,8 @@ public function dataDateAdd(): \Generator * @param string $interval The string representation of the appropriate number of units * @param string $datePart The part of the date to perform the addition on * @param string $expected The expected query string. - * - * @dataProvider dataDateAdd */ + #[DataProvider('dataDateAdd')] public function testDateAdd(string $date, string $interval, string $datePart, string $expected) { $this->assertSame( @@ -525,12 +519,14 @@ public function testLength() /** * Data provider for null date test cases * - * @return \Generator + * @return array */ - public function dataNullDate(): \Generator + public static function dataNullDate(): array { - yield 'null date with quote' => [true, "'0000-00-00 00:00:00'"]; - yield 'null date without quote' => [false, '0000-00-00 00:00:00']; + return [ + 'null date with quote' => [true, "'0000-00-00 00:00:00'"], + 'null date without quote' => [false, '0000-00-00 00:00:00'], + ]; } /** @@ -538,9 +534,8 @@ public function dataNullDate(): \Generator * * @param boolean $quoted Optionally wraps the null date in database quotes (true by default). * @param string $expected The expected query string. - * - * @dataProvider dataNullDate */ + #[DataProvider('dataNullDate')] public function testNullDate(bool $quoted, string $expected) { $this->db->expects($this->once()) @@ -566,10 +561,7 @@ public function testNullDateException() { $this->expectException(\RuntimeException::class); - $query = $this->getMockForAbstractClass( - DatabaseQuery::class, - [] - ); + $query = new TestDatabaseQuery(); $query->nullDate(); } @@ -627,10 +619,7 @@ public function testIsNullDatetimeException() { $this->expectException(\RuntimeException::class); - $query = $this->getMockForAbstractClass( - DatabaseQuery::class, - [] - ); + $query = new TestDatabaseQuery(); $query->isNullDatetime('a.created'); } @@ -673,10 +662,7 @@ public function testQuoteException() { $this->expectException(\RuntimeException::class); - $query = $this->getMockForAbstractClass( - DatabaseQuery::class, - [] - ); + $query = new TestDatabaseQuery(); $query->quote('foo'); } @@ -705,10 +691,7 @@ public function testQuoteNameException() { $this->expectException(\RuntimeException::class); - $query = $this->getMockForAbstractClass( - DatabaseQuery::class, - [] - ); + $query = new TestDatabaseQuery(); $query->quoteName('foo'); } @@ -930,28 +913,30 @@ public function testAndWhere() /** * Data provider for bind test cases * - * @return \Generator - */ - public function dataBind(): \Generator - { - yield 'string field' => ['foo', 'bar', ParameterType::STRING, [ - 'foo' => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - ]]; - yield 'numeric field' => ['foo', 42, ParameterType::INTEGER, [ - 'foo' => (object) ['value' => 42, 'dataType' => 'int', 'length' => 0, 'driverOptions' => []], - ]]; - yield 'numeric key' => [1, 'bar', ParameterType::STRING, [ - 1 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - ]]; - yield 'array of data' => [[1, 'foo'], [42, 'bar'], [ParameterType::INTEGER, ParameterType::STRING], [ - 1 => (object) ['value' => 42, 'dataType' => 'int', 'length' => 0, 'driverOptions' => []], - 'foo' => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - ]]; - yield 'key array, single data value' => [[1, 2, 3], 'bar', ParameterType::STRING, [ - 1 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - 2 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - 3 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - ]]; + * @return array + */ + public static function dataBind(): array + { + return [ + 'string field' => ['foo', 'bar', ParameterType::STRING, [ + 'foo' => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + ]], + 'numeric field' => ['foo', 42, ParameterType::INTEGER, [ + 'foo' => (object) ['value' => 42, 'dataType' => 'int', 'length' => 0, 'driverOptions' => []], + ]], + 'numeric key' => [1, 'bar', ParameterType::STRING, [ + 1 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + ]], + 'array of data' => [[1, 'foo'], [42, 'bar'], [ParameterType::INTEGER, ParameterType::STRING], [ + 1 => (object) ['value' => 42, 'dataType' => 'int', 'length' => 0, 'driverOptions' => []], + 'foo' => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + ]], + 'key array, single data value' => [[1, 2, 3], 'bar', ParameterType::STRING, [ + 1 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + 2 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + 3 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + ]], + ]; } /** @@ -965,9 +950,8 @@ public function dataBind(): \Generator * @param array|string $dataType Constant corresponding to a SQL datatype. It can be an array, in this case it * has to be same length of $key * @param array $expected The expected structure of `$bounded` - * - * @dataProvider dataBind */ + #[DataProvider('dataBind')] public function testBind($key, $value, $dataType, $expected) { $this->assertSame($this->query, $this->query->bind($key, $value, $dataType), 'The query builder supports method chaining'); diff --git a/Tests/Pgsql/PgsqlQueryTest.php b/Tests/Pgsql/PgsqlQueryTest.php index 7db376f2..a32a4eb0 100644 --- a/Tests/Pgsql/PgsqlQueryTest.php +++ b/Tests/Pgsql/PgsqlQueryTest.php @@ -45,14 +45,6 @@ protected function setUp(): void $this->query = new PgsqlQuery($this->db); } - /** - * @testdox A string is cast as a character string for the driver - */ - public function testCastAsChar() - { - $this->assertSame('foo::text', $this->query->castAsChar('foo')); - } - /** * @testdox A string is cast as a character string for the driver */ diff --git a/Tests/Query/QueryElementTest.php b/Tests/Query/QueryElementTest.php index 0b37877d..7fa6eccf 100644 --- a/Tests/Query/QueryElementTest.php +++ b/Tests/Query/QueryElementTest.php @@ -7,6 +7,7 @@ namespace Joomla\Database\Tests\Query; use Joomla\Database\Query\QueryElement; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; /** @@ -24,33 +25,35 @@ class QueryElementTest extends TestCase * glue => glue * - array $expected values in same array format * - * @return \Generator + * @return array */ - public function dataInstantiation(): \Generator + public static function dataInstantiation(): array { - yield 'array-element' => [ - [ - 'name' => 'FROM', - 'elements' => ['field1', 'field2'], - 'glue' => ',', - ], - [ - 'name' => 'FROM', - 'elements' => ['field1', 'field2'], - 'glue' => ',', + return [ + 'array-element' => [ + [ + 'name' => 'FROM', + 'elements' => ['field1', 'field2'], + 'glue' => ',', + ], + [ + 'name' => 'FROM', + 'elements' => ['field1', 'field2'], + 'glue' => ',', + ], ], - ]; - yield 'non-array-element' => [ - [ - 'name' => 'TABLE', - 'elements' => 'my_table_name', - 'glue' => ',', - ], - [ - 'name' => 'TABLE', - 'elements' => ['my_table_name'], - 'glue' => ',', + 'non-array-element' => [ + [ + 'name' => 'TABLE', + 'elements' => 'my_table_name', + 'glue' => ',', + ], + [ + 'name' => 'TABLE', + 'elements' => ['my_table_name'], + 'glue' => ',', + ], ], ]; } @@ -60,9 +63,8 @@ public function dataInstantiation(): \Generator * * @param array $element values for base element * @param array $expected values for expected fields - * - * @dataProvider dataInstantiation */ + #[DataProvider('dataInstantiation')] public function testInstantiation(array $element, array $expected) { $baseElement = new QueryElement($element['name'], $element['elements'], $element['glue']); @@ -92,36 +94,38 @@ public function testInstantiation(array $element, array $expected) * - string $glue the element glue * - string $expected expected result * - * @return \Generator + * @return array */ - public function dataCastingToString(): \Generator + public static function dataCastingToString(): array { - yield [ - 'FROM', - 'table1', - ',', - PHP_EOL . 'FROM table1', - ]; + return [ + [ + 'FROM', + 'table1', + ',', + PHP_EOL . 'FROM table1', + ], - yield [ - 'SELECT', - ['column1', 'column2'], - ',', - PHP_EOL . 'SELECT column1,column2', - ]; + [ + 'SELECT', + ['column1', 'column2'], + ',', + PHP_EOL . 'SELECT column1,column2', + ], - yield [ - '()', - ['column1', 'column2'], - ',', - PHP_EOL . '(column1,column2)', - ]; + [ + '()', + ['column1', 'column2'], + ',', + PHP_EOL . '(column1,column2)', + ], - yield [ - 'CONCAT()', - ['column1', 'column2'], - ',', - PHP_EOL . 'CONCAT(column1,column2)', + [ + 'CONCAT()', + ['column1', 'column2'], + ',', + PHP_EOL . 'CONCAT(column1,column2)', + ], ]; } @@ -132,9 +136,8 @@ public function dataCastingToString(): \Generator * @param mixed $elements String or array. * @param string $glue The glue for elements. * @param string $expected The expected value. - * - * @dataProvider dataCastingToString */ + #[DataProvider('dataCastingToString')] public function testCastingToString($name, $elements, $glue, $expected) { $this->assertThat( @@ -155,46 +158,48 @@ public function testCastingToString($name, $elements, $glue, $expected) * - array $expected array of elements that should be the value of the elements attribute after the merge * - string $string value of __toString() for element after append * - * @return \Generator + * @return array */ - public function dataAppend(): \Generator + public static function dataAppend(): array { - yield 'array-element' => [ - [ - 'name' => 'SELECT', - 'elements' => [], - 'glue' => ',', - ], - [ - 'name' => 'FROM', - 'elements' => ['my_table_name'], - 'glue' => ',', - ], - [ - 'name' => 'FROM', - 'elements' => ['my_table_name'], - 'glue' => ',', + return [ + 'array-element' => [ + [ + 'name' => 'SELECT', + 'elements' => [], + 'glue' => ',', + ], + [ + 'name' => 'FROM', + 'elements' => ['my_table_name'], + 'glue' => ',', + ], + [ + 'name' => 'FROM', + 'elements' => ['my_table_name'], + 'glue' => ',', + ], + PHP_EOL . 'SELECT ' . PHP_EOL . 'FROM my_table_name', ], - PHP_EOL . 'SELECT ' . PHP_EOL . 'FROM my_table_name', - ]; - yield 'non-array-element' => [ - [ - 'name' => 'SELECT', - 'elements' => [], - 'glue' => ',', - ], - [ - 'name' => 'FROM', - 'elements' => ['my_table_name'], - 'glue' => ',', - ], - [ - 'name' => 'FROM', - 'elements' => ['my_table_name'], - 'glue' => ',', + 'non-array-element' => [ + [ + 'name' => 'SELECT', + 'elements' => [], + 'glue' => ',', + ], + [ + 'name' => 'FROM', + 'elements' => ['my_table_name'], + 'glue' => ',', + ], + [ + 'name' => 'FROM', + 'elements' => ['my_table_name'], + 'glue' => ',', + ], + PHP_EOL . 'SELECT ' . PHP_EOL . 'FROM my_table_name', ], - PHP_EOL . 'SELECT ' . PHP_EOL . 'FROM my_table_name', ]; } @@ -205,9 +210,8 @@ public function dataAppend(): \Generator * @param array $append append element values * @param array $expected expected element values for elements field after append * @param string $string expected value of toString (not used in this test) - * - * @dataProvider dataAppend */ + #[DataProvider('dataAppend')] public function testAppend($element, $append, $expected, $string) { $baseElement = new QueryElement($element['name'], $element['elements'], $element['glue']); diff --git a/Tests/Sqlsrv/SqlsrvQueryTest.php b/Tests/Sqlsrv/SqlsrvQueryTest.php index 39b0d034..e7819d18 100644 --- a/Tests/Sqlsrv/SqlsrvQueryTest.php +++ b/Tests/Sqlsrv/SqlsrvQueryTest.php @@ -45,14 +45,6 @@ protected function setUp(): void $this->query = new SqlsrvQuery($this->db); } - /** - * @testdox A string is cast as a character string for the driver - */ - public function testCastAsChar() - { - $this->assertSame('CAST(foo as NVARCHAR(10))', $this->query->castAsChar('foo')); - } - /** * @testdox A string is cast as a character string for the driver */ diff --git a/Tests/Stubs/TestDatabaseExporter.php b/Tests/Stubs/TestDatabaseExporter.php new file mode 100644 index 00000000..c121d4d0 --- /dev/null +++ b/Tests/Stubs/TestDatabaseExporter.php @@ -0,0 +1,28 @@ + Date: Fri, 11 Jul 2025 11:33:07 +0200 Subject: [PATCH 06/11] Improvements from phpstan scan --- src/Command/ExportCommand.php | 28 ++++++++++++---------------- src/DatabaseDriver.php | 12 +++--------- src/Pgsql/PgsqlDriver.php | 1 + src/Pgsql/PgsqlExporter.php | 8 ++++++++ src/Pgsql/PgsqlImporter.php | 8 ++++++++ src/Query/MysqlQueryBuilder.php | 7 ++++++- src/Sqlsrv/SqlsrvDriver.php | 2 -- src/Sqlsrv/SqlsrvStatement.php | 6 +++--- 8 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/Command/ExportCommand.php b/src/Command/ExportCommand.php index ab4d172f..b3a9c009 100644 --- a/src/Command/ExportCommand.php +++ b/src/Command/ExportCommand.php @@ -95,7 +95,6 @@ protected function doExecute(InputInterface $input, OutputInterface $output): in $tableName = $input->getOption('table'); $zip = $input->getOption('zip'); - $zipFile = $folderPath . '/data_exported_' . date("Y-m-d\TH-i-s") . '.zip'; $tables = $this->db->getTableList(); $prefix = $this->db->getPrefix(); @@ -109,20 +108,15 @@ protected function doExecute(InputInterface $input, OutputInterface $output): in $tables = [$tableName]; } - if ($zip) { - if (!class_exists(Archive::class)) { - $symfonyStyle->error('The "joomla/archive" Composer package is not installed, cannot create ZIP files.'); - - return 1; - } - - /** @var Zip $zipArchive */ - $zipArchive = (new Archive())->getAdapter('zip'); + if ($zip && !class_exists(Archive::class)) { + $symfonyStyle->error('The "joomla/archive" Composer package is not installed, cannot create ZIP files.'); - $filenames = []; - $zipFilesArray = []; + return 1; } + $filenames = []; + $zipFilesArray = []; + foreach ($tables as $table) { // If an empty prefix is in use then we will dump all tables, otherwise the prefix must match if (strlen($prefix) === 0 || strpos(substr($table, 0, strlen($prefix)), $prefix) !== false) { @@ -139,16 +133,18 @@ protected function doExecute(InputInterface $input, OutputInterface $output): in File::write($filename, $data); - if ($zip) { - $zipFilesArray[] = ['name' => $table . '.xml', 'data' => $data]; - $filenames[] = $filename; - } + $zipFilesArray[] = ['name' => $table . '.xml', 'data' => $data]; + $filenames[] = $filename; $symfonyStyle->text(sprintf('Exported data for %s in %d seconds', $table, round(microtime(true) - $taskTime, 3))); } } if ($zip) { + /** @var Zip $zipArchive */ + $zipArchive = (new Archive())->getAdapter('zip'); + + $zipFile = $folderPath . '/data_exported_' . date("Y-m-d\TH-i-s") . '.zip'; $zipArchive->create($zipFile, $zipFilesArray); foreach ($filenames as $fname) { File::delete($fname); diff --git a/src/DatabaseDriver.php b/src/DatabaseDriver.php index 497d9cc0..b56d9229 100644 --- a/src/DatabaseDriver.php +++ b/src/DatabaseDriver.php @@ -250,7 +250,6 @@ public static function getConnectors() $baseName = $file->getBasename(); // Derive the class name from the type. - /** @var DatabaseDriver $class */ $class = __NAMESPACE__ . '\\' . ucfirst(strtolower($baseName)) . '\\' . ucfirst(strtolower($baseName)) . 'Driver'; // If the class doesn't exist, or if it's not supported on this system, move on to the next type. @@ -501,17 +500,12 @@ public function __destruct() * * @param string $dbName The database name that will be altered * - * @return boolean|resource + * @return boolean * * @since 2.0.0 - * @throws \RuntimeException */ - public function alterDbCharacterSet($dbName) + public function alterDbCharacterSet(string $dbName) { - if ($dbName === null) { - throw new \RuntimeException('Database name must not be null.'); - } - $this->setQuery($this->getAlterDbCharacterSet($dbName)); return $this->execute(); @@ -523,7 +517,7 @@ public function alterDbCharacterSet($dbName) * @param \stdClass $options Object used to pass user and database name to database driver. This object must have "db_name" and "db_user" set. * @param boolean $utf True if the database supports the UTF-8 character set. * - * @return boolean|resource + * @return boolean * * @since 2.0.0 * @throws \RuntimeException diff --git a/src/Pgsql/PgsqlDriver.php b/src/Pgsql/PgsqlDriver.php index 86ee0872..16c93d12 100644 --- a/src/Pgsql/PgsqlDriver.php +++ b/src/Pgsql/PgsqlDriver.php @@ -767,6 +767,7 @@ public function insertObject($table, &$object, $key = null) } // Create the base insert statement. + /** @var PgsqlQuery $query */ $query = $this->createQuery(); $query->insert($this->quoteName($table)) diff --git a/src/Pgsql/PgsqlExporter.php b/src/Pgsql/PgsqlExporter.php index 82d94e0d..124081f6 100644 --- a/src/Pgsql/PgsqlExporter.php +++ b/src/Pgsql/PgsqlExporter.php @@ -18,6 +18,14 @@ */ class PgsqlExporter extends DatabaseExporter { + /** + * The database connector to use for exporting structure and/or data. + * + * @var PgsqlDriver + * @since 1.0 + */ + protected $db; + /** * Builds the XML data for the tables to export. * diff --git a/src/Pgsql/PgsqlImporter.php b/src/Pgsql/PgsqlImporter.php index 1bc7d85f..207c25d7 100644 --- a/src/Pgsql/PgsqlImporter.php +++ b/src/Pgsql/PgsqlImporter.php @@ -18,6 +18,14 @@ */ class PgsqlImporter extends DatabaseImporter { + /** + * The database connector to use for exporting structure and/or data. + * + * @var PgsqlDriver + * @since 1.0 + */ + protected $db; + /** * Checks if all data and options are in order prior to exporting. * diff --git a/src/Query/MysqlQueryBuilder.php b/src/Query/MysqlQueryBuilder.php index a23f6f80..1ce5000b 100644 --- a/src/Query/MysqlQueryBuilder.php +++ b/src/Query/MysqlQueryBuilder.php @@ -9,6 +9,8 @@ namespace Joomla\Database\Query; +use Joomla\Database\Mysql\MysqlDriver; + /** * Trait for MySQL Query Building. * @@ -217,8 +219,11 @@ public function findInSet($value, $set) */ public function selectRowNumber($orderBy, $orderColumnAlias) { + /** @var MysqlDriver $db */ + $db = $this->db; + // Use parent method with ROW_NUMBER() window function on MariaDB >= 10.2.0 and MySQL >= 8.0.0. - if (version_compare($this->db->getVersion(), $this->db->isMariaDb() ? '10.2.0' : '8.0.0', '>=')) { + if (version_compare($db->getVersion(), $db->isMariaDb() ? '10.2.0' : '8.0.0', '>=')) { return parent::selectRowNumber($orderBy, $orderColumnAlias); } diff --git a/src/Sqlsrv/SqlsrvDriver.php b/src/Sqlsrv/SqlsrvDriver.php index d8b88cb8..dadbb27a 100644 --- a/src/Sqlsrv/SqlsrvDriver.php +++ b/src/Sqlsrv/SqlsrvDriver.php @@ -338,7 +338,6 @@ public function getCollation() * @return string|boolean The collation in use by the database connection (string) or boolean false if not supported. * * @since 1.6.0 - * @throws \RuntimeException */ public function getConnectionCollation() { @@ -352,7 +351,6 @@ public function getConnectionCollation() * @return string The database encryption details. * * @since 2.0.0 - * @throws \RuntimeException */ public function getConnectionEncryption(): string { diff --git a/src/Sqlsrv/SqlsrvStatement.php b/src/Sqlsrv/SqlsrvStatement.php index e93599fe..096c7d42 100644 --- a/src/Sqlsrv/SqlsrvStatement.php +++ b/src/Sqlsrv/SqlsrvStatement.php @@ -44,7 +44,7 @@ class SqlsrvStatement implements StatementInterface /** * The default class to use for building object result sets. * - * @var integer + * @var string * @since 2.0.0 */ protected $defaultObjectClass = \stdClass::class; @@ -80,7 +80,7 @@ class SqlsrvStatement implements StatementInterface /** * The prepared statement. * - * @var resource + * @var ?resource * @since 2.0.0 */ protected $statement; @@ -352,7 +352,7 @@ public function errorCode() return $errors[0]['code']; } - return false; + return ''; } /** From bdaa08b1962e6d300b4d7fec76abee64bd5c30bd Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Fri, 11 Jul 2025 11:33:29 +0200 Subject: [PATCH 07/11] Cleanup .gitattributes --- .gitattributes | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.gitattributes b/.gitattributes index f52ca844..a77d5a71 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,14 +1,11 @@ .github/ export-ignore -.phan/ export-ignore docs/ export-ignore Tests/ export-ignore -.appveyor.yml export-ignore -.drone.jsonnet export-ignore -.drone.yml export-ignore .editorconfig export-ignore .git-blame-ignore-revs export-ignore .gitattributes export-ignore .gitignore export-ignore +phpstan.neon export-ignore phpunit.*.xml.dist export-ignore phpunit.xml.dist export-ignore ruleset.xml export-ignore From cf27ee7a6d7a7431e63cb131270b4136f2e518f4 Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Sun, 13 Jul 2025 12:57:10 +0200 Subject: [PATCH 08/11] Updating Github Actions PHP versions --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc7faa1d..f302f38b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: composer: name: Install PHP dependencies runs-on: ubuntu-latest - container: joomlaprojects/docker-images:php8.1 + container: joomlaprojects/docker-images:php8.3 steps: - uses: actions/checkout@v4 - uses: actions/cache@v4 @@ -32,7 +32,7 @@ jobs: code-style-php: name: Check PHP code style runs-on: ubuntu-latest - container: joomlaprojects/docker-images:php8.1 + container: joomlaprojects/docker-images:php8.3 needs: [composer] steps: - uses: actions/checkout@v4 @@ -68,7 +68,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3', '8.4'] + php_version: ['8.3', '8.4'] steps: - uses: actions/checkout@v4 - name: Run Unit tests @@ -84,7 +84,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3', '8.4'] + php_version: ['8.3', '8.4'] db_engine: ['mysql', 'mysqli'] db_version: ['5.7', '8.0'] steps: @@ -110,7 +110,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3', '8.4'] + php_version: ['8.3', '8.4'] steps: - uses: actions/checkout@v4 - name: Run Unit tests @@ -134,7 +134,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3', '8.4'] + php_version: ['8.3', '8.4'] db_version: ['10', '11'] steps: - uses: actions/checkout@v4 @@ -158,7 +158,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3', '8.4'] + php_version: ['8.3', '8.4'] steps: - uses: actions/checkout@v4 - name: Run Unit tests @@ -190,7 +190,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3', '8.4'] + php_version: ['8.3', '8.4'] steps: - uses: actions/checkout@v4 - name: Setup PHP From c1c92c8820e29c8f8ff0baaf76734d17f2639658 Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Sun, 13 Jul 2025 15:30:38 +0200 Subject: [PATCH 09/11] Updating unittests to phpunit 12 - part 2 --- Tests/AbstractDatabaseDriverTestCase.php | 42 +++-- Tests/Mysql/MysqlDriverTest.php | 204 +++++++++++----------- Tests/Mysql/MysqlExporterTest.php | 82 ++++----- Tests/Mysql/MysqlImporterTest.php | 197 ++++++++++----------- Tests/Mysql/MysqlQueryTest.php | 14 +- Tests/Mysqli/MysqliDriverTest.php | 204 +++++++++++----------- Tests/Mysqli/MysqliExporterTest.php | 81 ++++----- Tests/Mysqli/MysqliImporterTest.php | 197 ++++++++++----------- Tests/Mysqli/MysqliQueryTest.php | 14 +- Tests/Pgsql/PgsqlDriverTest.php | 196 +++++++++++---------- Tests/Pgsql/PgsqlExporterTest.php | 81 ++++----- Tests/Pgsql/PgsqlImporterTest.php | 209 ++++++++++++----------- Tests/Pgsql/PgsqlQueryTest.php | 27 +-- Tests/Sqlite/SqliteDriverTest.php | 168 +++++++++--------- Tests/Sqlite/SqliteQueryTest.php | 27 +-- Tests/Sqlsrv/SqlsrvDriverTest.php | 134 ++++++++------- Tests/Sqlsrv/SqlsrvQueryTest.php | 27 +-- 17 files changed, 995 insertions(+), 909 deletions(-) diff --git a/Tests/AbstractDatabaseDriverTestCase.php b/Tests/AbstractDatabaseDriverTestCase.php index 2d7ea2b1..b4377cf7 100644 --- a/Tests/AbstractDatabaseDriverTestCase.php +++ b/Tests/AbstractDatabaseDriverTestCase.php @@ -13,6 +13,7 @@ use Joomla\Database\ParameterType; use Joomla\Database\QueryInterface; use Joomla\Test\DatabaseTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Base test class for Joomla\Database\DatabaseDriver @@ -72,13 +73,15 @@ public function testIsConnectionEncryptionSupported() /** * Data provider for table dropping test cases * - * @return \Generator + * @return array */ - public function dataDropTable() + public static function dataDropTable(): array { - yield 'database exists before query' => ['#__dbtest', true]; + return [ + 'database exists before query' => ['#__dbtest', true], - yield 'database does not exist before query' => ['#__foo', false]; + 'database does not exist before query' => ['#__foo', false], + ]; } /** @@ -86,9 +89,8 @@ public function dataDropTable() * * @param string $table The name of the database table to drop. * @param boolean $alreadyExists Flag indicating the table should exist before the DROP TABLE query. - * - * @dataProvider dataDropTable */ + #[DataProvider('dataDropTable')] public function testDropTable(string $table, bool $alreadyExists) { $this->assertSame( @@ -110,9 +112,9 @@ public function testDropTable(string $table, bool $alreadyExists) /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - abstract public function dataEscape(): \Generator; + abstract public static function dataEscape(): array; /** * @testdox Text can be escaped @@ -120,9 +122,8 @@ abstract public function dataEscape(): \Generator; * @param string $text The string to be escaped. * @param boolean $extra Optional parameter to provide extra escaping. * @param string $expected The expected result. - * - * @dataProvider dataEscape */ + #[DataProvider('dataEscape')] public function testEscape($text, $extra, $expected) { $this->assertSame( @@ -240,9 +241,9 @@ public function testGetIterator() /** * Data provider for fetching table column test cases * - * @return \Generator + * @return array */ - abstract public function dataGetTableColumns(): \Generator; + abstract public static function dataGetTableColumns(): array; /** * @testdox Information about the columns of a database table is returned @@ -250,9 +251,8 @@ abstract public function dataGetTableColumns(): \Generator; * @param string $table The name of the database table. * @param boolean $typeOnly True (default) to only return field types. * @param array $expected Expected result. - * - * @dataProvider dataGetTableColumns */ + #[DataProvider('dataGetTableColumns')] public function testGetTableColumns(string $table, bool $typeOnly, array $expected) { $this->assertEquals( @@ -596,18 +596,17 @@ public function testLockAndUnlockTable() /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - abstract public function dataQuoteBinary(): \Generator; + abstract public static function dataQuoteBinary(): array; /** * @testdox A binary value is quoted properly * * @param string $data The binary quoted input string. * @param string $expected The expected result. - * - * @dataProvider dataQuoteBinary */ + #[DataProvider('dataQuoteBinary')] public function testQuoteBinary($data, $expected) { $this->assertSame($expected, static::$connection->quoteBinary($data)); @@ -616,9 +615,9 @@ public function testQuoteBinary($data, $expected) /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - abstract public function dataQuoteName(): \Generator; + abstract public static function dataQuoteName(): array; /** * @testdox A value is name quoted properly @@ -626,9 +625,8 @@ abstract public function dataQuoteName(): \Generator; * @param array|string $name The identifier name to wrap in quotes, or an array of identifier names to wrap in quotes. * @param array|string $as The AS query part associated to $name. * @param array|string $expected The expected result. - * - * @dataProvider dataQuoteName */ + #[DataProvider('dataQuoteName')] public function testQuoteName($name, $as, $expected) { $this->assertSame( diff --git a/Tests/Mysql/MysqlDriverTest.php b/Tests/Mysql/MysqlDriverTest.php index 47d68214..feae9357 100644 --- a/Tests/Mysql/MysqlDriverTest.php +++ b/Tests/Mysql/MysqlDriverTest.php @@ -14,6 +14,7 @@ use Joomla\Database\Mysql\MysqlQuery; use Joomla\Database\ParameterType; use Joomla\Database\Tests\AbstractDatabaseDriverTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Test class for Joomla\Database\Mysql\MysqlDriver @@ -91,9 +92,9 @@ protected function tearDown(): void /** * Data provider for fetching table column test cases * - * @return \Generator + * @return array */ - public function dataGetTableColumns(): \Generator + public static function dataGetTableColumns(): array { // For unknown reasons, the connection gets lost on Travis. re-establish, if that happens if (static::$connection === null) { @@ -103,76 +104,78 @@ public function dataGetTableColumns(): \Generator $isMySQL8 = !static::$connection->isMariaDb() && version_compare(static::$connection->getVersion(), '8.0', '>='); $useDisplayWidth = static::$connection->isMariaDb() || version_compare(static::$connection->getVersion(), '8.0.17', '<'); - yield 'only column types' => [ - '#__dbtest', - true, - [ - 'id' => 'int unsigned', - 'title' => 'varchar', - 'start_date' => 'datetime', - 'description' => 'text', - 'data' => 'blob', + return [ + 'only column types' => [ + '#__dbtest', + true, + [ + 'id' => 'int unsigned', + 'title' => 'varchar', + 'start_date' => 'datetime', + 'description' => 'text', + 'data' => 'blob', + ], ], - ]; - yield 'full column information' => [ - '#__dbtest', - false, - [ - 'id' => (object) [ - 'Field' => 'id', - 'Type' => $useDisplayWidth ? 'int(10) unsigned' : 'int unsigned', - 'Collation' => $isMySQL8 ? null : '', - 'Null' => 'NO', - 'Key' => 'PRI', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => 'auto_increment', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'title' => (object) [ - 'Field' => 'title', - 'Type' => 'varchar(50)', - 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', - 'Null' => 'NO', - 'Key' => '', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'start_date' => (object) [ - 'Field' => 'start_date', - 'Type' => 'datetime', - 'Collation' => '', - 'Null' => 'NO', - 'Key' => '', - 'Default' => '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'description' => (object) [ - 'Field' => 'description', - 'Type' => 'text', - 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', - 'Null' => 'NO', - 'Key' => '', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'data' => (object) [ - 'Field' => 'data', - 'Type' => 'blob', - 'Collation' => '', - 'Null' => 'YES', - 'Key' => '', - 'Default' => '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', + 'full column information' => [ + '#__dbtest', + false, + [ + 'id' => (object) [ + 'Field' => 'id', + 'Type' => $useDisplayWidth ? 'int(10) unsigned' : 'int unsigned', + 'Collation' => $isMySQL8 ? null : '', + 'Null' => 'NO', + 'Key' => 'PRI', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => 'auto_increment', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'title' => (object) [ + 'Field' => 'title', + 'Type' => 'varchar(50)', + 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', + 'Null' => 'NO', + 'Key' => '', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'start_date' => (object) [ + 'Field' => 'start_date', + 'Type' => 'datetime', + 'Collation' => '', + 'Null' => 'NO', + 'Key' => '', + 'Default' => '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'description' => (object) [ + 'Field' => 'description', + 'Type' => 'text', + 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', + 'Null' => 'NO', + 'Key' => '', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'data' => (object) [ + 'Field' => 'data', + 'Type' => 'blob', + 'Collation' => '', + 'Null' => 'YES', + 'Key' => '', + 'Default' => '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], ], ], ]; @@ -181,50 +184,58 @@ public function dataGetTableColumns(): \Generator /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - public function dataEscape(): \Generator + public static function dataEscape(): array { - yield ["'%_abc123", false, '\\\'%_abc123']; - yield ["'%_abc123", true, '\\\'\\%\_abc123']; - yield [3, false, 3]; - yield [3.14, false, '3.14']; + return [ + ["'%_abc123", false, '\\\'%_abc123'], + ["'%_abc123", true, '\\\'\\%\_abc123'], + [3, false, 3], + [3.14, false, '3.14'], + ]; } /** * Data provider for table dropping test cases * - * @return \Generator + * @return array */ - public function dataDropTable() + public static function dataDropTable(): array { - yield 'database exists before query' => ['#__dbtest', true]; + return [ + 'database exists before query' => ['#__dbtest', true], - yield 'database does not exist before query' => ['#__foo', false]; + 'database does not exist before query' => ['#__foo', false], + ]; } /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteBinary(): \Generator + public static function dataQuoteBinary(): array { - yield ['DATA', "X'" . bin2hex('DATA') . "'"]; - yield ["\x00\x01\x02\xff", "X'000102ff'"]; - yield ["\x01\x01\x02\xff", "X'010102ff'"]; + return [ + ['DATA', "X'" . bin2hex('DATA') . "'"], + ["\x00\x01\x02\xff", "X'000102ff'"], + ["\x01\x01\x02\xff", "X'010102ff'"], + ]; } /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteName(): \Generator + public static function dataQuoteName(): array { - yield ['protected`title', null, '`protected``title`']; - yield ['protected"title', null, '`protected"title`']; - yield ['protected]title', null, '`protected]title`']; + return [ + ['protected`title', null, '`protected``title`'], + ['protected"title', null, '`protected"title`'], + ['protected]title', null, '`protected]title`'], + ]; } /* @@ -381,13 +392,15 @@ public function testTransactionCommit() /** * Data provider for transaction rollback test cases * - * @return \Generator + * @return array */ - public function dataTransactionRollback() + public static function dataTransactionRollback(): array { - yield 'rollback without savepoint' => [null, 0]; + return [ + 'rollback without savepoint' => [null, 0], - yield 'rollback with savepoint' => ['transactionSavepoint', 1]; + 'rollback with savepoint' => ['transactionSavepoint', 1], + ]; } /** @@ -395,9 +408,8 @@ public function dataTransactionRollback() * * @param string|null $toSavepoint Savepoint name to rollback transaction to * @param integer $tupleCount Number of tuples found after insertion and rollback - * - * @dataProvider dataTransactionRollback */ + #[DataProvider('dataTransactionRollback')] public function testTransactionRollback(?string $toSavepoint, int $tupleCount) { $this->loadExampleData(); diff --git a/Tests/Mysql/MysqlExporterTest.php b/Tests/Mysql/MysqlExporterTest.php index f44d075c..f7c4488f 100644 --- a/Tests/Mysql/MysqlExporterTest.php +++ b/Tests/Mysql/MysqlExporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Mysql\MysqlDriver; use Joomla\Database\Mysql\MysqlExporter; use Joomla\Database\Mysql\MysqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -120,11 +121,12 @@ function ($name, $as = null) { /** * Data provider for string casting test cases * - * @return \Generator + * @return array */ - public function dataCastingToString(): \Generator + public static function dataCastingToString(): array { - yield 'without structure or data' => [ + return [ + 'without structure or data' => [ false, false, << XML , - ]; + ], - yield 'with only structure' => [ + 'with only structure' => [ true, false, << XML , - ]; + ], - yield 'with only data' => [ + 'with only data' => [ false, true, << XML , - ]; + ], - yield 'with structure and data' => [ + 'with structure and data' => [ true, true, << XML , + ], ]; } @@ -209,9 +212,8 @@ public function dataCastingToString(): \Generator * @param boolean $withStructure True to export the structure, false to not. * @param boolean $withData True to export the data, false to not. * @param string $expectedXml Expected XML string. - * - * @dataProvider dataCastingToString */ + #[DataProvider('dataCastingToString')] public function testCastingToString(bool $withStructure, bool $withData, string $expectedXml) { $exporter = new MysqlExporter(); @@ -244,45 +246,46 @@ public function testCastingToString(bool $withStructure, bool $withData, string /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(MysqlDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + MysqlDriver::class, + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + DatabaseInterface::class, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(MysqlDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + MysqlDriver::class, + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The exporter checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the exporter. - * @param string[]|string|null $from Database tables to export from. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the exporter. + * @param string[]|string|null $from Database tables to export from. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -292,10 +295,11 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $exporter = new MysqlExporter(); if ($db) { - $exporter->setDbo($db); + $exporter->setDbo($this->createMock($db)); } if ($from) { + $exporter->from($from); } diff --git a/Tests/Mysql/MysqlImporterTest.php b/Tests/Mysql/MysqlImporterTest.php index d9484a30..512d4439 100644 --- a/Tests/Mysql/MysqlImporterTest.php +++ b/Tests/Mysql/MysqlImporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Mysql\MysqlDriver; use Joomla\Database\Mysql\MysqlImporter; use Joomla\Database\Mysql\MysqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -205,9 +206,9 @@ protected function tearDown(): void /** * Data provider for import test cases * - * @return \Generator + * @return array */ - public function dataImport(): \Generator + public static function dataImport(): array { $idField = ''; $titleField = ''; @@ -216,87 +217,89 @@ public function dataImport(): \Generator $idKey = ''; $titleKey = ''; - yield 'no changes in existing structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . ''), - [], - [], - ]; + return [ + 'no changes in existing structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . ''), + [], + [], + ], - yield 'inserts row into database' => [ - true, - true, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . ' 1Testing'), - [], - [ - 'jos_dbtest' => [ - (object) [ - 'id' => '1', - 'title' => 'Testing', + 'inserts row into database' => [ + true, + true, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . ' 1Testing'), + [], + [ + 'jos_dbtest' => [ + (object) [ + 'id' => '1', + 'title' => 'Testing', + ], ], ], ], - ]; - yield 'adds alias column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $aliasField . $idKey . ''), - [ - "ALTER TABLE `jos_dbtest` ADD COLUMN `alias` varchar(255) NOT NULL DEFAULT ''", + 'adds alias column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $aliasField . $idKey . ''), + [ + "ALTER TABLE `jos_dbtest` ADD COLUMN `alias` varchar(255) NOT NULL DEFAULT ''", + ], + [], ], - [], - ]; - yield 'adds key for the title column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . $titleKey . ''), - [ - 'ALTER TABLE `jos_dbtest` ADD UNIQUE KEY `idx_title` (`title`)', + 'adds key for the title column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . $titleKey . ''), + [ + 'ALTER TABLE `jos_dbtest` ADD UNIQUE KEY `idx_title` (`title`)', + ], + [], ], - [], - ]; - yield 'removes the title column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $idKey . ''), - [ - 'ALTER TABLE `jos_dbtest` DROP COLUMN `title`', + 'removes the title column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $idKey . ''), + [ + 'ALTER TABLE `jos_dbtest` DROP COLUMN `title`', + ], + [], ], - [], - ]; - yield 'removes the primary key based on the id column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . ''), - [ - 'ALTER TABLE `jos_dbtest` DROP PRIMARY KEY', + 'removes the primary key based on the id column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . ''), + [ + 'ALTER TABLE `jos_dbtest` DROP PRIMARY KEY', + ], + [], ], - [], - ]; - yield 'adds a new database table' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . '' . $idField . $titleField . $idKey . ''), - [ - "CREATE TABLE `#__newtest` (`id` int(11) unsigned NOT NULL DEFAULT '' AUTO_INCREMENT, `title` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`))", + 'adds a new database table' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . '' . $idField . $titleField . $idKey . ''), + [ + "CREATE TABLE `#__newtest` (`id` int(11) unsigned NOT NULL DEFAULT '' AUTO_INCREMENT, `title` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`))", + ], + [], ], - [], - ]; - yield 'changes the field type of the id field' => [ - true, - false, - new \SimpleXMLElement('' . $titleField . $idKey . ''), - [ - "ALTER TABLE `jos_dbtest` CHANGE COLUMN `id` `id` bigint() unsigned NOT NULL DEFAULT '' AUTO_INCREMENT", + 'changes the field type of the id field' => [ + true, + false, + new \SimpleXMLElement('' . $titleField . $idKey . ''), + [ + "ALTER TABLE `jos_dbtest` CHANGE COLUMN `id` `id` bigint() unsigned NOT NULL DEFAULT '' AUTO_INCREMENT", + ], + [], ], - [], ]; } @@ -308,9 +311,8 @@ public function dataImport(): \Generator * @param \SimpleXMLElement $from XML document to import. * @param string[] $expectedQueries The expected database queries to perform. * @param string[] $expectedInsertObjects The expected objects to be given to the database's insertObject method. - * - * @dataProvider dataImport */ + #[DataProvider('dataImport')] public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLElement $from, array $expectedQueries, array $expectedInsertObjects) { $importer = new MysqlImporter(); @@ -332,45 +334,46 @@ public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLEle /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(MysqlDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + MysqlDriver::class, + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + DatabaseInterface::class, + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(MysqlDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + MysqlDriver::class, + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The importer checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the importer. - * @param string[]|string|null $from Database structure to import. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the importer. + * @param string[]|string|null $from Database structure to import. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -380,7 +383,7 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $importer = new MysqlImporter(); if ($db) { - $importer->setDbo($db); + $importer->setDbo($this->createMock($db)); } if ($from) { diff --git a/Tests/Mysql/MysqlQueryTest.php b/Tests/Mysql/MysqlQueryTest.php index f8e6e4d0..a9d96c62 100644 --- a/Tests/Mysql/MysqlQueryTest.php +++ b/Tests/Mysql/MysqlQueryTest.php @@ -8,6 +8,7 @@ use Joomla\Database\DatabaseInterface; use Joomla\Database\Mysql\MysqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -48,12 +49,14 @@ protected function setUp(): void /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, 'CONCAT(foo,bar)']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "CONCAT_WS(' and ', foo, bar)"]; + return [ + 'values without separator' => [['foo', 'bar'], null, 'CONCAT(foo,bar)'], + 'values with separator' => [['foo', 'bar'], ' and ', "CONCAT_WS(' and ', foo, bar)"], + ]; } /** @@ -62,9 +65,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) diff --git a/Tests/Mysqli/MysqliDriverTest.php b/Tests/Mysqli/MysqliDriverTest.php index e2342239..59d5d33d 100644 --- a/Tests/Mysqli/MysqliDriverTest.php +++ b/Tests/Mysqli/MysqliDriverTest.php @@ -15,6 +15,7 @@ use Joomla\Database\Mysqli\MysqliQuery; use Joomla\Database\ParameterType; use Joomla\Database\Tests\AbstractDatabaseDriverTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Test class for Joomla\Database\Mysqli\MysqliDriver @@ -95,22 +96,24 @@ protected function tearDown(): void /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - public function dataEscape(): \Generator + public static function dataEscape(): array { - yield ["'%_abc123", false, '\\\'%_abc123']; - yield ["'%_abc123", true, '\\\'\\%\_abc123']; - yield [3, false, 3]; - yield [3.14, false, '3.14']; + return [ + ["'%_abc123", false, '\\\'%_abc123'], + ["'%_abc123", true, '\\\'\\%\_abc123'], + [3, false, 3], + [3.14, false, '3.14'], + ]; } /** * Data provider for fetching table column test cases * - * @return \Generator + * @return array */ - public function dataGetTableColumns(): \Generator + public static function dataGetTableColumns(): array { // For unknown reasons, the connection gets lost on Travis. re-establish, if that happens if (static::$connection === null) { @@ -120,76 +123,78 @@ public function dataGetTableColumns(): \Generator $isMySQL8 = !static::$connection->isMariaDb() && version_compare(static::$connection->getVersion(), '8.0', '>='); $useDisplayWidth = static::$connection->isMariaDb() || version_compare(static::$connection->getVersion(), '8.0.17', '<'); - yield 'only column types' => [ - '#__dbtest', - true, - [ - 'id' => 'int unsigned', - 'title' => 'varchar', - 'start_date' => 'datetime', - 'description' => 'text', - 'data' => 'blob', + return [ + 'only column types' => [ + '#__dbtest', + true, + [ + 'id' => 'int unsigned', + 'title' => 'varchar', + 'start_date' => 'datetime', + 'description' => 'text', + 'data' => 'blob', + ], ], - ]; - yield 'full column information' => [ - '#__dbtest', - false, - [ - 'id' => (object) [ - 'Field' => 'id', - 'Type' => $useDisplayWidth ? 'int(10) unsigned' : 'int unsigned', - 'Collation' => $isMySQL8 ? null : '', - 'Null' => 'NO', - 'Key' => 'PRI', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => 'auto_increment', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'title' => (object) [ - 'Field' => 'title', - 'Type' => 'varchar(50)', - 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', - 'Null' => 'NO', - 'Key' => '', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'start_date' => (object) [ - 'Field' => 'start_date', - 'Type' => 'datetime', - 'Collation' => '', - 'Null' => 'NO', - 'Key' => '', - 'Default' => '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'description' => (object) [ - 'Field' => 'description', - 'Type' => 'text', - 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', - 'Null' => 'NO', - 'Key' => '', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'data' => (object) [ - 'Field' => 'data', - 'Type' => 'blob', - 'Collation' => '', - 'Null' => 'YES', - 'Key' => '', - 'Default' => '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', + 'full column information' => [ + '#__dbtest', + false, + [ + 'id' => (object) [ + 'Field' => 'id', + 'Type' => $useDisplayWidth ? 'int(10) unsigned' : 'int unsigned', + 'Collation' => $isMySQL8 ? null : '', + 'Null' => 'NO', + 'Key' => 'PRI', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => 'auto_increment', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'title' => (object) [ + 'Field' => 'title', + 'Type' => 'varchar(50)', + 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', + 'Null' => 'NO', + 'Key' => '', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'start_date' => (object) [ + 'Field' => 'start_date', + 'Type' => 'datetime', + 'Collation' => '', + 'Null' => 'NO', + 'Key' => '', + 'Default' => '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'description' => (object) [ + 'Field' => 'description', + 'Type' => 'text', + 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', + 'Null' => 'NO', + 'Key' => '', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'data' => (object) [ + 'Field' => 'data', + 'Type' => 'blob', + 'Collation' => '', + 'Null' => 'YES', + 'Key' => '', + 'Default' => '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], ], ], ]; @@ -198,37 +203,43 @@ public function dataGetTableColumns(): \Generator /** * Data provider for table dropping test cases * - * @return \Generator + * @return array */ - public function dataDropTable() + public static function dataDropTable(): array { - yield 'database exists before query' => ['#__dbtest', true]; + return [ + 'database exists before query' => ['#__dbtest', true], - yield 'database does not exist before query' => ['#__foo', false]; + 'database does not exist before query' => ['#__foo', false], + ]; } /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteBinary(): \Generator + public static function dataQuoteBinary(): array { - yield ['DATA', "X'" . bin2hex('DATA') . "'"]; - yield ["\x00\x01\x02\xff", "X'000102ff'"]; - yield ["\x01\x01\x02\xff", "X'010102ff'"]; + return [ + ['DATA', "X'" . bin2hex('DATA') . "'"], + ["\x00\x01\x02\xff", "X'000102ff'"], + ["\x01\x01\x02\xff", "X'010102ff'"], + ]; } /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteName(): \Generator + public static function dataQuoteName(): array { - yield ['protected`title', null, '`protected``title`']; - yield ['protected"title', null, '`protected"title`']; - yield ['protected]title', null, '`protected]title`']; + return [ + ['protected`title', null, '`protected``title`'], + ['protected"title', null, '`protected"title`'], + ['protected]title', null, '`protected]title`'], + ]; } /* @@ -389,13 +400,15 @@ public function testTransactionCommit() /** * Data provider for transaction rollback test cases * - * @return \Generator + * @return array */ - public function dataTransactionRollback() + public static function dataTransactionRollback(): array { - yield 'rollback without savepoint' => [null, 0]; + return [ + 'rollback without savepoint' => [null, 0], - yield 'rollback with savepoint' => ['transactionSavepoint', 1]; + 'rollback with savepoint' => ['transactionSavepoint', 1], + ]; } /** @@ -403,9 +416,8 @@ public function dataTransactionRollback() * * @param string|null $toSavepoint Savepoint name to rollback transaction to * @param integer $tupleCount Number of tuples found after insertion and rollback - * - * @dataProvider dataTransactionRollback */ + #[DataProvider('dataTransactionRollback')] public function testTransactionRollback(?string $toSavepoint, int $tupleCount) { $this->loadExampleData(); diff --git a/Tests/Mysqli/MysqliExporterTest.php b/Tests/Mysqli/MysqliExporterTest.php index 429b41c8..9059f3fd 100644 --- a/Tests/Mysqli/MysqliExporterTest.php +++ b/Tests/Mysqli/MysqliExporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Mysqli\MysqliDriver; use Joomla\Database\Mysqli\MysqliExporter; use Joomla\Database\Mysqli\MysqliQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -120,11 +121,12 @@ function ($name, $as = null) { /** * Data provider for string casting test cases * - * @return \Generator + * @return array */ - public function dataCastingToString(): \Generator + public static function dataCastingToString(): array { - yield 'without structure or data' => [ + return [ + 'without structure or data' => [ false, false, << XML , - ]; + ], - yield 'with only structure' => [ + 'with only structure' => [ true, false, << XML , - ]; + ], - yield 'with only data' => [ + 'with only data' => [ false, true, << XML , - ]; + ], - yield 'with structure and data' => [ + 'with structure and data' => [ true, true, << XML , + ], ]; } @@ -209,9 +212,8 @@ public function dataCastingToString(): \Generator * @param boolean $withStructure True to export the structure, false to not. * @param boolean $withData True to export the data, false to not. * @param string $expectedXml Expected XML string. - * - * @dataProvider dataCastingToString */ + #[DataProvider('dataCastingToString')] public function testCastingToString(bool $withStructure, bool $withData, string $expectedXml) { $exporter = new MysqliExporter(); @@ -244,45 +246,46 @@ public function testCastingToString(bool $withStructure, bool $withData, string /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(MysqliDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + MysqliDriver::class, + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + DatabaseInterface::class, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(MysqliDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + MysqliDriver::class, + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The exporter checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the exporter. - * @param string[]|string|null $from Database tables to export from. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the exporter. + * @param string[]|string|null $from Database tables to export from. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -292,7 +295,7 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $exporter = new MysqliExporter(); if ($db) { - $exporter->setDbo($db); + $exporter->setDbo($this->createMock($db)); } if ($from) { diff --git a/Tests/Mysqli/MysqliImporterTest.php b/Tests/Mysqli/MysqliImporterTest.php index b5fb6c1d..b60f457d 100644 --- a/Tests/Mysqli/MysqliImporterTest.php +++ b/Tests/Mysqli/MysqliImporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Mysqli\MysqliDriver; use Joomla\Database\Mysqli\MysqliImporter; use Joomla\Database\Mysqli\MysqliQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -205,9 +206,9 @@ protected function tearDown(): void /** * Data provider for import test cases * - * @return \Generator + * @return array */ - public function dataImport(): \Generator + public static function dataImport(): array { $idField = ''; $titleField = ''; @@ -216,87 +217,89 @@ public function dataImport(): \Generator $idKey = ''; $titleKey = ''; - yield 'no changes in existing structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . ''), - [], - [], - ]; + return [ + 'no changes in existing structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . ''), + [], + [], + ], - yield 'inserts row into database' => [ - true, - true, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . ' 1Testing'), - [], - [ - 'jos_dbtest' => [ - (object) [ - 'id' => '1', - 'title' => 'Testing', + 'inserts row into database' => [ + true, + true, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . ' 1Testing'), + [], + [ + 'jos_dbtest' => [ + (object) [ + 'id' => '1', + 'title' => 'Testing', + ], ], ], ], - ]; - yield 'adds alias column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $aliasField . $idKey . ''), - [ - "ALTER TABLE `jos_dbtest` ADD COLUMN `alias` varchar(255) NOT NULL DEFAULT ''", + 'adds alias column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $aliasField . $idKey . ''), + [ + "ALTER TABLE `jos_dbtest` ADD COLUMN `alias` varchar(255) NOT NULL DEFAULT ''", + ], + [], ], - [], - ]; - yield 'adds key for the title column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . $titleKey . ''), - [ - 'ALTER TABLE `jos_dbtest` ADD UNIQUE KEY `idx_title` (`title`)', + 'adds key for the title column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . $titleKey . ''), + [ + 'ALTER TABLE `jos_dbtest` ADD UNIQUE KEY `idx_title` (`title`)', + ], + [], ], - [], - ]; - yield 'removes the title column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $idKey . ''), - [ - 'ALTER TABLE `jos_dbtest` DROP COLUMN `title`', + 'removes the title column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $idKey . ''), + [ + 'ALTER TABLE `jos_dbtest` DROP COLUMN `title`', + ], + [], ], - [], - ]; - yield 'removes the primary key based on the id column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . ''), - [ - 'ALTER TABLE `jos_dbtest` DROP PRIMARY KEY', + 'removes the primary key based on the id column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . ''), + [ + 'ALTER TABLE `jos_dbtest` DROP PRIMARY KEY', + ], + [], ], - [], - ]; - yield 'adds a new database table' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . '' . $idField . $titleField . $idKey . ''), - [ - "CREATE TABLE `#__newtest` (`id` int(11) unsigned NOT NULL DEFAULT '' AUTO_INCREMENT, `title` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`))", + 'adds a new database table' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . '' . $idField . $titleField . $idKey . ''), + [ + "CREATE TABLE `#__newtest` (`id` int(11) unsigned NOT NULL DEFAULT '' AUTO_INCREMENT, `title` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`))", + ], + [], ], - [], - ]; - yield 'changes the field type of the id field' => [ - true, - false, - new \SimpleXMLElement('' . $titleField . $idKey . ''), - [ - "ALTER TABLE `jos_dbtest` CHANGE COLUMN `id` `id` bigint() unsigned NOT NULL DEFAULT '' AUTO_INCREMENT", + 'changes the field type of the id field' => [ + true, + false, + new \SimpleXMLElement('' . $titleField . $idKey . ''), + [ + "ALTER TABLE `jos_dbtest` CHANGE COLUMN `id` `id` bigint() unsigned NOT NULL DEFAULT '' AUTO_INCREMENT", + ], + [], ], - [], ]; } @@ -308,9 +311,8 @@ public function dataImport(): \Generator * @param \SimpleXMLElement $from XML document to import. * @param string[] $expectedQueries The expected database queries to perform. * @param string[] $expectedInsertObjects The expected objects to be given to the database's insertObject method. - * - * @dataProvider dataImport */ + #[DataProvider('dataImport')] public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLElement $from, array $expectedQueries, array $expectedInsertObjects) { $importer = new MysqliImporter(); @@ -332,45 +334,46 @@ public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLEle /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(MysqliDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + MysqliDriver::class, + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + DatabaseInterface::class, + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(MysqliDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + MysqliDriver::class, + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The importer checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the importer. - * @param string[]|string|null $from Database structure to import. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the importer. + * @param string[]|string|null $from Database structure to import. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -380,7 +383,7 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $importer = new MysqliImporter(); if ($db) { - $importer->setDbo($db); + $importer->setDbo($this->createMock($db)); } if ($from) { diff --git a/Tests/Mysqli/MysqliQueryTest.php b/Tests/Mysqli/MysqliQueryTest.php index d14e795c..6b5893fe 100644 --- a/Tests/Mysqli/MysqliQueryTest.php +++ b/Tests/Mysqli/MysqliQueryTest.php @@ -8,6 +8,7 @@ use Joomla\Database\DatabaseInterface; use Joomla\Database\Mysqli\MysqliQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -48,12 +49,14 @@ protected function setUp(): void /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, 'CONCAT(foo,bar)']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "CONCAT_WS(' and ', foo, bar)"]; + return [ + 'values without separator' => [['foo', 'bar'], null, 'CONCAT(foo,bar)'], + 'values with separator' => [['foo', 'bar'], ' and ', "CONCAT_WS(' and ', foo, bar)"], + ]; } /** @@ -62,9 +65,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) diff --git a/Tests/Pgsql/PgsqlDriverTest.php b/Tests/Pgsql/PgsqlDriverTest.php index 93748813..ee297a71 100644 --- a/Tests/Pgsql/PgsqlDriverTest.php +++ b/Tests/Pgsql/PgsqlDriverTest.php @@ -12,6 +12,7 @@ use Joomla\Database\Pgsql\PgsqlImporter; use Joomla\Database\Pgsql\PgsqlQuery; use Joomla\Database\Tests\AbstractDatabaseDriverTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Test class for Joomla\Database\Pgsql\PgsqlDriver @@ -54,75 +55,77 @@ protected function tearDown(): void /** * Data provider for fetching table column test cases * - * @return \Generator + * @return array */ - public function dataGetTableColumns(): \Generator + public static function dataGetTableColumns(): array { - yield 'only column types' => [ - '#__dbtest', - true, - [ - 'id' => 'integer', - 'title' => 'character varying', - 'start_date' => 'timestamp without time zone', - 'description' => 'text', - 'data' => 'bytea', + return [ + 'only column types' => [ + '#__dbtest', + true, + [ + 'id' => 'integer', + 'title' => 'character varying', + 'start_date' => 'timestamp without time zone', + 'description' => 'text', + 'data' => 'bytea', + ], ], - ]; - yield 'full column information' => [ - '#__dbtest', - false, - [ - 'id' => (object) [ - 'column_name' => 'id', - 'Field' => 'id', - 'type' => 'integer', - 'Type' => 'integer', - 'null' => 'NO', - 'Null' => 'NO', - 'Default' => 'nextval(\'dbtest_id_seq\'::regclass)', - 'comments' => '', - ], - 'title' => (object) [ - 'column_name' => 'title', - 'Field' => 'title', - 'type' => 'character varying(50)', - 'Type' => 'character varying(50)', - 'null' => 'NO', - 'Null' => 'NO', - 'Default' => null, - 'comments' => '', - ], - 'start_date' => (object) [ - 'column_name' => 'start_date', - 'Field' => 'start_date', - 'type' => 'timestamp without time zone', - 'Type' => 'timestamp without time zone', - 'null' => 'NO', - 'Null' => 'NO', - 'Default' => null, - 'comments' => '', - ], - 'description' => (object) [ - 'column_name' => 'description', - 'Field' => 'description', - 'type' => 'text', - 'Type' => 'text', - 'null' => 'NO', - 'Null' => 'NO', - 'Default' => null, - 'comments' => '', - ], - 'data' => (object) [ - 'column_name' => 'data', - 'Field' => 'data', - 'type' => 'bytea', - 'Type' => 'bytea', - 'null' => 'YES', - 'Null' => 'YES', - 'Default' => null, - 'comments' => '', + 'full column information' => [ + '#__dbtest', + false, + [ + 'id' => (object) [ + 'column_name' => 'id', + 'Field' => 'id', + 'type' => 'integer', + 'Type' => 'integer', + 'null' => 'NO', + 'Null' => 'NO', + 'Default' => 'nextval(\'dbtest_id_seq\'::regclass)', + 'comments' => '', + ], + 'title' => (object) [ + 'column_name' => 'title', + 'Field' => 'title', + 'type' => 'character varying(50)', + 'Type' => 'character varying(50)', + 'null' => 'NO', + 'Null' => 'NO', + 'Default' => null, + 'comments' => '', + ], + 'start_date' => (object) [ + 'column_name' => 'start_date', + 'Field' => 'start_date', + 'type' => 'timestamp without time zone', + 'Type' => 'timestamp without time zone', + 'null' => 'NO', + 'Null' => 'NO', + 'Default' => null, + 'comments' => '', + ], + 'description' => (object) [ + 'column_name' => 'description', + 'Field' => 'description', + 'type' => 'text', + 'Type' => 'text', + 'null' => 'NO', + 'Null' => 'NO', + 'Default' => null, + 'comments' => '', + ], + 'data' => (object) [ + 'column_name' => 'data', + 'Field' => 'data', + 'type' => 'bytea', + 'Type' => 'bytea', + 'null' => 'YES', + 'Null' => 'YES', + 'Default' => null, + 'comments' => '', + ], ], ], ]; @@ -131,50 +134,58 @@ public function dataGetTableColumns(): \Generator /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteBinary(): \Generator + public static function dataQuoteBinary(): array { - yield ['DATA', "decode('44415441', 'hex')"]; - yield ["\x00\x01\x02\xff", "decode('000102ff', 'hex')"]; - yield ["\x01\x01\x02\xff", "decode('010102ff', 'hex')"]; + return [ + ['DATA', "decode('44415441', 'hex')"], + ["\x00\x01\x02\xff", "decode('000102ff', 'hex')"], + ["\x01\x01\x02\xff", "decode('010102ff', 'hex')"], + ]; } /** * Data provider for table dropping test cases * - * @return \Generator + * @return array */ - public function dataDropTable() + public static function dataDropTable(): array { - yield 'database does not exist before query' => ['#__foo', false]; + return [ + 'database does not exist before query' => ['#__foo', false], + ]; } /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - public function dataEscape(): \Generator + public static function dataEscape(): array { - yield ["'%_abc123", false, '\'\'%_abc123']; - yield ["'%_abc123", true, '\'\'%_abc123']; - yield ["\'%_abc123", false, '\\\\\'\'%_abc123']; - yield ["\'%_abc123", true, '\\\\\'\'%_abc123']; - yield [3, false, 3]; - yield [3.14, false, '3.14']; + return [ + ["'%_abc123", false, '\'\'%_abc123'], + ["'%_abc123", true, '\'\'%_abc123'], + ["\'%_abc123", false, '\\\\\'\'%_abc123'], + ["\'%_abc123", true, '\\\\\'\'%_abc123'], + [3, false, 3], + [3.14, false, '3.14'], + ]; } /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteName(): \Generator + public static function dataQuoteName(): array { - yield ['protected`title', null, '"protected`title"']; - yield ['protected"title', null, '"protected""title"']; - yield ['protected]title', null, '"protected]title"']; + return [ + ['protected`title', null, '"protected`title"'], + ['protected"title', null, '"protected""title"'], + ['protected]title', null, '"protected]title"'], + ]; } /* @@ -452,13 +463,15 @@ public function testTransactionCommit() /** * Data provider for transaction rollback test cases * - * @return \Generator + * @return array */ - public function dataTransactionRollback() + public static function dataTransactionRollback(): array { - yield 'rollback without savepoint' => [null, 0]; + return [ + 'rollback without savepoint' => [null, 0], - yield 'rollback with savepoint' => ['transactionSavepoint', 1]; + 'rollback with savepoint' => ['transactionSavepoint', 1], + ]; } /** @@ -466,9 +479,8 @@ public function dataTransactionRollback() * * @param string|null $toSavepoint Savepoint name to rollback transaction to * @param integer $tupleCount Number of tuples found after insertion and rollback - * - * @dataProvider dataTransactionRollback */ + #[DataProvider('dataTransactionRollback')] public function testTransactionRollback(?string $toSavepoint, int $tupleCount) { $this->loadExampleData(); diff --git a/Tests/Pgsql/PgsqlExporterTest.php b/Tests/Pgsql/PgsqlExporterTest.php index ad83cc38..468b7269 100644 --- a/Tests/Pgsql/PgsqlExporterTest.php +++ b/Tests/Pgsql/PgsqlExporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Pgsql\PgsqlDriver; use Joomla\Database\Pgsql\PgsqlExporter; use Joomla\Database\Pgsql\PgsqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -142,11 +143,12 @@ function ($name, $as = null) { /** * Data provider for string casting test cases * - * @return \Generator + * @return array */ - public function dataCastingToString(): \Generator + public static function dataCastingToString(): array { - yield 'without structure or data' => [ + return [ + 'without structure or data' => [ false, false, << XML , - ]; + ], - yield 'with only structure' => [ + 'with only structure' => [ true, false, << XML , - ]; + ], - yield 'with only data' => [ + 'with only data' => [ false, true, << XML , - ]; + ], - yield 'with structure and data' => [ + 'with structure and data' => [ true, true, << XML , + ], ]; } @@ -237,9 +240,8 @@ public function dataCastingToString(): \Generator * @param boolean $withStructure True to export the structure, false to not. * @param boolean $withData True to export the data, false to not. * @param string $expectedXml Expected XML string. - * - * @dataProvider dataCastingToString */ + #[DataProvider('dataCastingToString')] public function testCastingToString(bool $withStructure, bool $withData, string $expectedXml) { $exporter = new PgsqlExporter(); @@ -272,45 +274,46 @@ public function testCastingToString(bool $withStructure, bool $withData, string /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(PgsqlDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + PgsqlDriver::class, + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + DatabaseInterface::class, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(PgsqlDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + PgsqlDriver::class, + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The exporter checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the exporter. - * @param string[]|string|null $from Database tables to export from. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the exporter. + * @param string[]|string|null $from Database tables to export from. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -320,7 +323,7 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $exporter = new PgsqlExporter(); if ($db) { - $exporter->setDbo($db); + $exporter->setDbo($this->createMock($db)); } if ($from) { diff --git a/Tests/Pgsql/PgsqlImporterTest.php b/Tests/Pgsql/PgsqlImporterTest.php index 92750c88..ff87b852 100644 --- a/Tests/Pgsql/PgsqlImporterTest.php +++ b/Tests/Pgsql/PgsqlImporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Pgsql\PgsqlDriver; use Joomla\Database\Pgsql\PgsqlImporter; use Joomla\Database\Pgsql\PgsqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -211,9 +212,9 @@ protected function tearDown(): void /** * Data provider for import test cases * - * @return \Generator + * @return array */ - public function dataImport(): \Generator + public static function dataImport(): array { $idSequence = ''; @@ -224,93 +225,95 @@ public function dataImport(): \Generator $idKey = ''; $titleKey = ''; - yield 'no changes in existing structure' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . ''), - [], - [], - ]; + return [ + 'no changes in existing structure' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . ''), + [], + [], + ], - yield 'inserts row into database' => [ - true, - true, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . ' 1Testing'), - [], - [ - 'jos_dbtest' => [ - (object) [ - 'id' => '1', - 'title' => 'Testing', + 'inserts row into database' => [ + true, + true, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . ' 1Testing'), + [], + [ + 'jos_dbtest' => [ + (object) [ + 'id' => '1', + 'title' => 'Testing', + ], ], ], ], - ]; - yield 'adds alias column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $aliasField . $idKey . ''), - [ - "ALTER TABLE \"jos_dbtest\" ADD COLUMN \"alias\" character varying(255) NOT NULL DEFAULT 'test'", + 'adds alias column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $aliasField . $idKey . ''), + [ + "ALTER TABLE \"jos_dbtest\" ADD COLUMN \"alias\" character varying(255) NOT NULL DEFAULT 'test'", + ], + [], ], - [], - ]; - yield 'adds key for the title column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . $titleKey . ''), - [ - 'CREATE INDEX jos_dbtest_idx_name ON jos_dbtest USING btree (name)', + 'adds key for the title column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . $titleKey . ''), + [ + 'CREATE INDEX jos_dbtest_idx_name ON jos_dbtest USING btree (name)', + ], + [], ], - [], - ]; - yield 'removes the title column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $idKey . ''), - [ - 'ALTER TABLE "jos_dbtest" DROP COLUMN "title"', + 'removes the title column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $idKey . ''), + [ + 'ALTER TABLE "jos_dbtest" DROP COLUMN "title"', + ], + [], ], - [], - ]; - yield 'removes the primary key based on the id column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . ''), - [ - 'ALTER TABLE ONLY "jos_dbtest" DROP CONSTRAINT "jos_dbtest_pkey"', + 'removes the primary key based on the id column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . ''), + [ + 'ALTER TABLE ONLY "jos_dbtest" DROP CONSTRAINT "jos_dbtest_pkey"', + ], + [], ], - [], - ]; - yield 'adds a new database table' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . '' . $titleField . ''), - [ - 'CREATE TABLE "jos_newtest" ("id" SERIAL, "title" character varying(50) NOT NULL DEFAULT \'NULL\')', - 'CREATE SEQUENCE IF NOT EXISTS jos_newtest_id_seq INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 NO CYCLE OWNED BY "public.jos_newtest.id"', - "SELECT setval('jos_newtest_id_seq', , FALSE)", - 'ALTER TABLE jos_newtest ADD PRIMARY KEY (id)', + 'adds a new database table' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . '' . $titleField . ''), + [ + 'CREATE TABLE "jos_newtest" ("id" SERIAL, "title" character varying(50) NOT NULL DEFAULT \'NULL\')', + 'CREATE SEQUENCE IF NOT EXISTS jos_newtest_id_seq INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 NO CYCLE OWNED BY "public.jos_newtest.id"', + "SELECT setval('jos_newtest_id_seq', , FALSE)", + 'ALTER TABLE jos_newtest ADD PRIMARY KEY (id)', + ], + [], ], - [], - ]; - yield 'changes the field type of the id field' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . '' . $titleField . $idKey . ''), - [ - 'ALTER TABLE "jos_dbtest" ALTER COLUMN "id" TYPE bigint, -ALTER COLUMN "id" SET NOT NULL, -ALTER COLUMN "id" SET DEFAULT \'nextval(\'jos_dbtest_id_seq\'::regclass)\'; -ALTER SEQUENCE "jos_dbtest_id_seq" OWNED BY "jos_dbtest.id"', + 'changes the field type of the id field' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . '' . $titleField . $idKey . ''), + [ + 'ALTER TABLE "jos_dbtest" ALTER COLUMN "id" TYPE bigint, + ALTER COLUMN "id" SET NOT NULL, + ALTER COLUMN "id" SET DEFAULT \'nextval(\'jos_dbtest_id_seq\'::regclass)\'; + ALTER SEQUENCE "jos_dbtest_id_seq" OWNED BY "jos_dbtest.id"', + ], + [], ], - [], ]; } @@ -322,9 +325,8 @@ public function dataImport(): \Generator * @param \SimpleXMLElement $from XML document to import. * @param string[] $expectedQueries The expected database queries to perform. * @param string[] $expectedInsertObjects The expected objects to be given to the database's insertObject method. - * - * @dataProvider dataImport */ + #[DataProvider('dataImport')] public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLElement $from, array $expectedQueries, array $expectedInsertObjects) { $importer = new PgsqlImporter(); @@ -346,45 +348,46 @@ public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLEle /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(PgsqlDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + $this->createMock(PgsqlDriver::class), + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + $this->createMock(DatabaseInterface::class), + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(PgsqlDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + $this->createMock(PgsqlDriver::class), + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The importer checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the importer. - * @param string[]|string|null $from Database structure to import. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the importer. + * @param string[]|string|null $from Database structure to import. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -394,7 +397,7 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $importer = new PgsqlImporter(); if ($db) { - $importer->setDbo($db); + $importer->setDbo($this->createMock($db)); } if ($from) { diff --git a/Tests/Pgsql/PgsqlQueryTest.php b/Tests/Pgsql/PgsqlQueryTest.php index a32a4eb0..b04f63a6 100644 --- a/Tests/Pgsql/PgsqlQueryTest.php +++ b/Tests/Pgsql/PgsqlQueryTest.php @@ -8,6 +8,7 @@ use Joomla\Database\DatabaseInterface; use Joomla\Database\Pgsql\PgsqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -78,12 +79,14 @@ public function testCastAsWithIntegerType() /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, 'foo || bar']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "foo || ' and ' || bar"]; + return [ + 'values without separator' => [['foo', 'bar'], null, 'foo || bar'], + 'values with separator' => [['foo', 'bar'], ' and ', "foo || ' and ' || bar"], + ]; } /** @@ -92,9 +95,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) @@ -217,12 +219,14 @@ public function testSecond() /** * Data provider for dateAdd test cases * - * @return \Generator + * @return array */ - public function dataDateAdd(): \Generator + public static function dataDateAdd(): array { - yield 'date with positive interval' => ["'2019-10-13'", '1', 'DAY', "timestamp '2019-10-13' + interval '1 DAY'"]; - yield 'date with negative interval' => ["'2019-10-13'", '-1', 'DAY', "timestamp '2019-10-13' - interval '1 DAY'"]; + return [ + 'date with positive interval' => ["'2019-10-13'", '1', 'DAY', "timestamp '2019-10-13' + interval '1 DAY'"], + 'date with negative interval' => ["'2019-10-13'", '-1', 'DAY', "timestamp '2019-10-13' - interval '1 DAY'"], + ]; } /** @@ -232,9 +236,8 @@ public function dataDateAdd(): \Generator * @param string $interval The string representation of the appropriate number of units * @param string $datePart The part of the date to perform the addition on * @param string $expected The expected query string. - * - * @dataProvider dataDateAdd */ + #[DataProvider('dataDateAdd')] public function testDateAdd(string $date, string $interval, string $datePart, string $expected) { $this->assertSame( diff --git a/Tests/Sqlite/SqliteDriverTest.php b/Tests/Sqlite/SqliteDriverTest.php index 940198c5..3d1ec2fc 100644 --- a/Tests/Sqlite/SqliteDriverTest.php +++ b/Tests/Sqlite/SqliteDriverTest.php @@ -13,6 +13,7 @@ use Joomla\Database\Sqlite\SqliteDriver; use Joomla\Database\Sqlite\SqliteQuery; use Joomla\Database\Tests\AbstractDatabaseDriverTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Test class for Joomla\Database\Sqlite\SqliteDriver @@ -88,73 +89,77 @@ function (string $table): bool { /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - public function dataEscape(): \Generator + public static function dataEscape(): array { - yield ["'%_abc123", false, "''%_abc123"]; - yield ["'%_abc123", true, "''%_abc123"]; - yield [3, false, 3]; - yield [3.14, false, '3.14']; + return [ + ["'%_abc123", false, "''%_abc123"], + ["'%_abc123", true, "''%_abc123"], + [3, false, 3], + [3.14, false, '3.14'], + ]; } /** * Data provider for fetching table column test cases * - * @return \Generator - */ - public function dataGetTableColumns(): \Generator - { - yield 'only column types' => [ - '#__dbtest', - true, - [ - 'id' => 'INTEGER', - 'title' => 'TEXT', - 'start_date' => 'TEXT', - 'description' => 'TEXT', - 'data' => 'BLOB', + * @return array + */ + public static function dataGetTableColumns(): array + { + return [ + 'only column types' => [ + '#__dbtest', + true, + [ + 'id' => 'INTEGER', + 'title' => 'TEXT', + 'start_date' => 'TEXT', + 'description' => 'TEXT', + 'data' => 'BLOB', + ], ], - ]; - yield 'full column information' => [ - '#__dbtest', - false, - [ - 'id' => (object) [ - 'Field' => 'id', - 'Type' => 'INTEGER', - 'Null' => 'YES', - 'Default' => null, - 'Key' => 'PRI', - ], - 'title' => (object) [ - 'Field' => 'title', - 'Type' => 'TEXT', - 'Null' => 'NO', - 'Default' => '\'\'', - 'Key' => '', - ], - 'start_date' => (object) [ - 'Field' => 'start_date', - 'Type' => 'TEXT', - 'Null' => 'NO', - 'Default' => '\'\'', - 'Key' => '', - ], - 'description' => (object) [ - 'Field' => 'description', - 'Type' => 'TEXT', - 'Null' => 'NO', - 'Default' => '\'\'', - 'Key' => '', - ], - 'data' => (object) [ - 'Field' => 'data', - 'Type' => 'BLOB', - 'Null' => 'YES', - 'Default' => null, - 'Key' => '', + 'full column information' => [ + '#__dbtest', + false, + [ + 'id' => (object) [ + 'Field' => 'id', + 'Type' => 'INTEGER', + 'Null' => 'YES', + 'Default' => null, + 'Key' => 'PRI', + ], + 'title' => (object) [ + 'Field' => 'title', + 'Type' => 'TEXT', + 'Null' => 'NO', + 'Default' => '\'\'', + 'Key' => '', + ], + 'start_date' => (object) [ + 'Field' => 'start_date', + 'Type' => 'TEXT', + 'Null' => 'NO', + 'Default' => '\'\'', + 'Key' => '', + ], + 'description' => (object) [ + 'Field' => 'description', + 'Type' => 'TEXT', + 'Null' => 'NO', + 'Default' => '\'\'', + 'Key' => '', + ], + 'data' => (object) [ + 'Field' => 'data', + 'Type' => 'BLOB', + 'Null' => 'YES', + 'Default' => null, + 'Key' => '', + ], ], ], ]; @@ -163,37 +168,43 @@ public function dataGetTableColumns(): \Generator /** * Data provider for table dropping test cases * - * @return \Generator + * @return array */ - public function dataDropTable() + public static function dataDropTable(): array { - yield 'database exists before query' => ['#__dbtest', true]; + return [ + 'database exists before query' => ['#__dbtest', true], - yield 'database does not exist before query' => ['#__foo', false]; + 'database does not exist before query' => ['#__foo', false], + ]; } /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteBinary(): \Generator + public static function dataQuoteBinary(): array { - yield ['DATA', "X'" . bin2hex('DATA') . "'"]; - yield ["\x00\x01\x02\xff", "X'000102ff'"]; - yield ["\x01\x01\x02\xff", "X'010102ff'"]; + return [ + ['DATA', "X'" . bin2hex('DATA') . "'"], + ["\x00\x01\x02\xff", "X'000102ff'"], + ["\x01\x01\x02\xff", "X'010102ff'"], + ]; } /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteName(): \Generator + public static function dataQuoteName(): array { - yield ['protected`title', null, '`protected``title`']; - yield ['protected"title', null, '`protected"title`']; - yield ['protected]title', null, '`protected]title`']; + return [ + ['protected`title', null, '`protected``title`'], + ['protected"title', null, '`protected"title`'], + ['protected]title', null, '`protected]title`'], + ]; } /* @@ -412,13 +423,15 @@ public function testTransactionCommit() /** * Data provider for transaction rollback test cases * - * @return \Generator + * @return array */ - public function dataTransactionRollback() + public static function dataTransactionRollback() { - yield 'rollback without savepoint' => [null, 0]; + return [ + 'rollback without savepoint' => [null, 0], - yield 'rollback with savepoint' => ['transactionSavepoint', 1]; + 'rollback with savepoint' => ['transactionSavepoint', 1], + ]; } /** @@ -426,9 +439,8 @@ public function dataTransactionRollback() * * @param string|null $toSavepoint Savepoint name to rollback transaction to * @param integer $tupleCount Number of tuples found after insertion and rollback - * - * @dataProvider dataTransactionRollback */ + #[DataProvider('dataTransactionRollback')] public function testTransactionRollback(?string $toSavepoint, int $tupleCount) { $this->loadExampleData(); diff --git a/Tests/Sqlite/SqliteQueryTest.php b/Tests/Sqlite/SqliteQueryTest.php index fdb910c4..5a444d40 100644 --- a/Tests/Sqlite/SqliteQueryTest.php +++ b/Tests/Sqlite/SqliteQueryTest.php @@ -8,6 +8,7 @@ use Joomla\Database\DatabaseInterface; use Joomla\Database\Sqlite\SqliteQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -48,12 +49,14 @@ protected function setUp(): void /** * Data provider for character length test cases * - * @return \Generator + * @return array */ - public function dataCharLength(): \Generator + public static function dataCharLength(): array { - yield 'field without comparison' => ['a.title', null, null, 'length(a.title)']; - yield 'field with comparison' => ['a.title', '!=', '0', 'length(a.title) != 0']; + return [ + 'field without comparison' => ['a.title', null, null, 'length(a.title)'], + 'field with comparison' => ['a.title', '!=', '0', 'length(a.title) != 0'], + ]; } /** @@ -63,9 +66,8 @@ public function dataCharLength(): \Generator * @param string|null $operator Comparison operator between charLength integer value and $condition * @param string|null $condition Integer value to compare charLength with. * @param string $expected The expected query string. - * - * @dataProvider dataCharLength */ + #[DataProvider('dataCharLength')] public function testCharLength(string $field, ?string $operator, ?string $condition, string $expected) { $this->assertSame( @@ -77,12 +79,14 @@ public function testCharLength(string $field, ?string $operator, ?string $condit /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, 'foo || bar']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "foo || ' and ' || bar"]; + return [ + 'values without separator' => [['foo', 'bar'], null, 'foo || bar'], + 'values with separator' => [['foo', 'bar'], ' and ', "foo || ' and ' || bar"], + ]; } /** @@ -91,9 +95,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) diff --git a/Tests/Sqlsrv/SqlsrvDriverTest.php b/Tests/Sqlsrv/SqlsrvDriverTest.php index 9f8d9607..19bda8fc 100644 --- a/Tests/Sqlsrv/SqlsrvDriverTest.php +++ b/Tests/Sqlsrv/SqlsrvDriverTest.php @@ -12,6 +12,7 @@ use Joomla\Database\Sqlsrv\SqlsrvDriver; use Joomla\Database\Sqlsrv\SqlsrvQuery; use Joomla\Database\Tests\AbstractDatabaseDriverTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Test class for Joomla\Database\Sqlsrv\SqlsrvDriver. @@ -121,68 +122,72 @@ protected function loadExampleData(): void /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - public function dataEscape(): \Generator + public static function dataEscape(): array { - yield ["'%_abc123", false, '\'\'%_abc123']; - yield ["'%_abc123", true, '\'\'[%][_]abc123']; - yield [3, false, 3]; - yield [3.14, false, '3.14']; + return [ + ["'%_abc123", false, '\'\'%_abc123'], + ["'%_abc123", true, '\'\'[%][_]abc123'], + [3, false, 3], + [3.14, false, '3.14'], + ]; } /** * Data provider for fetching table column test cases * - * @return \Generator + * @return array */ - public function dataGetTableColumns(): \Generator + public static function dataGetTableColumns(): array { - yield 'only column types' => [ - '#__dbtest', - true, - [ - 'id' => 'int', - 'title' => 'nvarchar', - 'start_date' => 'datetime', - 'description' => 'nvarchar', - 'data' => 'nvarchar', + return [ + 'only column types' => [ + '#__dbtest', + true, + [ + 'id' => 'int', + 'title' => 'nvarchar', + 'start_date' => 'datetime', + 'description' => 'nvarchar', + 'data' => 'nvarchar', + ], ], - ]; - yield 'full column information' => [ - '#__dbtest', - false, - [ - 'id' => (object) [ - 'Field' => 'id', - 'Type' => 'int', - 'Null' => 'NO', - 'Default' => '', - ], - 'title' => (object) [ - 'Field' => 'title', - 'Type' => 'nvarchar', - 'Null' => 'NO', - 'Default' => '', - ], - 'start_date' => (object) [ - 'Field' => 'start_date', - 'Type' => 'datetime', - 'Null' => 'NO', - 'Default' => '', - ], - 'description' => (object) [ - 'Field' => 'description', - 'Type' => 'nvarchar', - 'Null' => 'NO', - 'Default' => '', - ], - 'data' => (object) [ - 'Field' => 'data', - 'Type' => 'nvarchar', - 'Null' => 'YES', - 'Default' => '', + 'full column information' => [ + '#__dbtest', + false, + [ + 'id' => (object) [ + 'Field' => 'id', + 'Type' => 'int', + 'Null' => 'NO', + 'Default' => '', + ], + 'title' => (object) [ + 'Field' => 'title', + 'Type' => 'nvarchar', + 'Null' => 'NO', + 'Default' => '', + ], + 'start_date' => (object) [ + 'Field' => 'start_date', + 'Type' => 'datetime', + 'Null' => 'NO', + 'Default' => '', + ], + 'description' => (object) [ + 'Field' => 'description', + 'Type' => 'nvarchar', + 'Null' => 'NO', + 'Default' => '', + ], + 'data' => (object) [ + 'Field' => 'data', + 'Type' => 'nvarchar', + 'Null' => 'YES', + 'Default' => '', + ], ], ], ]; @@ -191,25 +196,29 @@ public function dataGetTableColumns(): \Generator /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteBinary(): \Generator + public static function dataQuoteBinary(): array { - yield ['DATA', "0x" . bin2hex('DATA')]; - yield ["\x00\x01\x02\xff", "0x000102ff"]; - yield ["\x01\x01\x02\xff", "0x010102ff"]; + return [ + ['DATA', "0x" . bin2hex('DATA')], + ["\x00\x01\x02\xff", "0x000102ff"], + ["\x01\x01\x02\xff", "0x010102ff"], + ]; } /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteName(): \Generator + public static function dataQuoteName(): array { - yield ['protected`title', null, '[protected`title]']; - yield ['protected"title', null, '[protected"title]']; - yield ['protected]title', null, '[protected]]title]']; + return [ + ['protected`title', null, '[protected`title]'], + ['protected"title', null, '[protected"title]'], + ['protected]title', null, '[protected]]title]'], + ]; } /* @@ -469,9 +478,8 @@ public function testGetTableCreate() * @param string $table The name of the database table. * @param boolean $typeOnly True (default) to only return field types. * @param array $expected Expected result. - * - * @dataProvider dataGetTableColumns */ + #[DataProvider('dataGetTableColumns')] public function testGetTableColumns(string $table, bool $typeOnly, array $expected) { $this->assertEquals( diff --git a/Tests/Sqlsrv/SqlsrvQueryTest.php b/Tests/Sqlsrv/SqlsrvQueryTest.php index e7819d18..cddd4283 100644 --- a/Tests/Sqlsrv/SqlsrvQueryTest.php +++ b/Tests/Sqlsrv/SqlsrvQueryTest.php @@ -8,6 +8,7 @@ use Joomla\Database\DatabaseInterface; use Joomla\Database\Sqlsrv\SqlsrvQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -78,12 +79,14 @@ public function testCastAsWithIntegerType() /** * Data provider for character length test cases * - * @return \Generator + * @return array */ - public function dataCharLength(): \Generator + public static function dataCharLength(): array { - yield 'field without comparison' => ['a.title', null, null, 'DATALENGTH(a.title)']; - yield 'field with comparison' => ['a.title', '!=', '0', 'DATALENGTH(a.title) != 0']; + return [ + 'field without comparison' => ['a.title', null, null, 'DATALENGTH(a.title)'], + 'field with comparison' => ['a.title', '!=', '0', 'DATALENGTH(a.title) != 0'], + ]; } /** @@ -93,9 +96,8 @@ public function dataCharLength(): \Generator * @param string|null $operator Comparison operator between charLength integer value and $condition * @param string|null $condition Integer value to compare charLength with. * @param string $expected The expected query string. - * - * @dataProvider dataCharLength */ + #[DataProvider('dataCharLength')] public function testCharLength(string $field, ?string $operator, ?string $condition, string $expected) { $this->assertSame( @@ -107,12 +109,14 @@ public function testCharLength(string $field, ?string $operator, ?string $condit /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, '(foo+bar)']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "(foo+' and '+bar)"]; + return [ + 'values without separator' => [['foo', 'bar'], null, '(foo+bar)'], + 'values with separator' => [['foo', 'bar'], ' and ', "(foo+' and '+bar)"], + ]; } /** @@ -121,9 +125,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) From 7f403c1fbf90dfea14433a4740ddbfd247580e88 Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Sun, 13 Jul 2025 15:36:35 +0200 Subject: [PATCH 10/11] Updating unittests to phpunit 12 - part 3 --- Tests/Pgsql/PgsqlImporterTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/Pgsql/PgsqlImporterTest.php b/Tests/Pgsql/PgsqlImporterTest.php index ff87b852..b25ba792 100644 --- a/Tests/Pgsql/PgsqlImporterTest.php +++ b/Tests/Pgsql/PgsqlImporterTest.php @@ -308,9 +308,9 @@ public static function dataImport(): array new \SimpleXMLElement('' . $idSequence . '' . $titleField . $idKey . ''), [ 'ALTER TABLE "jos_dbtest" ALTER COLUMN "id" TYPE bigint, - ALTER COLUMN "id" SET NOT NULL, - ALTER COLUMN "id" SET DEFAULT \'nextval(\'jos_dbtest_id_seq\'::regclass)\'; - ALTER SEQUENCE "jos_dbtest_id_seq" OWNED BY "jos_dbtest.id"', +ALTER COLUMN "id" SET NOT NULL, +ALTER COLUMN "id" SET DEFAULT \'nextval(\'jos_dbtest_id_seq\'::regclass)\'; +ALTER SEQUENCE "jos_dbtest_id_seq" OWNED BY "jos_dbtest.id"', ], [], ], @@ -354,13 +354,13 @@ public static function dataCheck(): array { return [ 'passes checks' => [ - $this->createMock(PgsqlDriver::class), + PgsqlDriver::class, '#__dbtest', null, ], 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), + DatabaseInterface::class, new \SimpleXMLElement(''), 'Database connection wrong type.', ], @@ -372,7 +372,7 @@ public static function dataCheck(): array ], 'fails checks with no tables' => [ - $this->createMock(PgsqlDriver::class), + PgsqlDriver::class, null, 'ERROR: No Tables Specified', ], From ad1e06ed2442f7995519ba69ddc0e6f9c464d084 Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Sun, 13 Jul 2025 16:07:13 +0200 Subject: [PATCH 11/11] Adding baseline for phpstan --- .gitattributes | 1 + phpstan-baseline.neon | 721 ++++++++++++++++++++++++++++++++++++++++++ phpstan.neon | 1 + 3 files changed, 723 insertions(+) create mode 100644 phpstan-baseline.neon diff --git a/.gitattributes b/.gitattributes index a77d5a71..9333b663 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,6 +6,7 @@ Tests/ export-ignore .gitattributes export-ignore .gitignore export-ignore phpstan.neon export-ignore +phpstan-baseline.neon export-ignore phpunit.*.xml.dist export-ignore phpunit.xml.dist export-ignore ruleset.xml export-ignore diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 00000000..5d53a9ac --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,721 @@ +parameters: + ignoreErrors: + - + message: '#^Trait Joomla\\Database\\DatabaseAwareTrait is used zero times and is not analysed\.$#' + identifier: trait.unused + count: 1 + path: src/DatabaseAwareTrait.php + + - + message: '#^Access to an undefined property Joomla\\Database\\QueryInterface\:\:\$limit\.$#' + identifier: property.notFound + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Access to an undefined property Joomla\\Database\\QueryInterface\:\:\$offset\.$#' + identifier: property.notFound + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Call to function is_array\(\) with array will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Call to function is_object\(\) with array will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Call to function is_string\(\) with non\-falsy\-string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 11 + path: src/DatabaseDriver.php + + - + message: '#^Instanceof between Joomla\\Database\\QueryInterface and Joomla\\Database\\QueryInterface will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Method Joomla\\Database\\DatabaseDriver\:\:getQuery\(\) should return Joomla\\Database\\DatabaseQuery but returns Joomla\\Database\\QueryInterface\.$#' + identifier: return.type + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Parameter \#2 \$array of function implode expects array\, list\ given\.$#' + identifier: argument.type + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Property Joomla\\Database\\DatabaseDriver\:\:\$connection \(resource\) does not accept null\.$#' + identifier: assign.propertyType + count: 2 + path: src/DatabaseDriver.php + + - + message: '#^Property Joomla\\Database\\DatabaseDriver\:\:\$statement \(Joomla\\Database\\StatementInterface\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Strict comparison using \=\=\= between ''resource''\|''resource \(closed\)'' and ''object'' will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Strict comparison using \=\=\= between stdClass and null will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 2 + path: src/DatabaseDriver.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 5 + path: src/DatabaseIterator.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 2 + path: src/DatabaseIterator.php + + - + message: '#^Argument of an invalid type \$this\(Joomla\\Database\\DatabaseQuery\) supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable + count: 1 + path: src/DatabaseQuery.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 9 + path: src/DatabaseQuery.php + + - + message: '#^Instanceof between Joomla\\Database\\DatabaseInterface and Joomla\\Database\\DatabaseInterface will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue + count: 6 + path: src/DatabaseQuery.php + + - + message: '#^Instanceof between string and \$this\(Joomla\\Database\\DatabaseQuery\) will always evaluate to false\.$#' + identifier: instanceof.alwaysFalse + count: 1 + path: src/DatabaseQuery.php + + - + message: '#^Left side of \|\| is always true\.$#' + identifier: booleanOr.leftAlwaysTrue + count: 1 + path: src/DatabaseQuery.php + + - + message: '#^Parameter \#2 \$array of function implode expects array\|null, string given\.$#' + identifier: argument.type + count: 1 + path: src/DatabaseQuery.php + + - + message: '#^Parameter \#2 \$elements of class Joomla\\Database\\Query\\QueryElement constructor expects array\\|string, null given\.$#' + identifier: argument.type + count: 1 + path: src/DatabaseQuery.php + + - + message: '#^Property Joomla\\Database\\DatabaseQuery\:\:\$querySet has unknown class Joomla\\Database\\Query\\DatabaseQuery as its type\.$#' + identifier: class.notFound + count: 1 + path: src/DatabaseQuery.php + + - + message: '#^Return type \(string\) of method Joomla\\Database\\DatabaseQuery\:\:length\(\) should be compatible with return type \(int\) of method Joomla\\Database\\QueryInterface\:\:length\(\)$#' + identifier: method.childReturnType + count: 1 + path: src/DatabaseQuery.php + + - + message: '#^Unsafe usage of new static\(\)\.$#' + identifier: new.static + count: 1 + path: src/DatabaseQuery.php + + - + message: '#^Call to function is_float\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/Mysql/MysqlDriver.php + + - + message: '#^Call to function is_int\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/Mysql/MysqlDriver.php + + - + message: '#^Call to function is_string\(\) with non\-falsy\-string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: src/Mysql/MysqlDriver.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: src/Mysql/MysqlDriver.php + + - + message: '#^Parameter \#2 \$array of function implode expects array\, list\ given\.$#' + identifier: argument.type + count: 1 + path: src/Mysql/MysqlDriver.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: src/Mysql/MysqlDriver.php + + - + message: '#^Method Joomla\\Database\\Mysql\\MysqlImporter\:\:getKeyLookup\(\) has Exception in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Mysql/MysqlImporter.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: src/Mysql/MysqlQuery.php + + - + message: '#^Call to function is_callable\(\) with array\{mysqli, ''close''\} will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^Call to function is_float\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^Call to function is_int\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^Call to function is_object\(\) with mysqli will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^Call to function is_string\(\) with non\-falsy\-string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^Method Joomla\\Database\\Mysqli\\MysqliDriver\:\:connect\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^Method Joomla\\Database\\Mysqli\\MysqliDriver\:\:serverClaimsUtf8mb4Support\(\) is unused\.$#' + identifier: method.unused + count: 1 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^PHPDoc type mysqli of property Joomla\\Database\\Mysqli\\MysqliDriver\:\:\$connection is not covariant with PHPDoc type resource of overridden property Joomla\\Database\\DatabaseDriver\:\:\$connection\.$#' + identifier: property.phpDocType + count: 1 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^Parameter \#2 \$array of function implode expects array\, list\ given\.$#' + identifier: argument.type + count: 1 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^Property Joomla\\Database\\Mysqli\\MysqliDriver\:\:\$connection \(mysqli\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 2 + path: src/Mysqli/MysqliDriver.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: src/Mysqli/MysqliQuery.php + + - + message: '#^PHPDoc type array of property Joomla\\Database\\Mysqli\\MysqliQuery\:\:\$nullDatetimeList is not covariant with PHPDoc type array\ of overridden property Joomla\\Database\\DatabaseQuery\:\:\$nullDatetimeList\.$#' + identifier: property.phpDocType + count: 1 + path: src/Mysqli/MysqliQuery.php + + - + message: '#^PHPDoc tag @param for parameter \$dataType with type int is incompatible with native type string\.$#' + identifier: parameter.phpDocType + count: 1 + path: src/Mysqli/MysqliStatement.php + + - + message: '#^Parameter \#4 \$previous of class Joomla\\Database\\Exception\\ExecutionFailureException constructor expects Exception\|null, Throwable given\.$#' + identifier: argument.type + count: 1 + path: src/Mysqli/MysqliStatement.php + + - + message: '#^Return type \(int\) of method Joomla\\Database\\Mysqli\\MysqliStatement\:\:errorCode\(\) should be compatible with return type \(string\) of method Joomla\\Database\\StatementInterface\:\:errorCode\(\)$#' + identifier: method.childReturnType + count: 1 + path: src/Mysqli/MysqliStatement.php + + - + message: '#^Return type \(string\) of method Joomla\\Database\\Mysqli\\MysqliStatement\:\:errorInfo\(\) should be compatible with return type \(array\) of method Joomla\\Database\\StatementInterface\:\:errorInfo\(\)$#' + identifier: method.childReturnType + count: 1 + path: src/Mysqli/MysqliStatement.php + + - + message: '#^Strict comparison using \=\=\= between array\|bool and null will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: src/Mysqli/MysqliStatement.php + + - + message: '#^Call to function is_float\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/Pdo/PdoDriver.php + + - + message: '#^Call to function is_int\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/Pdo/PdoDriver.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 4 + path: src/Pdo/PdoDriver.php + + - + message: '#^Method Joomla\\Database\\Pdo\\PdoDriver\:\:connect\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Pdo/PdoDriver.php + + - + message: '#^PHPDoc type PDO of property Joomla\\Database\\Pdo\\PdoDriver\:\:\$connection is not covariant with PHPDoc type resource of overridden property Joomla\\Database\\DatabaseDriver\:\:\$connection\.$#' + identifier: property.phpDocType + count: 1 + path: src/Pdo/PdoDriver.php + + - + message: '#^Property Joomla\\Database\\Pdo\\PdoDriver\:\:\$connection \(PDO\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: src/Pdo/PdoDriver.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: src/Pdo/PdoDriver.php + + - + message: '#^PHPDoc type array of property Joomla\\Database\\Pdo\\PdoQuery\:\:\$nullDatetimeList is not covariant with PHPDoc type array\ of overridden property Joomla\\Database\\DatabaseQuery\:\:\$nullDatetimeList\.$#' + identifier: property.phpDocType + count: 1 + path: src/Pdo/PdoQuery.php + + - + message: '#^Call to function is_object\(\) with array will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/Pgsql/PgsqlDriver.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: src/Pgsql/PgsqlDriver.php + + - + message: '#^Method Joomla\\Database\\Pgsql\\PgsqlDriver\:\:getTableCreate\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Pgsql/PgsqlDriver.php + + - + message: '#^Strict comparison using \=\=\= between string and 0 will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: src/Pgsql/PgsqlDriver.php + + - + message: '#^Strict comparison using \=\=\= between string and 1 will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: src/Pgsql/PgsqlDriver.php + + - + message: '#^Strict comparison using \=\=\= between string and false will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: src/Pgsql/PgsqlDriver.php + + - + message: '#^Strict comparison using \=\=\= between string and true will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: src/Pgsql/PgsqlDriver.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: src/Pgsql/PgsqlDriver.php + + - + message: '#^Instanceof between Joomla\\Database\\Pgsql\\PgsqlDriver and Joomla\\Database\\Pgsql\\PgsqlDriver will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue + count: 1 + path: src/Pgsql/PgsqlExporter.php + + - + message: '#^Cannot access property \$Index on array\.$#' + identifier: property.nonObject + count: 1 + path: src/Pgsql/PgsqlImporter.php + + - + message: '#^Cannot access property \$Key_name on array\.$#' + identifier: property.nonObject + count: 1 + path: src/Pgsql/PgsqlImporter.php + + - + message: '#^Instanceof between Joomla\\Database\\Pgsql\\PgsqlDriver and Joomla\\Database\\Pgsql\\PgsqlDriver will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue + count: 1 + path: src/Pgsql/PgsqlImporter.php + + - + message: '#^Instanceof between array and SimpleXMLElement will always evaluate to false\.$#' + identifier: instanceof.alwaysFalse + count: 1 + path: src/Pgsql/PgsqlImporter.php + + - + message: '#^Method Joomla\\Database\\Pgsql\\PgsqlImporter\:\:getChangeSequenceSql\(\) invoked with 2 parameters, 1 required\.$#' + identifier: arguments.count + count: 1 + path: src/Pgsql/PgsqlImporter.php + + - + message: '#^Method Joomla\\Database\\Pgsql\\PgsqlImporter\:\:getSetvalSequenceSql\(\) invoked with 2 parameters, 1 required\.$#' + identifier: arguments.count + count: 1 + path: src/Pgsql/PgsqlImporter.php + + - + message: '#^Parameter \#1 \$field of method Joomla\\Database\\Pgsql\\PgsqlImporter\:\:getChangeSequenceSql\(\) expects SimpleXMLElement, \(int\|string\) given\.$#' + identifier: argument.type + count: 1 + path: src/Pgsql/PgsqlImporter.php + + - + message: '#^Parameter \#1 \$field of method Joomla\\Database\\Pgsql\\PgsqlImporter\:\:getSetvalSequenceSql\(\) expects SimpleXMLElement, \(int\|string\) given\.$#' + identifier: argument.type + count: 1 + path: src/Pgsql/PgsqlImporter.php + + - + message: '#^Parameter \#2 \$key of method Joomla\\Database\\Pgsql\\PgsqlImporter\:\:getAddUniqueSql\(\) expects array, SimpleXMLElement given\.$#' + identifier: argument.type + count: 1 + path: src/Pgsql/PgsqlImporter.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 12 + path: src/Pgsql/PgsqlQuery.php + + - + message: '#^Instanceof between string and \$this\(Joomla\\Database\\Pgsql\\PgsqlQuery\) will always evaluate to false\.$#' + identifier: instanceof.alwaysFalse + count: 1 + path: src/Pgsql/PgsqlQuery.php + + - + message: '#^Parameter \#2 \$elements of class Joomla\\Database\\Query\\QueryElement constructor expects array\\|string, int given\.$#' + identifier: argument.type + count: 2 + path: src/Pgsql/PgsqlQuery.php + + - + message: '#^Parameter \#2 \$elements of class Joomla\\Database\\Query\\QueryElement constructor expects array\\|string, null given\.$#' + identifier: argument.type + count: 1 + path: src/Pgsql/PgsqlQuery.php + + - + message: '#^Ternary operator condition is always true\.$#' + identifier: ternary.alwaysTrue + count: 1 + path: src/Pgsql/PgsqlQuery.php + + - + message: '#^Argument of an invalid type \$this\(Joomla\\Database\\Query\\QueryElement\) supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable + count: 1 + path: src/Query/QueryElement.php + + - + message: '#^Call to function is_float\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/Sqlite/SqliteDriver.php + + - + message: '#^Call to function is_int\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/Sqlite/SqliteDriver.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: src/Sqlite/SqliteDriver.php + + - + message: '#^Method Joomla\\Database\\Sqlite\\SqliteDriver\:\:alterDbCharacterSet\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Sqlite/SqliteDriver.php + + - + message: '#^Method Joomla\\Database\\Sqlite\\SqliteDriver\:\:connect\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Sqlite/SqliteDriver.php + + - + message: '#^Method Joomla\\Database\\Sqlite\\SqliteDriver\:\:createDatabase\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Sqlite/SqliteDriver.php + + - + message: '#^Method Joomla\\Database\\Sqlite\\SqliteDriver\:\:getConnectionCollation\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Sqlite/SqliteDriver.php + + - + message: '#^Method Joomla\\Database\\Sqlite\\SqliteDriver\:\:getConnectionEncryption\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Sqlite/SqliteDriver.php + + - + message: '#^Method Joomla\\Database\\Sqlite\\SqliteDriver\:\:lockTable\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Sqlite/SqliteDriver.php + + - + message: '#^Method Joomla\\Database\\Sqlite\\SqliteDriver\:\:unlockTables\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Sqlite/SqliteDriver.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: src/Sqlite/SqliteDriver.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: src/Sqlite/SqliteQuery.php + + - + message: '#^Left side of \|\| is always true\.$#' + identifier: booleanOr.leftAlwaysTrue + count: 1 + path: src/Sqlite/SqliteQuery.php + + - + message: '#^Result of \|\| is always true\.$#' + identifier: booleanOr.alwaysTrue + count: 1 + path: src/Sqlite/SqliteQuery.php + + - + message: '#^Unsafe usage of new static\(\)\.$#' + identifier: new.static + count: 1 + path: src/Sqlite/SqliteQuery.php + + - + message: '#^Call to function is_float\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/Sqlsrv/SqlsrvDriver.php + + - + message: '#^Call to function is_int\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: src/Sqlsrv/SqlsrvDriver.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 4 + path: src/Sqlsrv/SqlsrvDriver.php + + - + message: '#^Method Joomla\\Database\\Sqlsrv\\SqlsrvDriver\:\:connect\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Sqlsrv/SqlsrvDriver.php + + - + message: '#^Method Joomla\\Database\\Sqlsrv\\SqlsrvDriver\:\:lockTable\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Sqlsrv/SqlsrvDriver.php + + - + message: '#^Method Joomla\\Database\\Sqlsrv\\SqlsrvDriver\:\:unlockTables\(\) has RuntimeException in PHPDoc @throws tag but it''s not thrown\.$#' + identifier: throws.unusedType + count: 1 + path: src/Sqlsrv/SqlsrvDriver.php + + - + message: '#^Parameter \#2 \$array of function implode expects array\, list\ given\.$#' + identifier: argument.type + count: 1 + path: src/Sqlsrv/SqlsrvDriver.php + + - + message: '#^Parameter \#3 \$params of function sqlsrv_query expects array, null given\.$#' + identifier: argument.type + count: 1 + path: src/Sqlsrv/SqlsrvDriver.php + + - + message: '#^Property Joomla\\Database\\DatabaseDriver\:\:\$connection \(resource\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: src/Sqlsrv/SqlsrvDriver.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: src/Sqlsrv/SqlsrvDriver.php + + - + message: '#^Comparison operation "\>" between 0 and 1 is always false\.$#' + identifier: greater.alwaysFalse + count: 1 + path: src/Sqlsrv/SqlsrvQuery.php + + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 14 + path: src/Sqlsrv/SqlsrvQuery.php + + - + message: '#^Instanceof between Joomla\\Database\\DatabaseInterface and Joomla\\Database\\DatabaseInterface will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue + count: 1 + path: src/Sqlsrv/SqlsrvQuery.php + + - + message: '#^Left side of \|\| is always true\.$#' + identifier: booleanOr.leftAlwaysTrue + count: 1 + path: src/Sqlsrv/SqlsrvQuery.php + + - + message: '#^Offset int\<1, max\> on list in isset\(\) does not exist\.$#' + identifier: isset.offset + count: 1 + path: src/Sqlsrv/SqlsrvQuery.php + + - + message: '#^PHPDoc type array of property Joomla\\Database\\Sqlsrv\\SqlsrvQuery\:\:\$nullDatetimeList is not covariant with PHPDoc type array\ of overridden property Joomla\\Database\\DatabaseQuery\:\:\$nullDatetimeList\.$#' + identifier: property.phpDocType + count: 1 + path: src/Sqlsrv/SqlsrvQuery.php + + - + message: '#^Parameter \#2 \$array of function implode expects array\, array\ given\.$#' + identifier: argument.type + count: 1 + path: src/Sqlsrv/SqlsrvQuery.php + + - + message: '#^Result of \|\| is always true\.$#' + identifier: booleanOr.alwaysTrue + count: 1 + path: src/Sqlsrv/SqlsrvQuery.php + + - + message: '#^Return type \(string\) of method Joomla\\Database\\Sqlsrv\\SqlsrvQuery\:\:length\(\) should be compatible with return type \(int\) of method Joomla\\Database\\QueryInterface\:\:length\(\)$#' + identifier: method.childReturnType + count: 1 + path: src/Sqlsrv/SqlsrvQuery.php diff --git a/phpstan.neon b/phpstan.neon index 07d82270..305d72f1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,6 +1,7 @@ includes: - vendor/phpstan/phpstan-deprecation-rules/rules.neon + - phpstan-baseline.neon parameters: level: 5