Commit 5d457e37 authored by catch's avatar catch
Browse files

Issue #3063887 by mondrake, alexpott, longwave, catch, xjm: Support PHPUnit 8...

Issue #3063887 by mondrake, alexpott, longwave, catch, xjm: Support PHPUnit 8 in Drupal 9, drop support for PHPUnit 7
parent da21d14a
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "851ca5677985628c73d2d91f044760ce", "content-hash": "d8477fb085432c15724c090b7d20f6d2",
"packages": [ "packages": [
{ {
"name": "asm89/stack-cors", "name": "asm89/stack-cors",
...@@ -4985,40 +4985,40 @@ ...@@ -4985,40 +4985,40 @@
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "6.1.4", "version": "7.0.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf",
"reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-dom": "*", "ext-dom": "*",
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"php": "^7.1", "php": "^7.2",
"phpunit/php-file-iterator": "^2.0", "phpunit/php-file-iterator": "^2.0.2",
"phpunit/php-text-template": "^1.2.1", "phpunit/php-text-template": "^1.2.1",
"phpunit/php-token-stream": "^3.0", "phpunit/php-token-stream": "^3.1.1",
"sebastian/code-unit-reverse-lookup": "^1.0.1", "sebastian/code-unit-reverse-lookup": "^1.0.1",
"sebastian/environment": "^3.1 || ^4.0", "sebastian/environment": "^4.2.2",
"sebastian/version": "^2.0.1", "sebastian/version": "^2.0.1",
"theseer/tokenizer": "^1.1" "theseer/tokenizer": "^1.1.3"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^7.0" "phpunit/phpunit": "^8.2.2"
}, },
"suggest": { "suggest": {
"ext-xdebug": "^2.6.0" "ext-xdebug": "^2.7.2"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "6.1-dev" "dev-master": "7.0-dev"
} }
}, },
"autoload": { "autoload": {
...@@ -5044,7 +5044,7 @@ ...@@ -5044,7 +5044,7 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2018-10-31T16:06:48+00:00" "time": "2019-11-20T13:55:58+00:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
...@@ -5237,53 +5237,52 @@ ...@@ -5237,53 +5237,52 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "7.5.20", "version": "8.5.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "9467db479d1b0487c99733bb1e7944d32deded2c" "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9467db479d1b0487c99733bb1e7944d32deded2c", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/018b6ac3c8ab20916db85fa91bf6465acb64d1e0",
"reference": "9467db479d1b0487c99733bb1e7944d32deded2c", "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/instantiator": "^1.1", "doctrine/instantiator": "^1.2.0",
"ext-dom": "*", "ext-dom": "*",
"ext-json": "*", "ext-json": "*",
"ext-libxml": "*", "ext-libxml": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-xml": "*", "ext-xml": "*",
"myclabs/deep-copy": "^1.7", "ext-xmlwriter": "*",
"phar-io/manifest": "^1.0.2", "myclabs/deep-copy": "^1.9.1",
"phar-io/version": "^2.0", "phar-io/manifest": "^1.0.3",
"php": "^7.1", "phar-io/version": "^2.0.1",
"phpspec/prophecy": "^1.7", "php": "^7.2",
"phpunit/php-code-coverage": "^6.0.7", "phpspec/prophecy": "^1.8.1",
"phpunit/php-file-iterator": "^2.0.1", "phpunit/php-code-coverage": "^7.0.7",
"phpunit/php-file-iterator": "^2.0.2",
"phpunit/php-text-template": "^1.2.1", "phpunit/php-text-template": "^1.2.1",
"phpunit/php-timer": "^2.1", "phpunit/php-timer": "^2.1.2",
"sebastian/comparator": "^3.0", "sebastian/comparator": "^3.0.2",
"sebastian/diff": "^3.0", "sebastian/diff": "^3.0.2",
"sebastian/environment": "^4.0", "sebastian/environment": "^4.2.2",
"sebastian/exporter": "^3.1", "sebastian/exporter": "^3.1.1",
"sebastian/global-state": "^2.0", "sebastian/global-state": "^3.0.0",
"sebastian/object-enumerator": "^3.0.3", "sebastian/object-enumerator": "^3.0.3",
"sebastian/resource-operations": "^2.0", "sebastian/resource-operations": "^2.0.1",
"sebastian/type": "^1.1.3",
"sebastian/version": "^2.0.1" "sebastian/version": "^2.0.1"
}, },
"conflict": {
"phpunit/phpunit-mock-objects": "*"
},
"require-dev": { "require-dev": {
"ext-pdo": "*" "ext-pdo": "*"
}, },
"suggest": { "suggest": {
"ext-soap": "*", "ext-soap": "*",
"ext-xdebug": "*", "ext-xdebug": "*",
"phpunit/php-invoker": "^2.0" "phpunit/php-invoker": "^2.0.0"
}, },
"bin": [ "bin": [
"phpunit" "phpunit"
...@@ -5291,7 +5290,7 @@ ...@@ -5291,7 +5290,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "7.5-dev" "dev-master": "8.5-dev"
} }
}, },
"autoload": { "autoload": {
...@@ -5317,7 +5316,7 @@ ...@@ -5317,7 +5316,7 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2020-01-08T08:45:45+00:00" "time": "2020-01-08T08:49:49+00:00"
}, },
{ {
"name": "sebastian/code-unit-reverse-lookup", "name": "sebastian/code-unit-reverse-lookup",
...@@ -5606,23 +5605,26 @@ ...@@ -5606,23 +5605,26 @@
}, },
{ {
"name": "sebastian/global-state", "name": "sebastian/global-state",
"version": "2.0.0", "version": "3.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git", "url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4",
"reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.0" "php": "^7.2",
"sebastian/object-reflector": "^1.1.1",
"sebastian/recursion-context": "^3.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^6.0" "ext-dom": "*",
"phpunit/phpunit": "^8.0"
}, },
"suggest": { "suggest": {
"ext-uopz": "*" "ext-uopz": "*"
...@@ -5630,7 +5632,7 @@ ...@@ -5630,7 +5632,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.0-dev" "dev-master": "3.0-dev"
} }
}, },
"autoload": { "autoload": {
...@@ -5653,7 +5655,7 @@ ...@@ -5653,7 +5655,7 @@
"keywords": [ "keywords": [
"global state" "global state"
], ],
"time": "2017-04-27T15:39:26+00:00" "time": "2019-02-01T05:30:01+00:00"
}, },
{ {
"name": "sebastian/object-enumerator", "name": "sebastian/object-enumerator",
...@@ -5842,6 +5844,52 @@ ...@@ -5842,6 +5844,52 @@
"homepage": "https://www.github.com/sebastianbergmann/resource-operations", "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
"time": "2018-10-04T04:07:39+00:00" "time": "2018-10-04T04:07:39+00:00"
}, },
{
"name": "sebastian/type",
"version": "1.1.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
"reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3",
"reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3",
"shasum": ""
},
"require": {
"php": "^7.2"
},
"require-dev": {
"phpunit/phpunit": "^8.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Collection of value objects that represent the types of the PHP type system",
"homepage": "https://github.com/sebastianbergmann/type",
"time": "2019-07-02T08:10:15+00:00"
},
{ {
"name": "sebastian/version", "name": "sebastian/version",
"version": "2.0.1", "version": "2.0.1",
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
"justinrainbow/json-schema": "^5.2", "justinrainbow/json-schema": "^5.2",
"mikey179/vfsstream": "^1.6.8", "mikey179/vfsstream": "^1.6.8",
"phpspec/prophecy": "^1.7", "phpspec/prophecy": "^1.7",
"phpunit/phpunit": "^7", "phpunit/phpunit": "^8.4.1",
"symfony/browser-kit": "^4.4", "symfony/browser-kit": "^4.4",
"symfony/css-selector": "^4.4", "symfony/css-selector": "^4.4",
"symfony/debug": "^4.4", "symfony/debug": "^4.4",
......
...@@ -30,22 +30,23 @@ ...@@ -30,22 +30,23 @@
"phpdocumentor/reflection-docblock": "4.3.4", "phpdocumentor/reflection-docblock": "4.3.4",
"phpdocumentor/type-resolver": "1.0.1", "phpdocumentor/type-resolver": "1.0.1",
"phpspec/prophecy": "v1.10.2", "phpspec/prophecy": "v1.10.2",
"phpunit/php-code-coverage": "6.1.4", "phpunit/php-code-coverage": "7.0.10",
"phpunit/php-file-iterator": "2.0.2", "phpunit/php-file-iterator": "2.0.2",
"phpunit/php-text-template": "1.2.1", "phpunit/php-text-template": "1.2.1",
"phpunit/php-timer": "2.1.2", "phpunit/php-timer": "2.1.2",
"phpunit/php-token-stream": "3.1.1", "phpunit/php-token-stream": "3.1.1",
"phpunit/phpunit": "7.5.20", "phpunit/phpunit": "8.5.2",
"sebastian/code-unit-reverse-lookup": "1.0.1", "sebastian/code-unit-reverse-lookup": "1.0.1",
"sebastian/comparator": "3.0.2", "sebastian/comparator": "3.0.2",
"sebastian/diff": "3.0.2", "sebastian/diff": "3.0.2",
"sebastian/environment": "4.2.3", "sebastian/environment": "4.2.3",
"sebastian/exporter": "3.1.2", "sebastian/exporter": "3.1.2",
"sebastian/global-state": "2.0.0", "sebastian/global-state": "3.0.0",
"sebastian/object-enumerator": "3.0.3", "sebastian/object-enumerator": "3.0.3",
"sebastian/object-reflector": "1.1.1", "sebastian/object-reflector": "1.1.1",
"sebastian/recursion-context": "3.0.0", "sebastian/recursion-context": "3.0.0",
"sebastian/resource-operations": "2.0.1", "sebastian/resource-operations": "2.0.1",
"sebastian/type": "1.1.3",
"sebastian/version": "2.0.1", "sebastian/version": "2.0.1",
"seld/jsonlint": "1.7.2", "seld/jsonlint": "1.7.2",
"seld/phar-utils": "1.0.2", "seld/phar-utils": "1.0.2",
......
...@@ -180,7 +180,7 @@ public function __destruct() { ...@@ -180,7 +180,7 @@ public function __destruct() {
$count = $this->query('SELECT COUNT(*) FROM ' . $prefix . '.sqlite_master WHERE type = :type AND name NOT LIKE :pattern', [':type' => 'table', ':pattern' => 'sqlite_%'])->fetchField(); $count = $this->query('SELECT COUNT(*) FROM ' . $prefix . '.sqlite_master WHERE type = :type AND name NOT LIKE :pattern', [':type' => 'table', ':pattern' => 'sqlite_%'])->fetchField();
// We can prune the database file if it doesn't have any tables. // We can prune the database file if it doesn't have any tables.
if ($count == 0) { if ($count == 0 && file_exists($this->connectionOptions['database'] . '-' . $prefix)) {
// Detaching the database fails at this point, but no other queries // Detaching the database fails at this point, but no other queries
// are executed after the connection is destructed so we can simply // are executed after the connection is destructed so we can simply
// remove the database file. // remove the database file.
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Extension\ExtensionDiscovery; use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Test\Exception\MissingGroupException; use Drupal\Core\Test\Exception\MissingGroupException;
use Drupal\TestTools\PhpUnitCompatibility\PhpUnit8\ClassWriter;
use PHPUnit\Util\Test; use PHPUnit\Util\Test;
/** /**
...@@ -116,6 +117,10 @@ public function registerTestNamespaces() { ...@@ -116,6 +117,10 @@ public function registerTestNamespaces() {
$this->classLoader->addPsr4($prefix, $paths); $this->classLoader->addPsr4($prefix, $paths);
} }
$loader = require __DIR__ . '/../../../../../autoload.php';
// Ensure we have a valid TestCase class.
ClassWriter::mutateTestBase($loader);
return $this->testNamespaces; return $this->testNamespaces;
} }
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
beStrictAboutTestsThatDoNotTestAnything="true" beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutOutputDuringTests="true" beStrictAboutOutputDuringTests="true"
beStrictAboutChangesToGlobalState="true" beStrictAboutChangesToGlobalState="true"
printerClass="\Drupal\Tests\Listeners\HtmlOutputPrinter"> printerClass="\Drupal\Tests\Listeners\HtmlOutputPrinter"
cacheResult="false">
<php> <php>
<!-- Set error reporting to E_ALL. --> <!-- Set error reporting to E_ALL. -->
<ini name="error_reporting" value="32767"/> <ini name="error_reporting" value="32767"/>
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
use Drupal\Core\Test\TestDatabase; use Drupal\Core\Test\TestDatabase;
use Drupal\Core\Test\TestRunnerKernel; use Drupal\Core\Test\TestRunnerKernel;
use Drupal\Core\Test\TestDiscovery; use Drupal\Core\Test\TestDiscovery;
use Drupal\TestTools\PhpUnitCompatibility\PhpUnit8\ClassWriter;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use PHPUnit\Runner\Version; use PHPUnit\Runner\Version;
use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\ConsoleOutput;
...@@ -504,6 +505,7 @@ function simpletest_script_init() { ...@@ -504,6 +505,7 @@ function simpletest_script_init() {
$autoloader = require_once __DIR__ . '/../../autoload.php'; $autoloader = require_once __DIR__ . '/../../autoload.php';
// The PHPUnit compatibility layer needs to be available to autoload tests. // The PHPUnit compatibility layer needs to be available to autoload tests.
$autoloader->add('Drupal\\TestTools', __DIR__ . '/../tests'); $autoloader->add('Drupal\\TestTools', __DIR__ . '/../tests');
ClassWriter::mutateTestBase($autoloader);
// Get URL from arguments. // Get URL from arguments.
if (!empty($args['url'])) { if (!empty($args['url'])) {
......
<?php
namespace Drupal\TestTools\PhpUnitCompatibility\PhpUnit8;
/**
* Helper class to rewrite PHPUnit's TestCase class.
*
* This class contains static methods only and is not meant to be instantiated.
*
* @internal
* This should only be called by test running code. Drupal 9 will provide best
* effort to maintain this class for the Drupal 9 cycle. However if changes to
* PHP or PHPUnit make this impossible then support will be removed.
*/
final class ClassWriter {
/**
* This class should not be instantiated.
*/
private function __construct() {
}
/**
* Mutates the TestCase class from PHPUnit to make it compatible with Drupal.
*
* @param object $autoloader
* The autoloader.
*
* @throws \ReflectionException
*/
public static function mutateTestBase($autoloader) {
// If the class exists already there is nothing we can do. Hopefully this
// is happening because this has been called already. The call from
// \Drupal\Core\Test\TestDiscovery::registerTestNamespaces() necessitates
// this protection.
if (class_exists('PHPUnit\Framework\TestCase', FALSE)) {
return;
}
// Inspired by Symfony's simple-phpunit remove typehints from TestCase.
$reflector = new \ReflectionClass($autoloader);
$vendor_dir = dirname(dirname($reflector->getFileName()));
// Mutate TestCase code to make it compatible with Drupal 8 and 9 tests.
$alteredCode = file_get_contents($alteredFile = $vendor_dir . '/phpunit/phpunit/src/Framework/TestCase.php');
$alteredCode = preg_replace('/^ ((?:protected|public)(?: static)? function \w+\(\)): void/m', ' $1', $alteredCode);
$alteredCode = str_replace("__DIR__ . '/../Util/", "'$vendor_dir/phpunit/phpunit/src/Util/", $alteredCode);
$filename = __DIR__ . '/../../../../../../sites/simpletest/TestCase.php';
// Only write when necessary.
if (!file_exists($filename) || md5_file($filename) !== md5($alteredCode)) {
file_put_contents($filename, $alteredCode);
}
include $filename;
}
}
...@@ -479,7 +479,7 @@ public function testAccess() { ...@@ -479,7 +479,7 @@ public function testAccess() {
*/ */
public function testLabel() { public function testLabel() {
$this->expectDeprecation('Entity type ' . $this->entityTypeId . ' defines a label callback. Support for that is deprecated in drupal:8.0.0 and will be removed in drupal:9.0.0. Override the EntityInterface::label() method instead. See https://www.drupal.org/node/3050794'); $this->addExpectedDeprecationMessage('Entity type ' . $this->entityTypeId . ' defines a label callback. Support for that is deprecated in drupal:8.0.0 and will be removed in drupal:9.0.0. Override the EntityInterface::label() method instead. See https://www.drupal.org/node/3050794');
// Make a mock with one method that we use as the entity's label callback. // Make a mock with one method that we use as the entity's label callback.
// We check that it is called, and that the entity's label is the callback's // We check that it is called, and that the entity's label is the callback's
......
...@@ -173,7 +173,7 @@ public function testBundle() { ...@@ -173,7 +173,7 @@ public function testBundle() {
*/ */
public function testLabel() { public function testLabel() {
$this->expectDeprecation('Entity type ' . $this->entityTypeId . ' defines a label callback. Support for that is deprecated in drupal:8.0.0 and will be removed in drupal:9.0.0. Override the EntityInterface::label() method instead. See https://www.drupal.org/node/3050794'); $this->addExpectedDeprecationMessage('Entity type ' . $this->entityTypeId . ' defines a label callback. Support for that is deprecated in drupal:8.0.0 and will be removed in drupal:9.0.0. Override the EntityInterface::label() method instead. See https://www.drupal.org/node/3050794');
// Make a mock with one method that we use as the entity's uri_callback. We // Make a mock with one method that we use as the entity's uri_callback. We
// check that it is called, and that the entity's label is the callback's // check that it is called, and that the entity's label is the callback's
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
use Drupal\Component\Plugin\ConfigurableInterface; use Drupal\Component\Plugin\ConfigurableInterface;
use Drupal\Component\Plugin\PluginBase; use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection; use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
use PHPUnit\Framework\MockObject\Matcher\InvokedRecorder; use PHPUnit\Framework\MockObject\Rule\InvocationOrder;
/** /**
* @coversDefaultClass \Drupal\Core\Plugin\DefaultSingleLazyPluginCollection * @coversDefaultClass \Drupal\Core\Plugin\DefaultSingleLazyPluginCollection
...@@ -16,7 +16,7 @@ class DefaultSingleLazyPluginCollectionTest extends LazyPluginCollectionTestBase ...@@ -16,7 +16,7 @@ class DefaultSingleLazyPluginCollectionTest extends LazyPluginCollectionTestBase
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
protected function setupPluginCollection(InvokedRecorder $create_count = NULL) { protected function setupPluginCollection(InvocationOrder $create_count = NULL) {
$definitions = $this->getPluginDefinitions(); $definitions = $this->getPluginDefinitions();
$this->pluginInstances['apple'] = new ConfigurablePlugin(['id' => 'apple', 'key' => 'value'], 'apple', $definitions['apple']); $this->pluginInstances['apple'] = new ConfigurablePlugin(['id' => 'apple', 'key' => 'value'], 'apple', $definitions['apple']);
$this->pluginInstances['banana'] = new ConfigurablePlugin(['id' => 'banana', 'key' => 'other_value'], 'banana', $definitions['banana']); $this->pluginInstances['banana'] = new ConfigurablePlugin(['id' => 'banana', 'key' => 'other_value'], 'banana', $definitions['banana']);
......