plugin-8.x-2.8/tests/src/Unit/Plugin/Plugin/PluginSelector/AdvancedPluginSelectorBaseTest.php
tests/src/Unit/Plugin/Plugin/PluginSelector/AdvancedPluginSelectorBaseTest.php
<?php
namespace Drupal\Tests\plugin\Unit\Plugin\Plugin\PluginSelector;
use Drupal\Component\Plugin\PluginInspectionInterface;
use Drupal\Component\Utility\Html;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformState;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\plugin\Plugin\Plugin\PluginSelector\AdvancedPluginSelectorBase;
use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* @coversDefaultClass \Drupal\plugin\Plugin\Plugin\PluginSelector\AdvancedPluginSelectorBase
*
* @group Plugin
*/
class AdvancedPluginSelectorBaseTest extends PluginSelectorBaseTestBase {
/**
* The class under test.
*
* @var \Drupal\plugin\Plugin\Plugin\PluginSelector\AdvancedPluginSelectorBase|\PHPUnit\Framework\MockObject\MockObject
*/
protected $sut;
/**
* The string translator.
*
* @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $stringTranslation;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->stringTranslation = $this->getStringTranslationStub();
$this->sut = $this->getMockBuilder(AdvancedPluginSelectorBase::class)
->setConstructorArgs(array(
[],
$this->pluginId,
$this->pluginDefinition,
$this->defaultPluginResolver,
$this->stringTranslation
))
->getMockForAbstractClass();
$this->sut->setSelectablePluginType($this->selectablePluginType);
}
/**
* @covers ::create
* @covers ::__construct
*/
function testCreate() {
$container = $this->createMock(ContainerInterface::class);
$map = [
['plugin.default_plugin_resolver', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->defaultPluginResolver],
['string_translation', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->stringTranslation ],
];
$container->expects($this->any())
->method('get')
->willReturnMap($map);
/** @var \Drupal\plugin\Plugin\Plugin\PluginSelector\AdvancedPluginSelectorBase $class */
$class = get_class($this->sut);
$plugin = $class::create($container, [], $this->pluginId, $this->pluginDefinition);
$this->assertInstanceOf(AdvancedPluginSelectorBase::class, $plugin);
}
/**
* @covers ::buildPluginForm
*/
public function testBuildPluginForm() {
$form_state = $this->createMock(FormStateInterface::class);
$plugin_form = [
'#foo' => $this->randomMachineName(),
];
$plugin = $this->getMockForAbstractClass(AdvancedPluginSelectorBaseUnitTestPluginFormPluginInterface::class);
$plugin->expects($this->once())
->method('buildConfigurationForm')
->with([], $form_state)
->willReturn($plugin_form);
$method = new \ReflectionMethod($this->sut, 'buildPluginForm');
$method->setAccessible(TRUE);
$build = $method->invoke($this->sut, $form_state);
$this->assertSame('container', $build['#type']);
$this->sut->setSelectedPlugin($plugin);
$build = $method->invoke($this->sut, $form_state);
$this->assertSame('container', $build['#type']);
$this->assertSame($plugin_form['#foo'], $build['#foo']);
}
/**
* @covers ::buildPluginForm
*/
public function testBuildPluginFormWithoutPluginForm() {
$form_state = new FormState();
$plugin = $this->createMock(PluginInspectionInterface::class);
$method = new \ReflectionMethod($this->sut, 'buildPluginForm');
$method->setAccessible(TRUE);
$build = $method->invoke($this->sut, $form_state);
$this->assertSame('container', $build['#type']);
$this->sut->setSelectedPlugin($plugin);
$build = $method->invoke($this->sut, $form_state);
$this->assertSame('container', $build['#type']);
}
/**
* @covers ::buildSelectorForm
* @covers ::setPluginSelector
*/
public function testBuildSelectorFormWithoutAvailablePlugins() {
$form = [];
$form_state = $this->createMock(FormStateInterface::class);
$this->selectablePluginManager->expects($this->any())
->method('getDefinitions')
->willReturn([]);
$build = $this->sut->buildSelectorForm($form, $form_state);
unset($build['container']['#plugin_selector_form_state_key']);
$expected_build = [
'#cache' => [
'contexts' => [],
'tags' => [],
'max-age' => Cache::PERMANENT,
],
'container' => [
'#attributes' => [
'class' => ['plugin-selector-' . Html::getId($this->pluginId)],
],
'#available_plugins' => [],
'#process' => [
[
AdvancedPluginSelectorBase::class,
'processBuildSelectorForm'
]
],
'#tree' => TRUE,
'#type' => 'container',
],
];
$this->assertSame($expected_build, $build);
}
/**
* @covers ::buildSelectorForm
* @covers ::setPluginSelector
*/
public function testBuildSelectorFormWithOneAvailablePlugin() {
$form = [];
$form_state = $this->createMock(FormStateInterface::class);
$plugin_id = $this->randomMachineName();
$plugin = $this->createMock(PluginInspectionInterface::class);
$plugin_definitions = [
$plugin_id => [
'id' => $plugin_id,
],
];
$this->selectablePluginManager->expects($this->any())
->method('createInstance')
->with($plugin_id)
->willReturn($plugin);
$this->selectablePluginManager->expects($this->any())
->method('getDefinitions')
->willReturn($plugin_definitions);
$build = $this->sut->buildSelectorForm($form, $form_state);
unset($build['container']['#plugin_selector_form_state_key']);
$expected_build = [
'#cache' => [
'contexts' => [],
'tags' => [],
'max-age' => 0,
],
'container' => [
'#attributes' => [
'class' => ['plugin-selector-' . Html::getId($this->pluginId)],
],
'#available_plugins' => [$plugin],
'#process' => [
[
AdvancedPluginSelectorBase::class,
'processBuildSelectorForm'
]
],
'#tree' => TRUE,
'#type' => 'container',
],
];
$this->assertSame($expected_build, $build);
}
/**
* Configures a CacheableDependencyInterface mock.
*
* @param \PHPUnit\Framework\MockObject\MockObject $mock
* The mock to configure. It must also implement
* \Drupal\Core\Cache\CacheableDependencyInterface.
* @param string[] $contexts
* @param int $max_age
* @Param string[] $tags
*/
protected function configureMockCacheableDependency(MockObject $mock, array $contexts, $max_age, array $tags) {
$mock->expects($this->atLeastOnce())
->method('getCacheContexts')
->willReturn($contexts);
$mock->expects($this->atLeastOnce())
->method('getCacheMaxAge')
->willReturn($max_age);
$mock->expects($this->atLeastOnce())
->method('getCacheTags')
->willReturn($tags);
}
/**
* @covers ::buildSelectorForm
* @covers ::setPluginSelector
*/
public function testBuildSelectorFormWithMultipleAvailablePlugins() {
$form = [];
$form_state = $this->createMock(FormStateInterface::class);
$cache_contexts = [$this->randomMachineName()];
$cache_tags = [$this->randomMachineName()];
$plugin_id_a = $this->randomMachineName();
$plugin_a = $this->createMock(PluginInspectionInterface::class);
$plugin_id_b = $this->randomMachineName();
$plugin_b = $this->createMock(AdvancedPluginSelectorBaseUnitTestPluginFormPluginInterface::class);
$this->configureMockCacheableDependency($plugin_b, $cache_contexts, mt_rand(), $cache_tags);
$plugin_definitions = [
$plugin_id_a => [
'id' => $plugin_id_a,
],
$plugin_id_b => [
'id' => $plugin_id_b,
],
];
$map = [
[$plugin_id_a, [], $plugin_a],
[$plugin_id_b, [], $plugin_b],
];
$this->selectablePluginManager->expects($this->atLeastOnce())
->method('createInstance')
->willReturnMap($map);
$this->selectablePluginManager->expects($this->any())
->method('getDefinitions')
->willReturn($plugin_definitions);
$build = $this->sut->buildSelectorForm($form, $form_state);
unset($build['container']['#plugin_selector_form_state_key']);
$expected_build = [
'#cache' => [
'contexts' => $cache_contexts,
'tags' => $cache_tags,
'max-age' => 0,
],
'container' => [
'#attributes' => [
'class' => ['plugin-selector-' . Html::getId($this->pluginId)],
],
'#available_plugins' => [$plugin_a, $plugin_b],
'#process' => [
[
AdvancedPluginSelectorBase::class,
'processBuildSelectorForm'
]
],
'#tree' => TRUE,
'#type' => 'container',
],
];
$this->assertSame($expected_build, $build);
}
/**
* @covers ::submitSelectorForm
*/
public function testSubmitSelectorForm() {
$form = [
'container' => [
'plugin_form' => [
$this->randomMachineName() => [],
],
],
];
$form_state = $this->createMock(FormStateInterface::class);
$plugin = $this->getMockForAbstractClass(AdvancedPluginSelectorBaseUnitTestPluginFormPluginInterface::class);
$plugin->expects($this->once())
->method('submitConfigurationForm')
->with($form['container']['plugin_form'], $form_state);
$this->sut->submitSelectorForm($form, $form_state);
$this->sut->setSelectedPlugin($plugin);
$this->sut->submitSelectorForm($form, $form_state);
}
/**
* @covers ::validateSelectorForm
*/
public function testValidateSelectorForm() {
$plugin_id_a = $this->randomMachineName();
$plugin_id_b = $this->randomMachineName();
$form = [
'container' => [
'#parents' => ['foo', 'bar', 'container'],
'plugin_form' => [
$this->randomMachineName() => [],
],
],
];
$plugin_a = $this->getMockForAbstractClass(AdvancedPluginSelectorBaseUnitTestPluginFormPluginInterface::class);
$plugin_a->expects($this->any())
->method('getPluginId')
->willReturn($plugin_id_a);
$plugin_b = $this->getMockForAbstractClass(AdvancedPluginSelectorBaseUnitTestPluginFormPluginInterface::class);
$plugin_b->expects($this->never())
->method('validateConfigurationForm');
$plugin_b->expects($this->any())
->method('getPluginId')
->willReturn($plugin_id_b);
$map = [
[$plugin_id_a, [], $plugin_a],
[$plugin_id_b, [], $plugin_b],
];
$this->selectablePluginManager->expects($this->exactly(2))
->method('createInstance')
->willReturnMap($map);
// The plugin is set for the first time. The plugin form must not be
// validated, as there is no input for it yet.
$form_state = $this->createMock(FormStateInterface::class);
$form_state->expects($this->atLeastOnce())
->method('getValues')
->willReturn([
'foo' => [
'bar' => [
'container' => [
'select' => [
'container' => [
'plugin_id' => $plugin_id_a,
],
],
],
],
],
]);
$form_state->expects($this->once())
->method('setRebuild');
$this->sut->validateSelectorForm($form, $form_state);
$this->assertSame($plugin_a, $this->sut->getSelectedPlugin());
// The form is validated, but the plugin remains unchanged, and as such
// should validate its own form as well.
$form_state = $this->createMock(FormStateInterface::class);
$form_state->expects($this->atLeastOnce())
->method('getValues')
->willReturn([
'foo' => [
'bar' => [
'container' => [
'select' => [
'container' => [
'plugin_id' => $plugin_id_a,
],
],
],
],
],
]);
$form_state->expects($this->never())
->method('setRebuild');
$plugin_a->expects($this->once())
->method('validateConfigurationForm')
->with($form['container']['plugin_form'], $form_state);
$this->sut->validateSelectorForm($form, $form_state);
$this->assertSame($plugin_a, $this->sut->getSelectedPlugin());
// The plugin has changed. The plugin form must not be validated, as there
// is no input for it yet.
$form_state = $this->createMock(FormStateInterface::class);
$form_state->expects($this->atLeastOnce())
->method('getValues')
->willReturn([
'foo' => [
'bar' => [
'container' => [
'select' => [
'container' => [
'plugin_id' => $plugin_id_b,
],
],
],
],
],
]);
$form_state->expects($this->once())
->method('setRebuild');
$this->sut->validateSelectorForm($form, $form_state);
$this->assertSame($plugin_b, $this->sut->getSelectedPlugin());
// Change the plugin ID back to the original. No new plugin may be
// instantiated, nor must the plugin form be validated.
$form_state = $this->createMock(FormStateInterface::class);
$form_state->expects($this->atLeastOnce())
->method('getValues')
->willReturn([
'foo' => [
'bar' => [
'container' => [
'select' => [
'container' => [
'plugin_id' => $plugin_id_a,
],
],
],
],
],
]);
$form_state->expects($this->once())
->method('setRebuild');
$this->sut->validateSelectorForm($form, $form_state);
$this->assertSame($plugin_a, $this->sut->getSelectedPlugin());
}
/**
* @covers ::rebuildForm
*/
public function testRebuildForm() {
$form = [];
$form_state = $this->createMock(FormStateInterface::class);
$form_state->expects($this->once())
->method('setRebuild')
->with(TRUE);
$this->sut->rebuildForm($form, $form_state);
}
/**
* @covers ::buildNoAvailablePlugins
*/
public function testBuildNoAvailablePlugins() {
$element = [];
$form_state = $this->createMock(FormStateInterface::class);
$form = [];
$label = $this->randomMachineName();
$this->sut->setLabel($label);
$expected_build = $element + [
'select' => [
'message' => [
'#markup' => 'There are no available options.',
'#title' => $label,
'#type' => 'item',
],
'container' => [
'#type' => 'container',
'plugin_id' => [
'#type' => 'value',
'#value' => NULL,
],
],
],
];
$this->assertEquals($expected_build, $this->sut->buildNoAvailablePlugins($element, $form_state, $form));
}
/**
* @covers ::buildOneAvailablePlugin
*/
public function testBuildOneAvailablePlugin() {
$plugin_id = $this->randomMachineName();
$plugin_form = [
'#type' => $this->randomMachineName(),
];
$plugin = $this->getMockForAbstractClass(AdvancedPluginSelectorBaseUnitTestPluginFormPluginInterface::class);
$plugin->expects($this->atLeastOnce())
->method('getPluginId')
->willReturn($plugin_id);
$plugin->expects($this->once())
->method('buildConfigurationForm')
->willReturn($plugin_form);
$element = [
'#available_plugins' => [$plugin],
];
$form_state = $this->createMock(FormStateInterface::class);
$form = [];
$label = $this->randomMachineName();
$this->sut->setLabel($label);
$expected_build = [
'#available_plugins' => [$plugin],
'select' => [
'message' => [
'#title' => $label,
'#type' => 'item',
],
'container' => [
'#type' => 'container',
'plugin_id' => [
'#type' => 'value',
'#value' => $plugin_id,
],
],
],
'plugin_form' => [
'#attributes' => [
'class' => ['plugin-selector-' . Html::getId($this->pluginId) . '-plugin-form'],
],
'#type' => 'container',
] + $plugin_form,
];
$build = $this->sut->buildOneAvailablePlugin($element, $form_state, $form);
unset($build['plugin_form']['#id']);
$this->assertSame($expected_build, $build);
}
/**
* @covers ::buildMultipleAvailablePlugins
*/
public function testbuildMultipleAvailablePlugins() {
$plugin = $this->createMock(PluginInspectionInterface::class);
$element = [
'#available_plugins' => [$plugin],
];
$form_state = $this->createMock(FormStateInterface::class);
$form = [];
$plugin_form = [
'#type' => $this->randomMachineName(),
];
$selector = [
'#type' => $this->randomMachineName(),
];
/** @var \Drupal\plugin\Plugin\Plugin\PluginSelector\AdvancedPluginSelectorBase|\PHPUnit\Framework\MockObject\MockObject $plugin_selector */
$plugin_selector = $this->getMockBuilder(AdvancedPluginSelectorBase::class)
->setMethods(['buildPluginForm', 'buildSelector'])
->setConstructorArgs([
[],
$this->pluginId,
$this->pluginDefinition,
$this->defaultPluginResolver,
$this->stringTranslation
])
->getMockForAbstractClass();
$plugin_selector->setSelectablePluginType($this->selectablePluginType);
$plugin_selector->expects($this->once())
->method('buildPluginForm')
->with($form_state)
->willReturn($plugin_form);
$plugin_selector->expects($this->once())
->method('buildSelector')
->with($element, $form_state, [$plugin])
->willReturn($selector);
$plugin_selector->setSelectedPlugin($plugin);
$expected_build = [
'#available_plugins' => [$plugin],
'select' => $selector,
'plugin_form' => $plugin_form,
];
$this->assertEquals($expected_build, $plugin_selector->buildMultipleAvailablePlugins($element, $form_state, $form));
}
/**
* @covers ::setSelectedPlugin
* @covers ::getSelectedPlugin
*/
public function testGetPlugin() {
$plugin = $this->createMock(PluginInspectionInterface::class);
$this->assertSame($this->sut, $this->sut->setSelectedPlugin($plugin));
$this->assertSame($plugin, $this->sut->getSelectedPlugin());
}
/**
* @covers ::buildSelector
*/
public function testBuildSelector() {
$this->stringTranslation->expects($this->any())
->method('translate')
->willReturnArgument(0);
$method = new \ReflectionMethod($this->sut, 'buildSelector');
$method->setAccessible(TRUE);
$plugin_id = $this->randomMachineName();
$plugin_label = $this->randomMachineName();
$plugin = $this->createMock(PluginInspectionInterface::class);
$plugin->expects($this->any())
->method('getPluginId')
->willReturn($plugin_id);
$this->sut->setSelectedPlugin($plugin);
$element = [
'#parents' => ['foo', 'bar'],
];
$form_state = $this->createMock(FormStateInterface::class);
$available_plugins = [$plugin];
$expected_build_change = [
'#ajax' => [
'callback' => [
AdvancedPluginSelectorBase::class,
'ajaxRebuildForm'
],
],
'#attributes' => [
'class' => ['js-hide']
],
'#limit_validation_errors' => [
[
'foo',
'bar',
'select',
'plugin_id'
]
],
'#name' => 'foo__bar__select__container__change',
'#submit' => [[AdvancedPluginSelectorBase::class, 'rebuildForm']],
'#type' => 'submit',
'#value' => 'Choose',
];
$build = $method->invokeArgs($this->sut, [
$element,
$form_state,
$available_plugins
]);
$this->assertArrayHasKey('plugin_id', $build['container']);
$this->assertEquals($expected_build_change, $build['container']['change']);
$this->assertSame('container', $build['container']['#type']);
}
/**
* @covers ::defaultConfiguration
*/
public function testDefaultConfiguration() {
$this->assertIsArray($this->sut->defaultConfiguration());
$this->assertIsArray($this->sut->defaultConfiguration());
}
/**
* @covers ::buildConfigurationForm
*/
public function testBuildConfigurationForm() {
$form = [
'plugin' => [],
];
$form_state = new FormState();
$configuration_form = $form['plugin'];
$configuration_form_state = SubformState::createForSubform($configuration_form, $form, $form_state);
$this->assertIsArray($this->sut->buildConfigurationForm($configuration_form, $configuration_form_state));
}
/**
* @covers ::getSelectorVisibilityForSingleAvailability
* @covers ::setSelectorVisibilityForSingleAvailability
*/
public function testGetSelectorVisibilityForSingleAvailability() {
$this->assertFalse($this->sut->getSelectorVisibilityForSingleAvailability());
$this->sut->setSelectorVisibilityForSingleAvailability(TRUE);
$this->assertTrue($this->sut->getSelectorVisibilityForSingleAvailability());
}
}
/**
* Provides a plugin that provides a form and cacheability metadata.
*/
interface AdvancedPluginSelectorBaseUnitTestPluginFormPluginInterface extends PluginInspectionInterface, PluginFormInterface, CacheableDependencyInterface {
}
