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

Breadcrumb

  1. Drupal Core 11.1.x

TestResultCollector.php

Namespace

PHPUnit\Logging\TestDox

File

vendor/phpunit/phpunit/src/Logging/TestDox/TestResult/TestResultCollector.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\Logging\TestDox;

use function array_keys;
use function array_merge;
use function assert;
use function is_subclass_of;
use function ksort;
use function uksort;
use function usort;
use PHPUnit\Event\Code\TestMethod;
use PHPUnit\Event\Code\Throwable;
use PHPUnit\Event\EventFacadeIsSealedException;
use PHPUnit\Event\Facade;
use PHPUnit\Event\InvalidArgumentException;
use PHPUnit\Event\Test\ConsideredRisky;
use PHPUnit\Event\Test\DeprecationTriggered;
use PHPUnit\Event\Test\Errored;
use PHPUnit\Event\Test\Failed;
use PHPUnit\Event\Test\Finished;
use PHPUnit\Event\Test\MarkedIncomplete;
use PHPUnit\Event\Test\NoticeTriggered;
use PHPUnit\Event\Test\Passed;
use PHPUnit\Event\Test\PhpDeprecationTriggered;
use PHPUnit\Event\Test\PhpNoticeTriggered;
use PHPUnit\Event\Test\PhpunitDeprecationTriggered;
use PHPUnit\Event\Test\PhpunitErrorTriggered;
use PHPUnit\Event\Test\PhpunitWarningTriggered;
use PHPUnit\Event\Test\PhpWarningTriggered;
use PHPUnit\Event\Test\Prepared;
use PHPUnit\Event\Test\Skipped;
use PHPUnit\Event\Test\WarningTriggered;
use PHPUnit\Event\UnknownSubscriberTypeException;
use PHPUnit\Framework\TestStatus\TestStatus;
use PHPUnit\Logging\TestDox\TestResult as TestDoxTestMethod;
use PHPUnit\TextUI\Configuration\Source;
use PHPUnit\TextUI\Configuration\SourceFilter;
use ReflectionMethod;

/**
 * @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 TestResultCollector {
    private readonly Source $source;
    
    /**
     * @psalm-var array<string, list<TestDoxTestMethod>>
     */
    private array $tests = [];
    private ?TestStatus $status = null;
    private ?Throwable $throwable = null;
    private bool $prepared = false;
    
    /**
     * @throws EventFacadeIsSealedException
     * @throws UnknownSubscriberTypeException
     */
    public function __construct(Facade $facade, Source $source) {
        $this->source = $source;
        $this->registerSubscribers($facade);
    }
    
    /**
     * @psalm-return array<string, TestResultCollection>
     */
    public function testMethodsGroupedByClass() : array {
        $result = [];
        foreach ($this->tests as $prettifiedClassName => $tests) {
            $testsByDeclaringClass = [];
            foreach ($tests as $test) {
                $declaringClassName = (new ReflectionMethod($test->test()
                    ->className(), $test->test()
                    ->methodName()))
                    ->getDeclaringClass()
                    ->getName();
                if (!isset($testsByDeclaringClass[$declaringClassName])) {
                    $testsByDeclaringClass[$declaringClassName] = [];
                }
                $testsByDeclaringClass[$declaringClassName][] = $test;
            }
            foreach (array_keys($testsByDeclaringClass) as $declaringClassName) {
                usort($testsByDeclaringClass[$declaringClassName], static function (TestDoxTestMethod $a, TestDoxTestMethod $b) : int {
                    return $a->test()
                        ->line() <=> $b->test()
                        ->line();
                });
            }
            uksort($testsByDeclaringClass, static function (string $a, string $b) : int {
                if (is_subclass_of($b, $a)) {
                    return -1;
                }
                if (is_subclass_of($a, $b)) {
                    return 1;
                }
                return 0;
            });
            $tests = [];
            foreach ($testsByDeclaringClass as $_tests) {
                $tests = array_merge($tests, $_tests);
            }
            $result[$prettifiedClassName] = TestResultCollection::fromArray($tests);
        }
        ksort($result);
        return $result;
    }
    public function testPrepared(Prepared $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        $this->status = TestStatus::unknown();
        $this->throwable = null;
        $this->prepared = true;
    }
    public function testErrored(Errored $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        $this->status = TestStatus::error($event->throwable()
            ->message());
        $this->throwable = $event->throwable();
        if (!$this->prepared) {
            $test = $event->test();
            assert($test instanceof TestMethod);
            $this->process($test);
        }
    }
    public function testFailed(Failed $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        $this->status = TestStatus::failure($event->throwable()
            ->message());
        $this->throwable = $event->throwable();
    }
    public function testPassed(Passed $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        $this->updateTestStatus(TestStatus::success());
    }
    public function testSkipped(Skipped $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        $this->updateTestStatus(TestStatus::skipped($event->message()));
    }
    public function testMarkedIncomplete(MarkedIncomplete $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        $this->updateTestStatus(TestStatus::incomplete($event->throwable()
            ->message()));
        $this->throwable = $event->throwable();
    }
    public function testConsideredRisky(ConsideredRisky $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        $this->updateTestStatus(TestStatus::risky());
    }
    public function testTriggeredDeprecation(DeprecationTriggered $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        if ($event->ignoredByTest()) {
            return;
        }
        if ($event->ignoredByBaseline()) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfDeprecations() && $event->wasSuppressed()) {
            return;
        }
        if ($this->source
            ->restrictDeprecations() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        $this->updateTestStatus(TestStatus::deprecation());
    }
    public function testTriggeredNotice(NoticeTriggered $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        if ($event->ignoredByBaseline()) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfNotices() && $event->wasSuppressed()) {
            return;
        }
        if ($this->source
            ->restrictNotices() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        $this->updateTestStatus(TestStatus::notice());
    }
    public function testTriggeredWarning(WarningTriggered $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        if ($event->ignoredByBaseline()) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfWarnings() && $event->wasSuppressed()) {
            return;
        }
        if ($this->source
            ->restrictWarnings() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        $this->updateTestStatus(TestStatus::warning());
    }
    public function testTriggeredPhpDeprecation(PhpDeprecationTriggered $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        if ($event->ignoredByTest()) {
            return;
        }
        if ($event->ignoredByBaseline()) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfPhpDeprecations() && $event->wasSuppressed()) {
            return;
        }
        if ($this->source
            ->restrictDeprecations() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        $this->updateTestStatus(TestStatus::deprecation());
    }
    public function testTriggeredPhpNotice(PhpNoticeTriggered $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        if ($event->ignoredByBaseline()) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfPhpNotices() && $event->wasSuppressed()) {
            return;
        }
        if ($this->source
            ->restrictNotices() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        $this->updateTestStatus(TestStatus::notice());
    }
    public function testTriggeredPhpWarning(PhpWarningTriggered $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        if ($event->ignoredByBaseline()) {
            return;
        }
        if (!$this->source
            ->ignoreSuppressionOfPhpWarnings() && $event->wasSuppressed()) {
            return;
        }
        if ($this->source
            ->restrictWarnings() && !(new SourceFilter())->includes($this->source, $event->file())) {
            return;
        }
        $this->updateTestStatus(TestStatus::warning());
    }
    public function testTriggeredPhpunitDeprecation(PhpunitDeprecationTriggered $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        $this->updateTestStatus(TestStatus::deprecation());
    }
    public function testTriggeredPhpunitError(PhpunitErrorTriggered $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        $this->updateTestStatus(TestStatus::error());
    }
    public function testTriggeredPhpunitWarning(PhpunitWarningTriggered $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        $this->updateTestStatus(TestStatus::warning());
    }
    
    /**
     * @throws InvalidArgumentException
     */
    public function testFinished(Finished $event) : void {
        if (!$event->test()
            ->isTestMethod()) {
            return;
        }
        $test = $event->test();
        assert($test instanceof TestMethod);
        $this->process($test);
        $this->status = null;
        $this->throwable = null;
        $this->prepared = false;
    }
    
    /**
     * @throws EventFacadeIsSealedException
     * @throws UnknownSubscriberTypeException
     */
    private function registerSubscribers(Facade $facade) : void {
        $facade->registerSubscribers(new TestConsideredRiskySubscriber($this), new TestErroredSubscriber($this), new TestFailedSubscriber($this), new TestFinishedSubscriber($this), new TestMarkedIncompleteSubscriber($this), new TestPassedSubscriber($this), new TestPreparedSubscriber($this), new TestSkippedSubscriber($this), new TestTriggeredDeprecationSubscriber($this), new TestTriggeredNoticeSubscriber($this), new TestTriggeredPhpDeprecationSubscriber($this), new TestTriggeredPhpNoticeSubscriber($this), new TestTriggeredPhpunitDeprecationSubscriber($this), new TestTriggeredPhpunitErrorSubscriber($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 process(TestMethod $test) : void {
        if (!isset($this->tests[$test->testDox()
            ->prettifiedClassName()])) {
            $this->tests[$test->testDox()
                ->prettifiedClassName()] = [];
        }
        $this->tests[$test->testDox()
            ->prettifiedClassName()][] = new TestDoxTestMethod($test, $this->status, $this->throwable);
    }

}

Classes

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