diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml index f54e24c3ee9952cadf6be427683e74e07f5b3363..763853c1b460dcf3b85e044e314e5fd916a41edd 100644 --- a/core/config/schema/core.data_types.schema.yml +++ b/core/config/schema/core.data_types.schema.yml @@ -46,6 +46,10 @@ mapping: label: Mapping class: '\Drupal\Core\Config\Schema\Mapping' definition_class: '\Drupal\Core\TypedData\MapDataDefinition' + mapping: {} + constraints: + # By default, only allow the explicitly listed mapping keys. + ValidKeys: '<infer>' sequence: label: Sequence class: '\Drupal\Core\Config\Schema\Sequence' diff --git a/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockTest.php b/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockTest.php index 91b0a5542589a94b4aec0d2c3e203acb62fb717a..8192f5689a79121f8e11d781833ddd0bd4667b5c 100644 --- a/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockTest.php +++ b/core/modules/block/tests/src/Kernel/Migrate/d6/MigrateBlockTest.php @@ -309,7 +309,7 @@ public function testBlockMigration() { // Check migrate messages. $messages = iterator_to_array($this->getMigration('d6_block')->getIdMap()->getMessages()); $this->assertCount(2, $messages); - $this->assertSame($messages[1]->message, 'Schema errors for block.block.aggregator with the following errors: block.block.aggregator:settings.block_count missing schema, block.block.aggregator:settings.feed missing schema'); + $this->assertSame($messages[1]->message, 'Schema errors for block.block.aggregator with the following errors: block.block.aggregator:settings.block_count missing schema, block.block.aggregator:settings.feed missing schema, 0 [settings] 'block_count' is not a supported key., 1 [settings] 'feed' is not a supported key.'); } } diff --git a/core/modules/config/tests/src/Functional/SchemaConfigListenerWebTest.php b/core/modules/config/tests/src/Functional/SchemaConfigListenerWebTest.php index 3d78745758e8c0aff6566972a25e64d8bcebdc88..7701ff626880d98f3ac745b55fbf9b4a3b1d4681 100644 --- a/core/modules/config/tests/src/Functional/SchemaConfigListenerWebTest.php +++ b/core/modules/config/tests/src/Functional/SchemaConfigListenerWebTest.php @@ -55,7 +55,7 @@ public function testConfigSchemaChecker() { $this->fail('Expected SchemaIncompleteException thrown'); } catch (SchemaIncompleteException $e) { - $this->assertEquals('Schema errors for config_test.types with the following errors: config_test.types:array variable type is integer but applied schema class is Drupal\Core\Config\Schema\Sequence, config_test.types:foo missing schema', $e->getMessage()); + $this->assertEquals("Schema errors for config_test.types with the following errors: config_test.types:array variable type is integer but applied schema class is Drupal\Core\Config\Schema\Sequence, config_test.types:foo missing schema, 0 [] 'foo' is not a supported key.", $e->getMessage()); } // Test that the config event listener is working in the child site. diff --git a/core/tests/Drupal/KernelTests/Config/TypedConfigTest.php b/core/tests/Drupal/KernelTests/Config/TypedConfigTest.php index a9be4d4ce30d7c7ff48ab41778fb80cec2b55b3f..0b05694c08b48e659d3b5d391e3fc4a51c697cad 100644 --- a/core/tests/Drupal/KernelTests/Config/TypedConfigTest.php +++ b/core/tests/Drupal/KernelTests/Config/TypedConfigTest.php @@ -181,9 +181,20 @@ public function testSimpleConfigValidation() { $value['zebra'] = 'foo'; $typed_config->setValue($value); $result = $typed_config->validate(); - $this->assertCount(1, $result); - $this->assertEquals('', $result->get(0)->getPropertyPath()); - $this->assertEquals('Unexpected keys: elephant, zebra', $result->get(0)->getMessage()); + $this->assertCount(3, $result); + // 2 constraint violations triggered by the default validation constraint + // for `type: mapping` + // @see \Drupal\Core\Validation\Plugin\Validation\Constraint\ValidKeysConstraint + $this->assertSame('', $result->get(0)->getPropertyPath()); + $this->assertEquals("'elephant' is not a supported key.", $result->get(0)->getMessage()); + $this->assertSame('', $result->get(1)->getPropertyPath()); + $this->assertEquals("'zebra' is not a supported key.", $result->get(1)->getMessage()); + // 1 additional constraint violation triggered by the custom + // constraint for the `config_test.validation` type, which indirectly + // extends `type: mapping` (via `type: config_object`). + // @see \Drupal\config_test\ConfigValidation::validateMapping() + $this->assertEquals('', $result->get(2)->getPropertyPath()); + $this->assertEquals('Unexpected keys: elephant, zebra', $result->get(2)->getMessage()); } } diff --git a/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php b/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php index f04e330a4205751bd4abffe36bc3331e7e9870a7..cff3bc0e246b404158773fb41937ea222548e880 100644 --- a/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php +++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php @@ -75,6 +75,7 @@ public function testSchemaMapping() { $expected['type'] = 'config_schema_test.someschema'; $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition'; $expected['unwrap_for_canonical_representation'] = TRUE; + $expected['constraints'] = ['ValidKeys' => '<infer>']; $this->assertEquals($expected, $definition, 'Retrieved the right metadata for configuration with only some schema.'); // Check type detection on elements with undefined types. @@ -120,6 +121,7 @@ public function testSchemaMapping() { $expected['type'] = 'system.maintenance'; $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition'; $expected['unwrap_for_canonical_representation'] = TRUE; + $expected['constraints'] = ['ValidKeys' => '<infer>']; $this->assertEquals($expected, $definition, 'Retrieved the right metadata for system.maintenance'); // Mixed schema with ignore elements. @@ -150,6 +152,7 @@ public function testSchemaMapping() { ]; $expected['type'] = 'config_schema_test.ignore'; $expected['unwrap_for_canonical_representation'] = TRUE; + $expected['constraints'] = ['ValidKeys' => '<infer>']; $this->assertEquals($expected, $definition); @@ -194,6 +197,7 @@ public function testSchemaMapping() { $expected['mapping']['third_party_settings']['sequence']['type'] = '[%parent.%parent.%type].third_party.[%key]'; $expected['mapping']['_core']['type'] = '_core_config_info'; $expected['type'] = 'image.style.*'; + $expected['constraints'] = ['ValidKeys' => '<infer>']; $this->assertEquals($expected, $definition); @@ -212,6 +216,7 @@ public function testSchemaMapping() { $expected['mapping']['upscale']['type'] = 'boolean'; $expected['mapping']['upscale']['label'] = 'Upscale'; $expected['type'] = 'image.effect.image_scale'; + $expected['constraints'] = ['ValidKeys' => '<infer>']; $this->assertEquals($expected, $definition, 'Retrieved the right metadata for image.effect.image_scale'); @@ -235,6 +240,7 @@ public function testSchemaMapping() { 'integer' => ['type' => 'integer'], 'string' => ['type' => 'string'], ]; + $expected['constraints'] = ['ValidKeys' => '<infer>']; $this->assertEquals($expected, $definition, 'Retrieved the right metadata for config_test.dynamic.third_party:third_party_settings.config_schema_test'); // More complex, several level deep test. @@ -252,6 +258,7 @@ public function testSchemaMapping() { $expected['type'] = 'config_schema_test.someschema.somemodule.*.*'; $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition'; $expected['unwrap_for_canonical_representation'] = TRUE; + $expected['constraints'] = ['ValidKeys' => '<infer>']; $this->assertEquals($expected, $definition, 'Retrieved the right metadata for config_schema_test.someschema.somemodule.section_one.subsection'); @@ -520,6 +527,7 @@ public function testSchemaFallback() { $expected['mapping']['testdescription']['type'] = 'text'; $expected['mapping']['testdescription']['label'] = 'Description'; $expected['type'] = 'config_schema_test.wildcard_fallback.*'; + $expected['constraints'] = ['ValidKeys' => '<infer>']; $this->assertEquals($expected, $definition, 'Retrieved the right metadata for config_schema_test.wildcard_fallback.something'); diff --git a/core/tests/Drupal/KernelTests/Core/Config/SchemaCheckTraitTest.php b/core/tests/Drupal/KernelTests/Core/Config/SchemaCheckTraitTest.php index bd89523a54df07e3999b76e9991cc56311cd30b2..5aee77231a81b6ffb96629b2c4e2e1693105adaa 100644 --- a/core/tests/Drupal/KernelTests/Core/Config/SchemaCheckTraitTest.php +++ b/core/tests/Drupal/KernelTests/Core/Config/SchemaCheckTraitTest.php @@ -63,7 +63,9 @@ public function testTrait() { 'config_test.types:boolean' => 'non-scalar value but not defined as an array (such as mapping or sequence)', // Validation constraints violations. // @see \Drupal\Core\TypedData\TypedDataInterface::validate() - '0' => '[boolean] This value should be of the correct primitive type.', + '0' => "[] 'new_key' is not a supported key.", + '1' => "[] 'new_array' is not a supported key.", + '2' => '[boolean] This value should be of the correct primitive type.', ]; $this->assertEquals($expected, $ret); } diff --git a/core/tests/Drupal/Tests/Traits/Core/Config/SchemaConfigListenerTestTrait.php b/core/tests/Drupal/Tests/Traits/Core/Config/SchemaConfigListenerTestTrait.php index 2c66edb355cf91b3eff128dc43fbfff72523f983..8f792fb5954c5d67262b4811d73da4a91534c498 100644 --- a/core/tests/Drupal/Tests/Traits/Core/Config/SchemaConfigListenerTestTrait.php +++ b/core/tests/Drupal/Tests/Traits/Core/Config/SchemaConfigListenerTestTrait.php @@ -55,7 +55,7 @@ public function testConfigSchemaChecker() { $this->fail($message); } catch (SchemaIncompleteException $e) { - $this->assertEquals('Schema errors for config_test.types with the following errors: config_test.types:array variable type is integer but applied schema class is Drupal\Core\Config\Schema\Sequence, config_test.types:foo missing schema', $e->getMessage()); + $this->assertEquals("Schema errors for config_test.types with the following errors: config_test.types:array variable type is integer but applied schema class is Drupal\Core\Config\Schema\Sequence, config_test.types:foo missing schema, 0 [] 'foo' is not a supported key.", $e->getMessage()); } }