summaryrefslogtreecommitdiffstatshomepage
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/.phpunit-next.xml164
-rw-r--r--core/lib/Drupal/Core/Test/PhpUnitTestDiscovery.php346
-rw-r--r--core/lib/Drupal/Core/Test/RunTests/TestFileParser.php7
-rw-r--r--core/lib/Drupal/Core/Test/TestDiscovery.php41
-rw-r--r--core/modules/language/tests/src/Kernel/Migrate/d7/MigrateLanguageNegotiationSettingsTest.php1
-rw-r--r--core/modules/link/tests/src/Functional/LinkFieldUITest.php1
-rw-r--r--core/modules/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php1
-rw-r--r--core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php1
-rw-r--r--core/modules/system/tests/src/Kernel/DateFormatAccessControlHandlerTest.php11
-rw-r--r--core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeTest.php1
-rw-r--r--core/modules/workflows/tests/src/Kernel/WorkflowAccessControlHandlerTest.php11
-rwxr-xr-xcore/scripts/run-tests.sh222
-rw-r--r--core/tests/Drupal/KernelTests/Core/Test/PhpUnitApiFindAllClassFilesTest.php72
-rw-r--r--core/tests/Drupal/KernelTests/Core/Test/PhpUnitApiGetTestClassesTest.php109
-rw-r--r--core/tests/Drupal/KernelTests/Core/Test/PhpUnitTestDiscoveryTest.php28
-rw-r--r--core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php7
-rw-r--r--core/tests/Drupal/Tests/Core/Test/RunTests/TestFileParserTest.php18
-rw-r--r--core/tests/Drupal/Tests/Core/Test/TestDiscoveryTest.php40
18 files changed, 115 insertions, 966 deletions
diff --git a/core/.phpunit-next.xml b/core/.phpunit-next.xml
deleted file mode 100644
index 944ec9dfadd..00000000000
--- a/core/.phpunit-next.xml
+++ /dev/null
@@ -1,164 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-
-<!-- This is a near-copy of phpunit.xml.dist, used to test with upcoming
- PHPUnit versions.
-
- Current differences:
- * for PHPUnit 11: removed duplicate directories from <testsuites>,
- required in PHPUnit 10, but that cause duplication warnings in
- PHPUnit 11.
--->
-
-
-<!-- For how to customize PHPUnit configuration, see core/tests/README.md. -->
-<!-- TODO set checkForUnintentionallyCoveredCode="true" once https://www.drupal.org/node/2626832 is resolved. -->
-<!-- PHPUnit expects functional tests to be run with either a privileged user
- or your current system user. See core/tests/README.md and
- https://www.drupal.org/node/2116263 for details.
--->
-<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- bootstrap="tests/bootstrap.php"
- colors="true"
- beStrictAboutTestsThatDoNotTestAnything="true"
- beStrictAboutOutputDuringTests="true"
- beStrictAboutChangesToGlobalState="true"
- failOnRisky="true"
- failOnWarning="true"
- displayDetailsOnTestsThatTriggerErrors="true"
- displayDetailsOnTestsThatTriggerWarnings="true"
- displayDetailsOnTestsThatTriggerDeprecations="true"
- cacheResult="false"
- xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
- cacheDirectory=".phpunit.cache">
- <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"/>
- <!-- Example SIMPLETEST_BASE_URL value: http://localhost -->
- <env name="SIMPLETEST_BASE_URL" value=""/>
- <!-- Example SIMPLETEST_DB value: mysql://username:password@localhost/database_name#table_prefix -->
- <env name="SIMPLETEST_DB" value=""/>
- <!-- By default, browser tests will output links that use the base URL set
- in SIMPLETEST_BASE_URL. However, if your SIMPLETEST_BASE_URL is an internal
- path (such as may be the case in a virtual or Docker-based environment),
- you can set the base URL used in the browser test output links to something
- reachable from your host machine here. This will allow you to follow them
- directly and view the output. -->
- <env name="BROWSERTEST_OUTPUT_BASE_URL" value=""/>
- <!-- The environment variable SYMFONY_DEPRECATIONS_HELPER is used to configure
- the behavior of the deprecation tests.
- Drupal core's testing framework is setting this variable to its defaults.
- Projects with their own requirements need to manage this variable
- explicitly.
- -->
- <!-- To disable deprecation testing completely uncomment the next line. -->
- <!-- <env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled"/> -->
- <!-- Deprecation errors can be selectively ignored by specifying a file of
- regular expression patterns for exclusion.
- Uncomment the line below to specify a custom deprecations ignore file.
- NOTE: it may be required to specify the full path to the file to run tests
- correctly.
- -->
- <!-- <env name="SYMFONY_DEPRECATIONS_HELPER" value="ignoreFile=.deprecation-ignore.txt"/> -->
- <!-- Example for changing the driver class for mink tests MINK_DRIVER_CLASS value: 'Drupal\FunctionalJavascriptTests\DrupalSelenium2Driver' -->
- <env name="MINK_DRIVER_CLASS" value=""/>
- <!-- Example for changing the driver args to mink tests MINK_DRIVER_ARGS value: '["http://127.0.0.1:8510"]' -->
- <env name="MINK_DRIVER_ARGS" value=""/>
- <!-- Example for changing the driver args to webdriver tests MINK_DRIVER_ARGS_WEBDRIVER value: '["chrome", { "goog:chromeOptions": { "w3c": false } }, "http://localhost:4444/wd/hub"]' For using the Firefox browser, replace "chrome" with "firefox" -->
- <env name="MINK_DRIVER_ARGS_WEBDRIVER" value=""/>
- </php>
- <extensions>
- <!-- Functional tests HTML output logging. -->
- <bootstrap class="Drupal\TestTools\Extension\HtmlLogging\HtmlOutputLogger">
- <!-- The directory where the browser output will be stored. If a relative
- path is specified, it will be relative to the current working directory
- of the process running the PHPUnit CLI. In CI environments, this can be
- overridden by the value set for the "BROWSERTEST_OUTPUT_DIRECTORY"
- environment variable.
- -->
- <parameter name="outputDirectory" value="sites/simpletest/browser_output"/>
- <!-- By default browser tests print the individual links in the test run
- report. To avoid overcrowding the output in CI environments, you can
- set the "verbose" parameter or the "BROWSERTEST_OUTPUT_VERBOSE"
- environment variable to "false". In GitLabCI, the output is saved
- anyway as an artifact that can be browsed or downloaded from Gitlab.
- -->
- <parameter name="verbose" value="true"/>
- </bootstrap>
- <!-- Debug dump() printer. -->
- <bootstrap class="Drupal\TestTools\Extension\Dump\DebugDump">
- <parameter name="colors" value="true"/>
- <parameter name="printCaller" value="true"/>
- </bootstrap>
- </extensions>
- <testsuites>
- <testsuite name="unit-component">
- <directory>tests/Drupal/Tests/Component</directory>
- </testsuite>
- <testsuite name="unit">
- <directory>tests/Drupal/Tests</directory>
- <exclude>tests/Drupal/Tests/Component</exclude>
- <directory>modules/**/tests/src/Unit</directory>
- <directory>profiles/**/tests/src/Unit</directory>
- <directory>themes/**/tests/src/Unit</directory>
- <directory>../modules/**/tests/src/Unit</directory>
- <directory>../profiles/**/tests/src/Unit</directory>
- <directory>../themes/**/tests/src/Unit</directory>
- </testsuite>
- <testsuite name="kernel">
- <directory>tests/Drupal/KernelTests</directory>
- <directory>modules/**/tests/src/Kernel</directory>
- <directory>recipes/*/tests/src/Kernel</directory>
- <directory>profiles/**/tests/src/Kernel</directory>
- <directory>themes/**/tests/src/Kernel</directory>
- <directory>../modules/**/tests/src/Kernel</directory>
- <directory>../profiles/**/tests/src/Kernel</directory>
- <directory>../themes/**/tests/src/Kernel</directory>
- </testsuite>
- <testsuite name="functional">
- <directory>tests/Drupal/FunctionalTests</directory>
- <directory>modules/**/tests/src/Functional</directory>
- <directory>profiles/**/tests/src/Functional</directory>
- <directory>recipes/*/tests/src/Functional</directory>
- <directory>themes/**/tests/src/Functional</directory>
- <directory>../modules/**/tests/src/Functional</directory>
- <directory>../profiles/**/tests/src/Functional</directory>
- <directory>../themes/**/tests/src/Functional</directory>
- </testsuite>
- <testsuite name="functional-javascript">
- <directory>tests/Drupal/FunctionalJavascriptTests</directory>
- <directory>modules/**/tests/src/FunctionalJavascript</directory>
- <directory>recipes/*/tests/src/FunctionalJavascript</directory>
- <directory>profiles/**/tests/src/FunctionalJavascript</directory>
- <directory>themes/**/tests/src/FunctionalJavascript</directory>
- <directory>../modules/**/tests/src/FunctionalJavascript</directory>
- <directory>../profiles/**/tests/src/FunctionalJavascript</directory>
- <directory>../themes/**/tests/src/FunctionalJavascript</directory>
- </testsuite>
- <testsuite name="build">
- <directory>tests/Drupal/BuildTests</directory>
- <directory>modules/**/tests/src/Build</directory>
- </testsuite>
- </testsuites>
- <!-- Settings for coverage reports. -->
- <source ignoreSuppressionOfDeprecations="true">
- <include>
- <directory>./includes</directory>
- <directory>./lib</directory>
- <directory>./modules</directory>
- <directory>../modules</directory>
- <directory>../sites</directory>
- </include>
- <exclude>
- <directory>./lib/Drupal/Component</directory>
- <directory>./modules/*/src/Tests</directory>
- <directory>./modules/*/tests</directory>
- <directory>../modules/*/src/Tests</directory>
- <directory>../modules/*/tests</directory>
- <directory>../modules/*/*/src/Tests</directory>
- <directory>../modules/*/*/tests</directory>
- </exclude>
- </source>
-</phpunit>
diff --git a/core/lib/Drupal/Core/Test/PhpUnitTestDiscovery.php b/core/lib/Drupal/Core/Test/PhpUnitTestDiscovery.php
deleted file mode 100644
index d9737028821..00000000000
--- a/core/lib/Drupal/Core/Test/PhpUnitTestDiscovery.php
+++ /dev/null
@@ -1,346 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Core\Test;
-
-use Drupal\Core\Test\Exception\MissingGroupException;
-use Drupal\TestTools\PhpUnitCompatibility\RunnerVersion;
-use PHPUnit\Framework\DataProviderTestSuite;
-use PHPUnit\Framework\Test;
-use PHPUnit\Framework\TestCase;
-use PHPUnit\Framework\TestSuite;
-use PHPUnit\TextUI\Configuration\Builder;
-use PHPUnit\TextUI\Configuration\TestSuiteBuilder;
-
-/**
- * Discovers available tests using the PHPUnit API.
- *
- * @internal
- */
-class PhpUnitTestDiscovery {
-
- /**
- * The map of legacy test suite identifiers to phpunit.xml ones.
- *
- * @var array<string,string>
- */
- private array $map = [
- 'PHPUnit-FunctionalJavascript' => 'functional-javascript',
- 'PHPUnit-Functional' => 'functional',
- 'PHPUnit-Kernel' => 'kernel',
- 'PHPUnit-Unit' => 'unit',
- 'PHPUnit-Unit-Component' => 'unit-component',
- 'PHPUnit-Build' => 'build',
- ];
-
- /**
- * The reverse map of legacy test suite identifiers to phpunit.xml ones.
- *
- * @var array<string,string>
- */
- private array $reverseMap;
-
- /**
- * The warnings generated during the discovery.
- *
- * @var list<string>
- */
- private array $warnings = [];
-
- public function __construct(
- private string $configurationFilePath,
- ) {
- $this->reverseMap = array_flip($this->map);
- }
-
- /**
- * Discovers available tests.
- *
- * @param string|null $extension
- * (optional) The name of an extension to limit discovery to; e.g., 'node'.
- * @param list<string> $testSuites
- * (optional) An array of PHPUnit test suites to filter the discovery for.
- * @param string|null $directory
- * (optional) Limit discovered tests to a specific directory.
- *
- * @return array<string<array<class-string, array{name: class-string, description: string, group: string|int, groups: list<string|int>, type: string, file: string, tests_count: positive-int}>>>
- * An array of test groups keyed by the group name. Each test group is an
- * array of test class information arrays as returned by
- * ::getTestClassInfo(), keyed by test class. If a test class belongs to
- * multiple groups, it will appear under all group keys it belongs to.
- */
- public function getTestClasses(?string $extension = NULL, array $testSuites = [], ?string $directory = NULL): array {
- $this->warnings = [];
-
- $args = ['--configuration', $this->configurationFilePath];
-
- if (!empty($testSuites)) {
- // Convert $testSuites from Drupal's legacy syntax to the syntax used in
- // phpunit.xml, that is necessary to PHPUnit to be able to apply the
- // test suite filter. For example, 'PHPUnit-Unit' to 'unit'.
- $tmp = [];
- foreach ($testSuites as $i) {
- if (!is_string($i)) {
- throw new \InvalidArgumentException("Test suite must be a string");
- }
- if (str_contains($i, ' ')) {
- throw new \InvalidArgumentException("Test suite name '{$i}' is invalid");
- }
- $tmp[] = $this->map[$i] ?? $i;
- }
- $args[] = '--testsuite=' . implode(',', $tmp);
- }
-
- if ($directory !== NULL) {
- $args[] = $directory;
- }
-
- $phpUnitConfiguration = (new Builder())->build($args);
-
- // TestSuiteBuilder calls the test data providers during the discovery.
- // Data providers may be changing the Drupal service container, which leads
- // to potential issues. We save the current container before running the
- // discovery, and in case a change is detected, reset it and raise
- // warnings so that developers can tune their data provider code.
- if (\Drupal::hasContainer()) {
- $container = \Drupal::getContainer();
- $containerObjectId = spl_object_id($container);
- }
- $phpUnitTestSuite = (new TestSuiteBuilder())->build($phpUnitConfiguration);
- if (isset($containerObjectId) && $containerObjectId !== spl_object_id(\Drupal::getContainer())) {
- $this->warnings[] = '*** The service container was changed during the test discovery ***';
- $this->warnings[] = 'Probably a test data provider method called \\Drupal::setContainer.';
- $this->warnings[] = 'Ensure that all the data providers restore the original container before returning data.';
- assert(isset($container));
- \Drupal::setContainer($container);
- }
-
- $list = $directory === NULL ?
- $this->getTestList($phpUnitTestSuite, $extension) :
- $this->getTestListLimitedToDirectory($phpUnitTestSuite, $extension, $testSuites);
-
- // Sort the groups and tests within the groups by name.
- uksort($list, 'strnatcasecmp');
- foreach ($list as &$tests) {
- uksort($tests, 'strnatcasecmp');
- }
-
- return $list;
- }
-
- /**
- * Discovers all class files in all available extensions.
- *
- * @param string|null $extension
- * (optional) The name of an extension to limit discovery to; e.g., 'node'.
- * @param string|null $directory
- * (optional) Limit discovered tests to a specific directory.
- *
- * @return array
- * A classmap containing all discovered class files; i.e., a map of
- * fully-qualified classnames to path names.
- */
- public function findAllClassFiles(?string $extension = NULL, ?string $directory = NULL): array {
- $testClasses = $this->getTestClasses($extension, [], $directory);
- $classMap = [];
- foreach ($testClasses as $group) {
- foreach ($group as $className => $info) {
- $classMap[$className] = $info['file'];
- }
- }
- return $classMap;
- }
-
- /**
- * Returns the warnings generated during the discovery.
- *
- * @return list<string>
- * The warnings.
- */
- public function getWarnings(): array {
- return $this->warnings;
- }
-
- /**
- * Returns a list of tests from a TestSuite object.
- *
- * @param \PHPUnit\Framework\TestSuite $phpUnitTestSuite
- * The TestSuite object returned by PHPUnit test discovery.
- * @param string|null $extension
- * The name of an extension to limit discovery to; e.g., 'node'.
- *
- * @return array<string<array<class-string, array{name: class-string, description: string, group: string|int, groups: list<string|int>, type: string, file: string, tests_count: positive-int}>>>
- * An array of test groups keyed by the group name. Each test group is an
- * array of test class information arrays as returned by
- * ::getTestClassInfo(), keyed by test class. If a test class belongs to
- * multiple groups, it will appear under all group keys it belongs to.
- */
- private function getTestList(TestSuite $phpUnitTestSuite, ?string $extension): array {
- $list = [];
- foreach ($phpUnitTestSuite->tests() as $testSuite) {
- foreach ($testSuite->tests() as $testClass) {
- if ($extension !== NULL && !str_starts_with($testClass->name(), "Drupal\\Tests\\{$extension}\\")) {
- continue;
- }
-
- $item = $this->getTestClassInfo(
- $testClass,
- $this->reverseMap[$testSuite->name()] ?? $testSuite->name(),
- );
-
- foreach ($item['groups'] as $group) {
- $list[$group][$item['name']] = $item;
- }
- }
- }
- return $list;
- }
-
- /**
- * Returns a list of tests from a TestSuite object limited to a directory.
- *
- * @param \PHPUnit\Framework\TestSuite $phpUnitTestSuite
- * The TestSuite object returned by PHPUnit test discovery.
- * @param string|null $extension
- * The name of an extension to limit discovery to; e.g., 'node'.
- * @param list<string> $testSuites
- * An array of PHPUnit test suites to filter the discovery for.
- *
- * @return array<string<array<class-string, array{name: class-string, description: string, group: string|int, groups: list<string|int>, type: string, file: string, tests_count: positive-int}>>>
- * An array of test groups keyed by the group name. Each test group is an
- * array of test class information arrays as returned by
- * ::getTestClassInfo(), keyed by test class. If a test class belongs to
- * multiple groups, it will appear under all group keys it belongs to.
- */
- private function getTestListLimitedToDirectory(TestSuite $phpUnitTestSuite, ?string $extension, array $testSuites): array {
- $list = [];
-
- // In this case, PHPUnit found a single test class to run tests for.
- if ($phpUnitTestSuite->isForTestClass()) {
- if ($extension !== NULL && !str_starts_with($phpUnitTestSuite->name(), "Drupal\\Tests\\{$extension}\\")) {
- return [];
- }
-
- // Take the test suite name from the class namespace.
- $testSuite = 'PHPUnit-' . TestDiscovery::getPhpunitTestSuite($phpUnitTestSuite->name());
- if (!empty($testSuites) && !in_array($testSuite, $testSuites, TRUE)) {
- return [];
- }
-
- $item = $this->getTestClassInfo($phpUnitTestSuite, $testSuite);
-
- foreach ($item['groups'] as $group) {
- $list[$group][$item['name']] = $item;
- }
- return $list;
- }
-
- // Multiple test classes were found.
- $list = [];
- foreach ($phpUnitTestSuite->tests() as $testClass) {
- if ($extension !== NULL && !str_starts_with($testClass->name(), "Drupal\\Tests\\{$extension}\\")) {
- continue;
- }
-
- // Take the test suite name from the class namespace.
- $testSuite = 'PHPUnit-' . TestDiscovery::getPhpunitTestSuite($testClass->name());
- if (!empty($testSuites) && !in_array($testSuite, $testSuites, TRUE)) {
- continue;
- }
-
- $item = $this->getTestClassInfo($testClass, $testSuite);
-
- foreach ($item['groups'] as $group) {
- $list[$group][$item['name']] = $item;
- }
- }
- return $list;
-
- }
-
- /**
- * Returns the test class information.
- *
- * @param \PHPUnit\Framework\Test $testClass
- * The test class.
- * @param string $testSuite
- * The test suite of this test class.
- *
- * @return array{name: class-string, description: string, group: string|int, groups: list<string|int>, type: string, file: string, tests_count: positive-int}
- * The test class information.
- */
- private function getTestClassInfo(Test $testClass, string $testSuite): array {
- $reflection = new \ReflectionClass($testClass->name());
-
- // Let PHPUnit API return the groups, as it will deal transparently with
- // annotations or attributes, but skip groups generated by PHPUnit
- // internally and starting with a double underscore prefix.
- if (RunnerVersion::getMajor() < 11) {
- $groups = array_filter($testClass->groups(), function (string $value): bool {
- return !str_starts_with($value, '__phpunit');
- });
- }
- else {
- // In PHPUnit 11+, we need to coalesce the groups from individual tests
- // as they may not be available from the test class level (when tests are
- // backed by data providers).
- $tmp = [];
- foreach ($testClass as $test) {
- if ($test instanceof DataProviderTestSuite) {
- foreach ($test as $testWithData) {
- $tmp = array_merge($tmp, $testWithData->groups());
- }
- }
- else {
- $tmp = array_merge($tmp, $test->groups());
- }
- }
- $groups = array_filter(array_unique($tmp), function (string $value): bool {
- return !str_starts_with($value, '__phpunit');
- });
- }
- if (empty($groups)) {
- throw new MissingGroupException(sprintf('Missing group metadata in test class %s', $testClass->name()));
- }
-
- // Let PHPUnit API return the class coverage information.
- $test = $testClass;
- while (!$test instanceof TestCase) {
- $test = $test->tests()[0];
- }
- if (($metadata = $test->valueObjectForEvents()->metadata()->isCoversClass()) && $metadata->isNotEmpty()) {
- $description = sprintf('Tests %s.', $metadata->asArray()[0]->className());
- }
- elseif (($metadata = $test->valueObjectForEvents()->metadata()->isCoversDefaultClass()) && $metadata->isNotEmpty()) {
- $description = sprintf('Tests %s.', $metadata->asArray()[0]->className());
- }
- else {
- $description = TestDiscovery::parseTestClassSummary($reflection->getDocComment());
- }
-
- // Find the test cases count.
- $count = 0;
- foreach ($testClass->tests() as $testCase) {
- if ($testCase instanceof TestCase) {
- // If it's a straight test method, counts 1.
- $count++;
- }
- else {
- // It's a data provider test suite, count 1 per data set provided.
- $count += count($testCase->tests());
- }
- }
-
- return [
- 'name' => $testClass->name(),
- 'group' => $groups[0],
- 'groups' => $groups,
- 'type' => $testSuite,
- 'description' => $description,
- 'file' => $reflection->getFileName(),
- 'tests_count' => $count,
- ];
- }
-
-}
diff --git a/core/lib/Drupal/Core/Test/RunTests/TestFileParser.php b/core/lib/Drupal/Core/Test/RunTests/TestFileParser.php
index 8ab5260aa66..12aa757e57e 100644
--- a/core/lib/Drupal/Core/Test/RunTests/TestFileParser.php
+++ b/core/lib/Drupal/Core/Test/RunTests/TestFileParser.php
@@ -4,16 +4,9 @@ namespace Drupal\Core\Test\RunTests;
use PHPUnit\Framework\TestCase;
-@trigger_error('Drupal\Core\Test\RunTests\TestFileParser is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. There is no replacement. See https://www.drupal.org/node/3447698', E_USER_DEPRECATED);
-
/**
* Parses class names from PHP files without loading them.
*
- * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. There is no
- * replacement.
- *
- * @see https://www.drupal.org/node/3447698
- *
* @internal
*/
class TestFileParser {
diff --git a/core/lib/Drupal/Core/Test/TestDiscovery.php b/core/lib/Drupal/Core/Test/TestDiscovery.php
index 468256779b3..1347d0c583f 100644
--- a/core/lib/Drupal/Core/Test/TestDiscovery.php
+++ b/core/lib/Drupal/Core/Test/TestDiscovery.php
@@ -7,7 +7,6 @@ use Drupal\Component\Annotation\Reflection\MockFileFinder;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Test\Exception\MissingGroupException;
-use PHPUnit\Framework\Attributes\Group;
/**
* Discovers available tests.
@@ -27,11 +26,6 @@ class TestDiscovery {
* Statically cached list of test classes.
*
* @var array
- *
- * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. There is
- * no replacement.
- *
- * @see https://www.drupal.org/node/3447698
*/
protected $testClasses;
@@ -155,14 +149,8 @@ class TestDiscovery {
*
* @todo Remove singular grouping; retain list of groups in 'group' key.
* @see https://www.drupal.org/node/2296615
- *
- * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use
- * PhpUnitTestDiscovery::getTestClasses() instead.
- *
- * @see https://www.drupal.org/node/3447698
*/
public function getTestClasses($extension = NULL, array $types = [], ?string $directory = NULL) {
- @trigger_error(__METHOD__ . '() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use PhpUnitTestDiscovery::getTestClasses() instead. See https://www.drupal.org/node/3447698', E_USER_DEPRECATED);
if (!isset($extension) && empty($types)) {
if (!empty($this->testClasses)) {
return $this->testClasses;
@@ -187,15 +175,6 @@ class TestDiscovery {
catch (MissingGroupException $e) {
// If the class name ends in Test and is not a migrate table dump.
if (str_ends_with($classname, 'Test') && !str_contains($classname, 'migrate_drupal\Tests\Table')) {
- $reflection = new \ReflectionClass($classname);
- $groupAttributes = $reflection->getAttributes(Group::class, \ReflectionAttribute::IS_INSTANCEOF);
- if (!empty($groupAttributes)) {
- $group = '##no-group-annotations';
- $info['group'] = $group;
- $info['groups'] = [$group];
- $list[$group][$classname] = $info;
- continue;
- }
throw $e;
}
// If the class is @group annotation just skip it. Most likely it is an
@@ -237,14 +216,8 @@ class TestDiscovery {
* @return array
* A classmap containing all discovered class files; i.e., a map of
* fully-qualified classnames to path names.
- *
- * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use
- * PhpUnitTestDiscovery::findAllClassFiles() instead.
- *
- * @see https://www.drupal.org/node/3447698
*/
public function findAllClassFiles($extension = NULL, ?string $directory = NULL) {
- @trigger_error(__METHOD__ . '() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use PhpUnitTestDiscovery::findAllClassFiles() instead. See https://www.drupal.org/node/3447698', E_USER_DEPRECATED);
$classmap = [];
$namespaces = $this->registerTestNamespaces();
if (isset($extension)) {
@@ -283,14 +256,8 @@ class TestDiscovery {
*
* @todo Limit to '*Test.php' files (~10% less files to reflect/introspect).
* @see https://www.drupal.org/node/2296635
- *
- * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. There is
- * no replacement.
- *
- * @see https://www.drupal.org/node/3447698
*/
public static function scanDirectory($namespace_prefix, $path) {
- @trigger_error(__METHOD__ . '() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. There is no replacement. See https://www.drupal.org/node/3447698', E_USER_DEPRECATED);
if (!str_ends_with($namespace_prefix, '\\')) {
throw new \InvalidArgumentException("Namespace prefix for $path must contain a trailing namespace separator.");
}
@@ -345,14 +312,8 @@ class TestDiscovery {
*
* @throws \Drupal\Core\Test\Exception\MissingGroupException
* If the class does not have a @group annotation.
- *
- * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. There is
- * no replacement.
- *
- * @see https://www.drupal.org/node/3447698
*/
public static function getTestInfo($classname, $doc_comment = NULL) {
- @trigger_error(__METHOD__ . '() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. There is no replacement. See https://www.drupal.org/node/3447698', E_USER_DEPRECATED);
if ($doc_comment === NULL) {
$reflection = new \ReflectionClass($classname);
$doc_comment = $reflection->getDocComment();
@@ -389,7 +350,7 @@ class TestDiscovery {
$info['type'] = 'PHPUnit-' . static::getPhpunitTestSuite($classname);
if (!empty($annotations['coversDefaultClass'])) {
- $info['description'] = 'Tests ' . ltrim($annotations['coversDefaultClass']) . '.';
+ $info['description'] = 'Tests ' . $annotations['coversDefaultClass'] . '.';
}
else {
$info['description'] = static::parseTestClassSummary($doc_comment);
diff --git a/core/modules/language/tests/src/Kernel/Migrate/d7/MigrateLanguageNegotiationSettingsTest.php b/core/modules/language/tests/src/Kernel/Migrate/d7/MigrateLanguageNegotiationSettingsTest.php
index fe5ff0ca062..54fdf4b0d21 100644
--- a/core/modules/language/tests/src/Kernel/Migrate/d7/MigrateLanguageNegotiationSettingsTest.php
+++ b/core/modules/language/tests/src/Kernel/Migrate/d7/MigrateLanguageNegotiationSettingsTest.php
@@ -10,7 +10,6 @@ use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
/**
* Tests the migration of language negotiation.
*
- * @group #slow
* @group migrate_drupal_7
*/
class MigrateLanguageNegotiationSettingsTest extends MigrateDrupal7TestBase {
diff --git a/core/modules/link/tests/src/Functional/LinkFieldUITest.php b/core/modules/link/tests/src/Functional/LinkFieldUITest.php
index 5c78abc2391..694fb6b3677 100644
--- a/core/modules/link/tests/src/Functional/LinkFieldUITest.php
+++ b/core/modules/link/tests/src/Functional/LinkFieldUITest.php
@@ -15,7 +15,6 @@ use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
* Tests link field UI functionality.
*
* @group link
- * @group #slow
*/
class LinkFieldUITest extends BrowserTestBase {
diff --git a/core/modules/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php b/core/modules/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php
index 2e9a0977fa3..90348cdfdd3 100644
--- a/core/modules/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php
+++ b/core/modules/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php
@@ -13,6 +13,7 @@ use Drupal\Tests\package_manager\Traits\FixtureUtilityTrait;
* @coversDefaultClass \Drupal\package_manager\Validator\SupportedReleaseValidator
* @group #slow
* @group package_manager
+ * @group #slow
* @internal
*/
class SupportedReleaseValidatorTest extends PackageManagerKernelTestBase {
diff --git a/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php b/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php
index be5d811fe54..d5cc9759ab1 100644
--- a/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php
+++ b/core/modules/path/tests/src/Kernel/Migrate/d6/MigrateUrlAliasTest.php
@@ -13,7 +13,6 @@ use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/**
* URL alias migration.
*
- * @group #slow
* @group migrate_drupal_6
*/
class MigrateUrlAliasTest extends MigrateDrupal6TestBase {
diff --git a/core/modules/system/tests/src/Kernel/DateFormatAccessControlHandlerTest.php b/core/modules/system/tests/src/Kernel/DateFormatAccessControlHandlerTest.php
index 82d866e985e..6c8c42da59e 100644
--- a/core/modules/system/tests/src/Kernel/DateFormatAccessControlHandlerTest.php
+++ b/core/modules/system/tests/src/Kernel/DateFormatAccessControlHandlerTest.php
@@ -77,8 +77,6 @@ class DateFormatAccessControlHandlerTest extends KernelTestBase {
* An array of test cases.
*/
public static function providerTestAccess(): array {
- $originalContainer = \Drupal::hasContainer() ? \Drupal::getContainer() : NULL;
-
$c = new ContainerBuilder();
$cache_contexts_manager = (new Prophet())->prophesize(CacheContextsManager::class);
$cache_contexts_manager->assertValidTokens()->willReturn(TRUE);
@@ -86,7 +84,7 @@ class DateFormatAccessControlHandlerTest extends KernelTestBase {
$c->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($c);
- $data = [
+ return [
'No permission + unlocked' => [
[],
'unlocked',
@@ -124,13 +122,6 @@ class DateFormatAccessControlHandlerTest extends KernelTestBase {
AccessResult::allowed()->addCacheContexts(['user.permissions']),
],
];
-
- // Restore the original container if needed.
- if ($originalContainer) {
- \Drupal::setContainer($originalContainer);
- }
-
- return $data;
}
}
diff --git a/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeTest.php b/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeTest.php
index 511778daf20..1d9654dd505 100644
--- a/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeTest.php
+++ b/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeTest.php
@@ -10,7 +10,6 @@ use Drupal\node\Entity\Node;
/**
* Upgrade taxonomy term node associations.
*
- * @group #slow
* @group migrate_drupal_6
*/
class MigrateTermNodeTest extends MigrateDrupal6TestBase {
diff --git a/core/modules/workflows/tests/src/Kernel/WorkflowAccessControlHandlerTest.php b/core/modules/workflows/tests/src/Kernel/WorkflowAccessControlHandlerTest.php
index 180edc868f6..e46fbcf417b 100644
--- a/core/modules/workflows/tests/src/Kernel/WorkflowAccessControlHandlerTest.php
+++ b/core/modules/workflows/tests/src/Kernel/WorkflowAccessControlHandlerTest.php
@@ -124,8 +124,6 @@ class WorkflowAccessControlHandlerTest extends KernelTestBase {
* An array of test data.
*/
public static function checkAccessProvider() {
- $originalContainer = \Drupal::hasContainer() ? \Drupal::getContainer() : NULL;
-
$container = new ContainerBuilder();
$cache_contexts_manager = (new Prophet())->prophesize(CacheContextsManager::class);
$cache_contexts_manager->assertValidTokens()->willReturn(TRUE);
@@ -133,7 +131,7 @@ class WorkflowAccessControlHandlerTest extends KernelTestBase {
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
- $data = [
+ return [
'Admin view' => [
'adminUser',
'view',
@@ -277,13 +275,6 @@ class WorkflowAccessControlHandlerTest extends KernelTestBase {
AccessResult::allowed()->addCacheContexts(['user.permissions']),
],
];
-
- // Restore the original container if needed.
- if ($originalContainer) {
- \Drupal::setContainer($originalContainer);
- }
-
- return $data;
}
}
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 96f16eed9c7..4545a00cc3a 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -17,13 +17,14 @@ use Drupal\Component\Utility\Timer;
use Drupal\Core\Composer\Composer;
use Drupal\Core\Database\Database;
use Drupal\Core\Test\EnvironmentCleaner;
-use Drupal\Core\Test\PhpUnitTestDiscovery;
use Drupal\Core\Test\PhpUnitTestRunner;
use Drupal\Core\Test\SimpletestTestRunResultsStorage;
+use Drupal\Core\Test\RunTests\TestFileParser;
use Drupal\Core\Test\TestDatabase;
use Drupal\Core\Test\TestRun;
use Drupal\Core\Test\TestRunnerKernel;
use Drupal\Core\Test\TestRunResultsStorageInterface;
+use Drupal\Core\Test\TestDiscovery;
use Drupal\BuildTests\Framework\BuildTestBase;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\KernelTests\KernelTestBase;
@@ -48,10 +49,6 @@ const SIMPLETEST_SCRIPT_COLOR_EXCEPTION = 33;
const SIMPLETEST_SCRIPT_COLOR_YELLOW = 33;
// A refreshing cyan.
const SIMPLETEST_SCRIPT_COLOR_CYAN = 36;
-// A fainting gray.
-const SIMPLETEST_SCRIPT_COLOR_GRAY = 90;
-// A notable white.
-const SIMPLETEST_SCRIPT_COLOR_BRIGHT_WHITE = "1;97";
// Restricting the chunk of queries prevents memory exhaustion.
const SIMPLETEST_SCRIPT_SQLITE_VARIABLE_LIMIT = 350;
@@ -89,12 +86,12 @@ if ($args['list']) {
// Display all available tests organized by one @group annotation.
echo "\nAvailable test groups & classes\n";
echo "-------------------------------\n\n";
- $test_discovery = new PhpUnitTestDiscovery(\Drupal::root() . \DIRECTORY_SEPARATOR . 'core');
+ $test_discovery = new TestDiscovery(
+ \Drupal::root(),
+ \Drupal::service('class_loader')
+ );
try {
$groups = $test_discovery->getTestClasses($args['module']);
- foreach ($test_discovery->getWarnings() as $warning) {
- simpletest_script_print($warning . "\n", SIMPLETEST_SCRIPT_COLOR_EXCEPTION);
- }
}
catch (Exception $e) {
error_log((string) $e);
@@ -122,8 +119,11 @@ if ($args['list']) {
// @see https://www.drupal.org/node/2569585
if ($args['list-files'] || $args['list-files-json']) {
// List all files which could be run as tests.
- $test_discovery = new PhpUnitTestDiscovery(\Drupal::root() . \DIRECTORY_SEPARATOR . 'core');
- // PhpUnitTestDiscovery::findAllClassFiles() gives us a classmap similar to a
+ $test_discovery = new TestDiscovery(
+ \Drupal::root(),
+ \Drupal::service('class_loader')
+ );
+ // TestDiscovery::findAllClassFiles() gives us a classmap similar to a
// Composer 'classmap' array.
$test_classes = $test_discovery->findAllClassFiles();
// JSON output is the easiest.
@@ -177,15 +177,6 @@ if (!Composer::upgradePHPUnitCheck(Version::id())) {
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
}
-echo "\n";
-echo "Drupal test run\n\n";
-echo sprintf("Drupal Version: %s\n", \Drupal::VERSION);
-echo sprintf("PHP Version: %s\n", \PHP_VERSION);
-echo sprintf("PHP Binary: %s\n", $php ?? getenv('_'));
-echo sprintf("PHPUnit Version: %s\n", Version::id());
-echo "-------------------------------\n";
-echo "\n";
-
$test_list = simpletest_script_get_test_list();
// Try to allocate unlimited time to run the tests.
@@ -364,11 +355,6 @@ All arguments are long options.
The index of the job in the job set.
- --debug-discovery
-
- If provided, dumps detailed information on the tests selected
- for execution, before the execution starts.
-
<test1>[,<test2>[,<test3> ...]]
One or more tests to be run. By default, these are interpreted
@@ -441,7 +427,6 @@ function simpletest_script_parse_args() {
'non-html' => FALSE,
'ci-parallel-node-index' => 1,
'ci-parallel-node-total' => 1,
- 'debug-discovery' => FALSE,
];
// Override with set values.
@@ -934,15 +919,17 @@ function simpletest_script_command(TestRun $test_run, string $test_class): array
function simpletest_script_get_test_list() {
global $args;
- $test_discovery = new PhpUnitTestDiscovery(\Drupal::root() . \DIRECTORY_SEPARATOR . 'core');
+ $test_discovery = new TestDiscovery(
+ \Drupal::root(),
+ \Drupal::service('class_loader')
+ );
+ $types_processed = empty($args['types']);
$test_list = [];
$slow_tests = [];
if ($args['all'] || $args['module'] || $args['directory']) {
try {
$groups = $test_discovery->getTestClasses($args['module'], $args['types'], $args['directory']);
- foreach ($test_discovery->getWarnings() as $warning) {
- simpletest_script_print($warning . "\n", SIMPLETEST_SCRIPT_COLOR_EXCEPTION);
- }
+ $types_processed = TRUE;
}
catch (Exception $e) {
echo (string) $e;
@@ -951,34 +938,30 @@ function simpletest_script_get_test_list() {
// Ensure that tests marked explicitly as @group #slow are run at the
// beginning of each job.
if (key($groups) === '#slow') {
- $slow_tests = array_shift($groups);
+ $slow_tests = array_keys(array_shift($groups));
}
$not_slow_tests = [];
foreach ($groups as $group => $tests) {
- $not_slow_tests = array_merge($not_slow_tests, $tests);
+ $not_slow_tests = array_merge($not_slow_tests, array_keys($tests));
}
// Filter slow tests out of the not slow tests and ensure a unique list
// since tests may appear in more than one group.
- $not_slow_tests = array_diff_key($not_slow_tests, $slow_tests);
+ $not_slow_tests = array_unique(array_diff($not_slow_tests, $slow_tests));
// If the tests are not being run in parallel, then ensure slow tests run
// all together first.
if ((int) $args['ci-parallel-node-total'] <= 1 ) {
sort_tests_by_type_and_methods($slow_tests);
sort_tests_by_type_and_methods($not_slow_tests);
- $all_tests_list = array_merge($slow_tests, $not_slow_tests);
- assign_tests_sequence($all_tests_list);
- dump_tests_sequence($all_tests_list, $args);
- $test_list = array_keys($all_tests_list);
+ $test_list = array_merge($slow_tests, $not_slow_tests);
}
else {
- // Sort all tests by the number of test cases on the test class.
- // This is used in combination with @group #slow to start the slowest
- // tests first and distribute tests between test runners.
+ // Sort all tests by the number of public methods on the test class.
+ // This is a proxy for the approximate time taken to run the test,
+ // which is used in combination with @group #slow to start the slowest tests
+ // first and distribute tests between test runners.
sort_tests_by_public_method_count($slow_tests);
sort_tests_by_public_method_count($not_slow_tests);
- $all_tests_list = array_merge($slow_tests, $not_slow_tests);
- assign_tests_sequence($all_tests_list);
// Now set up a bin per test runner.
$bin_count = (int) $args['ci-parallel-node-total'];
@@ -992,8 +975,6 @@ function simpletest_script_get_test_list() {
$binned_other_tests = place_tests_into_bins($not_slow_tests, $bin_count);
$other_tests_for_job = $binned_other_tests[$args['ci-parallel-node-index'] - 1];
$test_list = array_merge($slow_tests_for_job, $other_tests_for_job);
- dump_bin_tests_sequence($args['ci-parallel-node-index'], $all_tests_list, $test_list, $args);
- $test_list = array_keys($test_list);
}
}
else {
@@ -1007,9 +988,6 @@ function simpletest_script_get_test_list() {
else {
try {
$groups = $test_discovery->getTestClasses(NULL, $args['types']);
- foreach ($test_discovery->getWarnings() as $warning) {
- simpletest_script_print($warning . "\n", SIMPLETEST_SCRIPT_COLOR_EXCEPTION);
- }
}
catch (Exception $e) {
echo (string) $e;
@@ -1027,24 +1005,19 @@ function simpletest_script_get_test_list() {
}
elseif ($args['file']) {
// Extract test case class names from specified files.
+ $parser = new TestFileParser();
foreach ($args['test_names'] as $file) {
- if (!file_exists($file) || is_dir($file)) {
+ if (!file_exists($file)) {
simpletest_script_print_error('File not found: ' . $file);
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
}
- $fileTests = current($test_discovery->getTestClasses(NULL, [], $file));
- $test_list = array_merge($test_list, $fileTests);
+ $test_list = array_merge($test_list, $parser->getTestListFromFile($file));
}
- assign_tests_sequence($test_list);
- dump_tests_sequence($test_list, $args);
- $test_list = array_keys($test_list);
}
else {
try {
$groups = $test_discovery->getTestClasses(NULL, $args['types']);
- foreach ($test_discovery->getWarnings() as $warning) {
- simpletest_script_print($warning . "\n", SIMPLETEST_SCRIPT_COLOR_EXCEPTION);
- }
+ $types_processed = TRUE;
}
catch (Exception $e) {
echo (string) $e;
@@ -1061,15 +1034,22 @@ function simpletest_script_get_test_list() {
}
// Merge the tests from the groups together.
foreach ($args['test_names'] as $group_name) {
- $test_list = array_merge($test_list, $groups[$group_name]);
+ $test_list = array_merge($test_list, array_keys($groups[$group_name]));
}
- assign_tests_sequence($test_list);
- dump_tests_sequence($test_list, $args);
// Ensure our list of tests contains only one entry for each test.
- $test_list = array_keys($test_list);
+ $test_list = array_unique($test_list);
}
}
+ // If the test list creation does not automatically limit by test type then
+ // we need to do so here.
+ if (!$types_processed) {
+ $test_list = array_filter($test_list, function ($test_class) use ($args) {
+ $test_info = TestDiscovery::getTestInfo($test_class);
+ return in_array($test_info['type'], $args['types'], TRUE);
+ });
+ }
+
if (empty($test_list)) {
simpletest_script_print_error('No valid tests were specified.');
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
@@ -1082,11 +1062,11 @@ function simpletest_script_get_test_list() {
* Sort tests by test type and number of public methods.
*/
function sort_tests_by_type_and_methods(array &$tests): void {
- uasort($tests, function ($a, $b) {
- if (get_test_type_weight($a['name']) === get_test_type_weight($b['name'])) {
- return $b['tests_count'] <=> $a['tests_count'];
+ usort($tests, function ($a, $b) {
+ if (get_test_type_weight($a) === get_test_type_weight($b)) {
+ return get_test_class_method_count($b) <=> get_test_class_method_count($a);
}
- return get_test_type_weight($b['name']) <=> get_test_type_weight($a['name']);
+ return get_test_type_weight($b) <=> get_test_type_weight($a);
});
}
@@ -1103,8 +1083,8 @@ function sort_tests_by_type_and_methods(array &$tests): void {
* An array of test class names.
*/
function sort_tests_by_public_method_count(array &$tests): void {
- uasort($tests, function ($a, $b) {
- return $b['tests_count'] <=> $a['tests_count'];
+ usort($tests, function ($a, $b) {
+ return get_test_class_method_count($b) <=> get_test_class_method_count($a);
});
}
@@ -1125,46 +1105,28 @@ function get_test_type_weight(string $class): int {
}
/**
- * Assigns the test sequence.
+ * Get an approximate test method count for a test class.
*
- * @param array $tests
- * The array of test class info.
- */
-function assign_tests_sequence(array &$tests): void {
- $i = 0;
- foreach ($tests as &$testInfo) {
- $testInfo['sequence'] = ++$i;
- }
-}
-
-/**
- * Dumps the list of tests in order of execution after sorting.
- *
- * @param array $tests
- * The array of test class info.
- * @param array $args
- * The command line arguments.
+ * @param string $class
+ * The test class name.
*/
-function dump_tests_sequence(array $tests, array $args): void {
- if ($args['debug-discovery'] === FALSE) {
- return;
- }
- echo "Test execution sequence\n";
- echo "-----------------------\n\n";
- echo " Seq Slow? Group Cnt Class\n";
- echo "-----------------------------------------\n";
- $i = 0;
- foreach ($tests as $testInfo) {
- echo sprintf(
- "%4d %5s %15s %4d %s\n",
- $testInfo['sequence'],
- in_array('#slow', $testInfo['groups']) ? '#slow' : '',
- trim_with_ellipsis($testInfo['group'], 15, \STR_PAD_RIGHT),
- $testInfo['tests_count'],
- trim_with_ellipsis($testInfo['name'], 60, \STR_PAD_LEFT),
- );
+function get_test_class_method_count(string $class): int {
+ $reflection = new \ReflectionClass($class);
+ $count = 0;
+ foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
+ // If a method uses a dataProvider, increase the count by 20 since data
+ // providers result in a single method running multiple times.
+ $comments = $method->getDocComment();
+ preg_match_all('#@(.*?)\n#s', $comments, $annotations);
+ foreach ($annotations[1] as $annotation) {
+ if (str_starts_with($annotation, 'dataProvider')) {
+ $count = $count + 20;
+ continue;
+ }
+ }
+ $count++;
}
- echo "-----------------------------------------\n\n";
+ return $count;
}
/**
@@ -1187,51 +1149,13 @@ function place_tests_into_bins(array $tests, int $bin_count) {
// Create a bin corresponding to each parallel test job.
$bins = array_fill(0, $bin_count, []);
// Go through each test and add them to one bin at a time.
- $i = 0;
foreach ($tests as $key => $test) {
- $bins[($i++ % $bin_count)][$key] = $test;
+ $bins[($key % $bin_count)][] = $test;
}
return $bins;
}
/**
- * Dumps the list of tests in order of execution for a bin.
- *
- * @param int $bin
- * The bin.
- * @param array $allTests
- * The list of all test classes discovered.
- * @param array $tests
- * The list of test class to run for this bin.
- * @param array $args
- * The command line arguments.
- */
-function dump_bin_tests_sequence(int $bin, array $allTests, array $tests, array $args): void {
- if ($args['debug-discovery'] === FALSE) {
- return;
- }
- echo "Test execution sequence. ";
- echo "Tests marked *** will be executed in this PARALLEL BIN #{$bin}.\n";
- echo "-------------------------------------------------------------------------------------\n\n";
- echo "Bin Seq Slow? Group Cnt Class\n";
- echo "--------------------------------------------\n";
- foreach ($allTests as $testInfo) {
- $inBin = isset($tests[$testInfo['name']]);
- $message = sprintf(
- "%s %4d %5s %15s %4d %s\n",
- $inBin ? "***" : " ",
- $testInfo['sequence'],
- in_array('#slow', $testInfo['groups']) ? '#slow' : '',
- trim_with_ellipsis($testInfo['group'], 15, \STR_PAD_RIGHT),
- $testInfo['tests_count'],
- trim_with_ellipsis($testInfo['name'], 60, \STR_PAD_LEFT),
- );
- simpletest_script_print($message, $inBin ? SIMPLETEST_SCRIPT_COLOR_BRIGHT_WHITE : SIMPLETEST_SCRIPT_COLOR_GRAY);
- }
- echo "-------------------------------------------------\n\n";
-}
-
-/**
* Initialize the reporter.
*/
function simpletest_script_reporter_init(): void {
@@ -1246,6 +1170,12 @@ function simpletest_script_reporter_init(): void {
'debug' => 'Log',
];
+ echo "\n";
+ echo "Drupal test run\n";
+ echo "Using PHP Binary: $php\n";
+ echo "---------------\n";
+ echo "\n";
+
// Tell the user about what tests are to be run.
if ($args['all']) {
echo "All tests will run.\n\n";
@@ -1448,7 +1378,7 @@ function simpletest_script_reporter_display_results(TestRunResultsStorageInterfa
function simpletest_script_format_result($result): void {
global $args, $results_map, $color;
- $summary = sprintf("%-9.9s %9.3fs %s\n", $results_map[$result->status], $result->time, trim_with_ellipsis($result->function, 80, STR_PAD_LEFT));
+ $summary = sprintf("%-9.9s %9.3fs %-80.80s\n", $results_map[$result->status], $result->time, trim_with_ellipsis($result->function, 80, STR_PAD_LEFT));
simpletest_script_print($summary, simpletest_script_color_code($result->status));
@@ -1610,12 +1540,12 @@ function simpletest_script_load_messages_by_test_id(TestRunResultsStorageInterfa
*/
function trim_with_ellipsis(string $input, int $length, int $side): string {
if (strlen($input) < $length) {
- return str_pad($input, $length, ' ', \STR_PAD_RIGHT);
+ return str_pad($input, $length, ' ', STR_PAD_RIGHT);
}
elseif (strlen($input) > $length) {
return match($side) {
- \STR_PAD_RIGHT => substr($input, 0, $length - 1) . '…',
- default => '…' . substr($input, -$length + 1),
+ STR_PAD_RIGHT => substr($input, 0, $length - 3) . '...',
+ default => '...' . substr($input, -$length + 3),
};
}
return $input;
diff --git a/core/tests/Drupal/KernelTests/Core/Test/PhpUnitApiFindAllClassFilesTest.php b/core/tests/Drupal/KernelTests/Core/Test/PhpUnitApiFindAllClassFilesTest.php
deleted file mode 100644
index feb6addef2a..00000000000
--- a/core/tests/Drupal/KernelTests/Core/Test/PhpUnitApiFindAllClassFilesTest.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\KernelTests\Core\Test;
-
-use Drupal\Core\Test\PhpUnitTestDiscovery;
-use Drupal\Core\Test\TestDiscovery;
-use Drupal\KernelTests\KernelTestBase;
-use Drupal\TestTools\PhpUnitCompatibility\RunnerVersion;
-use PHPUnit\Framework\Attributes\CoversClass;
-use PHPUnit\Framework\Attributes\DataProvider;
-use PHPUnit\Framework\Attributes\Group;
-use PHPUnit\Framework\Attributes\IgnoreDeprecations;
-
-/**
- * Tests ::findAllClassFiles() between TestDiscovery and PhpUnitTestDiscovery.
- *
- * PhpUnitTestDiscovery uses PHPUnit API to build the list of test classes,
- * while TestDiscovery uses Drupal legacy code.
- */
-#[CoversClass(PhpUnitTestDiscovery::class)]
-#[Group('TestSuites')]
-#[Group('Test')]
-#[Group('#slow')]
-class PhpUnitApiFindAllClassFilesTest extends KernelTestBase {
-
- /**
- * Checks that Drupal legacy and PHPUnit API based discoveries are equal.
- */
- #[DataProvider('argumentsProvider')]
- #[IgnoreDeprecations]
- public function testEquality(?string $extension = NULL, ?string $directory = NULL): void {
- $testDiscovery = new TestDiscovery(
- $this->container->getParameter('app.root'),
- $this->container->get('class_loader')
- );
- $internalList = $testDiscovery->findAllClassFiles($extension, $directory);
-
- // Location of PHPUnit configuration file.
- $configurationFilePath = $this->container->getParameter('app.root') . \DIRECTORY_SEPARATOR . 'core';
- // @todo once PHPUnit 10 is no longer used, remove the condition.
- // @see https://www.drupal.org/project/drupal/issues/3497116
- if (RunnerVersion::getMajor() >= 11) {
- $configurationFilePath .= \DIRECTORY_SEPARATOR . '.phpunit-next.xml';
- }
-
- $phpUnitTestDiscovery = new PhpUnitTestDiscovery($configurationFilePath);
-
- $phpUnitList = $phpUnitTestDiscovery->findAllClassFiles($extension, $directory);
-
- // Downgrade results to make them comparable, working around bugs and
- // additions.
- // 1. TestDiscovery discovers non-test classes that PHPUnit does not.
- $internalList = array_intersect_key($internalList, $phpUnitList);
-
- $this->assertEquals($internalList, $phpUnitList);
- }
-
- /**
- * Provides test data to ::testEquality.
- */
- public static function argumentsProvider(): \Generator {
- yield 'All tests' => [];
- yield 'Extension: system' => ['extension' => 'system'];
- yield 'Extension: system, directory' => [
- 'extension' => 'system',
- 'directory' => 'core/modules/system/tests/src',
- ];
- }
-
-}
diff --git a/core/tests/Drupal/KernelTests/Core/Test/PhpUnitApiGetTestClassesTest.php b/core/tests/Drupal/KernelTests/Core/Test/PhpUnitApiGetTestClassesTest.php
deleted file mode 100644
index 32d21e3e6c3..00000000000
--- a/core/tests/Drupal/KernelTests/Core/Test/PhpUnitApiGetTestClassesTest.php
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\KernelTests\Core\Test;
-
-use Drupal\Core\Test\PhpUnitTestDiscovery;
-use Drupal\Core\Test\TestDiscovery;
-use Drupal\KernelTests\KernelTestBase;
-use Drupal\TestTools\PhpUnitCompatibility\RunnerVersion;
-use PHPUnit\Framework\Attributes\CoversClass;
-use PHPUnit\Framework\Attributes\DataProvider;
-use PHPUnit\Framework\Attributes\Group;
-use PHPUnit\Framework\Attributes\IgnoreDeprecations;
-
-/**
- * Tests ::getTestClasses() between TestDiscovery and PhpPUnitTestDiscovery.
- *
- * PhpPUnitTestDiscovery uses PHPUnit API to build the list of test classes,
- * while TestDiscovery uses Drupal legacy code.
- */
-#[CoversClass(PhpUnitTestDiscovery::class)]
-#[Group('TestSuites')]
-#[Group('Test')]
-#[Group('#slow')]
-class PhpUnitApiGetTestClassesTest extends KernelTestBase {
-
- /**
- * Checks that Drupal legacy and PHPUnit API based discoveries are equal.
- */
- #[DataProvider('argumentsProvider')]
- #[IgnoreDeprecations]
- public function testEquality(array $suites, ?string $extension = NULL, ?string $directory = NULL): void {
- $testDiscovery = new TestDiscovery(
- $this->container->getParameter('app.root'),
- $this->container->get('class_loader')
- );
- $internalList = $testDiscovery->getTestClasses($extension, $suites, $directory);
-
- // Location of PHPUnit configuration file.
- $configurationFilePath = $this->container->getParameter('app.root') . \DIRECTORY_SEPARATOR . 'core';
- // @todo once PHPUnit 10 is no longer used, remove the condition.
- // @see https://www.drupal.org/project/drupal/issues/3497116
- if (RunnerVersion::getMajor() >= 11) {
- $configurationFilePath .= \DIRECTORY_SEPARATOR . '.phpunit-next.xml';
- }
-
- $phpUnitTestDiscovery = new PhpUnitTestDiscovery($configurationFilePath);
-
- $phpUnitList = $phpUnitTestDiscovery->getTestClasses($extension, $suites, $directory);
-
- // Downgrade results to make them comparable, working around bugs and
- // additions.
- // 1. Remove TestDiscovery empty groups.
- $internalList = array_filter($internalList);
- // 2. Remove TestDiscovery '##no-group-annotations' group.
- unset($internalList['##no-group-annotations']);
- // 3. Remove 'file' and 'tests_count' keys from PHPUnit results.
- foreach ($phpUnitList as &$group) {
- foreach ($group as &$testClass) {
- unset($testClass['file']);
- unset($testClass['tests_count']);
- }
- }
- // 4. Remove from PHPUnit results groups not found by TestDiscovery.
- $phpUnitList = array_intersect_key($phpUnitList, $internalList);
- // 5. Remove from PHPUnit groups classes not found by TestDiscovery.
- foreach ($phpUnitList as $groupName => &$group) {
- $group = array_intersect_key($group, $internalList[$groupName]);
- }
- // 6. Remove from PHPUnit test classes groups not found by TestDiscovery.
- foreach ($phpUnitList as $groupName => &$group) {
- foreach ($group as $testClassName => &$testClass) {
- $testClass['groups'] = array_intersect_key($testClass['groups'], $internalList[$groupName][$testClassName]['groups']);
- }
- }
-
- $this->assertEquals($internalList, $phpUnitList);
- }
-
- /**
- * Provides test data to ::testEquality.
- */
- public static function argumentsProvider(): \Generator {
- yield 'All tests' => ['suites' => []];
- yield 'Testsuite: functional-javascript' => ['suites' => ['PHPUnit-FunctionalJavascript']];
- yield 'Testsuite: functional' => ['suites' => ['PHPUnit-Functional']];
- yield 'Testsuite: kernel' => ['suites' => ['PHPUnit-Kernel']];
- yield 'Testsuite: unit' => ['suites' => ['PHPUnit-Unit']];
- yield 'Testsuite: unit-component' => ['suites' => ['PHPUnit-Unit-Component']];
- yield 'Testsuite: build' => ['suites' => ['PHPUnit-Build']];
- yield 'Extension: system' => ['suites' => [], 'extension' => 'system'];
- yield 'Extension: system, testsuite: unit' => [
- 'suites' => ['PHPUnit-Unit'],
- 'extension' => 'system',
- ];
- yield 'Extension: system, directory' => [
- 'suites' => [],
- 'extension' => 'system',
- 'directory' => 'core/modules/system/tests/src',
- ];
- yield 'Extension: system, testsuite: unit, directory' => [
- 'suites' => ['PHPUnit-Unit'],
- 'extension' => 'system',
- 'directory' => 'core/modules/system/tests/src',
- ];
- }
-
-}
diff --git a/core/tests/Drupal/KernelTests/Core/Test/PhpUnitTestDiscoveryTest.php b/core/tests/Drupal/KernelTests/Core/Test/PhpUnitTestDiscoveryTest.php
index d8534458049..705981f7507 100644
--- a/core/tests/Drupal/KernelTests/Core/Test/PhpUnitTestDiscoveryTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Test/PhpUnitTestDiscoveryTest.php
@@ -7,8 +7,6 @@ namespace Drupal\KernelTests\Core\Test;
use Drupal\Core\Test\TestDiscovery;
use Drupal\KernelTests\KernelTestBase;
use Drupal\TestTools\PhpUnitCompatibility\RunnerVersion;
-use PHPUnit\Framework\Attributes\Group;
-use PHPUnit\Framework\Attributes\IgnoreDeprecations;
use PHPUnit\TextUI\Configuration\Builder;
use PHPUnit\TextUI\Configuration\TestSuiteBuilder;
use Symfony\Component\Process\Process;
@@ -24,10 +22,11 @@ use Symfony\Component\Process\Process;
* list thus generated, with the list generated by
* \Drupal\Core\Test\TestDiscovery, which is used by run-tests.sh, to ensure
* both methods will run the same tests,
+ *
+ * @group TestSuites
+ * @group Test
+ * @group #slow
*/
-#[Group('TestSuites')]
-#[Group('Test')]
-#[Group('#slow')]
class PhpUnitTestDiscoveryTest extends KernelTestBase {
private const TEST_LIST_MISMATCH_MESSAGE =
@@ -62,7 +61,6 @@ class PhpUnitTestDiscoveryTest extends KernelTestBase {
/**
* Tests equality of test discovery between run-tests.sh and PHPUnit CLI.
*/
- #[IgnoreDeprecations]
public function testPhpUnitTestDiscoveryEqualsInternal(): void {
// Drupal's test discovery, used by run-tests.sh.
$testDiscovery = new TestDiscovery(
@@ -78,19 +76,11 @@ class PhpUnitTestDiscoveryTest extends KernelTestBase {
$internalList = array_unique($internalList);
asort($internalList);
- // Location of PHPUnit configuration file.
- $configurationFilePath = $this->root . \DIRECTORY_SEPARATOR . 'core';
- // @todo once PHPUnit 10 is no longer used, remove the condition.
- // @see https://www.drupal.org/project/drupal/issues/3497116
- if (RunnerVersion::getMajor() >= 11) {
- $configurationFilePath .= \DIRECTORY_SEPARATOR . '.phpunit-next.xml';
- }
-
// PHPUnit's test discovery - via CLI execution.
$process = new Process([
'vendor/bin/phpunit',
'--configuration',
- $configurationFilePath,
+ 'core',
'--list-tests-xml',
$this->xmlOutputFile,
], $this->root);
@@ -123,8 +113,14 @@ class PhpUnitTestDiscoveryTest extends KernelTestBase {
// Check against Drupal's discovery.
$this->assertEquals(implode("\n", $phpUnitClientList), implode("\n", $internalList), self::TEST_LIST_MISMATCH_MESSAGE);
+ // @todo once PHPUnit 10 is no longer used re-enable the rest of the test.
+ // @see https://www.drupal.org/project/drupal/issues/3497116
+ if (RunnerVersion::getMajor() >= 11) {
+ $this->markTestIncomplete('On PHPUnit 11+ the test triggers warnings due to phpunit.xml setup. Re-enable in https://www.drupal.org/project/drupal/issues/3497116.');
+ }
+
// PHPUnit's test discovery - via API.
- $phpUnitConfiguration = (new Builder())->build(['--configuration', $configurationFilePath]);
+ $phpUnitConfiguration = (new Builder())->build(['--configuration', 'core']);
$phpUnitTestSuite = (new TestSuiteBuilder())->build($phpUnitConfiguration);
$phpUnitApiList = [];
foreach ($phpUnitTestSuite->tests() as $testSuite) {
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php
index d0759a4bf08..08fa2eceaf5 100644
--- a/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php
@@ -203,8 +203,6 @@ class LocalActionManagerTest extends UnitTestCase {
}
public static function getActionsForRouteProvider() {
- $originalContainer = \Drupal::hasContainer() ? \Drupal::getContainer() : NULL;
-
$cache_contexts_manager = (new Prophet())->prophesize(CacheContextsManager::class);
$cache_contexts_manager->assertValidTokens(Argument::any())
->willReturn(TRUE);
@@ -386,11 +384,6 @@ class LocalActionManagerTest extends UnitTestCase {
],
];
- // Restore the original container if needed.
- if ($originalContainer) {
- \Drupal::setContainer($originalContainer);
- }
-
return $data;
}
diff --git a/core/tests/Drupal/Tests/Core/Test/RunTests/TestFileParserTest.php b/core/tests/Drupal/Tests/Core/Test/RunTests/TestFileParserTest.php
index 9138d54523d..957b2f61f97 100644
--- a/core/tests/Drupal/Tests/Core/Test/RunTests/TestFileParserTest.php
+++ b/core/tests/Drupal/Tests/Core/Test/RunTests/TestFileParserTest.php
@@ -6,18 +6,12 @@ namespace Drupal\Tests\Core\Test\RunTests;
use Drupal\Core\Test\RunTests\TestFileParser;
use Drupal\Tests\UnitTestCase;
-use PHPUnit\Framework\Attributes\CoversClass;
-use PHPUnit\Framework\Attributes\DataProvider;
-use PHPUnit\Framework\Attributes\Group;
-use PHPUnit\Framework\Attributes\IgnoreDeprecations;
/**
- * Tests for the deprecated TestFileParser class.
+ * @coversDefaultClass \Drupal\Core\Test\RunTests\TestFileParser
+ * @group Test
+ * @group RunTests
*/
-#[CoversClass(TestFileParser::class)]
-#[Group('Test')]
-#[Group('RunTest')]
-#[IgnoreDeprecations]
class TestFileParserTest extends UnitTestCase {
public static function provideTestFileContents() {
@@ -72,9 +66,9 @@ COMPOUND
}
/**
- * @legacy-covers ::parseContents
+ * @covers ::parseContents
+ * @dataProvider provideTestFileContents
*/
- #[DataProvider('provideTestFileContents')]
public function testParseContents($expected, $contents): void {
$parser = new TestFileParser();
@@ -84,7 +78,7 @@ COMPOUND
}
/**
- * @legacy-covers ::getTestListFromFile
+ * @covers ::getTestListFromFile
*/
public function testGetTestListFromFile(): void {
$parser = new TestFileParser();
diff --git a/core/tests/Drupal/Tests/Core/Test/TestDiscoveryTest.php b/core/tests/Drupal/Tests/Core/Test/TestDiscoveryTest.php
index 0fb55e6c7f8..bfbb4ca2e40 100644
--- a/core/tests/Drupal/Tests/Core/Test/TestDiscoveryTest.php
+++ b/core/tests/Drupal/Tests/Core/Test/TestDiscoveryTest.php
@@ -13,23 +13,17 @@ use Drupal\Core\Test\Exception\MissingGroupException;
use Drupal\Core\Test\TestDiscovery;
use Drupal\Tests\UnitTestCase;
use org\bovigo\vfs\vfsStream;
-use PHPUnit\Framework\Attributes\CoversClass;
-use PHPUnit\Framework\Attributes\DataProvider;
-use PHPUnit\Framework\Attributes\Group;
-use PHPUnit\Framework\Attributes\IgnoreDeprecations;
/**
- * Unit tests for TestDiscovery.
+ * @coversDefaultClass \Drupal\Core\Test\TestDiscovery
+ * @group Test
*/
-#[CoversClass(TestDiscovery::class)]
-#[Group('Test')]
-#[IgnoreDeprecations]
class TestDiscoveryTest extends UnitTestCase {
/**
- * @legacy-covers ::getTestInfo
+ * @covers ::getTestInfo
+ * @dataProvider infoParserProvider
*/
- #[DataProvider('infoParserProvider')]
public function testTestInfoParser($expected, $classname, $doc_comment = NULL): void {
$info = TestDiscovery::getTestInfo($classname, $doc_comment);
$this->assertEquals($expected, $info);
@@ -40,14 +34,14 @@ class TestDiscoveryTest extends UnitTestCase {
$tests[] = [
// Expected result.
[
- 'name' => TestDatabaseTest::class,
+ 'name' => static::class,
'group' => 'Test',
- 'groups' => ['Test', 'simpletest', 'Template'],
- 'description' => 'Tests \Drupal\Core\Test\TestDatabase.',
+ 'groups' => ['Test'],
+ 'description' => 'Tests \Drupal\Core\Test\TestDiscovery.',
'type' => 'PHPUnit-Unit',
],
// Classname.
- TestDatabaseTest::class,
+ static::class,
];
// A core unit test.
@@ -223,7 +217,7 @@ class TestDiscoveryTest extends UnitTestCase {
}
/**
- * @legacy-covers ::getTestInfo
+ * @covers ::getTestInfo
*/
public function testTestInfoParserMissingGroup(): void {
$classname = 'Drupal\KernelTests\field\BulkDeleteTest';
@@ -238,7 +232,7 @@ EOT;
}
/**
- * @legacy-covers ::getTestInfo
+ * @covers ::getTestInfo
*/
public function testTestInfoParserMissingSummary(): void {
$classname = 'Drupal\KernelTests\field\BulkDeleteTest';
@@ -317,7 +311,7 @@ EOF;
}
/**
- * @legacy-covers ::getTestClasses
+ * @covers ::getTestClasses
*/
public function testGetTestClasses(): void {
$this->setupVfsWithTestClasses();
@@ -386,7 +380,7 @@ EOF;
}
/**
- * @legacy-covers ::getTestClasses
+ * @covers ::getTestClasses
*/
public function testGetTestClassesWithSelectedTypes(): void {
$this->setupVfsWithTestClasses();
@@ -431,7 +425,7 @@ EOF;
}
/**
- * @legacy-covers ::getTestClasses
+ * @covers ::getTestClasses
*/
public function testGetTestsInProfiles(): void {
$this->setupVfsWithTestClasses();
@@ -460,9 +454,9 @@ EOF;
}
/**
- * @legacy-covers ::getPhpunitTestSuite
+ * @covers ::getPhpunitTestSuite
+ * @dataProvider providerTestGetPhpunitTestSuite
*/
- #[DataProvider('providerTestGetPhpunitTestSuite')]
public function testGetPhpunitTestSuite($classname, $expected): void {
$this->assertEquals($expected, TestDiscovery::getPhpunitTestSuite($classname));
}
@@ -488,7 +482,7 @@ EOF;
/**
* Ensure that classes are not reflected when the docblock is empty.
*
- * @legacy-covers ::getTestInfo
+ * @covers ::getTestInfo
*/
public function testGetTestInfoEmptyDocblock(): void {
// If getTestInfo() performed reflection, it won't be able to find the
@@ -503,7 +497,7 @@ EOF;
/**
* Ensure TestDiscovery::scanDirectory() ignores certain abstract file types.
*
- * @legacy-covers ::scanDirectory
+ * @covers ::scanDirectory
*/
public function testScanDirectoryNoAbstract(): void {
$this->setupVfsWithTestClasses();