3 namespace Drupal\KernelTests\Core\Config;
5 use Drupal\Core\Config\FileStorage;
6 use Drupal\Core\Config\InstallStorage;
7 use Drupal\Core\Config\Schema\ConfigSchemaAlterException;
8 use Drupal\Core\Config\Schema\Ignore;
9 use Drupal\Core\Config\Schema\Mapping;
10 use Drupal\Core\Config\Schema\Undefined;
11 use Drupal\Core\TypedData\Plugin\DataType\StringData;
12 use Drupal\Core\TypedData\Type\IntegerInterface;
13 use Drupal\Core\TypedData\Type\StringInterface;
14 use Drupal\KernelTests\KernelTestBase;
17 * Tests schema for configuration objects.
21 class ConfigSchemaTest extends KernelTestBase {
28 public static $modules = ['system', 'language', 'field', 'image', 'config_test', 'config_schema_test'];
33 protected function setUp() {
35 $this->installConfig(['system', 'image', 'config_schema_test']);
39 * Tests the basic metadata retrieval layer.
41 public function testSchemaMapping() {
42 // Nonexistent configuration key will have Undefined as metadata.
43 $this->assertIdentical(FALSE, \Drupal::service('config.typed')->hasConfigSchema('config_schema_test.no_such_key'));
44 $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.no_such_key');
46 $expected['label'] = 'Undefined';
47 $expected['class'] = Undefined::class;
48 $expected['type'] = 'undefined';
49 $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
50 $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.');
52 // Configuration file without schema will return Undefined as well.
53 $this->assertIdentical(FALSE, \Drupal::service('config.typed')->hasConfigSchema('config_schema_test.noschema'));
54 $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.noschema');
55 $this->assertEqual($definition, $expected, 'Retrieved the right metadata for configuration with no schema.');
57 // Configuration file with only some schema.
58 $this->assertIdentical(TRUE, \Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'));
59 $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.someschema');
61 $expected['label'] = 'Schema test data';
62 $expected['class'] = Mapping::class;
63 $expected['mapping']['langcode']['type'] = 'string';
64 $expected['mapping']['langcode']['label'] = 'Language code';
65 $expected['mapping']['_core']['type'] = '_core_config_info';
66 $expected['mapping']['testitem'] = ['label' => 'Test item'];
67 $expected['mapping']['testlist'] = ['label' => 'Test list'];
68 $expected['type'] = 'config_schema_test.someschema';
69 $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
70 $this->assertEqual($definition, $expected, 'Retrieved the right metadata for configuration with only some schema.');
72 // Check type detection on elements with undefined types.
73 $config = \Drupal::service('config.typed')->get('config_schema_test.someschema');
74 $definition = $config->get('testitem')->getDataDefinition()->toArray();
76 $expected['label'] = 'Test item';
77 $expected['class'] = Undefined::class;
78 $expected['type'] = 'undefined';
79 $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
80 $this->assertEqual($definition, $expected, 'Automatic type detected for a scalar is undefined.');
81 $definition = $config->get('testlist')->getDataDefinition()->toArray();
83 $expected['label'] = 'Test list';
84 $expected['class'] = Undefined::class;
85 $expected['type'] = 'undefined';
86 $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
87 $this->assertEqual($definition, $expected, 'Automatic type detected for a list is undefined.');
88 $definition = $config->get('testnoschema')->getDataDefinition()->toArray();
90 $expected['label'] = 'Undefined';
91 $expected['class'] = Undefined::class;
92 $expected['type'] = 'undefined';
93 $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
94 $this->assertEqual($definition, $expected, 'Automatic type detected for an undefined integer is undefined.');
96 // Simple case, straight metadata.
97 $definition = \Drupal::service('config.typed')->getDefinition('system.maintenance');
99 $expected['label'] = 'Maintenance mode';
100 $expected['class'] = Mapping::class;
101 $expected['mapping']['message'] = [
102 'label' => 'Message to display when in maintenance mode',
105 $expected['mapping']['langcode'] = [
106 'label' => 'Language code',
109 $expected['mapping']['_core']['type'] = '_core_config_info';
110 $expected['type'] = 'system.maintenance';
111 $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
112 $this->assertEqual($definition, $expected, 'Retrieved the right metadata for system.maintenance');
114 // Mixed schema with ignore elements.
115 $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.ignore');
117 $expected['label'] = 'Ignore test';
118 $expected['class'] = Mapping::class;
119 $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
120 $expected['mapping']['langcode'] = [
122 'label' => 'Language code',
124 $expected['mapping']['_core']['type'] = '_core_config_info';
125 $expected['mapping']['label'] = [
129 $expected['mapping']['irrelevant'] = [
130 'label' => 'Irrelevant',
133 $expected['mapping']['indescribable'] = [
134 'label' => 'Indescribable',
137 $expected['mapping']['weight'] = [
141 $expected['type'] = 'config_schema_test.ignore';
143 $this->assertEqual($definition, $expected);
145 // The ignore elements themselves.
146 $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('irrelevant')->getDataDefinition()->toArray();
148 $expected['type'] = 'ignore';
149 $expected['label'] = 'Irrelevant';
150 $expected['class'] = Ignore::class;
151 $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
152 $this->assertEqual($definition, $expected);
153 $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('indescribable')->getDataDefinition()->toArray();
154 $expected['label'] = 'Indescribable';
155 $this->assertEqual($definition, $expected);
157 // More complex case, generic type. Metadata for image style.
158 $definition = \Drupal::service('config.typed')->getDefinition('image.style.large');
160 $expected['label'] = 'Image style';
161 $expected['class'] = Mapping::class;
162 $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
163 $expected['mapping']['name']['type'] = 'string';
164 $expected['mapping']['uuid']['type'] = 'string';
165 $expected['mapping']['uuid']['label'] = 'UUID';
166 $expected['mapping']['langcode']['type'] = 'string';
167 $expected['mapping']['langcode']['label'] = 'Language code';
168 $expected['mapping']['status']['type'] = 'boolean';
169 $expected['mapping']['status']['label'] = 'Status';
170 $expected['mapping']['dependencies']['type'] = 'config_dependencies';
171 $expected['mapping']['dependencies']['label'] = 'Dependencies';
172 $expected['mapping']['name']['type'] = 'string';
173 $expected['mapping']['label']['type'] = 'label';
174 $expected['mapping']['label']['label'] = 'Label';
175 $expected['mapping']['effects']['type'] = 'sequence';
176 $expected['mapping']['effects']['sequence']['type'] = 'mapping';
177 $expected['mapping']['effects']['sequence']['mapping']['id']['type'] = 'string';
178 $expected['mapping']['effects']['sequence']['mapping']['data']['type'] = 'image.effect.[%parent.id]';
179 $expected['mapping']['effects']['sequence']['mapping']['weight']['type'] = 'integer';
180 $expected['mapping']['effects']['sequence']['mapping']['uuid']['type'] = 'string';
181 $expected['mapping']['third_party_settings']['type'] = 'sequence';
182 $expected['mapping']['third_party_settings']['label'] = 'Third party settings';
183 $expected['mapping']['third_party_settings']['sequence']['type'] = '[%parent.%parent.%type].third_party.[%key]';
184 $expected['mapping']['_core']['type'] = '_core_config_info';
185 $expected['type'] = 'image.style.*';
187 $this->assertEqual($definition, $expected);
189 // More complex, type based on a complex one.
190 $definition = \Drupal::service('config.typed')->getDefinition('image.effect.image_scale');
191 // This should be the schema for image.effect.image_scale.
193 $expected['label'] = 'Image scale';
194 $expected['class'] = Mapping::class;
195 $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
196 $expected['mapping']['width']['type'] = 'integer';
197 $expected['mapping']['width']['label'] = 'Width';
198 $expected['mapping']['height']['type'] = 'integer';
199 $expected['mapping']['height']['label'] = 'Height';
200 $expected['mapping']['upscale']['type'] = 'boolean';
201 $expected['mapping']['upscale']['label'] = 'Upscale';
202 $expected['type'] = 'image.effect.image_scale';
205 $this->assertEqual($definition, $expected, 'Retrieved the right metadata for image.effect.image_scale');
207 // Most complex case, get metadata for actual configuration element.
208 $effects = \Drupal::service('config.typed')->get('image.style.medium')->get('effects');
209 $definition = $effects->get('bddf0d06-42f9-4c75-a700-a33cafa25ea0')->get('data')->getDataDefinition()->toArray();
210 // This should be the schema for image.effect.image_scale, reuse previous one.
211 $expected['type'] = 'image.effect.image_scale';
213 $this->assertEqual($definition, $expected, 'Retrieved the right metadata for the first effect of image.style.medium');
215 $a = \Drupal::config('config_test.dynamic.third_party');
216 $test = \Drupal::service('config.typed')->get('config_test.dynamic.third_party')->get('third_party_settings.config_schema_test');
217 $definition = $test->getDataDefinition()->toArray();
219 $expected['type'] = 'config_test.dynamic.*.third_party.config_schema_test';
220 $expected['label'] = 'Mapping';
221 $expected['class'] = Mapping::class;
222 $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
223 $expected['mapping'] = [
224 'integer' => ['type' => 'integer'],
225 'string' => ['type' => 'string'],
227 $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_test.dynamic.third_party:third_party_settings.config_schema_test');
229 // More complex, several level deep test.
230 $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.someschema.somemodule.section_one.subsection');
231 // This should be the schema of config_schema_test.someschema.somemodule.*.*.
233 $expected['label'] = 'Schema multiple filesystem marker test';
234 $expected['class'] = Mapping::class;
235 $expected['mapping']['langcode']['type'] = 'string';
236 $expected['mapping']['langcode']['label'] = 'Language code';
237 $expected['mapping']['_core']['type'] = '_core_config_info';
238 $expected['mapping']['testid']['type'] = 'string';
239 $expected['mapping']['testid']['label'] = 'ID';
240 $expected['mapping']['testdescription']['type'] = 'text';
241 $expected['mapping']['testdescription']['label'] = 'Description';
242 $expected['type'] = 'config_schema_test.someschema.somemodule.*.*';
243 $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
245 $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.someschema.somemodule.section_one.subsection');
247 $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.someschema.somemodule.section_two.subsection');
248 // The other file should have the same schema.
249 $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.someschema.somemodule.section_two.subsection');
253 * Tests metadata retrieval with several levels of %parent indirection.
255 public function testSchemaMappingWithParents() {
256 $config_data = \Drupal::service('config.typed')->get('config_schema_test.someschema.with_parents');
258 // Test fetching parent one level up.
259 $entry = $config_data->get('one_level');
260 $definition = $entry->get('testitem')->getDataDefinition()->toArray();
262 'type' => 'config_schema_test.someschema.with_parents.key_1',
263 'label' => 'Test item nested one level',
264 'class' => StringData::class,
265 'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
267 $this->assertEqual($definition, $expected);
269 // Test fetching parent two levels up.
270 $entry = $config_data->get('two_levels');
271 $definition = $entry->get('wrapper')->get('testitem')->getDataDefinition()->toArray();
273 'type' => 'config_schema_test.someschema.with_parents.key_2',
274 'label' => 'Test item nested two levels',
275 'class' => StringData::class,
276 'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
278 $this->assertEqual($definition, $expected);
280 // Test fetching parent three levels up.
281 $entry = $config_data->get('three_levels');
282 $definition = $entry->get('wrapper_1')->get('wrapper_2')->get('testitem')->getDataDefinition()->toArray();
284 'type' => 'config_schema_test.someschema.with_parents.key_3',
285 'label' => 'Test item nested three levels',
286 'class' => StringData::class,
287 'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
289 $this->assertEqual($definition, $expected);
293 * Tests metadata applied to configuration objects.
295 public function testSchemaData() {
296 // Try a simple property.
297 $meta = \Drupal::service('config.typed')->get('system.site');
298 $property = $meta->get('page')->get('front');
299 $this->assertTrue($property instanceof StringInterface, 'Got the right wrapper fo the page.front property.');
300 $this->assertEqual($property->getValue(), '/user/login', 'Got the right value for page.front data.');
301 $definition = $property->getDataDefinition();
302 $this->assertTrue(empty($definition['translatable']), 'Got the right translatability setting for page.front data.');
304 // Check nested array of properties.
305 $list = $meta->get('page')->getElements();
306 $this->assertEqual(count($list), 3, 'Got a list with the right number of properties for site page data');
307 $this->assertTrue(isset($list['front']) && isset($list['403']) && isset($list['404']), 'Got a list with the right properties for site page data.');
308 $this->assertEqual($list['front']->getValue(), '/user/login', 'Got the right value for page.front data from the list.');
310 // And test some TypedConfigInterface methods.
312 $this->assertTrue(count($properties) == 3 && $properties['front'] == $list['front'], 'Got the right properties for site page.');
313 $values = $meta->get('page')->toArray();
314 $this->assertTrue(count($values) == 3 && $values['front'] == '/user/login', 'Got the right property values for site page.');
316 // Now let's try something more complex, with nested objects.
317 $wrapper = \Drupal::service('config.typed')->get('image.style.large');
318 $effects = $wrapper->get('effects');
319 $this->assertTrue(count($effects->toArray()) == 1, 'Got an array with effects for image.style.large data');
320 $uuid = key($effects->getValue());
321 $effect = $effects->get($uuid)->getElements();
322 $this->assertTrue(!$effect['data']->isEmpty() && $effect['id']->getValue() == 'image_scale', 'Got data for the image scale effect from metadata.');
323 $this->assertTrue($effect['data']->get('width') instanceof IntegerInterface, 'Got the right type for the scale effect width.');
324 $this->assertEqual($effect['data']->get('width')->getValue(), 480, 'Got the right value for the scale effect width.' );
328 * Test configuration value data type enforcement using schemas.
330 public function testConfigSaveWithSchema() {
333 'empty_string' => '',
334 'null_string' => NULL,
336 'null_integer' => '',
338 // If the config schema doesn't have a type it shouldn't be casted.
345 'sequence' => [1, 0, 1],
346 'sequence_bc' => [1, 0, 1],
347 // Not in schema and therefore should be left untouched.
348 'not_present_in_schema' => TRUE,
349 // Test a custom type.
350 'config_schema_test_integer' => '1',
351 'config_schema_test_integer_empty_string' => '',
353 $untyped_to_typed = $untyped_values;
357 'empty_string' => '',
358 'null_string' => NULL,
360 'null_integer' => NULL,
367 'null_float' => NULL,
368 'sequence' => [TRUE, FALSE, TRUE],
369 'sequence_bc' => [TRUE, FALSE, TRUE],
370 'not_present_in_schema' => TRUE,
371 'config_schema_test_integer' => 1,
372 'config_schema_test_integer_empty_string' => NULL,
375 // Save config which has a schema that enforces types.
376 $this->config('config_schema_test.schema_data_types')
377 ->setData($untyped_to_typed)
379 $this->assertIdentical($this->config('config_schema_test.schema_data_types')->get(), $typed_values);
381 // Save config which does not have a schema that enforces types.
382 $this->config('config_schema_test.no_schema_data_types')
383 ->setData($untyped_values)
385 $this->assertIdentical($this->config('config_schema_test.no_schema_data_types')->get(), $untyped_values);
387 // Ensure that configuration objects with keys marked as ignored are not
388 // changed when saved. The 'config_schema_test.ignore' will have been saved
389 // during the installation of configuration in the setUp method.
390 $extension_path = __DIR__ . '/../../../../../modules/config/tests/config_schema_test/';
391 $install_storage = new FileStorage($extension_path . InstallStorage::CONFIG_INSTALL_DIRECTORY);
392 $original_data = $install_storage->read('config_schema_test.ignore');
393 $installed_data = $this->config('config_schema_test.ignore')->get();
394 unset($installed_data['_core']);
395 $this->assertIdentical($installed_data, $original_data);
399 * Tests fallback to a greedy wildcard.
401 public function testSchemaFallback() {
402 $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.wildcard_fallback.something');
403 // This should be the schema of config_schema_test.wildcard_fallback.*.
405 $expected['label'] = 'Schema wildcard fallback test';
406 $expected['class'] = Mapping::class;
407 $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
408 $expected['mapping']['langcode']['type'] = 'string';
409 $expected['mapping']['langcode']['label'] = 'Language code';
410 $expected['mapping']['_core']['type'] = '_core_config_info';
411 $expected['mapping']['testid']['type'] = 'string';
412 $expected['mapping']['testid']['label'] = 'ID';
413 $expected['mapping']['testdescription']['type'] = 'text';
414 $expected['mapping']['testdescription']['label'] = 'Description';
415 $expected['type'] = 'config_schema_test.wildcard_fallback.*';
417 $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.wildcard_fallback.something');
419 $definition2 = \Drupal::service('config.typed')->getDefinition('config_schema_test.wildcard_fallback.something.something');
420 // This should be the schema of config_schema_test.wildcard_fallback.* as
422 $this->assertIdentical($definition, $definition2);
426 * Tests use of colons in schema type determination.
428 * @see \Drupal\Core\Config\TypedConfigManager::getFallbackName()
430 public function testColonsInSchemaTypeDetermination() {
431 $tests = \Drupal::service('config.typed')->get('config_schema_test.plugin_types')->get('tests')->getElements();
432 $definition = $tests[0]->getDataDefinition()->toArray();
433 $this->assertEqual($definition['type'], 'test.plugin_types.boolean');
435 $definition = $tests[1]->getDataDefinition()->toArray();
436 $this->assertEqual($definition['type'], 'test.plugin_types.boolean:*');
438 $definition = $tests[2]->getDataDefinition()->toArray();
439 $this->assertEqual($definition['type'], 'test.plugin_types.*');
441 $definition = $tests[3]->getDataDefinition()->toArray();
442 $this->assertEqual($definition['type'], 'test.plugin_types.*');
444 $tests = \Drupal::service('config.typed')->get('config_schema_test.plugin_types')->get('test_with_parents')->getElements();
445 $definition = $tests[0]->get('settings')->getDataDefinition()->toArray();
446 $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.boolean');
448 $definition = $tests[1]->get('settings')->getDataDefinition()->toArray();
449 $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.boolean:*');
451 $definition = $tests[2]->get('settings')->getDataDefinition()->toArray();
452 $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.*');
454 $definition = $tests[3]->get('settings')->getDataDefinition()->toArray();
455 $this->assertEqual($definition['type'], 'test_with_parents.plugin_types.*');
459 * Tests hook_config_schema_info_alter().
461 public function testConfigSchemaInfoAlter() {
462 /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */
463 $typed_config = \Drupal::service('config.typed');
464 $typed_config->clearCachedDefinitions();
466 // Ensure that keys can not be added or removed by
467 // hook_config_schema_info_alter().
468 \Drupal::state()->set('config_schema_test_exception_remove', TRUE);
469 $message = 'Expected ConfigSchemaAlterException thrown.';
471 $typed_config->getDefinitions();
472 $this->fail($message);
474 catch (ConfigSchemaAlterException $e) {
475 $this->pass($message);
476 $this->assertEqual($e->getMessage(), 'Invoking hook_config_schema_info_alter() has removed (config_schema_test.hook) schema definitions');
479 \Drupal::state()->set('config_schema_test_exception_add', TRUE);
480 $message = 'Expected ConfigSchemaAlterException thrown.';
482 $typed_config->getDefinitions();
483 $this->fail($message);
485 catch (ConfigSchemaAlterException $e) {
486 $this->pass($message);
487 $this->assertEqual($e->getMessage(), 'Invoking hook_config_schema_info_alter() has added (config_schema_test.hook_added_defintion) and removed (config_schema_test.hook) schema definitions');
490 \Drupal::state()->set('config_schema_test_exception_remove', FALSE);
491 $message = 'Expected ConfigSchemaAlterException thrown.';
493 $typed_config->getDefinitions();
494 $this->fail($message);
496 catch (ConfigSchemaAlterException $e) {
497 $this->pass($message);
498 $this->assertEqual($e->getMessage(), 'Invoking hook_config_schema_info_alter() has added (config_schema_test.hook_added_defintion) schema definitions');
501 // Tests that hook_config_schema_info_alter() can add additional metadata to
502 // existing configuration schema.
503 \Drupal::state()->set('config_schema_test_exception_add', FALSE);
504 $definitions = $typed_config->getDefinitions();
505 $this->assertEqual($definitions['config_schema_test.hook']['additional_metadata'], 'new schema info');
509 * Tests saving config when the type is wrapped by a dynamic type.
511 public function testConfigSaveWithWrappingSchema() {
515 'wrapper_value' => 'foo',
516 'plugin_id' => 'wrapper:foo',
517 'internal_value' => 100,
525 'wrapper_value' => 'foo',
526 'plugin_id' => 'wrapper:foo',
527 'internal_value' => '100',
532 // Save config which has a schema that enforces types.
533 \Drupal::configFactory()->getEditable('wrapping.config_schema_test.plugin_types')
534 ->setData($untyped_values)
536 $this->assertIdentical(\Drupal::config('wrapping.config_schema_test.plugin_types')
537 ->get(), $typed_values);
541 * Tests dynamic config schema type with multiple sub-key references.
543 public function testConfigSaveWithWrappingSchemaDoubleBrackets() {
547 'wrapper_value' => 'foo',
550 // Converted to a string by 'test.double_brackets.turtle.horse'
552 'another_key' => '100',
560 'wrapper_value' => 'foo',
563 'another_key' => 100,
568 // Save config which has a schema that enforces types.
569 \Drupal::configFactory()->getEditable('wrapping.config_schema_test.double_brackets')
570 ->setData($untyped_values)
572 $this->assertIdentical(\Drupal::config('wrapping.config_schema_test.double_brackets')
573 ->get(), $typed_values);
575 $tests = \Drupal::service('config.typed')->get('wrapping.config_schema_test.double_brackets')->get('tests')->getElements();
576 $definition = $tests[0]->getDataDefinition()->toArray();
577 $this->assertEqual($definition['type'], 'wrapping.test.double_brackets.*||test.double_brackets.turtle.horse');
582 'wrapper_value' => 'foo',
585 // Converted to a string by 'test.double_brackets.cat.dog' schema.
586 'another_key' => 100,
594 'wrapper_value' => 'foo',
597 'another_key' => '100',
602 // Save config which has a schema that enforces types.
603 \Drupal::configFactory()->getEditable('wrapping.config_schema_test.double_brackets')
604 ->setData($untyped_values)
606 $this->assertIdentical(\Drupal::config('wrapping.config_schema_test.double_brackets')
607 ->get(), $typed_values);
609 $tests = \Drupal::service('config.typed')->get('wrapping.config_schema_test.double_brackets')->get('tests')->getElements();
610 $definition = $tests[0]->getDataDefinition()->toArray();
611 $this->assertEqual($definition['type'], 'wrapping.test.double_brackets.*||test.double_brackets.cat.dog');
613 // Combine everything in a single save.
617 'wrapper_value' => 'foo',
620 'another_key' => 100,
623 'wrapper_value' => 'foo',
626 'another_key' => '100',
630 \Drupal::configFactory()->getEditable('wrapping.config_schema_test.double_brackets')
631 ->setData($typed_values)
633 $tests = \Drupal::service('config.typed')->get('wrapping.config_schema_test.double_brackets')->get('tests')->getElements();
634 $definition = $tests[0]->getDataDefinition()->toArray();
635 $this->assertEqual($definition['type'], 'wrapping.test.double_brackets.*||test.double_brackets.cat.dog');
636 $definition = $tests[1]->getDataDefinition()->toArray();
637 $this->assertEqual($definition['type'], 'wrapping.test.double_brackets.*||test.double_brackets.turtle.horse');
642 'id' => 'cat:persion.dog',
645 'breed' => 'persion',
650 \Drupal::configFactory()->getEditable('wrapping.config_schema_test.other_double_brackets')
651 ->setData($typed_values)
653 $tests = \Drupal::service('config.typed')->get('wrapping.config_schema_test.other_double_brackets')->get('tests')->getElements();
654 $definition = $tests[0]->getDataDefinition()->toArray();
655 // Check that definition type is a merge of the expected types.
656 $this->assertEqual($definition['type'], 'wrapping.test.other_double_brackets.*||test.double_brackets.cat:*.*');
657 // Check that breed was inherited from parent definition.
658 $this->assertEqual($definition['mapping']['breed'], ['type' => 'string']);