Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add phpunit v10 testing support #2133

Merged
merged 13 commits into from
Nov 26, 2023
48 changes: 24 additions & 24 deletions .github/workflows/test-unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ jobs:

- name: Install PHP dependencies
run: |
if [ "${{ matrix.type }}" != "Phpunit" ] && [ "${{ matrix.type }}" != "StaticAnalysis" ]; then composer remove --no-interaction --no-update phpunit/phpunit johnkary/phpunit-speedtrap --dev; fi
if [ "${{ matrix.type }}" != "CodingStyle" ]; then composer remove --no-interaction --no-update friendsofphp/php-cs-fixer --dev; fi
if [ "${{ matrix.type }}" != "Phpunit" ] && [ "${{ matrix.type }}" != "StaticAnalysis" ]; then composer remove --no-interaction --no-update phpunit/phpunit atk4/ergebnis-phpunit-slow-test-detector --dev; fi
if [ "${{ matrix.type }}" != "CodingStyle" ]; then composer remove --no-interaction --no-update friendsofphp/php-cs-fixer ergebnis/composer-normalize --dev; fi
if [ "${{ matrix.type }}" != "StaticAnalysis" ]; then composer remove --no-interaction --no-update phpstan/\* behat/\* --dev; fi
composer update --ansi --prefer-dist --no-interaction --no-progress --optimize-autoloader

- name: "Run tests: SQLite (only for Phpunit)"
if: startsWith(matrix.type, 'Phpunit')
run: |
php demos/_demo-data/create-db.php
vendor/bin/phpunit --exclude-group none --no-coverage -v
vendor/bin/phpunit --exclude-group none --no-coverage --fail-on-warning --fail-on-risky $(if vendor/bin/phpunit --version | grep -q '^PHPUnit 9\.'; then echo -v; else echo --fail-on-notice --fail-on-deprecation --display-notices --display-deprecations --display-warnings --display-errors --display-incomplete --display-skipped; fi)

- name: Check Coding Style (only for CodingStyle)
if: matrix.type == 'CodingStyle'
Expand Down Expand Up @@ -133,13 +133,13 @@ jobs:

- name: Install PHP dependencies
run: |
if [ "${{ matrix.type }}" != "Phpunit" ] && [ "${{ matrix.type }}" != "Phpunit Lowest" ] && [ "${{ matrix.type }}" != "Phpunit Burn" ]; then composer remove --no-interaction --no-update phpunit/phpunit johnkary/phpunit-speedtrap --dev; fi
if [ "${{ matrix.type }}" != "CodingStyle" ]; then composer remove --no-interaction --no-update friendsofphp/php-cs-fixer --dev; fi
if [ "${{ matrix.type }}" != "Phpunit" ] && [ "${{ matrix.type }}" != "Phpunit Lowest" ] && [ "${{ matrix.type }}" != "Phpunit Burn" ]; then composer remove --no-interaction --no-update phpunit/phpunit atk4/ergebnis-phpunit-slow-test-detector --dev; fi
if [ "${{ matrix.type }}" != "CodingStyle" ]; then composer remove --no-interaction --no-update friendsofphp/php-cs-fixer ergebnis/composer-normalize --dev; fi
if [ "${{ matrix.type }}" != "StaticAnalysis" ]; then composer remove --no-interaction --no-update phpstan/\* behat/\* --dev; fi
if [ -n "$LOG_COVERAGE" ]; then composer require --no-interaction --no-install phpunit/phpcov; fi
composer update --ansi --prefer-dist --no-interaction --no-progress --optimize-autoloader
if [ "${{ matrix.type }}" = "Phpunit Lowest" ]; then composer update --ansi --prefer-dist --prefer-lowest --prefer-stable --no-interaction --no-progress --optimize-autoloader; fi
if [ "${{ matrix.type }}" = "Phpunit Burn" ]; then sed -i 's~ *public function runBare(): void~public function runBare(): void { gc_collect_cycles(); gc_collect_cycles(); $memDiffs = array_fill(0, '"$(if [ \"$GITHUB_EVENT_NAME\" == \"schedule\" ]; then echo 64; else echo 16; fi)"', 0); for ($i = -1; $i < count($memDiffs); ++$i) { $this->_runBare(); gc_collect_cycles(); gc_collect_cycles(); $mem = memory_get_usage(); if ($i !== -1) { $memDiffs[$i] = $mem - $memPrev; } $memPrev = $mem; rsort($memDiffs); if (array_sum($memDiffs) >= 4096 * 1024 || $memDiffs[2] > 0) { $this->onNotSuccessfulTest(new AssertionFailedError("Memory leak detected! (" . implode(" + ", array_map(static fn ($v) => number_format($v / 1024, 3, ".", " "), array_filter($memDiffs))) . " KB, " . ($i + 2) . " iterations)")); } } } private function _runBare(): void~' vendor/phpunit/phpunit/src/Framework/TestCase.php && cat vendor/phpunit/phpunit/src/Framework/TestCase.php | grep '_runBare('; fi
if [ "${{ matrix.type }}" = "Phpunit Burn" ]; then sed -i 's~public function runBare(): void~public function runBare(): void { gc_collect_cycles(); gc_collect_cycles(); $memDiffs = array_fill(0, '"$(if [ \"$GITHUB_EVENT_NAME\" == \"schedule\" ]; then echo 64; else echo 16; fi)"', 0); for ($i = -1; $i < count($memDiffs); ++$i) { $this->_runBare(); gc_collect_cycles(); gc_collect_cycles(); $mem = memory_get_usage(); if ($i !== -1) { $memDiffs[$i] = $mem - $memPrev; } $memPrev = $mem; rsort($memDiffs); if (array_sum($memDiffs) >= 4096 * 1024 || $memDiffs[2] > 0) { $this->onNotSuccessfulTest(new AssertionFailedError("Memory leak detected! (" . implode(" + ", array_map(static fn ($v) => number_format($v / 1024, 3, ".", " "), array_filter($memDiffs))) . " KB, " . ($i + 2) . " iterations)")); } } } private function _runBare(): void~' vendor/phpunit/phpunit/src/Framework/TestCase.php && cat vendor/phpunit/phpunit/src/Framework/TestCase.php | grep '_runBare('; fi

- name: Init
run: |
Expand All @@ -152,31 +152,31 @@ jobs:
- name: "Run tests: SQLite"
run: |
php demos/_demo-data/create-db.php
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) -v
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) --fail-on-warning --fail-on-risky $(if vendor/bin/phpunit --version | grep -q '^PHPUnit 9\.'; then echo -v; else echo --fail-on-notice --fail-on-deprecation --display-notices --display-deprecations --display-warnings --display-errors --display-incomplete --display-skipped; fi)
if [ -n "$LOG_COVERAGE" ]; then mv coverage/phpunit.cov coverage/phpunit-sqlite.cov; fi

- name: "Run tests: MySQL"
if: success() || failure()
- name: "Run tests: MySQL (only for cron)"
if: (success() || failure()) && github.event_name == 'schedule'
env:
DB_DSN: "mysql:host=mysql;dbname=atk4_test"
DB_USER: atk4_test_user
DB_PASSWORD: atk4_pass
run: |
sed -E "s~(\\\$db = new.+Persistence\\\\Sql)\(.+\);~\\1('$DB_DSN', '$DB_USER', '$DB_PASSWORD');~g" -i demos/db.default.php
php demos/_demo-data/create-db.php
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) -v
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) --fail-on-warning --fail-on-risky $(if vendor/bin/phpunit --version | grep -q '^PHPUnit 9\.'; then echo -v; else echo --fail-on-notice --fail-on-deprecation --display-notices --display-deprecations --display-warnings --display-errors --display-incomplete --display-skipped; fi)
if [ -n "$LOG_COVERAGE" ]; then mv coverage/phpunit.cov coverage/phpunit-mysql.cov; fi

- name: "Run tests: MariaDB (only for cron)"
if: (success() || failure()) && github.event_name == 'schedule'
- name: "Run tests: MariaDB"
if: success() || failure()
env:
DB_DSN: "mysql:host=mariadb;dbname=atk4_test"
DB_USER: atk4_test_user
DB_PASSWORD: atk4_pass
run: |
sed -E "s~(\\\$db = new.+Persistence\\\\Sql)\(.+\);~\\1('$DB_DSN', '$DB_USER', '$DB_PASSWORD');~g" -i demos/db.default.php
php demos/_demo-data/create-db.php
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) -v
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) --fail-on-warning --fail-on-risky $(if vendor/bin/phpunit --version | grep -q '^PHPUnit 9\.'; then echo -v; else echo --fail-on-notice --fail-on-deprecation --display-notices --display-deprecations --display-warnings --display-errors --display-incomplete --display-skipped; fi)
if [ -n "$LOG_COVERAGE" ]; then mv coverage/phpunit.cov coverage/phpunit-mariadb.cov; fi

- name: "Run tests: PostgreSQL (only for cron)"
Expand All @@ -188,7 +188,7 @@ jobs:
run: |
sed -E "s~(\\\$db = new.+Persistence\\\\Sql)\(.+\);~\\1('$DB_DSN', '$DB_USER', '$DB_PASSWORD');~g" -i demos/db.default.php
php demos/_demo-data/create-db.php
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) -v
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) --fail-on-warning --fail-on-risky $(if vendor/bin/phpunit --version | grep -q '^PHPUnit 9\.'; then echo -v; else echo --fail-on-notice --fail-on-deprecation --display-notices --display-deprecations --display-warnings --display-errors --display-incomplete --display-skipped; fi)
if [ -n "$LOG_COVERAGE" ]; then mv coverage/phpunit.cov coverage/phpunit-postgres.cov; fi

- name: "Run tests: MSSQL (only for cron)"
Expand All @@ -200,20 +200,20 @@ jobs:
run: |
sed -E "s~(\\\$db = new.+Persistence\\\\Sql)\(.+\);~\\1('$DB_DSN', '$DB_USER', '$DB_PASSWORD');~g" -i demos/db.default.php
php demos/_demo-data/create-db.php
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) -v
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) --fail-on-warning --fail-on-risky $(if vendor/bin/phpunit --version | grep -q '^PHPUnit 9\.'; then echo -v; else echo --fail-on-notice --fail-on-deprecation --display-notices --display-deprecations --display-warnings --display-errors --display-incomplete --display-skipped; fi)
if [ -n "$LOG_COVERAGE" ]; then mv coverage/phpunit.cov coverage/phpunit-mssql.cov; fi

- name: "Run tests: Oracle (only for cron)"
if: (success() || failure()) && github.event_name == 'schedule'
env:
DB_DSN: "oci:dbname=oracle/xe"
DB_DSN: "oci:dbname=oracle/free"
DB_USER: system
DB_PASSWORD: atk4_pass
NLS_LANG: AMERICAN_AMERICA.AL32UTF8
run: |
sed -E "s~(\\\$db = new.+Persistence\\\\Sql)\(.+\);~\\1('$DB_DSN', '$DB_USER', '$DB_PASSWORD');~g" -i demos/db.default.php
php demos/_demo-data/create-db.php
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) -v
php -d opcache.enable_cli=1 vendor/bin/phpunit --exclude-group none $(if [ -n "$LOG_COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) --fail-on-warning --fail-on-risky $(if vendor/bin/phpunit --version | grep -q '^PHPUnit 9\.'; then echo -v; else echo --fail-on-notice --fail-on-deprecation --display-notices --display-deprecations --display-warnings --display-errors --display-incomplete --display-skipped; fi)
if [ -n "$LOG_COVERAGE" ]; then mv coverage/phpunit.cov coverage/phpunit-oracle.cov; fi

- name: Upload coverage logs 1/2 (only for latest Phpunit)
Expand Down Expand Up @@ -353,8 +353,8 @@ jobs:

- name: Install PHP dependencies
run: |
composer remove --no-interaction --no-update phpunit/phpunit johnkary/phpunit-speedtrap --dev
composer remove --no-interaction --no-update friendsofphp/php-cs-fixer --dev
composer remove --no-interaction --no-update phpunit/phpunit atk4/ergebnis-phpunit-slow-test-detector --dev
composer remove --no-interaction --no-update friendsofphp/php-cs-fixer ergebnis/composer-normalize --dev
composer remove --no-interaction --no-update phpstan/\* --dev
if [ -n "$LOG_COVERAGE" ]; then composer require --no-interaction --no-install phpunit/phpcov; fi
composer update --ansi --prefer-dist --no-interaction --no-progress --optimize-autoloader
Expand Down Expand Up @@ -383,8 +383,8 @@ jobs:
php demos/_demo-data/create-db.php
vendor/bin/behat -vv --config behat.yml.dist

- name: "Run tests: MySQL (only for coverage or cron)"
if: (success() || failure()) && (env.LOG_COVERAGE || github.event_name == 'schedule')
- name: "Run tests: MySQL (only for cron)"
if: (success() || failure()) && github.event_name == 'schedule'
env:
DB_DSN: "mysql:host=mysql;dbname=atk4_test"
DB_USER: atk4_test_user
Expand All @@ -394,8 +394,8 @@ jobs:
php demos/_demo-data/create-db.php
vendor/bin/behat -vv --config behat.yml.dist

- name: "Run tests: MariaDB (only for cron)"
if: (success() || failure()) && github.event_name == 'schedule'
- name: "Run tests: MariaDB (only for coverage or cron)"
if: (success() || failure()) && (env.LOG_COVERAGE || github.event_name == 'schedule')
env:
DB_DSN: "mysql:host=mariadb;dbname=atk4_test"
DB_USER: atk4_test_user
Expand Down Expand Up @@ -430,7 +430,7 @@ jobs:
- name: "Run tests: Oracle (only for cron)"
if: (success() || failure()) && github.event_name == 'schedule'
env:
DB_DSN: "oci:dbname=oracle/xe"
DB_DSN: "oci:dbname=oracle/free"
DB_USER: system
DB_PASSWORD: atk4_pass
NLS_LANG: AMERICAN_AMERICA.AL32UTF8
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,17 @@
},
"require-dev": {
"atk4/behat-mink-selenium2-driver": "^1.6.2",
"atk4/ergebnis-phpunit-slow-test-detector": "^2.4",
"behat/mink-extension": "^2.3.1",
"ergebnis/composer-normalize": "^2.13",
"friendsofphp/php-cs-fixer": "^3.0",
"fzaninotto/faker": "^1.6",
"guzzlehttp/guzzle": "^7.3",
"johnkary/phpunit-speedtrap": "^3.3",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-strict-rules": "^1.3",
"phpunit/phpunit": "^9.5.5",
"phpunit/phpunit": "^9.5.5 || ^10.0",
"symfony/process": "^4.4.30 || ^5.3.7 || ^6.0"
},
"conflict": {
Expand Down
10 changes: 10 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ parameters:
- '~^Only booleans are allowed in .+, .+ given( on the (left|right) side)?\.~'
- '~^Variable (static )?(property access|method call) on .+\.~'

# remove once PHPUnit 9.x support is removed
-
path: 'tests/DemosTest.php'
message: '~^Access to constant (STATUS_PASSED|STATUS_INCOMPLETE|STATUS_SKIPPED) on an unknown class PHPUnit\\Runner\\BaseTestRunner\.$~'
count: 3
-
path: 'tests/DemosTest.php'
message: '~^Call to an undefined method Atk4\\Ui\\Tests\\DemosTest::(getName|getStatus)\(\)\.$~'
count: 4

# TODO these rules are generated, this ignores should be fixed in the code
# for level = 2
-
Expand Down
12 changes: 7 additions & 5 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<phpunit bootstrap="vendor/autoload.php" printerClass="Atk4\Core\Phpunit\ResultPrinter" colors="true">
<phpunit bootstrap="vendor/autoload.php" colors="true">
<testsuites>
<testsuite name="tests">
<directory>tests</directory>
Expand All @@ -16,17 +16,19 @@
<group>require_session</group>
</exclude>
</groups>
<listeners>
<listener class="JohnKary\PHPUnit\Listener\SpeedTrapListener" />
</listeners>
<coverage>
<extensions>
<bootstrap class="Ergebnis\PHPUnit\SlowTestDetector\Extension" />
</extensions>
<source>
<include>
<directory>src</directory>
<directory>tests</directory>
</include>
<exclude>
<directory>src/Behat</directory>
</exclude>
</source>
<coverage>
<report>
<php outputFile="coverage/phpunit.cov" />
</report>
Expand Down
2 changes: 1 addition & 1 deletion src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public function __construct(array $defaults = [])
if ($this->catchExceptions) {
set_exception_handler(\Closure::fromCallable([$this, 'caughtException']));
set_error_handler(static function (int $severity, string $msg, string $file, int $line): bool {
if ((error_reporting() & ~(\PHP_MAJOR_VERSION >= 8 ? 4437 : 0)) === 0) {
if ((error_reporting() & ~(\PHP_MAJOR_VERSION >= 8 ? (\E_ERROR | \E_PARSE | \E_CORE_ERROR | \E_COMPILE_ERROR | \E_USER_ERROR | \E_RECOVERABLE_ERROR) : 0)) === 0) {
$isFirstFrame = true;
foreach (array_slice(debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 10), 1) as $frame) {
// allow to suppress any warning outside Atk4
Expand Down
8 changes: 4 additions & 4 deletions src/Behat/CoverageUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,18 @@ public static function startFromPhpunitConfig(string $phpunitConfigDir): void
{
$filter = new Filter();

$phpunitCoverageConfig = simplexml_load_file($phpunitConfigDir . '/phpunit.xml.dist')->coverage;
$phpunitCoverageConfig = simplexml_load_file($phpunitConfigDir . '/phpunit.xml.dist')->source;
foreach ($phpunitCoverageConfig->include->directory ?? [] as $path) {
$filter->includeDirectory($phpunitConfigDir . '/' . $path);
$filter->includeDirectory($phpunitConfigDir . '/' . $path); // @phpstan-ignore-line
}
foreach ($phpunitCoverageConfig->include->file ?? [] as $path) {
$filter->includeFile($phpunitConfigDir . '/' . $path);
}
foreach ($phpunitCoverageConfig->exclude->directory ?? [] as $path) {
$filter->excludeDirectory($phpunitConfigDir . '/' . $path);
$filter->excludeDirectory($phpunitConfigDir . '/' . $path); // @phpstan-ignore-line
}
foreach ($phpunitCoverageConfig->exclude->file ?? [] as $path) {
$filter->excludeFile($phpunitConfigDir . '/' . $path);
$filter->excludeFile($phpunitConfigDir . '/' . $path); // @phpstan-ignore-line
}

static::start($filter);
Expand Down
2 changes: 1 addition & 1 deletion tests/AppTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public function testEmptyRequestPathException(): void
$this->createApp(['request' => $request]);
}

public function provideUrlCases(): iterable
public static function provideUrlCases(): iterable
{
foreach (['/', '/page.html', '/d/', '/0/index.php'] as $requestPage) {
yield [$requestPage, [], ['x'], [], 'x.php'];
Expand Down
2 changes: 1 addition & 1 deletion tests/DemosHttpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public function testDemoLateOutputError(string $urlTrigger, string $expectedOutp
self::assertSame($expectedOutput, $response->getBody()->getContents());
}

public function provideDemoLateOutputErrorCases(): iterable
public static function provideDemoLateOutputErrorCases(): iterable
{
$hOutput = "\n" . '!! FATAL UI ERROR: Headers already sent, more headers cannot be set at this stage !!' . "\n";
$oOutput = 'unmanaged output' . "\n" . '!! FATAL UI ERROR: Unexpected output detected !!' . "\n";
Expand Down
Loading