Skip to content
Snippets Groups Projects
Commit 58dd736c authored by catch's avatar catch
Browse files

Issue #3400366 by mondrake, alexpott, mglaman, longwave, Spokje: Remove...

Issue #3400366 by mondrake, alexpott, mglaman, longwave, Spokje: Remove DrupalComponentTestListenerTrait and replace with a PHPStan rule
parent f757b3d3
No related branches found
No related tags found
29 merge requests!12227Issue #3181946 by jonmcl, mglaman,!11131[10.4.x-only-DO-NOT-MERGE]: Issue ##2842525 Ajax attached to Views exposed filter form does not trigger callbacks,!9470[10.3.x-only-DO-NOT-MERGE]: #3331771 Fix file_get_contents(): Passing null to parameter,!8540Issue #3457061: Bootstrap Modal dialog Not closing after 10.3.0 Update,!8528Issue #3456871 by Tim Bozeman: Support NULL services,!8373Issue #3427374 by danflanagan8, Vighneshh: taxonomy_tid ViewsArgumentDefault...,!5423Draft: Resolve #3329907 "Test2",!3878Removed unused condition head title for views,!3818Issue #2140179: $entity->original gets stale between updates,!3742Issue #3328429: Create item list field formatter for displaying ordered and unordered lists,!3731Claro: role=button on status report items,!3651Issue #3347736: Create new SDC component for Olivero (header-search),!3531Issue #3336994: StringFormatter always displays links to entity even if the user in context does not have access,!3478Issue #3337882: Deleted menus are not removed from content type config,!3355Issue #3209129: Scrolling problems when adding a block via layout builder,!3154Fixes #2987987 - CSRF token validation broken on routes with optional parameters.,!3133core/modules/system/css/components/hidden.module.css,!2964Issue #2865710 : Dependencies from only one instance of a widget are used in display modes,!2812Issue #3312049: [Followup] Fix Drupal.Commenting.FunctionComment.MissingReturnType returns for NULL,!2378Issue #2875033: Optimize joins and table selection in SQL entity query implementation,!2062Issue #3246454: Add weekly granularity to views date sort,!1105Issue #3025039: New non translatable field on translatable content throws error,!1073issue #3191727: Focus states on mobile second level navigation items fixed,!10223132456: Fix issue where views instances are emptied before an ajax request is complete,!877Issue #2708101: Default value for link text is not saved,!579Issue #2230909: Simple decimals fail to pass validation,!560Move callback classRemove outside of the loop,!555Issue #3202493,!213Issue #2906496: Give Media a menu item under Content
Pipeline #163869 canceled
Pipeline: drupal

#163870

    Showing
    with 337 additions and 40 deletions
    # cspell:ignore drupaltestbot drupaltestbotpw
    # cspell:ignore cobertura drupaltestbot drupaltestbotpw
    stages:
    - 🗜️ Test
    ......@@ -173,6 +173,35 @@ variables:
    TESTSUITE: PHPUnit-Unit
    KUBERNETES_CPU_REQUEST: "16"
    '✅️ PHPStan Tests':
    <<: [ *default-job-settings ]
    variables:
    KUBERNETES_CPU_REQUEST: "2"
    # Run if PHPStan files have changed, or manually.
    rules:
    - if: $CI_PIPELINE_SOURCE == "parent_pipeline" && $PERFORMANCE_TEST != "1"
    changes:
    - core/tests/PHPStan/*
    - composer/Metapackage/PinnedDevDependencies/composer.json
    - when: manual
    allow_failure: true
    # Default job settings runs a script that expects vendor to exist.
    before_script: []
    script:
    - docker-php-ext-enable pcov
    - cd core/tests/PHPStan
    - composer install
    - vendor/bin/phpunit tests --coverage-text --colors=never --coverage-cobertura=coverage.cobertura.xml --log-junit junit.xml
    # Default job settings runs a script that junit files in a specific location..
    after_script: []
    artifacts:
    when: always
    reports:
    junit: core/tests/PHPStan/junit.xml
    coverage_report:
    coverage_format: cobertura
    path: core/tests/PHPStan/coverage.cobertura.xml
    '🦉️️️ Nightwatch':
    <<: [ *with-composer-and-yarn, *default-job-settings ]
    variables:
    ......
    ......@@ -105,6 +105,11 @@
    "Drupal\\Composer\\": "composer"
    }
    },
    "autoload-dev": {
    "psr-4": {
    "Drupal\\PHPStan\\Rules\\": "core/tests/PHPStan/Rules"
    }
    },
    "scripts": {
    "pre-install-cmd": "Drupal\\Composer\\Composer::ensureComposerVersion",
    "pre-update-cmd": "Drupal\\Composer\\Composer::ensureComposerVersion",
    ......
    ......@@ -26,6 +26,7 @@
    "profiles/demo_umami/modules/demo_umami_content/default_content/languages/es/**/*",
    "tests/fixtures/files/*",
    "tests/Drupal/Tests/Component/Annotation/Doctrine/**",
    "tests/PHPStan/vendor/**",
    "themes/olivero/fonts/**",
    "COPYRIGHT.txt",
    "MAINTAINERS.txt",
    ......
    ......@@ -26,6 +26,8 @@ parameters:
    - ../*/node_modules/*
    - */tests/fixtures/*.php
    - */tests/fixtures/*.php.gz
    # Skip Drupal's own PHPStan rules test fixtures.
    - tests/PHPStan/fixtures/*
    # Skip Drupal 6 & 7 code.
    - scripts/dump-database-d?.sh
    - scripts/generate-d?-content.sh
    ......@@ -44,3 +46,6 @@ parameters:
    - "#Drupal calls should be avoided in classes, use dependency injection instead#"
    - "#^Plugin definitions cannot be altered.#"
    - "#^Class .* extends @internal class#"
    rules:
    - Drupal\PHPStan\Rules\ComponentTestDoesNotExtendCoreTest
    <?php
    declare(strict_types=1);
    namespace Drupal\Tests\Listeners;
    use Drupal\KernelTests\KernelTestBase;
    use Drupal\Tests\BrowserTestBase;
    use Drupal\Tests\UnitTestCase;
    use PHPUnit\Framework\AssertionFailedError;
    /**
    * Ensures that no component tests are extending a core test base class.
    *
    * @internal
    */
    trait DrupalComponentTestListenerTrait {
    /**
    * Reacts to the end of a test.
    *
    * @param \PHPUnit\Framework\Test $test
    * The test object that has ended its test run.
    * @param float $time
    * The time the test took.
    */
    protected function componentEndTest($test, $time) {
    /** @var \PHPUnit\Framework\Test $test */
    if (str_starts_with($test->toString(), 'Drupal\Tests\Component')) {
    if ($test instanceof BrowserTestBase || $test instanceof KernelTestBase || $test instanceof UnitTestCase) {
    $error = new AssertionFailedError('Component tests should not extend a core test base class.');
    $test->getTestResultObject()->addFailure($test, $error, $time);
    }
    }
    }
    }
    ......@@ -18,7 +18,6 @@
    class DrupalListener implements TestListener {
    use TestListenerDefaultImplementation;
    use DrupalComponentTestListenerTrait;
    /**
    * The wrapped Symfony test listener.
    ......@@ -60,7 +59,6 @@ public function startTest(Test $test): void {
    */
    public function endTest(Test $test, float $time): void {
    $this->symfonyListener->endTest($test, $time);
    $this->componentEndTest($test, $time);
    }
    }
    composer.lock
    coverage.cobertura.xml
    junit.xml
    vendor/
    # Drupal custom PHPStan rules
    This directory contains PHPStan rules specifically developed for Drupal.
    ## Subdirectories
    * _Rules_: contains the actual rules.
    * _tests_: contains PHPUnit tests for the rules.
    * _fixtures_: contains fixture files for the PHPUnit tests of the rules.
    ## Enabling rules
    Rules are executed when they are added to the the phpstan.neon(.dist)
    configuration file of a PHPStan scan run. You need to add them under the
    `rules` entry in the file, specifying the fully qualified class name of the
    rule. For example:
    ```
    rules:
    - Drupal\PHPStan\Rules\ComponentTestDoesNotExtendCoreTest
    ```
    ## Testing rules
    PHPStan rules must be tested in the context of the PHPStan testing framework,
    that differs in terms of dependencies from Drupal's one.
    Note that for this reason, these tests are run _separately_ from Drupal core
    tests.
    A _composer.json_ file is present in this directory, indicating the required
    packages for the execution of the tests. Installing via composer
    ```
    $ composer install
    ```
    builds a _vendor_ subdirectory that includes all the packages required. Note
    this packages' codebase is totally independent from Drupal core's one.
    In the context of this directory, you can then execute the rule tests like
    ```
    $ vendor/bin/phpunit tests
    ```
    <?php
    declare(strict_types=1);
    // cspell:ignore analyse
    namespace Drupal\PHPStan\Rules;
    use Drupal\BuildTests\Framework\BuildTestBase;
    use Drupal\KernelTests\KernelTestBase;
    use Drupal\Tests\BrowserTestBase;
    use Drupal\Tests\UnitTestCase;
    use PhpParser\Node;
    use PHPStan\Analyser\Scope;
    use PHPStan\Node\InClassNode;
    use PHPStan\Rules\Rule;
    use PHPStan\Rules\RuleErrorBuilder;
    /**
    * Ensures that no component tests are extending a core test base class.
    *
    * @implements Rule<\PHPStan\Node\InClassNode>
    *
    * @internal
    */
    final class ComponentTestDoesNotExtendCoreTest implements Rule {
    /**
    * {@inheritdoc}
    */
    public function getNodeType(): string {
    return InClassNode::class;
    }
    /**
    * {@inheritdoc}
    */
    public function processNode(Node $node, Scope $scope): array {
    $class = $node->getClassReflection();
    if (!str_starts_with($class->getName(), 'Drupal\Tests\Component')) {
    return [];
    }
    $invalidParents = [
    UnitTestCase::class,
    BuildTestBase::class,
    KernelTestBase::class,
    BrowserTestBase::class,
    ];
    foreach ($invalidParents as $invalidParent) {
    if ($class->isSubclassOf($invalidParent)) {
    return [
    RuleErrorBuilder::message("Component tests should not extend {$invalidParent}.")
    ->line($node->getStartLine())
    ->build(),
    ];
    }
    }
    return [];
    }
    }
    {
    "name": "drupal/phpstan-testing",
    "description": "Tests Drupal core's PHPStan rules",
    "require-dev": {
    "phpunit/phpunit": "^9",
    "phpstan/phpstan": "1.10.66"
    },
    "license": "GPL-2.0-or-later",
    "autoload": {
    "psr-4": {
    "Drupal\\PHPStan\\Rules\\": "Rules/",
    "Drupal\\BuildTests\\": "../Drupal/BuildTests/",
    "Drupal\\FunctionalJavascriptTests\\": "../Drupal/FunctionalJavascriptTests",
    "Drupal\\FunctionalTests\\": "../Drupal/FunctionalTests",
    "Drupal\\KernelTests\\": "../Drupal/KernelTests/",
    "Drupal\\Tests\\": "../Drupal/Tests/"
    }
    },
    "require": {}
    }
    <?php
    // phpcs:ignoreFile
    declare(strict_types=1);
    namespace Drupal\Tests\Component\Foo {
    use Drupal\BuildTests\Framework\BuildTestBase;
    use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
    use Drupal\KernelTests\KernelTestBase;
    use Drupal\Tests\BrowserTestBase;
    use Drupal\Tests\UnitTestCase;
    use PHPUnit\Framework\TestCase;
    final class FooTest extends TestCase {
    }
    final class UnitTest extends UnitTestCase {
    }
    final class BuildTest extends BuildTestBase {
    }
    final class KernelTest extends KernelTestBase {
    }
    final class FunctionalTest extends BrowserTestBase {
    }
    final class FunctionalJavascriptTest extends WebDriverTestBase {
    }
    }
    namespace Drupal\Tests\Core\Foo {
    use Drupal\BuildTests\Framework\BuildTestBase;
    use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
    use Drupal\KernelTests\KernelTestBase;
    use Drupal\Tests\BrowserTestBase;
    use Drupal\Tests\UnitTestCase;
    use PHPUnit\Framework\TestCase;
    final class FooTest extends TestCase {
    }
    final class UnitTest extends UnitTestCase {
    }
    final class BuildTest extends BuildTestBase {
    }
    final class KernelTest extends KernelTestBase {
    }
    final class FunctionalTest extends BrowserTestBase {
    }
    final class FunctionalJavascriptTest extends WebDriverTestBase {
    }
    }
    <?xml version="1.0" encoding="UTF-8"?>
    <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    colors="true"
    beStrictAboutTestsThatDoNotTestAnything="true"
    beStrictAboutOutputDuringTests="true"
    beStrictAboutChangesToGlobalState="true"
    failOnWarning="true"
    cacheResult="false"
    xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
    <php>
    <!-- Set error reporting to E_ALL. -->
    <ini name="error_reporting" value="32767"/>
    <!-- Do not limit the amount of memory tests take to run. -->
    <ini name="memory_limit" value="-1"/>
    </php>
    <testsuites>
    <testsuite name="PHPStan tests">
    <directory>tests</directory>
    </testsuite>
    </testsuites>
    <!-- Settings for coverage reports. -->
    <coverage>
    <include>
    <directory>Rules</directory>
    </include>
    </coverage>
    </phpunit>
    <?php
    declare(strict_types=1);
    // cspell:ignore analyse
    namespace Drupal\PHPStan\Tests;
    use Drupal\PHPStan\Rules\ComponentTestDoesNotExtendCoreTest;
    use PHPStan\Rules\Rule;
    use PHPStan\Testing\RuleTestCase;
    /**
    * Tests ComponentTestDoesNotExtendCoreTest rule.
    */
    class ComponentTestDoesNotExtendCoreTestTest extends RuleTestCase {
    /**
    * {@inheritdoc}
    */
    protected function getRule(): Rule {
    return new ComponentTestDoesNotExtendCoreTest();
    }
    /**
    * {@inheritdoc}
    */
    public function testRule(): void {
    $this->analyse(
    [__DIR__ . '/../fixtures/component-tests.php'],
    [
    [
    'Component tests should not extend Drupal\Tests\UnitTestCase.',
    19,
    ],
    [
    'Component tests should not extend Drupal\BuildTests\Framework\BuildTestBase.',
    22,
    ],
    [
    'Component tests should not extend Drupal\KernelTests\KernelTestBase.',
    25,
    ],
    [
    'Component tests should not extend Drupal\Tests\BrowserTestBase.',
    28,
    ],
    [
    'Component tests should not extend Drupal\Tests\BrowserTestBase.',
    31,
    ],
    ]
    );
    }
    }
    <?php
    declare(strict_types=1);
    namespace Drupal\PHPStan\Tests;
    use PHPUnit\Framework\TestCase;
    /**
    * Tests that PHPStan versions match.
    */
    class EnsurePHPStanVersionsMatchTest extends TestCase {
    public function testVersions(): void {
    $test_composer = json_decode(file_get_contents(__DIR__ . '/../composer.json'), TRUE);
    $drupal_composer = json_decode(file_get_contents(__DIR__ . '/../../../../composer/Metapackage/PinnedDevDependencies/composer.json'), TRUE);
    $this->assertSame($test_composer['require-dev']['phpstan/phpstan'], $drupal_composer['require']['phpstan/phpstan']);
    }
    }
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Please to comment