3 namespace Drupal\Tests\Core\Config;
5 use Drupal\Core\DependencyInjection\ContainerBuilder;
6 use Drupal\Core\Render\Markup;
7 use Drupal\Tests\UnitTestCase;
8 use Drupal\Core\Config\Config;
9 use Drupal\Core\Config\ConfigValueException;
14 * @coversDefaultClass \Drupal\Core\Config\Config
18 * @see \Drupal\Core\Config\Config
20 class ConfigTest extends UnitTestCase {
25 * @var \Drupal\Core\Config\Config
32 * @var \Drupal\Core\Config\StorageInterface|\PHPUnit_Framework_MockObject_MockObject
39 * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject
41 protected $eventDispatcher;
46 * @var \Drupal\Core\Config\TypedConfigManagerInterface|\PHPUnit_Framework_MockObject_MockObject
48 protected $typedConfig;
51 * The mocked cache tags invalidator.
53 * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject
55 protected $cacheTagsInvalidator;
57 protected function setUp() {
58 $this->storage = $this->getMock('Drupal\Core\Config\StorageInterface');
59 $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
60 $this->typedConfig = $this->getMock('\Drupal\Core\Config\TypedConfigManagerInterface');
61 $this->config = new Config('config.test', $this->storage, $this->eventDispatcher, $this->typedConfig);
62 $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface');
64 $container = new ContainerBuilder();
65 $container->set('cache_tags.invalidator', $this->cacheTagsInvalidator);
66 \Drupal::setContainer($container);
71 * @dataProvider setNameProvider
73 public function testSetName($name) {
75 $this->config->setName($name);
77 // Check that the name has been set correctly.
78 $this->assertEquals($name, $this->config->getName());
80 // Check that the name validates.
81 // Should throw \Drupal\Core\Config\ConfigNameException if invalid.
82 $this->config->validateName($name);
86 * Provides config names to test.
88 * @see \Drupal\Tests\Core\Config\ConfigTest::testSetName()
90 public function setNameProvider() {
92 // Valid name with dot.
98 'test.' . str_repeat('a', Config::MAX_NAME_LENGTH - 5),
106 public function testIsNew() {
107 // Config should be new by default.
108 $this->assertTrue($this->config->isNew());
110 // Config is no longer new once saved.
111 $this->config->save();
112 $this->assertFalse($this->config->isNew());
117 * @dataProvider nestedDataProvider
119 public function testSetData($data) {
120 $this->config->setData($data);
121 $this->assertEquals($data, $this->config->getRawData());
122 $this->assertConfigDataEquals($data);
127 * @dataProvider nestedDataProvider
129 public function testSaveNew($data) {
130 $this->cacheTagsInvalidator->expects($this->never())
131 ->method('invalidateTags');
134 $this->config->setData($data);
136 // Check that original data has not been set yet.
137 foreach ($data as $key => $value) {
138 $this->assertNull($this->config->getOriginal($key, FALSE));
141 // Save so that the original data is set.
142 $config = $this->config->save();
144 // Check that returned $config is instance of Config.
145 $this->assertInstanceOf('\Drupal\Core\Config\Config', $config);
147 // Check that the original data it saved.
148 $this->assertOriginalConfigDataEquals($data, TRUE);
153 * @dataProvider nestedDataProvider
155 public function testSaveExisting($data) {
156 $this->cacheTagsInvalidator->expects($this->once())
157 ->method('invalidateTags')
158 ->with(['config:config.test']);
161 $this->config->setData($data);
162 $this->config->save();
166 $new_data['a']['d'] = 2;
167 $this->config->setData($new_data);
168 $this->config->save();
169 $this->assertOriginalConfigDataEquals($new_data, TRUE);
173 * @covers ::setModuleOverride
174 * @covers ::setSettingsOverride
175 * @covers ::getOriginal
176 * @covers ::hasOverrides
177 * @dataProvider overrideDataProvider
179 public function testOverrideData($data, $module_data, $setting_data) {
181 $this->config->setData($data);
183 // Check original data was set correctly.
184 $this->assertConfigDataEquals($data);
186 // Save so that the original data is stored.
187 $this->config->save();
188 $this->assertFalse($this->config->hasOverrides());
189 $this->assertOverriddenKeys($data, []);
191 // Set module override data and check value before and after save.
192 $this->config->setModuleOverride($module_data);
193 $this->assertConfigDataEquals($module_data);
194 $this->assertOverriddenKeys($data, $module_data);
196 $this->config->save();
197 $this->assertConfigDataEquals($module_data);
198 $this->assertOverriddenKeys($data, $module_data);
200 // Reset the module overrides.
201 $this->config->setModuleOverride([]);
202 $this->assertOverriddenKeys($data, []);
204 // Set setting override data and check value before and after save.
205 $this->config->setSettingsOverride($setting_data);
206 $this->assertConfigDataEquals($setting_data);
207 $this->assertOverriddenKeys($data, $setting_data);
208 $this->config->save();
209 $this->assertConfigDataEquals($setting_data);
210 $this->assertOverriddenKeys($data, $setting_data);
212 // Set module overrides again to ensure override order is correct.
213 $this->config->setModuleOverride($module_data);
214 $merged_overrides = array_merge($module_data, $setting_data);
216 // Setting data should be overriding module data.
217 $this->assertConfigDataEquals($setting_data);
218 $this->assertOverriddenKeys($data, $merged_overrides);
219 $this->config->save();
220 $this->assertConfigDataEquals($setting_data);
221 $this->assertOverriddenKeys($data, $merged_overrides);
223 // Check original data has not changed.
224 $this->assertOriginalConfigDataEquals($data, FALSE);
226 // Check setting overrides are returned with $apply_overrides = TRUE.
227 $this->assertOriginalConfigDataEquals($setting_data, TRUE);
229 // Check that $apply_overrides defaults to TRUE.
230 foreach ($setting_data as $key => $value) {
231 $config_value = $this->config->getOriginal($key);
232 $this->assertEquals($value, $config_value);
235 // Check that the overrides can be completely reset.
236 $this->config->setModuleOverride([]);
237 $this->config->setSettingsOverride([]);
238 $this->assertConfigDataEquals($data);
239 $this->assertOverriddenKeys($data, []);
240 $this->config->save();
241 $this->assertConfigDataEquals($data);
242 $this->assertOverriddenKeys($data, []);
247 * @dataProvider nestedDataProvider
249 public function testSetValue($data) {
250 foreach ($data as $key => $value) {
251 $this->config->set($key, $value);
253 $this->assertConfigDataEquals($data);
259 public function testSetValidation() {
260 $this->setExpectedException(ConfigValueException::class);
261 $this->config->set('testData', ['dot.key' => 1]);
267 public function testSetIllegalOffsetValue() {
268 // Set a single value.
269 $this->config->set('testData', 1);
271 // Attempt to treat the single value as a nested item.
272 $this->setExpectedException(\PHPUnit_Framework_Error_Warning::class);
273 $this->config->set('testData.illegalOffset', 1);
277 * @covers ::initWithData
278 * @dataProvider nestedDataProvider
280 public function testInitWithData($data) {
281 $config = $this->config->initWithData($data);
283 // Should return the Config object.
284 $this->assertInstanceOf('\Drupal\Core\Config\Config', $config);
286 // Check config is not new.
287 $this->assertEquals(FALSE, $this->config->isNew());
289 // Check that data value was set correctly.
290 $this->assertConfigDataEquals($data);
292 // Check that original data was set.
293 $this->assertOriginalConfigDataEquals($data, TRUE);
295 // Check without applying overrides.
296 $this->assertOriginalConfigDataEquals($data, FALSE);
301 * @dataProvider simpleDataProvider
303 public function testClear($data) {
304 foreach ($data as $key => $value) {
305 // Check that values are cleared.
306 $this->config->set($key, $value);
307 $this->assertEquals($value, $this->config->get($key));
308 $this->config->clear($key);
309 $this->assertNull($this->config->get($key));
315 * @dataProvider nestedDataProvider
317 public function testNestedClear($data) {
318 foreach ($data as $key => $value) {
319 // Check that values are cleared.
320 $this->config->set($key, $value);
321 // Check each nested value.
322 foreach ($value as $nested_key => $nested_value) {
323 $full_nested_key = $key . '.' . $nested_key;
324 $this->assertEquals($nested_value, $this->config->get($full_nested_key));
325 $this->config->clear($full_nested_key);
326 $this->assertNull($this->config->get($full_nested_key));
333 * @dataProvider overrideDataProvider
335 public function testDelete($data, $module_data) {
336 $this->cacheTagsInvalidator->expects($this->once())
337 ->method('invalidateTags')
338 ->with(['config:config.test']);
341 foreach ($data as $key => $value) {
342 $this->config->set($key, $value);
345 $this->config->setModuleOverride($module_data);
348 $this->config->save();
350 // Check that original data is still correct.
351 $this->assertOriginalConfigDataEquals($data, FALSE);
353 // Check overrides have been set.
354 $this->assertConfigDataEquals($module_data);
355 $this->assertOriginalConfigDataEquals($module_data, TRUE);
357 // Check that config is new.
358 $this->assertFalse($this->config->isNew());
361 $this->config->delete();
363 // Check object properties have been reset.
364 $this->assertTrue($this->config->isNew());
365 foreach ($data as $key => $value) {
366 $this->assertEmpty($this->config->getOriginal($key, FALSE));
369 // Check that overrides have persisted.
370 foreach ($module_data as $key => $value) {
371 $this->assertConfigDataEquals($module_data);
372 $this->assertOriginalConfigDataEquals($module_data, TRUE);
378 * @dataProvider mergeDataProvider
380 public function testMerge($data, $data_to_merge, $merged_data) {
382 $this->config->setData($data);
385 $this->config->merge($data_to_merge);
387 // Check that data has merged correctly.
388 $this->assertEquals($merged_data, $this->config->getRawData());
392 * Provides data to test merges.
394 * @see \Drupal\Tests\Core\Config\ConfigTest::testMerge()
396 public function mergeDataProvider() {
400 ['a' => 1, 'b' => 2, 'c' => ['d' => 3]],
402 ['a' => 2, 'e' => 4, 'c' => ['f' => 5]],
404 ['a' => 2, 'b' => 2, 'c' => ['d' => 3, 'f' => 5], 'e' => 4],
410 * @covers ::validateName
411 * @dataProvider validateNameProvider
413 public function testValidateNameException($name, $exception_message) {
414 $this->setExpectedException('\Drupal\Core\Config\ConfigNameException', $exception_message);
415 $this->config->validateName($name);
419 * @covers ::getCacheTags
421 public function testGetCacheTags() {
422 $this->assertSame(['config:' . $this->config->getName()], $this->config->getCacheTags());
426 * Provides data to test name validation.
428 * @see \Drupal\Tests\Core\Config\ConfigTest::testValidateNameException()
430 public function validateNameProvider() {
432 // Name missing namespace (dot).
435 'Missing namespace in Config object name MissingNamespace.',
437 // Exceeds length (max length plus an extra dot).
439 str_repeat('a', Config::MAX_NAME_LENGTH) . ".",
440 'Config object name ' . str_repeat('a', Config::MAX_NAME_LENGTH) . '. exceeds maximum allowed length of ' . Config::MAX_NAME_LENGTH . ' characters.',
443 // Name must not contain : ? * < > " ' / \
444 foreach ([':', '?', '*', '<', '>', '"', "'", '/', '\\'] as $char) {
445 $name = 'name.' . $char;
448 "Invalid character in Config object name $name.",
455 * Provides override data.
457 * @see \Drupal\Tests\Core\Config\ConfigTest::testOverrideData()
458 * @see \Drupal\Tests\Core\Config\ConfigTest::testDelete()
460 public function overrideDataProvider() {
465 'a' => 'originalValue',
469 'a' => 'moduleValue',
471 // Setting overrides.
473 'a' => 'settingValue',
479 'a' => 'originalValue',
480 'b' => 'originalValue',
481 'c' => 'originalValue',
485 'a' => 'moduleValue',
486 'b' => 'moduleValue',
488 // Setting overrides.
490 'a' => 'settingValue',
496 'a' => 'allTheSameValue',
500 'a' => 'allTheSameValue',
502 // Setting overrides.
504 'a' => 'allTheSameValue',
508 // For each of the above test cases create duplicate test case except with
509 // config values nested.
510 foreach ($test_cases as $test_key => $test_case) {
511 foreach ($test_case as $parameter) {
512 $nested_parameter = [];
513 foreach ($parameter as $config_key => $value) {
514 // Nest config value 5 levels.
515 $nested_value = $value;
516 for ($i = 5; $i >= 0; $i--) {
521 $nested_parameter[$config_key] = $nested_value;
523 $test_cases["nested:$test_key"][] = $nested_parameter;
530 * Provides simple test data.
532 * @see \Drupal\Tests\Core\Config\ConfigTest::testClear()
534 public function simpleDataProvider() {
547 * Provides nested test data.
549 * @see \Drupal\Tests\Core\Config\ConfigTest::testSetData()
550 * @see \Drupal\Tests\Core\Config\ConfigTest::testSave()
551 * @see \Drupal\Tests\Core\Config\ConfigTest::testSetValue()
552 * @see \Drupal\Tests\Core\Config\ConfigTest::testInitWithData()
553 * @see \Drupal\Tests\Core\Config\ConfigTest::testNestedClear()
555 public function nestedDataProvider() {
574 * Asserts all config data equals $data provided.
577 * Config data to be checked.
579 public function assertConfigDataEquals($data) {
580 foreach ($data as $key => $value) {
581 $this->assertEquals($value, $this->config->get($key));
586 * Asserts all original config data equals $data provided.
589 * Config data to be checked.
590 * @param bool $apply_overrides
591 * Apply any overrides to the original data.
593 public function assertOriginalConfigDataEquals($data, $apply_overrides) {
594 foreach ($data as $key => $value) {
595 $config_value = $this->config->getOriginal($key, $apply_overrides);
596 $this->assertEquals($value, $config_value);
603 * @covers ::initWithData
605 public function testSafeStringHandling() {
606 // Safe strings are cast when using ::set().
607 $safe_string = Markup::create('bar');
608 $this->config->set('foo', $safe_string);
609 $this->assertSame('bar', $this->config->get('foo'));
610 $this->config->set('foo', ['bar' => $safe_string]);
611 $this->assertSame('bar', $this->config->get('foo.bar'));
613 // Safe strings are cast when using ::setData().
614 $this->config->setData(['bar' => $safe_string]);
615 $this->assertSame('bar', $this->config->get('bar'));
617 // Safe strings are not cast when using ::initWithData().
618 $this->config->initWithData(['bar' => $safe_string]);
619 $this->assertSame($safe_string, $this->config->get('bar'));
623 * Asserts that the correct keys are overridden.
627 * @param array $overridden_data
628 * The overridden data.
630 protected function assertOverriddenKeys(array $data, array $overridden_data) {
631 if (empty($overridden_data)) {
632 $this->assertFalse($this->config->hasOverrides());
635 $this->assertTrue($this->config->hasOverrides());
636 foreach ($overridden_data as $key => $value) {
637 // If there are nested overrides test a keys at every level.
638 if (is_array($value)) {
640 $nested_value = $overridden_data[$key];
641 while (is_array($nested_value)) {
642 $nested_key .= '.' . key($nested_value);
643 $this->assertTrue($this->config->hasOverrides($nested_key));
644 $nested_value = array_pop($nested_value);
647 $this->assertTrue($this->config->hasOverrides($key));
651 $non_overridden_keys = array_diff(array_keys($data), array_keys($overridden_data));
652 foreach ($non_overridden_keys as $non_overridden_key) {
653 $this->assertFalse($this->config->hasOverrides($non_overridden_key));
654 // If there are nested overrides test keys at every level.
655 if (is_array($data[$non_overridden_key])) {
656 $nested_key = $non_overridden_key;
657 $nested_value = $data[$non_overridden_key];
658 while (is_array($nested_value)) {
659 $nested_key .= '.' . key($nested_value);
660 $this->assertFalse($this->config->hasOverrides($nested_key));
661 $nested_value = array_pop($nested_value);