Skip to content
Snippets Groups Projects
Unverified Commit 2af907ca authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2296615 by Mile23, chr.fritsch, jibran, borisson_, dawehner, alexpott,...

Issue #2296615 by Mile23, chr.fritsch, jibran, borisson_, dawehner, alexpott, andypost: Accurately support multiple @groups per test class
parent 165ba7ec
No related branches found
No related tags found
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
namespace Drupal\simpletest; namespace Drupal\simpletest;
use Doctrine\Common\Annotations\SimpleAnnotationReader;
use Doctrine\Common\Reflection\StaticReflectionParser; use Doctrine\Common\Reflection\StaticReflectionParser;
use Drupal\Component\Annotation\Reflection\MockFileFinder; use Drupal\Component\Annotation\Reflection\MockFileFinder;
use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\NestedArray;
...@@ -137,13 +136,16 @@ public function registerTestNamespaces() { ...@@ -137,13 +136,16 @@ public function registerTestNamespaces() {
* An array of included test types. * An array of included test types.
* *
* @return array * @return array
* An array of tests keyed by the the group name. * An array of tests keyed by the the group name. If a test is annotated to
* belong to multiple groups, it will appear under all group keys it belongs
* to.
* @code * @code
* $groups['block'] => array( * $groups['block'] => array(
* 'Drupal\Tests\block\Functional\BlockTest' => array( * 'Drupal\Tests\block\Functional\BlockTest' => array(
* 'name' => 'Drupal\Tests\block\Functional\BlockTest', * 'name' => 'Drupal\Tests\block\Functional\BlockTest',
* 'description' => 'Tests block UI CRUD functionality.', * 'description' => 'Tests block UI CRUD functionality.',
* 'group' => 'block', * 'group' => 'block',
* 'groups' => ['block', 'group2', 'group3'],
* ), * ),
* ); * );
* @endcode * @endcode
...@@ -152,9 +154,6 @@ public function registerTestNamespaces() { ...@@ -152,9 +154,6 @@ public function registerTestNamespaces() {
* @see https://www.drupal.org/node/2296615 * @see https://www.drupal.org/node/2296615
*/ */
public function getTestClasses($extension = NULL, array $types = []) { public function getTestClasses($extension = NULL, array $types = []) {
$reader = new SimpleAnnotationReader();
$reader->addNamespace('Drupal\\simpletest\\Annotation');
if (!isset($extension) && empty($types)) { if (!isset($extension) && empty($types)) {
if (!empty($this->testClasses)) { if (!empty($this->testClasses)) {
return $this->testClasses; return $this->testClasses;
...@@ -199,7 +198,9 @@ public function getTestClasses($extension = NULL, array $types = []) { ...@@ -199,7 +198,9 @@ public function getTestClasses($extension = NULL, array $types = []) {
} }
} }
$list[$info['group']][$classname] = $info; foreach ($info['groups'] as $group) {
$list[$group][$classname] = $info;
}
} }
// Sort the groups and tests within the groups by name. // Sort the groups and tests within the groups by name.
...@@ -325,6 +326,8 @@ public static function scanDirectory($namespace_prefix, $path) { ...@@ -325,6 +326,8 @@ public static function scanDirectory($namespace_prefix, $path) {
* - name: The test class name. * - name: The test class name.
* - description: The test (PHPDoc) summary. * - description: The test (PHPDoc) summary.
* - group: The test's first @group (parsed from PHPDoc annotations). * - group: The test's first @group (parsed from PHPDoc annotations).
* - groups: All of the test's @group annotations, as an array (parsed from
* PHPDoc annotations).
* - requires: An associative array containing test requirements parsed from * - requires: An associative array containing test requirements parsed from
* PHPDoc annotations: * PHPDoc annotations:
* - module: List of Drupal module extension names the test depends on. * - module: List of Drupal module extension names the test depends on.
...@@ -346,9 +349,14 @@ public static function getTestInfo($classname, $doc_comment = NULL) { ...@@ -346,9 +349,14 @@ public static function getTestInfo($classname, $doc_comment = NULL) {
preg_match_all('/^[ ]*\* \@([^\s]*) (.*$)/m', $doc_comment, $matches); preg_match_all('/^[ ]*\* \@([^\s]*) (.*$)/m', $doc_comment, $matches);
if (isset($matches[1])) { if (isset($matches[1])) {
foreach ($matches[1] as $key => $annotation) { foreach ($matches[1] as $key => $annotation) {
// For historical reasons, there is a single-value 'group' result key
// and a 'groups' key as an array.
if ($annotation === 'group') {
$annotations['groups'][] = $matches[2][$key];
}
if (!empty($annotations[$annotation])) { if (!empty($annotations[$annotation])) {
// Only have the first match per annotation. This deals with // Only @group is allowed to have more than one annotation, in the
// multiple @group annotations. // 'groups' key. Other annotations only have one value per key.
continue; continue;
} }
$annotations[$annotation] = $matches[2][$key]; $annotations[$annotation] = $matches[2][$key];
...@@ -360,7 +368,9 @@ public static function getTestInfo($classname, $doc_comment = NULL) { ...@@ -360,7 +368,9 @@ public static function getTestInfo($classname, $doc_comment = NULL) {
throw new MissingGroupException(sprintf('Missing @group annotation in %s', $classname)); throw new MissingGroupException(sprintf('Missing @group annotation in %s', $classname));
} }
$info['group'] = $annotations['group']; $info['group'] = $annotations['group'];
// Put PHPUnit test suites into their own custom groups. $info['groups'] = $annotations['groups'];
// Sort out PHPUnit-runnable tests by type.
if ($testsuite = static::getPhpunitTestSuite($classname)) { if ($testsuite = static::getPhpunitTestSuite($classname)) {
$info['type'] = 'PHPUnit-' . $testsuite; $info['type'] = 'PHPUnit-' . $testsuite;
} }
......
...@@ -15,10 +15,6 @@ ...@@ -15,10 +15,6 @@
/** /**
* @coversDefaultClass \Drupal\simpletest\TestDiscovery * @coversDefaultClass \Drupal\simpletest\TestDiscovery
* @group simpletest * @group simpletest
*
* Since TestDiscovery is expected to discover Simpletest-based tests, it will
* likely trigger deprecation errors. Therefore, we add the legacy group.
* @group legacy
*/ */
class TestDiscoveryTest extends UnitTestCase { class TestDiscoveryTest extends UnitTestCase {
...@@ -36,13 +32,14 @@ public function infoParserProvider() { ...@@ -36,13 +32,14 @@ public function infoParserProvider() {
$tests[] = [ $tests[] = [
// Expected result. // Expected result.
[ [
'name' => 'Drupal\Tests\simpletest\Unit\TestDiscoveryTest', 'name' => static::class,
'group' => 'simpletest', 'group' => 'simpletest',
'groups' => ['simpletest'],
'description' => 'Tests \Drupal\simpletest\TestDiscovery.', 'description' => 'Tests \Drupal\simpletest\TestDiscovery.',
'type' => 'PHPUnit-Unit', 'type' => 'PHPUnit-Unit',
], ],
// Classname. // Classname.
'Drupal\Tests\simpletest\Unit\TestDiscoveryTest', static::class,
]; ];
// A core unit test. // A core unit test.
...@@ -51,6 +48,7 @@ public function infoParserProvider() { ...@@ -51,6 +48,7 @@ public function infoParserProvider() {
[ [
'name' => 'Drupal\Tests\Core\DrupalTest', 'name' => 'Drupal\Tests\Core\DrupalTest',
'group' => 'DrupalTest', 'group' => 'DrupalTest',
'groups' => ['DrupalTest'],
'description' => 'Tests \Drupal.', 'description' => 'Tests \Drupal.',
'type' => 'PHPUnit-Unit', 'type' => 'PHPUnit-Unit',
], ],
...@@ -64,6 +62,7 @@ public function infoParserProvider() { ...@@ -64,6 +62,7 @@ public function infoParserProvider() {
[ [
'name' => 'Drupal\FunctionalTests\BrowserTestBaseTest', 'name' => 'Drupal\FunctionalTests\BrowserTestBaseTest',
'group' => 'browsertestbase', 'group' => 'browsertestbase',
'groups' => ['browsertestbase'],
'description' => 'Tests BrowserTestBase functionality.', 'description' => 'Tests BrowserTestBase functionality.',
'type' => 'PHPUnit-Functional', 'type' => 'PHPUnit-Functional',
], ],
...@@ -77,6 +76,7 @@ public function infoParserProvider() { ...@@ -77,6 +76,7 @@ public function infoParserProvider() {
[ [
'name' => '\Drupal\Tests\file\Kernel\FileItemValidationTest', 'name' => '\Drupal\Tests\file\Kernel\FileItemValidationTest',
'group' => 'file', 'group' => 'file',
'groups' => ['file'],
'description' => 'Tests that files referenced in file and image fields are always validated.', 'description' => 'Tests that files referenced in file and image fields are always validated.',
'type' => 'PHPUnit-Kernel', 'type' => 'PHPUnit-Kernel',
], ],
...@@ -91,6 +91,7 @@ public function infoParserProvider() { ...@@ -91,6 +91,7 @@ public function infoParserProvider() {
[ [
'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest', 'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest',
'group' => 'simpletest', 'group' => 'simpletest',
'groups' => ['simpletest'],
'description' => 'Tests the Simpletest UI internal browser.', 'description' => 'Tests the Simpletest UI internal browser.',
'type' => 'Simpletest', 'type' => 'Simpletest',
], ],
...@@ -111,6 +112,7 @@ public function infoParserProvider() { ...@@ -111,6 +112,7 @@ public function infoParserProvider() {
[ [
'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest', 'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest',
'group' => 'simpletest', 'group' => 'simpletest',
'groups' => ['simpletest'],
'description' => 'Tests the Simpletest UI internal browser.', 'description' => 'Tests the Simpletest UI internal browser.',
'type' => 'Simpletest', 'type' => 'Simpletest',
], ],
...@@ -133,6 +135,7 @@ public function infoParserProvider() { ...@@ -133,6 +135,7 @@ public function infoParserProvider() {
[ [
'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest', 'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest',
'group' => 'simpletest', 'group' => 'simpletest',
'groups' => ['simpletest'],
'description' => 'Tests the Simpletest UI internal browser. * @', 'description' => 'Tests the Simpletest UI internal browser. * @',
'type' => 'Simpletest', 'type' => 'Simpletest',
], ],
...@@ -153,6 +156,7 @@ public function infoParserProvider() { ...@@ -153,6 +156,7 @@ public function infoParserProvider() {
[ [
'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest', 'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest',
'group' => 'Test', 'group' => 'Test',
'groups' => ['Test', 'simpletest'],
'description' => 'Tests the Simpletest UI internal browser.', 'description' => 'Tests the Simpletest UI internal browser.',
'type' => 'Simpletest', 'type' => 'Simpletest',
], ],
...@@ -168,6 +172,33 @@ public function infoParserProvider() { ...@@ -168,6 +172,33 @@ public function infoParserProvider() {
", ",
]; ];
// A great number of @group annotations.
$tests['many-group-annotations'] = [
// Expected result.
[
'name' => 'Drupal\simpletest\Tests\ExampleSimpleTest',
'group' => 'Test',
'groups' => ['Test', 'simpletest', 'another', 'more', 'many', 'enough', 'whoa'],
'description' => 'Tests the Simpletest UI internal browser.',
'type' => 'Simpletest',
],
// Classname.
'Drupal\simpletest\Tests\ExampleSimpleTest',
// Doc block.
"/**
* Tests the Simpletest UI internal browser.
*
* @group Test
* @group simpletest
* @group another
* @group more
* @group many
* @group enough
* @group whoa
*/
",
];
// @dependencies annotation. // @dependencies annotation.
$tests[] = [ $tests[] = [
// Expected result. // Expected result.
...@@ -177,6 +208,7 @@ public function infoParserProvider() { ...@@ -177,6 +208,7 @@ public function infoParserProvider() {
'type' => 'Simpletest', 'type' => 'Simpletest',
'requires' => ['module' => ['test']], 'requires' => ['module' => ['test']],
'group' => 'simpletest', 'group' => 'simpletest',
'groups' => ['simpletest'],
], ],
// Classname. // Classname.
'Drupal\simpletest\Tests\ExampleSimpleTest', 'Drupal\simpletest\Tests\ExampleSimpleTest',
...@@ -199,6 +231,7 @@ public function infoParserProvider() { ...@@ -199,6 +231,7 @@ public function infoParserProvider() {
'type' => 'Simpletest', 'type' => 'Simpletest',
'requires' => ['module' => ['test', 'test1', 'test2']], 'requires' => ['module' => ['test', 'test1', 'test2']],
'group' => 'simpletest', 'group' => 'simpletest',
'groups' => ['simpletest'],
], ],
// Classname. // Classname.
'Drupal\simpletest\Tests\ExampleSimpleTest', 'Drupal\simpletest\Tests\ExampleSimpleTest',
...@@ -220,6 +253,7 @@ public function infoParserProvider() { ...@@ -220,6 +253,7 @@ public function infoParserProvider() {
'description' => 'Tests the Simpletest UI internal browser. And the summary line continues an there is no gap to the annotation.', 'description' => 'Tests the Simpletest UI internal browser. And the summary line continues an there is no gap to the annotation.',
'type' => 'Simpletest', 'type' => 'Simpletest',
'group' => 'simpletest', 'group' => 'simpletest',
'groups' => ['simpletest'],
], ],
// Classname. // Classname.
'Drupal\simpletest\Tests\ExampleSimpleTest', 'Drupal\simpletest\Tests\ExampleSimpleTest',
...@@ -298,7 +332,7 @@ class FunctionalExampleTest {} ...@@ -298,7 +332,7 @@ class FunctionalExampleTest {}
'FunctionalExampleTest2.php' => str_replace(['FunctionalExampleTest', '@group example'], ['FunctionalExampleTest2', '@group example2'], $test_file), 'FunctionalExampleTest2.php' => str_replace(['FunctionalExampleTest', '@group example'], ['FunctionalExampleTest2', '@group example2'], $test_file),
], ],
'Kernel' => [ 'Kernel' => [
'KernelExampleTest3.php' => str_replace(['FunctionalExampleTest', '@group example'], ['KernelExampleTest3', '@group example2'], $test_file), 'KernelExampleTest3.php' => str_replace(['FunctionalExampleTest', '@group example'], ['KernelExampleTest3', "@group example2\n * @group kernel\n"], $test_file),
'KernelExampleTestBase.php' => str_replace(['FunctionalExampleTest', '@group example'], ['KernelExampleTestBase', '@group example2'], $test_file), 'KernelExampleTestBase.php' => str_replace(['FunctionalExampleTest', '@group example'], ['KernelExampleTestBase', '@group example2'], $test_file),
'KernelExampleTrait.php' => str_replace(['FunctionalExampleTest', '@group example'], ['KernelExampleTrait', '@group example2'], $test_file), 'KernelExampleTrait.php' => str_replace(['FunctionalExampleTest', '@group example'], ['KernelExampleTrait', '@group example2'], $test_file),
'KernelExampleInterface.php' => str_replace(['FunctionalExampleTest', '@group example'], ['KernelExampleInterface', '@group example2'], $test_file), 'KernelExampleInterface.php' => str_replace(['FunctionalExampleTest', '@group example'], ['KernelExampleInterface', '@group example2'], $test_file),
...@@ -342,13 +376,14 @@ public function testGetTestClasses() { ...@@ -342,13 +376,14 @@ public function testGetTestClasses() {
]; ];
$test_discovery->setExtensions($extensions); $test_discovery->setExtensions($extensions);
$result = $test_discovery->getTestClasses(); $result = $test_discovery->getTestClasses();
$this->assertCount(2, $result); $this->assertCount(3, $result);
$this->assertEquals([ $this->assertEquals([
'example' => [ 'example' => [
'Drupal\Tests\test_module\Functional\FunctionalExampleTest' => [ 'Drupal\Tests\test_module\Functional\FunctionalExampleTest' => [
'name' => 'Drupal\Tests\test_module\Functional\FunctionalExampleTest', 'name' => 'Drupal\Tests\test_module\Functional\FunctionalExampleTest',
'description' => 'Test description', 'description' => 'Test description',
'group' => 'example', 'group' => 'example',
'groups' => ['example'],
'type' => 'PHPUnit-Functional', 'type' => 'PHPUnit-Functional',
], ],
], ],
...@@ -357,12 +392,23 @@ public function testGetTestClasses() { ...@@ -357,12 +392,23 @@ public function testGetTestClasses() {
'name' => 'Drupal\Tests\test_module\Functional\FunctionalExampleTest2', 'name' => 'Drupal\Tests\test_module\Functional\FunctionalExampleTest2',
'description' => 'Test description', 'description' => 'Test description',
'group' => 'example2', 'group' => 'example2',
'groups' => ['example2'],
'type' => 'PHPUnit-Functional', 'type' => 'PHPUnit-Functional',
], ],
'Drupal\Tests\test_module\Kernel\KernelExampleTest3' => [ 'Drupal\Tests\test_module\Kernel\KernelExampleTest3' => [
'name' => 'Drupal\Tests\test_module\Kernel\KernelExampleTest3', 'name' => 'Drupal\Tests\test_module\Kernel\KernelExampleTest3',
'description' => 'Test description', 'description' => 'Test description',
'group' => 'example2', 'group' => 'example2',
'groups' => ['example2', 'kernel'],
'type' => 'PHPUnit-Kernel',
],
],
'kernel' => [
'Drupal\Tests\test_module\Kernel\KernelExampleTest3' => [
'name' => 'Drupal\Tests\test_module\Kernel\KernelExampleTest3',
'description' => 'Test description',
'group' => 'example2',
'groups' => ['example2', 'kernel'],
'type' => 'PHPUnit-Kernel', 'type' => 'PHPUnit-Kernel',
], ],
], ],
...@@ -385,7 +431,7 @@ public function testGetTestClassesWithSelectedTypes() { ...@@ -385,7 +431,7 @@ public function testGetTestClassesWithSelectedTypes() {
]; ];
$test_discovery->setExtensions($extensions); $test_discovery->setExtensions($extensions);
$result = $test_discovery->getTestClasses(NULL, ['PHPUnit-Kernel']); $result = $test_discovery->getTestClasses(NULL, ['PHPUnit-Kernel']);
$this->assertCount(3, $result); $this->assertCount(4, $result);
$this->assertEquals([ $this->assertEquals([
'example' => [], 'example' => [],
'example2' => [ 'example2' => [
...@@ -393,6 +439,16 @@ public function testGetTestClassesWithSelectedTypes() { ...@@ -393,6 +439,16 @@ public function testGetTestClassesWithSelectedTypes() {
'name' => 'Drupal\Tests\test_module\Kernel\KernelExampleTest3', 'name' => 'Drupal\Tests\test_module\Kernel\KernelExampleTest3',
'description' => 'Test description', 'description' => 'Test description',
'group' => 'example2', 'group' => 'example2',
'groups' => ['example2', 'kernel'],
'type' => 'PHPUnit-Kernel',
],
],
'kernel' => [
'Drupal\Tests\test_module\Kernel\KernelExampleTest3' => [
'name' => 'Drupal\Tests\test_module\Kernel\KernelExampleTest3',
'description' => 'Test description',
'group' => 'example2',
'groups' => ['example2', 'kernel'],
'type' => 'PHPUnit-Kernel', 'type' => 'PHPUnit-Kernel',
], ],
], ],
...@@ -401,6 +457,7 @@ public function testGetTestClassesWithSelectedTypes() { ...@@ -401,6 +457,7 @@ public function testGetTestClassesWithSelectedTypes() {
'name' => 'Drupal\Tests\test_profile_module\Kernel\KernelExampleTest4', 'name' => 'Drupal\Tests\test_profile_module\Kernel\KernelExampleTest4',
'description' => 'Test description', 'description' => 'Test description',
'group' => 'example3', 'group' => 'example3',
'groups' => ['example3'],
'type' => 'PHPUnit-Kernel', 'type' => 'PHPUnit-Kernel',
], ],
], ],
...@@ -429,6 +486,7 @@ public function testGetTestsInProfiles() { ...@@ -429,6 +486,7 @@ public function testGetTestsInProfiles() {
'name' => 'Drupal\Tests\test_profile_module\Kernel\KernelExampleTest4', 'name' => 'Drupal\Tests\test_profile_module\Kernel\KernelExampleTest4',
'description' => 'Test description', 'description' => 'Test description',
'group' => 'example3', 'group' => 'example3',
'groups' => ['example3'],
'type' => 'PHPUnit-Kernel', 'type' => 'PHPUnit-Kernel',
], ],
], ],
...@@ -512,15 +570,3 @@ protected function getExtensions() { ...@@ -512,15 +570,3 @@ protected function getExtensions() {
} }
} }
namespace Drupal\simpletest\Tests;
use Drupal\simpletest\WebTestBase;
/**
* Tests the Simpletest UI internal browser.
*
* @group simpletest
*/
class ExampleSimpleTest extends WebTestBase {
}
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
} }
if ($args['list']) { if ($args['list']) {
// Display all available tests. // Display all available tests organized by one @group annotation.
echo "\nAvailable test groups & classes\n"; echo "\nAvailable test groups & classes\n";
echo "-------------------------------\n\n"; echo "-------------------------------\n\n";
try { try {
...@@ -73,11 +73,18 @@ ...@@ -73,11 +73,18 @@
echo (string) $e; echo (string) $e;
exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION); exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
} }
// A given class can appear in multiple groups. For historical reasons, we
// need to present each test only once. The test is shown in the group that is
// printed first.
$printed_tests = [];
foreach ($groups as $group => $tests) { foreach ($groups as $group => $tests) {
echo $group . "\n"; echo $group . "\n";
foreach ($tests as $class => $info) { $tests = array_diff(array_keys($tests), $printed_tests);
echo " - $class\n"; foreach ($tests as $test) {
echo " - $test\n";
} }
$printed_tests = array_merge($printed_tests, $tests);
} }
exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS); exit(SIMPLETEST_SCRIPT_EXIT_SUCCESS);
} }
...@@ -1146,16 +1153,20 @@ function simpletest_script_get_test_list() { ...@@ -1146,16 +1153,20 @@ function simpletest_script_get_test_list() {
echo (string) $e; echo (string) $e;
exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION); exit(SIMPLETEST_SCRIPT_EXIT_EXCEPTION);
} }
// Store all the groups so we can suggest alternatives if we need to.
$all_groups = array_keys($groups);
// Verify that the groups exist.
if (!empty($unknown_groups = array_diff($args['test_names'], $all_groups))) {
$first_group = reset($unknown_groups);
simpletest_script_print_error('Test group not found: ' . $first_group);
simpletest_script_print_alternatives($first_group, $all_groups);
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
}
// Ensure our list of tests contains only one entry for each test.
foreach ($args['test_names'] as $group_name) { foreach ($args['test_names'] as $group_name) {
if (isset($groups[$group_name])) { $test_list = array_merge($test_list, array_flip(array_keys($groups[$group_name])));
$test_list = array_merge($test_list, array_keys($groups[$group_name]));
}
else {
simpletest_script_print_error('Test group not found: ' . $group_name);
simpletest_script_print_alternatives($group_name, array_keys($groups));
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
}
} }
$test_list = array_flip($test_list);
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment