Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
19ee1ed
feat: add `MySQL` CI workflow and corresponding test classes for impr…
terabytesoftw Jul 6, 2025
64bc5d5
fix: update action reference in `MySQL` CI workflow for correct path,
terabytesoftw Jul 6, 2025
26ba362
fix: specify version for phpunit-database workflow in `MySQL` CI conf…
terabytesoftw Jul 6, 2025
f66dfa2
fix: update database connection settings in `MySQL` test classes.
terabytesoftw Jul 6, 2025
cc2773e
fix: rename 'user' to 'username' in database connection configuration…
terabytesoftw Jul 6, 2025
c089ff4
fix: remove redundant name from `MySQL` CI job configuration.
terabytesoftw Jul 6, 2025
a69fe70
fix: add descriptive name to `MySQL` job in CI configuration.
terabytesoftw Jul 6, 2025
f476257
fix: rename 'user' to 'username' in `MySQL` test classes for consiste…
terabytesoftw Jul 6, 2025
7ca0902
fix: execute `dropTable()` commands in `TestCase` to ensure proper ta…
terabytesoftw Jul 6, 2025
8d723b4
fix: add `phpunit` group to `MySQL` CI configuration for improved tes…
terabytesoftw Jul 6, 2025
62de88f
fix: rename CI workflow to `build-mysql` for clarity and correct `php…
terabytesoftw Jul 6, 2025
16bfd6f
fix: rename `group-phpunit` to `phpunit-group` for consistency in CI …
terabytesoftw Jul 6, 2025
1e58e92
fix: update CI configuration to use `phpunit-group` for `MySQL` compa…
terabytesoftw Jul 6, 2025
73ef80c
feat: add initial CI workflow for MySQL tests with phpunit integration.
terabytesoftw Jul 6, 2025
2dca3d6
feat: Add `PostgreSQL` test suite with multiple test cases for improv…
terabytesoftw Jul 6, 2025
e04784e
fix: sort dataset queries by `id` for consistent order in test cases.
terabytesoftw Jul 6, 2025
f43e8bb
feat: add `driverName` property to test classes for database compatib…
terabytesoftw Jul 6, 2025
e90daf5
fix: update `DSN` property placement in `MySQL` and `PostgreSQL` test…
terabytesoftw Jul 6, 2025
762243b
feat: add `SQLServer` test suite with multiple test cases for improve…
terabytesoftw Jul 6, 2025
9d40d7e
feat: add installation command for Microsoft ODBC Driver in `SQLServe…
terabytesoftw Jul 6, 2025
6321cb8
fix: reorder `username` and `password` properties for consistency acr…
terabytesoftw Jul 6, 2025
cf299b0
fix: enhance root node insertion logic to check for existing nodes wi…
terabytesoftw Jul 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions .github/workflows/build-mssql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
on:
pull_request:
paths-ignore:
- 'docs/**'
- 'README.md'
- 'CHANGELOG.md'
- '.gitignore'
- '.gitattributes'

push:
paths-ignore:
- 'docs/**'
- 'README.md'
- 'CHANGELOG.md'
- '.gitignore'
- '.gitattributes'

name: build-mssql

jobs:
mssql:
name: SQL Server tests.
uses: php-forge/actions/.github/workflows/phpunit-database.yml@main
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
concurrency-group: mssql-${{ github.ref }}
database-env: |
{
"ACCEPT_EULA": "Y",
"SA_PASSWORD": "YourStrong!Passw0rd",
"MSSQL_PID": "Developer"
}
database-health-cmd: "/opt/mssql-tools18/bin/sqlcmd -C -S localhost -U SA -P 'YourStrong!Passw0rd' -Q 'SELECT 1'"
database-health-retries: 5
database-image: mcr.microsoft.com/mssql/server
database-port: 1433
database-type: mssql
database-versions: '["2022-latest"]'
enable-concurrency: true
extensions: pdo, pdo_sqlsrv, sqlsrv
os: '["ubuntu-latest"]'
php-version: '["8.4"]'
phpunit-group: mssql
setup-commands: |
# Install Microsoft ODBC Driver for SQL Server
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18

# Wait for SQL Server to be fully ready
sleep 15

# Create test database
docker exec -i database /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U SA -P 'YourStrong!Passw0rd' -Q "
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'yiitest')
BEGIN
CREATE DATABASE yiitest;
END
"
43 changes: 43 additions & 0 deletions .github/workflows/build-mysql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
on:
pull_request:
paths-ignore:
- 'docs/**'
- 'README.md'
- 'CHANGELOG.md'
- '.gitignore'
- '.gitattributes'

push:
paths-ignore:
- 'docs/**'
- 'README.md'
- 'CHANGELOG.md'
- '.gitignore'
- '.gitattributes'

name: build-mysql

jobs:
mysql:
name: MySQL tests.
uses: php-forge/actions/.github/workflows/phpunit-database.yml@main
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
concurrency-group: mysql-${{ github.ref }}
database-env: |
{
"MYSQL_DATABASE": "yiitest",
"MYSQL_ROOT_PASSWORD": "root",
}
database-health-cmd: "mysqladmin ping"
database-health-retries: 3
database-image: mysql
database-port: 3306
database-type: mysql
database-versions: '["8.0", "8.4", "latest"]'
enable-concurrency: true
extensions: pdo, pdo_mysql
os: '["ubuntu-latest"]'
php-version: '["8.4"]'
phpunit-group: mysql
44 changes: 44 additions & 0 deletions .github/workflows/build-pgsql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
on:
pull_request:
paths-ignore:
- 'docs/**'
- 'README.md'
- 'CHANGELOG.md'
- '.gitignore'
- '.gitattributes'

push:
paths-ignore:
- 'docs/**'
- 'README.md'
- 'CHANGELOG.md'
- '.gitignore'
- '.gitattributes'

name: build-pgsql

jobs:
pgsql:
name: PostgreSQL tests.
uses: php-forge/actions/.github/workflows/phpunit-database.yml@main
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
concurrency-group: pgsql-${{ github.ref }}
database-env: |
{
"POSTGRES_DB": "yiitest",
"POSTGRES_USER": "root",
"POSTGRES_PASSWORD": "root"
}
database-health-cmd: "pg_isready -U postgres"
database-health-retries: 3
database-image: postgres
database-port: 5432
database-type: pgsql
database-versions: '["15", "16", "17"]'
enable-concurrency: true
extensions: pdo, pdo_pgsql
os: '["ubuntu-latest"]'
php-version: '["8.4"]'
phpunit-group: pgsql
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ jobs:
composer require yiisoft/yii2:22.0.x-dev --prefer-dist --no-progress --no-interaction --no-scripts --ansi
concurrency-group: phpunit-${{ github.workflow }}-${{ github.ref }}
extensions: pdo, pdo_sqlite
phpunit-group: sqlite
phpunit-compatibility:
uses: php-forge/actions/.github/workflows/phpunit.yml@main
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
concurrency-group: compatibility-${{ github.workflow }}-${{ github.ref }}
extensions: pdo, pdo_sqlite
phpunit-group: sqlite
1 change: 1 addition & 0 deletions .github/workflows/mutation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ jobs:
uses: php-forge/actions/.github/workflows/infection.yml@main
with:
phpstan: true
framework-options: --test-framework-options="--group=sqlite"
secrets:
STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }}
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
"scripts": {
"check-dependencies": "./vendor/bin/composer-require-checker check",
"ecs": "./vendor/bin/ecs --fix",
"mutation": "./vendor/bin/infection --threads=4 --ignore-msi-with-no-mutations --only-covered --min-msi=100 --min-covered-msi=100",
"mutation-static": "./vendor/bin/infection --threads=4 --ignore-msi-with-no-mutations --only-covered --min-msi=100 --min-covered-msi=100 --static-analysis-tool=phpstan",
"mutation": "./vendor/bin/infection --threads=4 --ignore-msi-with-no-mutations --only-covered --min-msi=100 --min-covered-msi=100 --test-framework-options=--group=sqlite",
"mutation-static": "./vendor/bin/infection --threads=4 --ignore-msi-with-no-mutations --only-covered --min-msi=100 --min-covered-msi=100 --static-analysis-tool=phpstan --test-framework-options=--group=sqlite",
"rector": "./vendor/bin/rector process src",
"static": "./vendor/bin/phpstan --memory-limit=512M",
"tests": "./vendor/bin/phpunit"
Expand Down
5 changes: 4 additions & 1 deletion src/NestedSetsBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,10 @@
*/
protected function beforeInsertRootNode(): void
{
if ($this->treeAttribute === false && $this->getOwner()::find()->roots()->exists()) {
if (
$this->treeAttribute === false &&
$this->getOwner()::find()->andWhere([$this->leftAttribute => 1])->exists()

Check warning on line 1075 in src/NestedSetsBehavior.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "ArrayItemRemoval": @@ @@ */ protected function beforeInsertRootNode(): void { - if ($this->treeAttribute === false && $this->getOwner()::find()->andWhere([$this->leftAttribute => 1])->exists()) { + if ($this->treeAttribute === false && $this->getOwner()::find()->andWhere([])->exists()) { throw new Exception('Can not create more than one root when "treeAttribute" is false.'); } $this->getOwner()->setAttribute($this->leftAttribute, 1);

Check warning on line 1075 in src/NestedSetsBehavior.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "IncrementInteger": @@ @@ */ protected function beforeInsertRootNode(): void { - if ($this->treeAttribute === false && $this->getOwner()::find()->andWhere([$this->leftAttribute => 1])->exists()) { + if ($this->treeAttribute === false && $this->getOwner()::find()->andWhere([$this->leftAttribute => 2])->exists()) { throw new Exception('Can not create more than one root when "treeAttribute" is false.'); } $this->getOwner()->setAttribute($this->leftAttribute, 1);

Check warning on line 1075 in src/NestedSetsBehavior.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "ArrayItemRemoval": @@ @@ */ protected function beforeInsertRootNode(): void { - if ($this->treeAttribute === false && $this->getOwner()::find()->andWhere([$this->leftAttribute => 1])->exists()) { + if ($this->treeAttribute === false && $this->getOwner()::find()->andWhere([])->exists()) { throw new Exception('Can not create more than one root when "treeAttribute" is false.'); } $this->getOwner()->setAttribute($this->leftAttribute, 1);

Check warning on line 1075 in src/NestedSetsBehavior.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "IncrementInteger": @@ @@ */ protected function beforeInsertRootNode(): void { - if ($this->treeAttribute === false && $this->getOwner()::find()->andWhere([$this->leftAttribute => 1])->exists()) { + if ($this->treeAttribute === false && $this->getOwner()::find()->andWhere([$this->leftAttribute => 2])->exists()) { throw new Exception('Can not create more than one root when "treeAttribute" is false.'); } $this->getOwner()->setAttribute($this->leftAttribute, 1);
) {
throw new Exception('Can not create more than one root when "treeAttribute" is false.');
}

Expand Down
54 changes: 47 additions & 7 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use function array_values;
use function dom_import_simplexml;
use function file_get_contents;
use function preg_replace;
use function simplexml_load_string;
use function str_replace;

Expand All @@ -38,9 +39,12 @@
class TestCase extends \PHPUnit\Framework\TestCase
{
use SchemaBuilderTrait;
protected string $driverName = 'sqlite';

protected string|null $dsn = null;
protected string $fixtureDirectory = __DIR__ . '/support/data/';
protected string $password = '';
protected string $username = '';

protected function setUp(): void
{
Expand Down Expand Up @@ -103,12 +107,12 @@ protected function assertQueryHasOrderBy(ActiveQuery $query, string $methodName)

self::assertStringContainsString(
'ORDER BY',
$sql,
$this->replaceQuotes($sql),
"'{$methodName}' query should include 'ORDER BY' clause for deterministic results.",
);

self::assertStringContainsString(
'`lft`',
$this->replaceQuotes('[[lft]]'),
$sql,
"'{$methodName}' query should order by 'left' attribute for consistent ordering.",
);
Expand Down Expand Up @@ -167,11 +171,11 @@ protected function createDatabase(): void
$command = $this->getDb()->createCommand();

if ($this->getDb()->getTableSchema('tree', true) !== null) {
$command->dropTable('tree');
$command->dropTable('tree')->execute();
}

if ($this->getDb()->getTableSchema('multiple_tree', true) !== null) {
$command->dropTable('multiple_tree');
$command->dropTable('multiple_tree')->execute();
}

$command->createTable(
Expand Down Expand Up @@ -291,14 +295,14 @@ protected function generateFixtureTree(): void
*/
protected function getDataSet(): array
{
$dataSetTree = Tree::find()->asArray()->all();
$dataSetTree = Tree::find()->orderBy(['id' => SORT_ASC])->asArray()->all();

foreach ($dataSetTree as $key => $value) {
$dataSetTree[$key]['type'] = 'tree';
$dataSetTree[$key]['tree'] = 0;
}

$dataSetMultipleTree = MultipleTree::find()->asArray()->all();
$dataSetMultipleTree = MultipleTree::find()->orderBy(['id' => SORT_ASC])->asArray()->all();

foreach ($dataSetMultipleTree as $key => $value) {
$dataSetMultipleTree[$key]['type'] = 'multiple_tree';
Expand All @@ -314,7 +318,7 @@ protected function getDataSet(): array
*/
protected function getDataSetMultipleTree(): array
{
$dataSetMultipleTree = MultipleTree::find()->asArray()->all();
$dataSetMultipleTree = MultipleTree::find()->orderBy(['id' => SORT_ASC])->asArray()->all();

foreach ($dataSetMultipleTree as $key => $value) {
$dataSetMultipleTree[$key]['type'] = 'multiple_tree';
Expand Down Expand Up @@ -352,12 +356,48 @@ protected function mockConsoleApplication(): void
'db' => [
'class' => Connection::class,
'dsn' => $this->dsn !== null ? $this->dsn : 'sqlite::memory:',
'password' => $this->password,
'username' => $this->username,
],
],
],
);
}

/**
* Adjust dbms specific escaping.
*
* @param string $sql SQL to adjust.
*
* @return string Adjusted SQL.
*/
protected function replaceQuotes(string $sql): string
{
return match ($this->driverName) {
'mysql', 'sqlite' => str_replace(
['[[', ']]'],
'`',
$sql,
),
'oci' => str_replace(
['[[', ']]'],
'"',
$sql,
),
'pgsql' => str_replace(
['\\[', '\\]'],
['[', ']'],
preg_replace('/(\[\[)|((?<!(\[))\]\])/', '"', $sql) ?? $sql,
),
'sqlsrv' => str_replace(
['[[', ']]'],
['[', ']'],
$sql,
),
default => $sql,
};
}

/**
* Applies database updates to tree nodes.
*
Expand Down
2 changes: 1 addition & 1 deletion tests/base/AbstractQueryBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public function testRootsMethodRequiresLeftAttributeOrderingWhenTreeAttributeIsD
"'roots()' query should include 'ORDER BY' clause for consistent results.",
);
self::assertStringContainsString(
'`lft`',
$this->replaceQuotes('[[lft]]'),
$sql,
"'roots()' query should order by 'left' attribute for deterministic ordering.",
);
Expand Down
17 changes: 17 additions & 0 deletions tests/mssql/CacheManagementTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace yii2\extensions\nestedsets\tests\mssql;

use PHPUnit\Framework\Attributes\Group;
use yii2\extensions\nestedsets\tests\base\AbstractCacheManagement;

#[Group('mssql')]
final class CacheManagementTest extends AbstractCacheManagement
{
protected string $driverName = 'sqlsrv';
protected string|null $dsn = 'sqlsrv:Server=127.0.0.1,1433;Database=yiitest;Encrypt=no';
protected string $password = 'YourStrong!Passw0rd';
protected string $username = 'SA';
}
17 changes: 17 additions & 0 deletions tests/mssql/ExceptionHandlingTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace yii2\extensions\nestedsets\tests\mssql;

use PHPUnit\Framework\Attributes\Group;
use yii2\extensions\nestedsets\tests\base\AbstractExceptionHandling;

#[Group('mssql')]
final class ExceptionHandlingTest extends AbstractExceptionHandling
{
protected string $driverName = 'sqlsrv';
protected string|null $dsn = 'sqlsrv:Server=127.0.0.1,1433;Database=yiitest;Encrypt=no';
protected string $password = 'YourStrong!Passw0rd';
protected string $username = 'SA';
}
17 changes: 17 additions & 0 deletions tests/mssql/ExtensibilityTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace yii2\extensions\nestedsets\tests\mssql;

use PHPUnit\Framework\Attributes\Group;
use yii2\extensions\nestedsets\tests\base\AbstractExtensibility;

#[Group('mssql')]
final class ExtensibilityTest extends AbstractExtensibility
{
protected string $driverName = 'sqlsrv';
protected string|null $dsn = 'sqlsrv:Server=127.0.0.1,1433;Database=yiitest;Encrypt=no';
protected string $password = 'YourStrong!Passw0rd';
protected string $username = 'SA';
}
17 changes: 17 additions & 0 deletions tests/mssql/NodeAppendTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace yii2\extensions\nestedsets\tests\mssql;

use PHPUnit\Framework\Attributes\Group;
use yii2\extensions\nestedsets\tests\base\AbstractNodeAppend;

#[Group('mssql')]
final class NodeAppendTest extends AbstractNodeAppend
{
protected string $driverName = 'sqlsrv';
protected string|null $dsn = 'sqlsrv:Server=127.0.0.1,1433;Database=yiitest;Encrypt=no';
protected string $password = 'YourStrong!Passw0rd';
protected string $username = 'SA';
}
Loading