Issue #2913819 by Mile23, Wim Leers: run-tests.sh ignores final classes
parent
5db19a052f
commit
73972cc6a1
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Core\Test\RunTests;
|
||||||
|
|
||||||
|
use Drupal\simpletest\TestBase;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses class names from PHP files without loading them.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class TestFileParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the classes from a PHP file.
|
||||||
|
*
|
||||||
|
* @param string $file
|
||||||
|
* The path to the file to parse.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
* Array of fully qualified class names within the PHP file.
|
||||||
|
*/
|
||||||
|
public function getTestListFromFile($file) {
|
||||||
|
$test_list = $this->parseContents(file_get_contents($file));
|
||||||
|
return array_filter($test_list, function ($class) {
|
||||||
|
return (is_subclass_of($class, TestCase::class) || is_subclass_of($class, TestBase::class));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse class names out of PHP file contents.
|
||||||
|
*
|
||||||
|
* @param string $contents
|
||||||
|
* The contents of a PHP file.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
* Array of fully qualified class names within the PHP file contents.
|
||||||
|
*/
|
||||||
|
protected function parseContents($contents) {
|
||||||
|
// Extract a potential namespace.
|
||||||
|
$namespace = FALSE;
|
||||||
|
if (preg_match('@^\s*namespace ([^ ;]+)@m', $contents, $matches)) {
|
||||||
|
$namespace = $matches[1];
|
||||||
|
}
|
||||||
|
$test_list = [];
|
||||||
|
// Extract all class names. Abstract classes are excluded on purpose.
|
||||||
|
preg_match_all('@^\s*(?!abstract\s+)(?:final\s+|\s*)class ([^ ]+)@m', $contents, $matches);
|
||||||
|
if (!$namespace) {
|
||||||
|
$test_list = $matches[1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foreach ($matches[1] as $class_name) {
|
||||||
|
$namespace_class = $namespace . '\\' . $class_name;
|
||||||
|
$test_list[] = $namespace_class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $test_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ use Drupal\Core\File\FileSystemInterface;
|
||||||
use Drupal\Core\StreamWrapper\PublicStream;
|
use Drupal\Core\StreamWrapper\PublicStream;
|
||||||
use Drupal\Core\Test\EnvironmentCleaner;
|
use Drupal\Core\Test\EnvironmentCleaner;
|
||||||
use Drupal\Core\Test\PhpUnitTestRunner;
|
use Drupal\Core\Test\PhpUnitTestRunner;
|
||||||
|
use Drupal\Core\Test\RunTests\TestFileParser;
|
||||||
use Drupal\Core\Test\TestDatabase;
|
use Drupal\Core\Test\TestDatabase;
|
||||||
use Drupal\Core\Test\TestRunnerKernel;
|
use Drupal\Core\Test\TestRunnerKernel;
|
||||||
use Drupal\simpletest\Form\SimpletestResultsForm;
|
use Drupal\simpletest\Form\SimpletestResultsForm;
|
||||||
|
@ -1054,31 +1055,13 @@ function simpletest_script_get_test_list() {
|
||||||
}
|
}
|
||||||
elseif ($args['file']) {
|
elseif ($args['file']) {
|
||||||
// Extract test case class names from specified files.
|
// Extract test case class names from specified files.
|
||||||
|
$parser = new TestFileParser();
|
||||||
foreach ($args['test_names'] as $file) {
|
foreach ($args['test_names'] as $file) {
|
||||||
if (!file_exists($file)) {
|
if (!file_exists($file)) {
|
||||||
simpletest_script_print_error('File not found: ' . $file);
|
simpletest_script_print_error('File not found: ' . $file);
|
||||||
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
|
exit(SIMPLETEST_SCRIPT_EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
$content = file_get_contents($file);
|
$test_list = array_merge($test_list, $parser->getTestListFromFile($file));
|
||||||
// Extract a potential namespace.
|
|
||||||
$namespace = FALSE;
|
|
||||||
if (preg_match('@^namespace ([^ ;]+)@m', $content, $matches)) {
|
|
||||||
$namespace = $matches[1];
|
|
||||||
}
|
|
||||||
// Extract all class names.
|
|
||||||
// Abstract classes are excluded on purpose.
|
|
||||||
preg_match_all('@^class ([^ ]+)@m', $content, $matches);
|
|
||||||
if (!$namespace) {
|
|
||||||
$test_list = array_merge($test_list, $matches[1]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
foreach ($matches[1] as $class_name) {
|
|
||||||
$namespace_class = $namespace . '\\' . $class_name;
|
|
||||||
if (is_subclass_of($namespace_class, '\Drupal\simpletest\TestBase') || is_subclass_of($namespace_class, TestCase::class)) {
|
|
||||||
$test_list[] = $namespace_class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif ($args['directory']) {
|
elseif ($args['directory']) {
|
||||||
|
@ -1112,27 +1095,9 @@ function simpletest_script_get_test_list() {
|
||||||
$files[$filename] = $filename;
|
$files[$filename] = $filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$parser = new TestFileParser();
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
$content = file_get_contents($file);
|
$test_list = array_merge($test_list, $parser->getTestListFromFile($file));
|
||||||
// Extract a potential namespace.
|
|
||||||
$namespace = FALSE;
|
|
||||||
if (preg_match('@^\s*namespace ([^ ;]+)@m', $content, $matches)) {
|
|
||||||
$namespace = $matches[1];
|
|
||||||
}
|
|
||||||
// Extract all class names.
|
|
||||||
// Abstract classes are excluded on purpose.
|
|
||||||
preg_match_all('@^\s*class ([^ ]+)@m', $content, $matches);
|
|
||||||
if (!$namespace) {
|
|
||||||
$test_list = array_merge($test_list, $matches[1]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
foreach ($matches[1] as $class_name) {
|
|
||||||
$namespace_class = $namespace . '\\' . $class_name;
|
|
||||||
if (is_subclass_of($namespace_class, '\Drupal\simpletest\TestBase') || is_subclass_of($namespace_class, TestCase::class)) {
|
|
||||||
$test_list[] = $namespace_class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Tests\Core\Test\RunTests;
|
||||||
|
|
||||||
|
use Drupal\Core\Test\RunTests\TestFileParser;
|
||||||
|
use Drupal\Tests\UnitTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @coversDefaultClass \Drupal\Core\Test\RunTests\TestFileParser
|
||||||
|
* @group Test
|
||||||
|
* @group RunTests
|
||||||
|
*/
|
||||||
|
class TestFileParserTest extends UnitTestCase {
|
||||||
|
|
||||||
|
public function provideTestFileContents() {
|
||||||
|
return [
|
||||||
|
'empty' => [[], ''],
|
||||||
|
'no-namespace' => [['ConcreteClass'],
|
||||||
|
<<< 'NO_NAMESPACE'
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class ConcreteClass {}
|
||||||
|
NO_NAMESPACE
|
||||||
|
],
|
||||||
|
'concrete' => [['Namespace\Is\Complex\ConcreteClass'],
|
||||||
|
<<< 'CONCRETE_CLASS'
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Namespace\Is\Complex;
|
||||||
|
|
||||||
|
class ConcreteClass {}
|
||||||
|
CONCRETE_CLASS
|
||||||
|
],
|
||||||
|
'abstract' => [[],
|
||||||
|
<<< 'ABSTRACT_CLASS'
|
||||||
|
<?php
|
||||||
|
namespace Namespace\Is\Complex;
|
||||||
|
|
||||||
|
abstract class AbstractClass {}
|
||||||
|
ABSTRACT_CLASS
|
||||||
|
],
|
||||||
|
'final' => [['Namespace\Is\Complex\FinalClass'],
|
||||||
|
<<< 'FINAL_CLASS'
|
||||||
|
<?php
|
||||||
|
namespace Namespace\Is\Complex;
|
||||||
|
|
||||||
|
final class FinalClass {}
|
||||||
|
FINAL_CLASS
|
||||||
|
],
|
||||||
|
'compound_declarations' => [[
|
||||||
|
'Namespace\Is\Complex\FinalClass',
|
||||||
|
'Namespace\Is\Complex\AnotherClass',
|
||||||
|
],
|
||||||
|
<<< 'COMPOUND'
|
||||||
|
<?php
|
||||||
|
namespace Namespace\Is\Complex;
|
||||||
|
|
||||||
|
final class FinalClass {}
|
||||||
|
|
||||||
|
class AnotherClass {}
|
||||||
|
COMPOUND
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::parseContents
|
||||||
|
* @dataProvider provideTestFileContents
|
||||||
|
*/
|
||||||
|
public function testParseContents($expected, $contents) {
|
||||||
|
$parser = new TestFileParser();
|
||||||
|
|
||||||
|
$ref_parse = new \ReflectionMethod($parser, 'parseContents');
|
||||||
|
$ref_parse->setAccessible(TRUE);
|
||||||
|
|
||||||
|
$this->assertSame($expected, $ref_parse->invoke($parser, $contents));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::getTestListFromFile
|
||||||
|
*/
|
||||||
|
public function testGetTestListFromFile() {
|
||||||
|
$parser = new TestFileParser();
|
||||||
|
$this->assertArrayEquals(
|
||||||
|
['Drupal\Tests\Core\Test\RunTests\TestFileParserTest'],
|
||||||
|
$parser->getTestListFromFile(__FILE__)
|
||||||
|
);
|
||||||
|
// This WebTestBase test will eventually move, so we'll need to update it.
|
||||||
|
$this->assertArrayEquals(
|
||||||
|
['Drupal\simpletest\Tests\TimeZoneTest'],
|
||||||
|
$parser->getTestListFromFile(__DIR__ . '/../../../../../../modules/simpletest/src/Tests/TimeZoneTest.php')
|
||||||
|
);
|
||||||
|
// Not a test.
|
||||||
|
$this->assertEmpty(
|
||||||
|
$parser->getTestListFromFile(__DIR__ . '/../../../AssertHelperTrait.php')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue