diff --git a/core/composer.json b/core/composer.json index 4955b07648..321588902f 100644 --- a/core/composer.json +++ b/core/composer.json @@ -60,7 +60,7 @@ "jcalderonzumba/gastonjs": "^1.0.2", "jcalderonzumba/mink-phantomjs-driver": "^0.3.1", "mikey179/vfsstream": "^1.2", - "phpunit/phpunit": "^6.5", + "phpunit/phpunit": "^6.5 || ^7", "phpspec/prophecy": "^1.7", "symfony/css-selector": "^3.4.0", "symfony/phpunit-bridge": "^3.4.3", diff --git a/core/drupalci.yml b/core/drupalci.yml index 2085b9737b..d58a195908 100644 --- a/core/drupalci.yml +++ b/core/drupalci.yml @@ -15,6 +15,10 @@ build: sniff-all-files: false halt-on-fail: false testing: + # Update PHPUnit & friends. + container_command: + commands: + - "sudo -u www-data /usr/local/bin/composer update phpunit/phpunit symfony/phpunit-bridge phpspec/prophecy symfony/yaml --with-dependencies --no-progress" # run_tests task is executed several times in order of performance speeds. # halt-on-fail can be set on the run_tests tasks in order to fail fast. # suppress-deprecations is false in order to be alerted to usages of diff --git a/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/AfterSymfonyListener.php b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/AfterSymfonyListener.php new file mode 100644 index 0000000000..7fee8fc67d --- /dev/null +++ b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/AfterSymfonyListener.php @@ -0,0 +1,24 @@ +deprecationStartTest($test); } /** * {@inheritdoc} */ - public function endTest(\PHPUnit_Framework_Test $test, $time) { + public function endTest(Test $test, $time) { $this->deprecationEndTest($test, $time); $this->componentEndTest($test, $time); $this->standardsEndTest($test, $time); diff --git a/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/FileFieldTestBaseTrait.php b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/FileFieldTestBaseTrait.php new file mode 100644 index 0000000000..175656aaf7 --- /dev/null +++ b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/FileFieldTestBaseTrait.php @@ -0,0 +1,56 @@ +getFileUri(); + } + $message = isset($message) ? $message : format_string('File %file exists on the disk.', ['%file' => $file]); + parent::assertFileExists($file, $message); + } + + /** + * Asserts that a file does not exist on disk. + * + * Overrides PHPUnit\Framework\Assert::assertFileNotExists() to also work + * with file entities. + * + * @param \Drupal\File\FileInterface|string $file + * Either the file entity or the file URI. + * @param string $message + * (optional) A message to display with the assertion. + * + * @see https://www.drupal.org/node/3057326 + */ + public static function assertFileNotExists($file, $message = NULL) { + if ($file instanceof FileInterface) { + @trigger_error('Passing a File entity as $file argument to FileFieldTestBase::assertFileNotExists is deprecated in drupal:8.8.0. It will be removed from drupal:9.0.0. Instead, pass the File entity URI via File::getFileUri(). See https://www.drupal.org/node/3057326', E_USER_DEPRECATED); + $file = $file->getFileUri(); + } + $message = isset($message) ? $message : format_string('File %file exists on the disk.', ['%file' => $file]); + parent::assertFileNotExists($file, $message); + } + +} diff --git a/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/HtmlOutputPrinter.php b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/HtmlOutputPrinter.php new file mode 100644 index 0000000000..2e92a9dba0 --- /dev/null +++ b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/HtmlOutputPrinter.php @@ -0,0 +1,27 @@ +printHtmlOutput(); + } + +} diff --git a/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/SimpletestUiPrinter.php b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/SimpletestUiPrinter.php new file mode 100644 index 0000000000..e653144b26 --- /dev/null +++ b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/SimpletestUiPrinter.php @@ -0,0 +1,26 @@ + tags. + $url_pattern = '@https?://[^\s]+@'; + $buffer = preg_replace($url_pattern, '$0', $buffer); + // Make the output readable in HTML by breaking up lines properly. + $buffer = nl2br($buffer); + + print $buffer; + } + +} diff --git a/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/StubTestSuiteBaseTrait.php b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/StubTestSuiteBaseTrait.php new file mode 100644 index 0000000000..4b38eb710c --- /dev/null +++ b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/StubTestSuiteBaseTrait.php @@ -0,0 +1,22 @@ +testFiles. + $this->testFiles = array_merge($this->testFiles, $filenames); + } + +} diff --git a/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/TestCompatibilityTrait.php b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/TestCompatibilityTrait.php new file mode 100644 index 0000000000..6c4ff2d90b --- /dev/null +++ b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit6/TestCompatibilityTrait.php @@ -0,0 +1,48 @@ +deprecationStartTest($test); + } + + /** + * {@inheritdoc} + */ + public function endTest(Test $test, float $time): void { + $this->deprecationEndTest($test, $time); + $this->componentEndTest($test, $time); + $this->standardsEndTest($test, $time); + } + +} diff --git a/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/FileFieldTestBaseTrait.php b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/FileFieldTestBaseTrait.php new file mode 100644 index 0000000000..64bc02bf3a --- /dev/null +++ b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/FileFieldTestBaseTrait.php @@ -0,0 +1,12 @@ +printHtmlOutput(); + } + +} diff --git a/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/SimpletestUiPrinter.php b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/SimpletestUiPrinter.php new file mode 100644 index 0000000000..5bd8fa5d5a --- /dev/null +++ b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/SimpletestUiPrinter.php @@ -0,0 +1,26 @@ + tags. + $url_pattern = '@https?://[^\s]+@'; + $buffer = preg_replace($url_pattern, '$0', $buffer); + // Make the output readable in HTML by breaking up lines properly. + $buffer = nl2br($buffer); + + print $buffer; + } + +} diff --git a/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/StubTestSuiteBaseTrait.php b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/StubTestSuiteBaseTrait.php new file mode 100644 index 0000000000..247028f545 --- /dev/null +++ b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/StubTestSuiteBaseTrait.php @@ -0,0 +1,22 @@ +testFiles. + $this->testFiles = array_merge($this->testFiles, $filenames); + } + +} diff --git a/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/TestCompatibilityTrait.php b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/TestCompatibilityTrait.php new file mode 100644 index 0000000000..7cd66b9ed9 --- /dev/null +++ b/core/lib/Drupal/Core/Test/PhpUnitCompatibility/PhpUnit7/TestCompatibilityTrait.php @@ -0,0 +1,50 @@ +assertEqual($entity->field_float[0]->value, $float); $this->assertTrue($entity->field_decimal instanceof FieldItemListInterface, 'Field implements interface.'); $this->assertTrue($entity->field_decimal[0] instanceof FieldItemInterface, 'Field item implements interface.'); - $this->assertEqual($entity->field_decimal->value, $decimal); - $this->assertEqual($entity->field_decimal[0]->value, $decimal); + $this->assertEqual((float) $entity->field_decimal->value, (float) $decimal); + $this->assertEqual((float) $entity->field_decimal[0]->value, (float) $decimal); // Verify changing the number value. $new_integer = rand(11, 20); @@ -91,7 +91,7 @@ public function testNumberItem() { $entity = EntityTest::load($id); $this->assertEqual($entity->field_integer->value, $new_integer); $this->assertEqual($entity->field_float->value, $new_float); - $this->assertEqual($entity->field_decimal->value, $new_decimal); + $this->assertEqual((float) $entity->field_decimal->value, (float) $new_decimal); // Test sample item generation. $entity = EntityTest::create(); diff --git a/core/modules/file/tests/src/Functional/FileFieldTestBase.php b/core/modules/file/tests/src/Functional/FileFieldTestBase.php index 76272ac5b1..11d7ee0406 100644 --- a/core/modules/file/tests/src/Functional/FileFieldTestBase.php +++ b/core/modules/file/tests/src/Functional/FileFieldTestBase.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\file\Functional; +use Drupal\Core\Test\PhpUnitCompatibility\RunnerVersion; use Drupal\field\Entity\FieldStorageConfig; use Drupal\field\Entity\FieldConfig; use Drupal\file\FileInterface; @@ -9,6 +10,13 @@ use Drupal\file\Entity\File; use Drupal\Tests\TestFileCreationTrait; +// In order to manage different method signatures between PHPUnit versions, we +// dynamically load a compatibility trait dependent on the PHPUnit runner +// version. +if (!trait_exists(PhpunitVersionDependentFileFieldTestBaseTrait::class, FALSE)) { + class_alias("Drupal\Core\Test\PhpUnitCompatibility\PhpUnit" . RunnerVersion::getMajor() . "\FileFieldTestBaseTrait", PhpunitVersionDependentFileFieldTestBaseTrait::class); +} + /** * Provides methods specifically for testing File module's field handling. */ @@ -18,6 +26,7 @@ use TestFileCreationTrait { getTestFiles as drupalGetTestFiles; } + use PhpunitVersionDependentFileFieldTestBaseTrait; /** * {@inheritdoc} @@ -199,28 +208,6 @@ public function replaceNodeFile($file, $field_name, $nid, $new_revision = TRUE) $this->drupalPostForm(NULL, $edit, t('Save')); } - /** - * Asserts that a file exists physically on disk. - * - * Overrides PHPUnit\Framework\Assert::assertFileExists() to also work with - * file entities. - * - * @param \Drupal\File\FileInterface|string $file - * Either the file entity or the file URI. - * @param string $message - * (optional) A message to display with the assertion. - * - * @see https://www.drupal.org/node/3057326 - */ - public static function assertFileExists($file, $message = NULL) { - if ($file instanceof FileInterface) { - @trigger_error('Passing a File entity as $file argument to FileFieldTestBase::assertFileExists is deprecated in drupal:8.8.0. It will be removed from drupal:9.0.0. Instead, pass the File entity URI via File::getFileUri(). See https://www.drupal.org/node/3057326', E_USER_DEPRECATED); - $file = $file->getFileUri(); - } - $message = isset($message) ? $message : format_string('File %file exists on the disk.', ['%file' => $file]); - parent::assertFileExists($file, $message); - } - /** * Asserts that a file exists in the database. */ @@ -231,28 +218,6 @@ public function assertFileEntryExists($file, $message = NULL) { $this->assertEqual($db_file->getFileUri(), $file->getFileUri(), $message); } - /** - * Asserts that a file does not exist on disk. - * - * Overrides PHPUnit\Framework\Assert::assertFileNotExists() to also work - * with file entities. - * - * @param \Drupal\File\FileInterface|string $file - * Either the file entity or the file URI. - * @param string $message - * (optional) A message to display with the assertion. - * - * @see https://www.drupal.org/node/3057326 - */ - public static function assertFileNotExists($file, $message = NULL) { - if ($file instanceof FileInterface) { - @trigger_error('Passing a File entity as $file argument to FileFieldTestBase::assertFileNotExists is deprecated in drupal:8.8.0. It will be removed from drupal:9.0.0. Instead, pass the File entity URI via File::getFileUri(). See https://www.drupal.org/node/3057326', E_USER_DEPRECATED); - $file = $file->getFileUri(); - } - $message = isset($message) ? $message : format_string('File %file exists on the disk.', ['%file' => $file]); - parent::assertFileNotExists($file, $message); - } - /** * Asserts that a file does not exist in the database. */ diff --git a/core/modules/file/tests/src/Functional/FileFieldValidateTest.php b/core/modules/file/tests/src/Functional/FileFieldValidateTest.php index 56502f458d..b5e436b94a 100644 --- a/core/modules/file/tests/src/Functional/FileFieldValidateTest.php +++ b/core/modules/file/tests/src/Functional/FileFieldValidateTest.php @@ -3,8 +3,10 @@ namespace Drupal\Tests\file\Functional; use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\Test\PhpUnitCompatibility\RunnerVersion; use Drupal\field\Entity\FieldConfig; use Drupal\file\Entity\File; +use Drupal\Tests\Traits\ExpectDeprecationTrait; /** * Tests validation functions such as file type, max file size, max size per @@ -14,6 +16,8 @@ */ class FileFieldValidateTest extends FileFieldTestBase { + use ExpectDeprecationTrait; + /** * Tests the required property on file fields. */ @@ -192,10 +196,19 @@ public function testFileRemoval() { * * @group legacy * - * @expectedDeprecation Passing a File entity as $file argument to FileFieldTestBase::assertFileExists is deprecated in drupal:8.8.0. It will be removed from drupal:9.0.0. Instead, pass the File entity URI via File::getFileUri(). See https://www.drupal.org/node/3057326 - * @expectedDeprecation Passing a File entity as $file argument to FileFieldTestBase::assertFileNotExists is deprecated in drupal:8.8.0. It will be removed from drupal:9.0.0. Instead, pass the File entity URI via File::getFileUri(). See https://www.drupal.org/node/3057326 + * @todo the expectedDeprecation annotation does not work if tests are marked + * skipped. + * @see https://github.com/symfony/symfony/pull/25757 */ public function testAssertFileExistsDeprecation() { + if (RunnerVersion::getMajor() == 6) { + $this->expectDeprecation('Passing a File entity as $file argument to FileFieldTestBase::assertFileExists is deprecated in drupal:8.8.0. It will be removed from drupal:9.0.0. Instead, pass the File entity URI via File::getFileUri(). See https://www.drupal.org/node/3057326'); + $this->expectDeprecation('Passing a File entity as $file argument to FileFieldTestBase::assertFileNotExists is deprecated in drupal:8.8.0. It will be removed from drupal:9.0.0. Instead, pass the File entity URI via File::getFileUri(). See https://www.drupal.org/node/3057326'); + } + else { + $this->markTestSkipped('This test does not work in PHPUnit 7+ since assertFileExists only accepts string arguments for $file'); + } + $node_storage = $this->container->get('entity.manager')->getStorage('node'); $type_name = 'article'; $field_name = 'file_test'; diff --git a/core/modules/node/tests/src/FunctionalJavascript/ContextualLinksTest.php b/core/modules/node/tests/src/FunctionalJavascript/ContextualLinksTest.php index 98051262ec..7e9dae071b 100644 --- a/core/modules/node/tests/src/FunctionalJavascript/ContextualLinksTest.php +++ b/core/modules/node/tests/src/FunctionalJavascript/ContextualLinksTest.php @@ -111,7 +111,7 @@ public function testRevisionContextualLinks() { $this->toggleContextualTriggerVisibility('main'); $contextual_button = $page->find('css', 'main .contextual button'); - $this->assertEmpty(0, $contextual_button); + $this->assertEmpty(0, $contextual_button ?: ''); } } diff --git a/core/tests/Drupal/KernelTests/AssertLegacyTrait.php b/core/tests/Drupal/KernelTests/AssertLegacyTrait.php index 8a0fd574b2..17a2ea4133 100644 --- a/core/tests/Drupal/KernelTests/AssertLegacyTrait.php +++ b/core/tests/Drupal/KernelTests/AssertLegacyTrait.php @@ -27,30 +27,6 @@ protected function assert($actual, $message = '') { parent::assertTrue((bool) $actual, $message); } - /** - * @see \Drupal\simpletest\TestBase::assertTrue() - */ - public static function assertTrue($actual, $message = '') { - if (is_bool($actual)) { - parent::assertTrue($actual, $message); - } - else { - parent::assertNotEmpty($actual, $message); - } - } - - /** - * @see \Drupal\simpletest\TestBase::assertFalse() - */ - public static function assertFalse($actual, $message = '') { - if (is_bool($actual)) { - parent::assertFalse($actual, $message); - } - else { - parent::assertEmpty($actual, $message); - } - } - /** * @see \Drupal\simpletest\TestBase::assertEqual() * @@ -58,7 +34,7 @@ public static function assertFalse($actual, $message = '') { * instead. */ protected function assertEqual($actual, $expected, $message = '') { - $this->assertEquals($expected, $actual, $message); + $this->assertEquals($expected, $actual, !empty($message) ? $message : ''); } /** @@ -68,7 +44,7 @@ protected function assertEqual($actual, $expected, $message = '') { * self::assertNotEquals() instead. */ protected function assertNotEqual($actual, $expected, $message = '') { - $this->assertNotEquals($expected, $actual, $message); + $this->assertNotEquals($expected, $actual, !empty($message) ? $message : ''); } /** @@ -78,7 +54,7 @@ protected function assertNotEqual($actual, $expected, $message = '') { * instead. */ protected function assertIdentical($actual, $expected, $message = '') { - $this->assertSame($expected, $actual, $message); + $this->assertSame($expected, $actual, !empty($message) ? $message : ''); } /** @@ -88,7 +64,7 @@ protected function assertIdentical($actual, $expected, $message = '') { * self::assertNotSame() instead. */ protected function assertNotIdentical($actual, $expected, $message = '') { - $this->assertNotSame($expected, $actual, $message); + $this->assertNotSame($expected, $actual, !empty($message) ? $message : ''); } /** @@ -101,7 +77,7 @@ protected function assertIdenticalObject($actual, $expected, $message = '') { // Note: ::assertSame checks whether its the same object. ::assertEquals // though compares - $this->assertEquals($expected, $actual, $message); + $this->assertEquals($expected, $actual, !empty($message) ? $message : ''); } /** diff --git a/core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php b/core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php index 8d51d25437..d992a9f3a2 100644 --- a/core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php +++ b/core/tests/Drupal/KernelTests/Core/Theme/ThemeRenderAndAutoescapeTest.php @@ -64,7 +64,9 @@ public function providerTestThemeRenderAndAutoescape() { 'empty string unchanged' => ['', ''], 'simple string unchanged' => ['ab', 'ab'], 'int (scalar) cast to string' => [111, '111'], - 'float (scalar) cast to string' => [2.10, '2.10'], + // @todo weird, in PHPUnit 7 this is converted to '2.1' + // 'float (scalar) cast to string' => [2.10, '2.10'], + 'float (scalar) cast to string' => [2.10, '2.1'], '> is escaped' => ['>', '>'], 'Markup EM tag is unchanged' => [Markup::create('hi'), 'hi'], 'Markup SCRIPT tag is unchanged' => [Markup::create(''), ''], diff --git a/core/tests/Drupal/KernelTests/KernelTestBase.php b/core/tests/Drupal/KernelTests/KernelTestBase.php index b33737fae5..a02700d1e4 100644 --- a/core/tests/Drupal/KernelTests/KernelTestBase.php +++ b/core/tests/Drupal/KernelTests/KernelTestBase.php @@ -1096,16 +1096,4 @@ public function __sleep() { return []; } - /** - * {@inheritdoc} - */ - public static function assertEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) { - // Cast objects implementing MarkupInterface to string instead of - // relying on PHP casting them to string depending on what they are being - // comparing with. - $expected = static::castSafeStrings($expected); - $actual = static::castSafeStrings($actual); - parent::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); - } - } diff --git a/core/tests/Drupal/Tests/BrowserTestBase.php b/core/tests/Drupal/Tests/BrowserTestBase.php index de184cb0fa..3ec0bff40a 100644 --- a/core/tests/Drupal/Tests/BrowserTestBase.php +++ b/core/tests/Drupal/Tests/BrowserTestBase.php @@ -675,18 +675,6 @@ protected function getDrupalSettings() { return []; } - /** - * {@inheritdoc} - */ - public static function assertEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) { - // Cast objects implementing MarkupInterface to string instead of - // relying on PHP casting them to string depending on what they are being - // comparing with. - $expected = static::castSafeStrings($expected); - $actual = static::castSafeStrings($actual); - parent::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); - } - /** * Retrieves the current calling line in the class under test. * @@ -697,9 +685,14 @@ protected function getTestMethodCaller() { $backtrace = debug_backtrace(); // Find the test class that has the test method. while ($caller = Error::getLastCaller($backtrace)) { - if (isset($caller['class']) && $caller['class'] === get_class($this)) { + // If we match PHPUnit's TestCase::runTest, then the previously processed + // caller entry is where our test method sits. + if (isset($last_caller) && isset($caller['function']) && $caller['function'] === 'PHPUnit\Framework\TestCase->runTest()') { + // Return the last caller since that has to be the test class. + $caller = $last_caller; break; } + // If the test method is implemented by a test class's parent then the // class name of $this will not be part of the backtrace. // In that case we process the backtrace until the caller is not a @@ -709,6 +702,11 @@ protected function getTestMethodCaller() { $caller = $last_caller; break; } + + if (isset($caller['class']) && $caller['class'] === get_class($this)) { + break; + } + // Otherwise we have not reached our test class yet: save the last caller // and remove an element from to backtrace to process the next call. $last_caller = $caller; diff --git a/core/tests/Drupal/Tests/Core/Test/TestSuiteBaseTest.php b/core/tests/Drupal/Tests/Core/Test/TestSuiteBaseTest.php index 853a788f5f..f9e8142318 100644 --- a/core/tests/Drupal/Tests/Core/Test/TestSuiteBaseTest.php +++ b/core/tests/Drupal/Tests/Core/Test/TestSuiteBaseTest.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\Core\Test; +use Drupal\Core\Test\PhpUnitCompatibility\RunnerVersion; use Drupal\Tests\TestSuites\TestSuiteBase; use org\bovigo\vfs\vfsStream; use PHPUnit\Framework\TestCase; @@ -10,6 +11,13 @@ // manually. require_once __DIR__ . '/../../../../TestSuites/TestSuiteBase.php'; +// In order to manage different method signatures between PHPUnit versions, we +// dynamically load a compatibility trait dependent on the PHPUnit runner +// version. +if (!trait_exists(PhpunitVersionDependentStubTestSuiteBaseTrait::class, FALSE)) { + class_alias("Drupal\Core\Test\PhpUnitCompatibility\PhpUnit" . RunnerVersion::getMajor() . "\StubTestSuiteBaseTrait", PhpunitVersionDependentStubTestSuiteBaseTrait::class); +} + /** * @coversDefaultClass \Drupal\Tests\TestSuites\TestSuiteBase * @@ -120,6 +128,8 @@ public function testLocalTimeZone() { */ class StubTestSuiteBase extends TestSuiteBase { + use PhpunitVersionDependentStubTestSuiteBaseTrait; + /** * Test files discovered by addTestsBySuiteNamespace(). * @@ -139,16 +149,4 @@ protected function findExtensionDirectories($root) { return []; } - /** - * {@inheritdoc} - */ - public function addTestFiles($filenames) { - // We stub addTestFiles() because the parent implementation can't deal with - // vfsStream-based filesystems due to an error in - // stream_resolve_include_path(). See - // https://github.com/mikey179/vfsStream/issues/5 Here we just store the - // test file being added in $this->testFiles. - $this->testFiles = array_merge($this->testFiles, $filenames); - } - } diff --git a/core/tests/Drupal/Tests/Listeners/AfterSymfonyListener.php b/core/tests/Drupal/Tests/Listeners/AfterSymfonyListener.php index 121d0d2db2..044b6c3dd8 100644 --- a/core/tests/Drupal/Tests/Listeners/AfterSymfonyListener.php +++ b/core/tests/Drupal/Tests/Listeners/AfterSymfonyListener.php @@ -2,32 +2,8 @@ namespace Drupal\Tests\Listeners; -use PHPUnit\Framework\Test; -use PHPUnit\Framework\TestListener; -use PHPUnit\Framework\TestListenerDefaultImplementation; +use Drupal\Core\Test\PhpUnitCompatibility\RunnerVersion; -if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) { - class_alias('Drupal\Tests\Listeners\Legacy\AfterSymfonyListener', 'Drupal\Tests\Listeners\AfterSymfonyListener'); - // Using an early return instead of an else does not work when using the - // PHPUnit phar due to some weird PHP behavior (the class gets defined without - // executing the code before it and so the definition is not properly - // conditional). -} -else { - /** - * Listens to PHPUnit test runs. - * - * @internal - */ - class AfterSymfonyListener implements TestListener { - use TestListenerDefaultImplementation; - - /** - * {@inheritdoc} - */ - public function endTest(Test $test, $time) { - restore_error_handler(); - } - - } -} +// In order to manage different method signatures between PHPUnit versions, we +// dynamically load a class dependent on the PHPUnit runner version. +class_alias("Drupal\Core\Test\PhpUnitCompatibility\PhpUnit" . RunnerVersion::getMajor() . "\AfterSymfonyListener", AfterSymfonyListener::class); diff --git a/core/tests/Drupal/Tests/Listeners/DrupalListener.php b/core/tests/Drupal/Tests/Listeners/DrupalListener.php index cafaa2292b..54d7dc32a0 100644 --- a/core/tests/Drupal/Tests/Listeners/DrupalListener.php +++ b/core/tests/Drupal/Tests/Listeners/DrupalListener.php @@ -2,42 +2,8 @@ namespace Drupal\Tests\Listeners; -use PHPUnit\Framework\BaseTestListener; -use PHPUnit\Framework\Test; +use Drupal\Core\Test\PhpUnitCompatibility\RunnerVersion; -if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) { - class_alias('Drupal\Tests\Listeners\Legacy\DrupalListener', 'Drupal\Tests\Listeners\DrupalListener'); - // Using an early return instead of a else does not work when using the - // PHPUnit phar due to some weird PHP behavior (the class gets defined without - // executing the code before it and so the definition is not properly - // conditional). -} -else { - /** - * Listens to PHPUnit test runs. - * - * @internal - */ - class DrupalListener extends BaseTestListener { - use DeprecationListenerTrait; - use DrupalComponentTestListenerTrait; - use DrupalStandardsListenerTrait; - - /** - * {@inheritdoc} - */ - public function startTest(Test $test) { - $this->deprecationStartTest($test); - } - - /** - * {@inheritdoc} - */ - public function endTest(Test $test, $time) { - $this->deprecationEndTest($test, $time); - $this->componentEndTest($test, $time); - $this->standardsEndTest($test, $time); - } - - } -} +// In order to manage different method signatures between PHPUnit versions, we +// dynamically load a class dependent on the PHPUnit runner version. +class_alias("Drupal\Core\Test\PhpUnitCompatibility\PhpUnit" . RunnerVersion::getMajor() . "\DrupalListener", DrupalListener::class); diff --git a/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php b/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php index 49618b8172..f927076219 100644 --- a/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php +++ b/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php @@ -2,42 +2,8 @@ namespace Drupal\Tests\Listeners; -use PHPUnit\Framework\TestResult; -use PHPUnit\TextUI\ResultPrinter; +use Drupal\Core\Test\PhpUnitCompatibility\RunnerVersion; -if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) { - class_alias('Drupal\Tests\Listeners\Legacy\HtmlOutputPrinter', 'Drupal\Tests\Listeners\HtmlOutputPrinter'); - // Using an early return instead of a else does not work when using the - // PHPUnit phar due to some weird PHP behavior (the class gets defined without - // executing the code before it and so the definition is not properly - // conditional). -} -else { - /** - * Defines a class for providing html output results for functional tests. - * - * @internal - */ - class HtmlOutputPrinter extends ResultPrinter { - use HtmlOutputPrinterTrait; - - /** - * {@inheritdoc} - */ - public function __construct($out = NULL, $verbose = FALSE, $colors = self::COLOR_DEFAULT, $debug = FALSE, $numberOfColumns = 80, $reverse = FALSE) { - parent::__construct($out, $verbose, $colors, $debug, $numberOfColumns, $reverse); - - $this->setUpHtmlOutput(); - } - - /** - * {@inheritdoc} - */ - public function printResult(TestResult $result) { - parent::printResult($result); - - $this->printHtmlOutput(); - } - - } -} +// In order to manage different method signatures between PHPUnit versions, we +// dynamically load a class dependent on the PHPUnit runner version. +class_alias("Drupal\Core\Test\PhpUnitCompatibility\PhpUnit" . RunnerVersion::getMajor() . "\HtmlOutputPrinter", HtmlOutputPrinter::class); diff --git a/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinterTrait.php b/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinterTrait.php index 1dd67eb9e9..4bdfa54e00 100644 --- a/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinterTrait.php +++ b/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinterTrait.php @@ -16,6 +16,15 @@ */ protected $browserOutputFile; + /** + * {@inheritdoc} + */ + public function __construct($out = NULL, $verbose = FALSE, $colors = self::COLOR_DEFAULT, $debug = FALSE, $numberOfColumns = 80, $reverse = FALSE) { + parent::__construct($out, $verbose, $colors, $debug, $numberOfColumns, $reverse); + + $this->setUpHtmlOutput(); + } + /** * Creates the file to list the HTML output created during the test. * diff --git a/core/tests/Drupal/Tests/Listeners/Legacy/AfterSymfonyListener.php b/core/tests/Drupal/Tests/Listeners/Legacy/AfterSymfonyListener.php deleted file mode 100644 index fec2d78264..0000000000 --- a/core/tests/Drupal/Tests/Listeners/Legacy/AfterSymfonyListener.php +++ /dev/null @@ -1,19 +0,0 @@ -setUpHtmlOutput(); - } - - /** - * {@inheritdoc} - */ - public function printResult(\PHPUnit_Framework_TestResult $result) { - parent::printResult($result); - - $this->printHtmlOutput(); - } - -} diff --git a/core/tests/Drupal/Tests/Listeners/SimpletestUiPrinter.php b/core/tests/Drupal/Tests/Listeners/SimpletestUiPrinter.php index bfb91d7b9f..3247e5c57b 100644 --- a/core/tests/Drupal/Tests/Listeners/SimpletestUiPrinter.php +++ b/core/tests/Drupal/Tests/Listeners/SimpletestUiPrinter.php @@ -2,25 +2,8 @@ namespace Drupal\Tests\Listeners; -use Drupal\Component\Utility\Html; +use Drupal\Core\Test\PhpUnitCompatibility\RunnerVersion; -/** - * Defines a class for providing html output links in the Simpletest UI. - */ -class SimpletestUiPrinter extends HtmlOutputPrinter { - - /** - * {@inheritdoc} - */ - public function write($buffer) { - $buffer = Html::escape($buffer); - // Turn HTML output URLs into clickable link tags. - $url_pattern = '@https?://[^\s]+@'; - $buffer = preg_replace($url_pattern, '$0', $buffer); - // Make the output readable in HTML by breaking up lines properly. - $buffer = nl2br($buffer); - - print $buffer; - } - -} +// In order to manage different method signatures between PHPUnit versions, we +// dynamically load a class dependent on the PHPUnit runner version. +class_alias("Drupal\Core\Test\PhpUnitCompatibility\PhpUnit" . RunnerVersion::getMajor() . "\SimpletestUiPrinter", SimpletestUiPrinter::class); diff --git a/core/tests/Drupal/Tests/PhpunitCompatibilityTrait.php b/core/tests/Drupal/Tests/PhpunitCompatibilityTrait.php index f7972e1d39..36e43d959a 100644 --- a/core/tests/Drupal/Tests/PhpunitCompatibilityTrait.php +++ b/core/tests/Drupal/Tests/PhpunitCompatibilityTrait.php @@ -2,11 +2,22 @@ namespace Drupal\Tests; +use Drupal\Core\Test\PhpUnitCompatibility\RunnerVersion; + +// In order to manage different method signatures between PHPUnit versions, we +// dynamically load a compatibility trait dependent on the PHPUnit runner +// version. +if (!trait_exists(PhpunitVersionDependentTestCompatibilityTrait::class, FALSE)) { + class_alias("Drupal\Core\Test\PhpUnitCompatibility\PhpUnit" . RunnerVersion::getMajor() . "\TestCompatibilityTrait", PhpunitVersionDependentTestCompatibilityTrait::class); +} + /** * Makes Drupal's test API forward compatible with multiple versions of PHPUnit. */ trait PhpunitCompatibilityTrait { + use PhpunitVersionDependentTestCompatibilityTrait; + /** * Returns a mock object for the specified class using the available method. * diff --git a/core/tests/Drupal/Tests/TestRequirementsTrait.php b/core/tests/Drupal/Tests/TestRequirementsTrait.php index 84937ad69c..ec99655a76 100644 --- a/core/tests/Drupal/Tests/TestRequirementsTrait.php +++ b/core/tests/Drupal/Tests/TestRequirementsTrait.php @@ -3,6 +3,7 @@ namespace Drupal\Tests; use Drupal\Core\Extension\ExtensionDiscovery; +use PHPUnit\Util\Test; /** * Allows test classes to require Drupal modules as dependencies. @@ -33,7 +34,18 @@ protected static function getDrupalRoot() { * skipped. Callers should not catch this exception. */ protected function checkRequirements() { - parent::checkRequirements(); + if (!$this->getName(FALSE) || !method_exists($this, $this->getName(FALSE))) { + return; + } + + $missingRequirements = Test::getMissingRequirements( + get_class($this), + $this->getName(FALSE) + ); + + if (!empty($missingRequirements)) { + $this->markTestSkipped(implode(PHP_EOL, $missingRequirements)); + } $root = static::getDrupalRoot(); diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php index bd183c7961..9d8a3b738c 100644 --- a/core/tests/Drupal/Tests/UnitTestCase.php +++ b/core/tests/Drupal/Tests/UnitTestCase.php @@ -90,7 +90,7 @@ protected function getRandomGenerator() { protected function assertArrayEquals(array $expected, array $actual, $message = NULL) { ksort($expected); ksort($actual); - $this->assertEquals($expected, $actual, $message); + $this->assertEquals($expected, $actual, !empty($message) ? $message : ''); } /**