From 4b23ac965715a186378ae62593a967642b0f136e Mon Sep 17 00:00:00 2001 From: Francesco Danti Date: Mon, 4 Mar 2024 20:40:24 +0100 Subject: [PATCH] Fix tests (#47) * Update js library * Extend PHP Test to 8.2 & 8.3 * Fix tests --- .github/workflows/test-unit.yml | 38 +++++----- composer.json | 16 ++-- demos/_includes/Model/Post.php | 4 +- demos/index.php | 13 ++-- demos/init-app.php | 10 ++- demos/init-autoloader.php | 3 +- demos/init-db.php | 4 +- src/TextEditor.php | 4 +- tests-behat/Context.php | 2 +- tests-behat/editor.feature | 2 +- tests/TextEditorTest.php | 126 ++++++++++++++------------------ tools/CoverageUtil.php | 2 +- 12 files changed, 108 insertions(+), 116 deletions(-) diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index 9ec6aca..b0e313b 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -25,7 +25,7 @@ jobs: type: 'StaticAnalysis' steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Configure PHP run: | @@ -38,7 +38,7 @@ jobs: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Setup cache 2/2 - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-smoke-${{ matrix.php }}-${{ matrix.type }}-${{ hashFiles('composer.json') }} @@ -78,10 +78,10 @@ jobs: strategy: fail-fast: false matrix: - php: ['7.4', '8.0', '8.1'] + php: ['7.4', '8.0', '8.1', '8.2', '8.3'] type: ['Phpunit', 'Phpunit Lowest'] include: - - php: '8.1' # TODO replace with 'latest' once it represents at least PHP 8.1 + - php: 'latest' type: 'Phpunit Burn' env: LOG_COVERAGE: "${{ fromJSON('{true: \"1\", false: \"\"}')[matrix.php == '8.0' && matrix.type == 'Phpunit' && (github.event_name == 'pull_request' || (github.event_name == 'push' && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master')))] }}" @@ -91,7 +91,7 @@ jobs: options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5 -e MYSQL_ROOT_PASSWORD=atk4_pass_root -e MYSQL_USER=atk4_test_user -e MYSQL_PASSWORD=atk4_pass -e MYSQL_DATABASE=atk4_test --entrypoint sh mysql:8 -c "exec docker-entrypoint.sh mysqld --default-authentication-plugin=mysql_native_password" mariadb: image: mariadb - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5 -e MYSQL_ROOT_PASSWORD=atk4_pass_root -e MYSQL_USER=atk4_test_user -e MYSQL_PASSWORD=atk4_pass -e MYSQL_DATABASE=atk4_test + options: --health-cmd="mariadb-admin ping" --health-interval=10s --health-timeout=5s --health-retries=5 -e MYSQL_ROOT_PASSWORD=atk4_pass_root -e MYSQL_USER=atk4_test_user -e MYSQL_PASSWORD=atk4_pass -e MYSQL_DATABASE=atk4_test postgres: image: postgres:12-alpine env: @@ -105,13 +105,12 @@ jobs: ACCEPT_EULA: Y SA_PASSWORD: atk4_pass oracle: - image: gvenzl/oracle-xe:18 + image: gvenzl/oracle-xe:18-slim-faststart env: ORACLE_PASSWORD: atk4_pass - options: --health-cmd healthcheck.sh --health-interval=10s --health-timeout=5s --health-retries=10 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Configure PHP run: | @@ -124,7 +123,7 @@ jobs: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Setup cache 2/2 - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ matrix.type }}-${{ hashFiles('composer.json') }} @@ -136,7 +135,7 @@ jobs: 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 }}" != "StaticAnalysis" ]; then composer remove --no-interaction --no-update phpstan/\* behat/\* --dev; fi - if [ -n "$LOG_COVERAGE" ]; then composer require --no-interaction --no-update phpunit/phpcov; 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(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 @@ -146,7 +145,8 @@ jobs: php -r '(new PDO("mysql:host=mysql", "root", "atk4_pass_root"))->exec("ALTER USER '"'"'atk4_test_user'"'"'@'"'"'%'"'"' WITH MAX_USER_CONNECTIONS 5");' php -r '(new PDO("mysql:host=mariadb", "root", "atk4_pass_root"))->exec("ALTER USER '"'"'atk4_test_user'"'"'@'"'"'%'"'"' WITH MAX_USER_CONNECTIONS 5");' php -r '(new PDO("pgsql:host=postgres;dbname=atk4_test", "atk4_test_user", "atk4_pass"))->exec("ALTER ROLE atk4_test_user CONNECTION LIMIT 1");' - if [ -n "$LOG_COVERAGE" ]; then mkdir coverage && cp tools/CoverageUtil.php demos; fi + /usr/lib/oracle/setup.sh + if [ -n "$LOG_COVERAGE" ]; then mkdir coverage; fi - name: "Run tests: SQLite" run: | @@ -218,7 +218,7 @@ jobs: - name: Upload coverage logs 2/2 (only for latest Phpunit) if: env.LOG_COVERAGE - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} file: coverage/merged.xml @@ -231,7 +231,7 @@ jobs: strategy: fail-fast: false matrix: - php: ['7.4', '8.0', '8.1'] + php: ['7.4', '8.0', '8.1', '8.2', '8.3'] type: ['Chrome', 'Chrome Lowest'] include: - php: 'latest' @@ -246,7 +246,7 @@ jobs: options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5 -e MYSQL_ROOT_PASSWORD=atk4_pass_root -e MYSQL_USER=atk4_test_user -e MYSQL_PASSWORD=atk4_pass -e MYSQL_DATABASE=atk4_test --entrypoint sh mysql:8 -c "exec docker-entrypoint.sh mysqld --default-authentication-plugin=mysql_native_password" mariadb: image: mariadb - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5 -e MYSQL_ROOT_PASSWORD=atk4_pass_root -e MYSQL_USER=atk4_test_user -e MYSQL_PASSWORD=atk4_pass -e MYSQL_DATABASE=atk4_test + options: --health-cmd="mariadb-admin ping" --health-interval=10s --health-timeout=5s --health-retries=5 -e MYSQL_ROOT_PASSWORD=atk4_pass_root -e MYSQL_USER=atk4_test_user -e MYSQL_PASSWORD=atk4_pass -e MYSQL_DATABASE=atk4_test postgres: image: postgres:12-alpine env: @@ -260,13 +260,12 @@ jobs: ACCEPT_EULA: Y SA_PASSWORD: atk4_pass oracle: - image: gvenzl/oracle-xe:18 + image: gvenzl/oracle-xe:18-slim-faststart env: ORACLE_PASSWORD: atk4_pass - options: --health-cmd healthcheck.sh --health-interval=10s --health-timeout=5s --health-retries=10 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Configure PHP run: | @@ -279,7 +278,7 @@ jobs: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Setup cache 2/2 - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-behat-${{ matrix.php }}-${{ matrix.type }}-${{ hashFiles('composer.json') }} @@ -317,6 +316,7 @@ jobs: php -r '(new PDO("mysql:host=mysql", "root", "atk4_pass_root"))->exec("ALTER USER '"'"'atk4_test_user'"'"'@'"'"'%'"'"' WITH MAX_USER_CONNECTIONS 5");' php -r '(new PDO("mysql:host=mariadb", "root", "atk4_pass_root"))->exec("ALTER USER '"'"'atk4_test_user'"'"'@'"'"'%'"'"' WITH MAX_USER_CONNECTIONS 5");' php -r '(new PDO("pgsql:host=postgres;dbname=atk4_test", "atk4_test_user", "atk4_pass"))->exec("ALTER ROLE atk4_test_user CONNECTION LIMIT 1");' + /usr/lib/oracle/setup.sh if [ -n "$LOG_COVERAGE" ]; then mkdir coverage && cp tools/CoverageUtil.php demos; fi sed -i "s~'https://raw.githack.com/atk4/ui/develop/public.*~'/vendor/atk4/ui/public',~" vendor/atk4/ui/src/App.php ci_wait_until () { timeout 30 sh -c "until { $1 2> /dev/null; }; do sleep 0.02; done" || timeout 15 sh -c "$1" || { echo "health timeout: $1"; exit 1; }; } @@ -399,7 +399,7 @@ jobs: - name: Upload coverage logs 2/2 (only for latest Chrome) if: env.LOG_COVERAGE - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} file: coverage/merged.xml diff --git a/composer.json b/composer.json index a35e120..f5c8804 100644 --- a/composer.json +++ b/composer.json @@ -10,18 +10,12 @@ } ], "require": { - "php": "<8.4", - "atk4/ui": "dev-develop" - }, - "require-release": { - "php": ">=7.4 <8.2", - "atk4/ui": "3.1" + "php": ">=7.4 <8.4", + "atk4/ui": "5.0" }, "require-dev": { - "behat/behat": "^3.9", - "behat/mink": "^1.9", + "atk4/behat-mink-selenium2-driver": "^1.6.2", "behat/mink-extension": "^2.3.1", - "behat/mink-selenium2-driver": "^1.5", "ergebnis/composer-normalize": "^2.13", "friendsofphp/php-cs-fixer": "^3.0", "instaclick/php-webdriver": "^1.4.7", @@ -33,6 +27,10 @@ "symfony/console": "^4.4.30 || ^5.3.7", "symfony/css-selector": "^4.4.24 || ^5.2.9" }, + "conflict": { + "behat/behat": "<3.9", + "behat/mink": "<1.9" + }, "minimum-stability": "dev", "prefer-stable": true, "autoload": { diff --git a/demos/_includes/Model/Post.php b/demos/_includes/Model/Post.php index 1b4ddd2..e9390a3 100644 --- a/demos/_includes/Model/Post.php +++ b/demos/_includes/Model/Post.php @@ -4,7 +4,9 @@ namespace Atk4\TextEditor\Demos\Model; -class Post extends \Atk4\Data\Model +use Atk4\Data\Model; + +class Post extends Model { public $table = 'post'; diff --git a/demos/index.php b/demos/index.php index 447876a..be644c1 100644 --- a/demos/index.php +++ b/demos/index.php @@ -6,6 +6,7 @@ use Atk4\TextEditor\Demos\Model\Post; use Atk4\TextEditor\TextEditor; +use Atk4\Ui\App; use Atk4\Ui\Button; use Atk4\Ui\Form; use Atk4\Ui\Form\Control\Input; @@ -16,7 +17,7 @@ require_once __DIR__ . '/../vendor/autoload.php'; -/** @var \Atk4\Ui\App $app */ +/** @var App $app */ require __DIR__ . '/init-app.php'; $app->initLayout([Centered::class]); @@ -30,7 +31,7 @@ 'placeholder' => 'test placeholder', ]); -$form->onSubmit(function ($f) { +$form->onSubmit(static function ($f) { $view = new Message(); $view->setApp($f->getApp()); $view->invokeInit(); @@ -46,18 +47,18 @@ /** @var TextEditor $editor */ $editor = $form->getControl('body'); -Button::addTo($app, ['set editor content with random value'])->on('click', function ($jq) use ($editor) { +Button::addTo($app, ['set editor content with random value'])->on('click', static function ($jq) use ($editor) { return $editor->jsSetHtml(true, (string) random_int(0, 10000)); }); -Button::addTo($app, ['get editor content'])->on('click', function ($jq, $content) { +Button::addTo($app, ['get editor content'])->on('click', static function ($jq, $content) { return $content; }, [$editor->jsGetHtml()]); -Button::addTo($app, ['refresh editor'])->on('click', function ($jq) use ($editor) { +Button::addTo($app, ['refresh editor'])->on('click', static function ($jq) use ($editor) { return $editor->jsReload(); }); -Button::addTo($app, ['refresh input'])->on('click', function ($jq) use ($input) { +Button::addTo($app, ['refresh input'])->on('click', static function ($jq) use ($input) { return $input->jsReload(); }); diff --git a/demos/init-app.php b/demos/init-app.php index 17692c0..48b2bd2 100644 --- a/demos/init-app.php +++ b/demos/init-app.php @@ -6,13 +6,15 @@ use Atk4\Data\Persistence; use Atk4\Ui\App; +use Atk4\Ui\Exception; +use PHPUnit\Framework\TestCase; date_default_timezone_set('UTC'); require_once __DIR__ . '/init-autoloader.php'; // collect coverage for HTTP tests 1/2 -if (file_exists(__DIR__ . '/CoverageUtil.php') && !class_exists(\PHPUnit\Framework\TestCase::class, false)) { +if (file_exists(__DIR__ . '/CoverageUtil.php') && !class_exists(TestCase::class, false)) { require_once __DIR__ . '/CoverageUtil.php'; \CoverageUtil::start(); } @@ -20,8 +22,8 @@ $app = new App(['title' => 'ATK4 :: Trumbowyg Demo']); // collect coverage for HTTP tests 2/2 -if (file_exists(__DIR__ . '/CoverageUtil.php') && !class_exists(\PHPUnit\Framework\TestCase::class, false)) { - $app->onHook(\Atk4\Ui\App::HOOK_BEFORE_EXIT, function () { +if (file_exists(__DIR__ . '/CoverageUtil.php') && !class_exists(TestCase::class, false)) { + $app->onHook(App::HOOK_BEFORE_EXIT, static function () { \CoverageUtil::saveData(); }); } @@ -32,5 +34,5 @@ $app->db = $db; unset($db); } catch (\Throwable $e) { - throw new \Atk4\Ui\Exception('Database error: ' . $e->getMessage()); + throw new Exception('Database error: ' . $e->getMessage()); } diff --git a/demos/init-autoloader.php b/demos/init-autoloader.php index 88f7229..c48e9f2 100644 --- a/demos/init-autoloader.php +++ b/demos/init-autoloader.php @@ -5,9 +5,10 @@ namespace Atk4\TextEditor\Demos; use Atk4\TextEditor\Tests\TextEditorTest; +use Composer\Autoload\ClassLoader; $isRootProject = file_exists(__DIR__ . '/../vendor/autoload.php'); -/** @var \Composer\Autoload\ClassLoader $loader */ +/** @var ClassLoader $loader */ $loader = require dirname(__DIR__, $isRootProject ? 1 : 4) . '/vendor/autoload.php'; if (!$isRootProject && !class_exists(TextEditorTest::class)) { throw new \Error('Demos can be run only if atk4/login is a root composer project or if dev files are autoloaded'); diff --git a/demos/init-db.php b/demos/init-db.php index 265eb2b..fa2baf3 100644 --- a/demos/init-db.php +++ b/demos/init-db.php @@ -6,12 +6,14 @@ namespace Atk4\TextEditor\Demos; +use Atk4\Ui\Exception; + try { require_once file_exists(__DIR__ . '/db.php') ? __DIR__ . '/db.php' : __DIR__ . '/db.default.php'; } catch (\PDOException $e) { // do not show $e unless you can secure DSN! - throw (new \Atk4\Ui\Exception('This demo requires access to the database. See "demos/init-db.php"')) + throw (new Exception('This demo requires access to the database. See "demos/init-db.php"')) ->addMoreInfo('PDO error', $e->getMessage()); } diff --git a/src/TextEditor.php b/src/TextEditor.php index 2dbbe85..e759ecc 100644 --- a/src/TextEditor.php +++ b/src/TextEditor.php @@ -11,8 +11,8 @@ class TextEditor extends Textarea { protected static array $loaded_assets = []; - //public $assets_path = '/assets'; - public string $assets_path = 'https://cdnjs.cloudflare.com/ajax/libs/Trumbowyg/2.25.1'; + // public $assets_path = '/assets'; + public string $assets_path = 'https://cdnjs.cloudflare.com/ajax/libs/Trumbowyg/2.27.3'; public bool $option_resetCss = true; public bool $option_autogrow = true; public array $editor_options = [ diff --git a/tests-behat/Context.php b/tests-behat/Context.php index 1072171..16d9c60 100644 --- a/tests-behat/Context.php +++ b/tests-behat/Context.php @@ -22,7 +22,7 @@ public function iTypeInEditor(string $name, string $text): void */ public function modalIsOpenWithRawText(string $text, string $tag = 'div'): void { - $html = $this->getElementInPage('.modal.visible.active.front')->getHtml(); + $html = $this->findElement(null, '.modal.visible.active.front')->getHtml(); if (empty($html)) { throw new \Exception('Modal html is empty'); diff --git a/tests-behat/editor.feature b/tests-behat/editor.feature index ae461c0..2aa42d8 100644 --- a/tests-behat/editor.feature +++ b/tests-behat/editor.feature @@ -35,6 +35,6 @@ Feature: Editor Given I am on "index.php" When I fill in "subject" with "the subject" When I type in editor "body" with text "editor content" - When I click icon using css ".trumbowyg-viewHTML-button" + When I click using selector ".trumbowyg-viewHTML-button" When I press button "Save" Then Modal is open with raw text "body : <p>editor content</p>" in tag "p" \ No newline at end of file diff --git a/tests/TextEditorTest.php b/tests/TextEditorTest.php index 0e599c4..e2f9883 100644 --- a/tests/TextEditorTest.php +++ b/tests/TextEditorTest.php @@ -22,86 +22,72 @@ protected function setUp(): void public function testInit(): void { - ob_start(); - try { - $app = $this->getApp(); - - $app->initLayout([Centered::class]); - - $form = Form::addTo($app); - $form->addControl('subject'); - $form->addControl('editor', [ - TextEditor::class, - 'placeholder' => 'test placeholder', - ]); - $app->run(); - } finally { - $output = ob_get_clean(); - } - - $this->assertSame(1, substr_count($output, (new TextEditor())->assets_path . '/trumbowyg.js')); - $this->assertSame(1, substr_count($output, (new TextEditor())->assets_path . '/ui/trumbowyg.css')); + $app = $this->getApp(); + $app->initLayout([Centered::class]); + + $form = Form::addTo($app); + $form->addControl('subject'); + $form->addControl('editor', [ + TextEditor::class, + 'placeholder' => 'test placeholder', + ]); + $app->run(); + + $this->assertSame(1, substr_count($app->output, (new TextEditor())->assets_path . '/trumbowyg.js')); + $this->assertSame(1, substr_count($app->output, (new TextEditor())->assets_path . '/ui/trumbowyg.css')); } public function testCheckDouble(): void { - ob_start(); - try { - $app = $this->getApp(); - - $app->initLayout([Centered::class]); - - $form = Form::addTo($app); - $form->addControl('subject'); - $form->addControl('editor', [ - TextEditor::class, - 'placeholder' => 'test placeholder', - ]); - $form->addControl('editor2', [ - TextEditor::class, - 'placeholder' => 'test placeholder', - ]); - $app->run(); - } finally { - $output = ob_get_clean(); - } - - $this->assertSame(1, substr_count($output, (new TextEditor())->assets_path . '/trumbowyg.js')); - $this->assertSame(1, substr_count($output, (new TextEditor())->assets_path . '/ui/trumbowyg.css')); + $app = $this->getApp(); + + $app->initLayout([Centered::class]); + + $form = Form::addTo($app); + $form->addControl('subject'); + $form->addControl('editor', [ + TextEditor::class, + 'placeholder' => 'test placeholder', + ]); + $form->addControl('editor2', [ + TextEditor::class, + 'placeholder' => 'test placeholder', + ]); + $app->run(); + + $this->assertSame(1, substr_count($app->output, (new TextEditor())->assets_path . '/trumbowyg.js')); + $this->assertSame(1, substr_count($app->output, (new TextEditor())->assets_path . '/ui/trumbowyg.css')); } public function testPlugin(): void { - ob_start(); - try { - $app = $this->getApp(); - - $app->initLayout([Centered::class]); - - $form = Form::addTo($app); - $form->addControl('subject'); - $form->addControl('editor', [ - TextEditor::class, - 'placeholder' => 'test placeholder', - 'plugins' => [ - 'base64', - ], - ]); - $app->run(); - } finally { - $output = ob_get_clean(); - } - - $this->assertStringContainsString('plugins/base64', $output); + $app = $this->getApp(); + + $app->initLayout([Centered::class]); + + $form = Form::addTo($app); + $form->addControl('subject'); + $form->addControl('editor', [ + TextEditor::class, + 'placeholder' => 'test placeholder', + 'plugins' => [ + 'base64', + ], + ]); + $app->run(); + + $this->assertStringContainsString('plugins/base64', $app->output); } - private function getApp(): App + private function getApp(): AppFormTestMock { - return new App([ - 'catch_exceptions' => false, - 'always_run' => false, - 'catch_runaway_callbacks' => false, - 'call_exit' => false, + $_SERVER['REQUEST_URI'] = '/'; + + return new AppFormTestMock([ + 'catchExceptions' => false, + 'alwaysRun' => false, + 'catchRunawayCallbacks' => false, + 'callExit' => false, ]); } } @@ -110,7 +96,7 @@ class AppFormTestMock extends App { public string $output; - protected function outputResponse(string $data, array $headers): void + protected function outputResponse(string $data): void { $this->output = $data; } diff --git a/tools/CoverageUtil.php b/tools/CoverageUtil.php index 90a0d84..0062191 100644 --- a/tools/CoverageUtil.php +++ b/tools/CoverageUtil.php @@ -20,7 +20,7 @@ private function __construct() public static function start(): void { if (self::$coverage !== null) { - throw new \Error('Coverage already started'); + throw new Error('Coverage already started'); } $filter = new Filter();