Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x

ProgressPrinter.php

Namespace

PHPUnit\TextUI\Output\Default\ProgressPrinter

File

vendor/phpunit/phpunit/src/TextUI/Output/Default/ProgressPrinter/ProgressPrinter.php

View source
<?php

declare (strict_types=1);

/*
 * This file is part of PHPUnit.
 *
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace PHPUnit\TextUI\Output\Default\ProgressPrinter;

use function floor;
use function sprintf;
use function str_contains;
use function str_repeat;
use function strlen;
use PHPUnit\Event\EventFacadeIsSealedException;
use PHPUnit\Event\Facade;
use PHPUnit\Event\Test\DeprecationTriggered;
use PHPUnit\Event\Test\Errored;
use PHPUnit\Event\Test\ErrorTriggered;
use PHPUnit\Event\Test\NoticeTriggered;
use PHPUnit\Event\Test\PhpDeprecationTriggered;
use PHPUnit\Event\Test\PhpNoticeTriggered;
use PHPUnit\Event\Test\PhpWarningTriggered;
use PHPUnit\Event\Test\WarningTriggered;
use PHPUnit\Event\TestRunner\ExecutionStarted;
use PHPUnit\Event\UnknownSubscriberTypeException;
use PHPUnit\Framework\TestStatus\TestStatus;
use PHPUnit\TextUI\Configuration\Source;
use PHPUnit\TextUI\Configuration\SourceFilter;
use PHPUnit\TextUI\Output\Printer;
use PHPUnit\Util\Color;

/**
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
 *
 * @internal This class is not covered by the backward compatibility promise for PHPUnit
 */
final class ProgressPrinter {
    private readonly Printer $printer;
    private readonly bool $colors;
    private readonly int $numberOfColumns;
    private readonly Source $source;
    private int $column = 0;
    private int $numberOfTests = 0;
    private int $numberOfTestsWidth = 0;
    private int $maxColumn = 0;
    private int $numberOfTestsRun = 0;
    private ?TestStatus $status = null;
    private bool $prepared = false;
    
    /**
     * @throws EventFacadeIsSealedException
     * @throws UnknownSubscriberTypeException
     */
    public function __construct(Printer $printer, Facade $facade, bool $colors, int $numberOfColumns, Source $source) {
        $this->printer = $printer;
        $this->colors = $colors;
        $this->numberOfColumns = $numberOfColumns;
        $this->source = $source;
        $this->registerSubscribers($facade);
    }
    public function testRunnerExecutionStarted(ExecutionStarted $event) : void {
        $this->numberOfTestsRun = 0;
        $this->numberOfTests = $event->testSuite()
            ->count();
        $this->numberOfTestsWidth = strlen((string) $this->numberOfTests);
        $this->column = 0;
        $this->maxColumn = $this->numberOfColumns - strlen('  /  (XXX%)') - 2 * $this->numberOfTestsWidth;
    }
    public function beforeTestClassMethodErrored() : void {
        $this->printProgressForError();
        $this->updateTestStatus(TestStatus::error());
    }
    public function testPrepared() : void {
        $this->prepared = true;
    }
    public function testSkipped() : void {
        if (!$this->prepared) {
            $this->printProgressForSkipped();
        }
        else {
            $this->updateTestStatus(TestStatus::skipped());
        }
    }
    public function testMarkedIncomplete() : void {
        $this->updateTestStatus(TestStatus::incomplete());
    }
    public function testTriggeredNotice(NoticeTriggered $event) : void {
        if ($event->ignoredByBaseline()) {
            return;
        }
        if ($this->source
            ->restrictNotices() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfNotices() && $event->wasSuppressed()) {
            return;
        }
        $this->updateTestStatus(TestStatus::notice());
    }
    public function testTriggeredPhpNotice(PhpNoticeTriggered $event) : void {
        if ($event->ignoredByBaseline()) {
            return;
        }
        if ($this->source
            ->restrictNotices() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfPhpNotices() && $event->wasSuppressed()) {
            return;
        }
        $this->updateTestStatus(TestStatus::notice());
    }
    public function testTriggeredDeprecation(DeprecationTriggered $event) : void {
        if ($event->ignoredByBaseline() || $event->ignoredByTest()) {
            return;
        }
        if ($this->source
            ->restrictDeprecations() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfDeprecations() && $event->wasSuppressed()) {
            return;
        }
        $this->updateTestStatus(TestStatus::deprecation());
    }
    public function testTriggeredPhpDeprecation(PhpDeprecationTriggered $event) : void {
        if ($event->ignoredByBaseline() || $event->ignoredByTest()) {
            return;
        }
        if ($this->source
            ->restrictDeprecations() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfPhpDeprecations() && $event->wasSuppressed()) {
            return;
        }
        $this->updateTestStatus(TestStatus::deprecation());
    }
    public function testTriggeredPhpunitDeprecation() : void {
        $this->updateTestStatus(TestStatus::deprecation());
    }
    public function testConsideredRisky() : void {
        $this->updateTestStatus(TestStatus::risky());
    }
    public function testTriggeredWarning(WarningTriggered $event) : void {
        if ($event->ignoredByBaseline()) {
            return;
        }
        if ($this->source
            ->restrictWarnings() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfWarnings() && $event->wasSuppressed()) {
            return;
        }
        $this->updateTestStatus(TestStatus::warning());
    }
    public function testTriggeredPhpWarning(PhpWarningTriggered $event) : void {
        if ($event->ignoredByBaseline()) {
            return;
        }
        if ($this->source
            ->restrictWarnings() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfPhpWarnings() && $event->wasSuppressed()) {
            return;
        }
        $this->updateTestStatus(TestStatus::warning());
    }
    public function testTriggeredPhpunitWarning() : void {
        $this->updateTestStatus(TestStatus::warning());
    }
    public function testTriggeredError(ErrorTriggered $event) : void {
        if (!$this->source
            ->ignoreSuppressionOfErrors() && $event->wasSuppressed()) {
            return;
        }
        $this->updateTestStatus(TestStatus::error());
    }
    public function testFailed() : void {
        $this->updateTestStatus(TestStatus::failure());
    }
    public function testErrored(Errored $event) : void {
        
        /*
         * @todo Eliminate this special case
         */
        if (str_contains($event->asString(), 'Test was run in child process and ended unexpectedly')) {
            $this->updateTestStatus(TestStatus::error());
            return;
        }
        if (!$this->prepared) {
            $this->printProgressForError();
        }
        else {
            $this->updateTestStatus(TestStatus::error());
        }
    }
    public function testFinished() : void {
        if ($this->status === null) {
            $this->printProgressForSuccess();
        }
        elseif ($this->status
            ->isSkipped()) {
            $this->printProgressForSkipped();
        }
        elseif ($this->status
            ->isIncomplete()) {
            $this->printProgressForIncomplete();
        }
        elseif ($this->status
            ->isRisky()) {
            $this->printProgressForRisky();
        }
        elseif ($this->status
            ->isNotice()) {
            $this->printProgressForNotice();
        }
        elseif ($this->status
            ->isDeprecation()) {
            $this->printProgressForDeprecation();
        }
        elseif ($this->status
            ->isWarning()) {
            $this->printProgressForWarning();
        }
        elseif ($this->status
            ->isFailure()) {
            $this->printProgressForFailure();
        }
        else {
            $this->printProgressForError();
        }
        $this->status = null;
        $this->prepared = false;
    }
    
    /**
     * @throws EventFacadeIsSealedException
     * @throws UnknownSubscriberTypeException
     */
    private function registerSubscribers(Facade $facade) : void {
        $facade->registerSubscribers(new BeforeTestClassMethodErroredSubscriber($this), new TestConsideredRiskySubscriber($this), new TestErroredSubscriber($this), new TestFailedSubscriber($this), new TestFinishedSubscriber($this), new TestMarkedIncompleteSubscriber($this), new TestPreparedSubscriber($this), new TestRunnerExecutionStartedSubscriber($this), new TestSkippedSubscriber($this), new TestTriggeredDeprecationSubscriber($this), new TestTriggeredNoticeSubscriber($this), new TestTriggeredPhpDeprecationSubscriber($this), new TestTriggeredPhpNoticeSubscriber($this), new TestTriggeredPhpunitDeprecationSubscriber($this), new TestTriggeredPhpunitWarningSubscriber($this), new TestTriggeredPhpWarningSubscriber($this), new TestTriggeredWarningSubscriber($this));
    }
    private function updateTestStatus(TestStatus $status) : void {
        if ($this->status !== null && $this->status
            ->isMoreImportantThan($status)) {
            return;
        }
        $this->status = $status;
    }
    private function printProgressForSuccess() : void {
        $this->printProgress('.');
    }
    private function printProgressForSkipped() : void {
        $this->printProgressWithColor('fg-cyan, bold', 'S');
    }
    private function printProgressForIncomplete() : void {
        $this->printProgressWithColor('fg-yellow, bold', 'I');
    }
    private function printProgressForNotice() : void {
        $this->printProgressWithColor('fg-yellow, bold', 'N');
    }
    private function printProgressForDeprecation() : void {
        $this->printProgressWithColor('fg-yellow, bold', 'D');
    }
    private function printProgressForRisky() : void {
        $this->printProgressWithColor('fg-yellow, bold', 'R');
    }
    private function printProgressForWarning() : void {
        $this->printProgressWithColor('fg-yellow, bold', 'W');
    }
    private function printProgressForFailure() : void {
        $this->printProgressWithColor('bg-red, fg-white', 'F');
    }
    private function printProgressForError() : void {
        $this->printProgressWithColor('fg-red, bold', 'E');
    }
    private function printProgressWithColor(string $color, string $progress) : void {
        if ($this->colors) {
            $progress = Color::colorizeTextBox($color, $progress);
        }
        $this->printProgress($progress);
    }
    private function printProgress(string $progress) : void {
        $this->printer
            ->print($progress);
        $this->column++;
        $this->numberOfTestsRun++;
        if ($this->column === $this->maxColumn || $this->numberOfTestsRun === $this->numberOfTests) {
            if ($this->numberOfTestsRun === $this->numberOfTests) {
                $this->printer
                    ->print(str_repeat(' ', $this->maxColumn - $this->column));
            }
            $this->printer
                ->print(sprintf(' %' . $this->numberOfTestsWidth . 'd / %' . $this->numberOfTestsWidth . 'd (%3s%%)', $this->numberOfTestsRun, $this->numberOfTests, floor($this->numberOfTestsRun / $this->numberOfTests * 100)));
            if ($this->column === $this->maxColumn) {
                $this->column = 0;
                $this->printer
                    ->print("\n");
            }
        }
    }

}

Classes

Title Deprecated Summary
ProgressPrinter @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
RSS feed
Powered by Drupal