1fe0f5c207bccf1de8bce2cdca328418b6e365db
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Config / ConfigTest.php
1 <?php
2
3 namespace Drupal\Tests\Core\Config;
4
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;
10
11 /**
12  * Tests the Config.
13  *
14  * @coversDefaultClass \Drupal\Core\Config\Config
15  *
16  * @group Config
17  *
18  * @see \Drupal\Core\Config\Config
19  */
20 class ConfigTest extends UnitTestCase {
21
22   /**
23    * Config.
24    *
25    * @var \Drupal\Core\Config\Config
26    */
27   protected $config;
28
29   /**
30    * Storage.
31    *
32    * @var \Drupal\Core\Config\StorageInterface|\PHPUnit_Framework_MockObject_MockObject
33    */
34   protected $storage;
35
36   /**
37    * Event Dispatcher.
38    *
39    * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject
40    */
41   protected $eventDispatcher;
42
43   /**
44    * Typed Config.
45    *
46    * @var \Drupal\Core\Config\TypedConfigManagerInterface|\PHPUnit_Framework_MockObject_MockObject
47    */
48   protected $typedConfig;
49
50   /**
51    * The mocked cache tags invalidator.
52    *
53    * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject
54    */
55   protected $cacheTagsInvalidator;
56
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');
63
64     $container = new ContainerBuilder();
65     $container->set('cache_tags.invalidator', $this->cacheTagsInvalidator);
66     \Drupal::setContainer($container);
67   }
68
69   /**
70    * @covers ::setName
71    * @dataProvider setNameProvider
72    */
73   public function testSetName($name) {
74     // Set the name.
75     $this->config->setName($name);
76
77     // Check that the name has been set correctly.
78     $this->assertEquals($name, $this->config->getName());
79
80     // Check that the name validates.
81     // Should throw \Drupal\Core\Config\ConfigNameException if invalid.
82     $this->config->validateName($name);
83   }
84
85   /**
86    * Provides config names to test.
87    *
88    * @see \Drupal\Tests\Core\Config\ConfigTest::testSetName()
89    */
90   public function setNameProvider() {
91     return [
92       // Valid name with dot.
93       [
94         'test.name',
95       ],
96       // Maximum length.
97       [
98         'test.' . str_repeat('a', Config::MAX_NAME_LENGTH - 5),
99       ],
100     ];
101   }
102
103   /**
104    * @covers ::isNew
105    */
106   public function testIsNew() {
107     // Config should be new by default.
108     $this->assertTrue($this->config->isNew());
109
110     // Config is no longer new once saved.
111     $this->config->save();
112     $this->assertFalse($this->config->isNew());
113   }
114
115   /**
116    * @covers ::setData
117    * @dataProvider nestedDataProvider
118    */
119   public function testSetData($data) {
120     $this->config->setData($data);
121     $this->assertEquals($data, $this->config->getRawData());
122     $this->assertConfigDataEquals($data);
123   }
124
125   /**
126    * @covers ::save
127    * @dataProvider nestedDataProvider
128    */
129   public function testSaveNew($data) {
130     $this->cacheTagsInvalidator->expects($this->never())
131       ->method('invalidateTags');
132
133     // Set initial data.
134     $this->config->setData($data);
135
136     // Check that original data has not been set yet.
137     foreach ($data as $key => $value) {
138       $this->assertNull($this->config->getOriginal($key, FALSE));
139     }
140
141     // Save so that the original data is set.
142     $config = $this->config->save();
143
144     // Check that returned $config is instance of Config.
145     $this->assertInstanceOf('\Drupal\Core\Config\Config', $config);
146
147     // Check that the original data it saved.
148     $this->assertOriginalConfigDataEquals($data, TRUE);
149   }
150
151   /**
152    * @covers ::save
153    * @dataProvider nestedDataProvider
154    */
155   public function testSaveExisting($data) {
156     $this->cacheTagsInvalidator->expects($this->once())
157       ->method('invalidateTags')
158       ->with(['config:config.test']);
159
160     // Set initial data.
161     $this->config->setData($data);
162     $this->config->save();
163
164     // Update.
165     $new_data = $data;
166     $new_data['a']['d'] = 2;
167     $this->config->setData($new_data);
168     $this->config->save();
169     $this->assertOriginalConfigDataEquals($new_data, TRUE);
170   }
171
172   /**
173    * @covers ::setModuleOverride
174    * @covers ::setSettingsOverride
175    * @covers ::getOriginal
176    * @covers ::hasOverrides
177    * @dataProvider overrideDataProvider
178    */
179   public function testOverrideData($data, $module_data, $setting_data) {
180     // Set initial data.
181     $this->config->setData($data);
182
183     // Check original data was set correctly.
184     $this->assertConfigDataEquals($data);
185
186     // Save so that the original data is stored.
187     $this->config->save();
188     $this->assertFalse($this->config->hasOverrides());
189     $this->assertOverriddenKeys($data, []);
190
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);
195
196     $this->config->save();
197     $this->assertConfigDataEquals($module_data);
198     $this->assertOverriddenKeys($data, $module_data);
199
200     // Reset the module overrides.
201     $this->config->setModuleOverride([]);
202     $this->assertOverriddenKeys($data, []);
203
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);
211
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);
215
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);
222
223     // Check original data has not changed.
224     $this->assertOriginalConfigDataEquals($data, FALSE);
225
226     // Check setting overrides are returned with $apply_overrides = TRUE.
227     $this->assertOriginalConfigDataEquals($setting_data, TRUE);
228
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);
233     }
234
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, []);
243   }
244
245   /**
246    * @covers ::set
247    * @dataProvider nestedDataProvider
248    */
249   public function testSetValue($data) {
250     foreach ($data as $key => $value) {
251       $this->config->set($key, $value);
252     }
253     $this->assertConfigDataEquals($data);
254   }
255
256   /**
257    * @covers ::set
258    */
259   public function testSetValidation() {
260     $this->setExpectedException(ConfigValueException::class);
261     $this->config->set('testData', ['dot.key' => 1]);
262   }
263
264   /**
265    * @covers ::set
266    */
267   public function testSetIllegalOffsetValue() {
268     // Set a single value.
269     $this->config->set('testData', 1);
270
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);
274   }
275
276   /**
277    * @covers ::initWithData
278    * @dataProvider nestedDataProvider
279    */
280   public function testInitWithData($data) {
281     $config = $this->config->initWithData($data);
282
283     // Should return the Config object.
284     $this->assertInstanceOf('\Drupal\Core\Config\Config', $config);
285
286     // Check config is not new.
287     $this->assertEquals(FALSE, $this->config->isNew());
288
289     // Check that data value was set correctly.
290     $this->assertConfigDataEquals($data);
291
292     // Check that original data was set.
293     $this->assertOriginalConfigDataEquals($data, TRUE);
294
295     // Check without applying overrides.
296     $this->assertOriginalConfigDataEquals($data, FALSE);
297   }
298
299   /**
300    * @covers ::clear
301    * @dataProvider simpleDataProvider
302    */
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));
310     }
311   }
312
313   /**
314    * @covers ::clear
315    * @dataProvider nestedDataProvider
316    */
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));
327       }
328     }
329   }
330
331   /**
332    * @covers ::delete
333    * @dataProvider overrideDataProvider
334    */
335   public function testDelete($data, $module_data) {
336     $this->cacheTagsInvalidator->expects($this->once())
337       ->method('invalidateTags')
338       ->with(['config:config.test']);
339
340     // Set initial data.
341     foreach ($data as $key => $value) {
342       $this->config->set($key, $value);
343     }
344     // Set overrides.
345     $this->config->setModuleOverride($module_data);
346
347     // Save.
348     $this->config->save();
349
350     // Check that original data is still correct.
351     $this->assertOriginalConfigDataEquals($data, FALSE);
352
353     // Check overrides have been set.
354     $this->assertConfigDataEquals($module_data);
355     $this->assertOriginalConfigDataEquals($module_data, TRUE);
356
357     // Check that config is new.
358     $this->assertFalse($this->config->isNew());
359
360     // Delete.
361     $this->config->delete();
362
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));
367     }
368
369     // Check that overrides have persisted.
370     foreach ($module_data as $key => $value) {
371       $this->assertConfigDataEquals($module_data);
372       $this->assertOriginalConfigDataEquals($module_data, TRUE);
373     }
374   }
375
376   /**
377    * @covers ::merge
378    * @dataProvider mergeDataProvider
379    */
380   public function testMerge($data, $data_to_merge, $merged_data) {
381     // Set initial data.
382     $this->config->setData($data);
383
384     // Data to merge.
385     $this->config->merge($data_to_merge);
386
387     // Check that data has merged correctly.
388     $this->assertEquals($merged_data, $this->config->getRawData());
389   }
390
391   /**
392    * Provides data to test merges.
393    *
394    * @see \Drupal\Tests\Core\Config\ConfigTest::testMerge()
395    */
396   public function mergeDataProvider() {
397     return [
398       [
399         // Data.
400         ['a' => 1, 'b' => 2, 'c' => ['d' => 3]],
401         // Data to merge.
402         ['a' => 2, 'e' => 4, 'c' => ['f' => 5]],
403         // Data merged.
404         ['a' => 2, 'b' => 2, 'c' => ['d' => 3, 'f' => 5], 'e' => 4],
405       ],
406     ];
407   }
408
409   /**
410    * @covers ::validateName
411    * @dataProvider validateNameProvider
412    */
413   public function testValidateNameException($name, $exception_message) {
414     $this->setExpectedException('\Drupal\Core\Config\ConfigNameException', $exception_message);
415     $this->config->validateName($name);
416   }
417
418   /**
419    * @covers ::getCacheTags
420    */
421   public function testGetCacheTags() {
422     $this->assertSame(['config:' . $this->config->getName()], $this->config->getCacheTags());
423   }
424
425   /**
426    * Provides data to test name validation.
427    *
428    * @see \Drupal\Tests\Core\Config\ConfigTest::testValidateNameException()
429    */
430   public function validateNameProvider() {
431     $return = [
432       // Name missing namespace (dot).
433       [
434         'MissingNamespace',
435         'Missing namespace in Config object name MissingNamespace.',
436       ],
437       // Exceeds length (max length plus an extra dot).
438       [
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.',
441       ],
442     ];
443     // Name must not contain : ? * < > " ' / \
444     foreach ([':', '?', '*', '<', '>', '"', "'", '/', '\\'] as $char) {
445       $name = 'name.' . $char;
446       $return[] = [
447         $name,
448         "Invalid character in Config object name $name.",
449       ];
450     }
451     return $return;
452   }
453
454   /**
455    * Provides override data.
456    *
457    * @see \Drupal\Tests\Core\Config\ConfigTest::testOverrideData()
458    * @see \Drupal\Tests\Core\Config\ConfigTest::testDelete()
459    */
460   public function overrideDataProvider() {
461     $test_cases = [
462       [
463         // Original data.
464         [
465           'a' => 'originalValue',
466         ],
467         // Module overrides.
468         [
469           'a' => 'moduleValue',
470         ],
471         // Setting overrides.
472         [
473           'a' => 'settingValue',
474         ],
475       ],
476       [
477         // Original data.
478         [
479           'a' => 'originalValue',
480           'b' => 'originalValue',
481           'c' => 'originalValue',
482         ],
483         // Module overrides.
484         [
485           'a' => 'moduleValue',
486           'b' => 'moduleValue',
487         ],
488         // Setting overrides.
489         [
490           'a' => 'settingValue',
491         ],
492       ],
493       [
494         // Original data.
495         [
496           'a' => 'allTheSameValue',
497         ],
498         // Module overrides.
499         [
500           'a' => 'allTheSameValue',
501         ],
502         // Setting overrides.
503         [
504           'a' => 'allTheSameValue',
505         ],
506       ],
507     ];
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--) {
517             $nested_value = [
518               $i => $nested_value,
519             ];
520           }
521           $nested_parameter[$config_key] = $nested_value;
522         }
523         $test_cases["nested:$test_key"][] = $nested_parameter;
524       }
525     }
526     return $test_cases;
527   }
528
529   /**
530    * Provides simple test data.
531    *
532    * @see \Drupal\Tests\Core\Config\ConfigTest::testClear()
533    */
534   public function simpleDataProvider() {
535     return [
536       [
537         [
538           'a' => '1',
539           'b' => '2',
540           'c' => '3',
541         ],
542       ],
543     ];
544   }
545
546   /**
547    * Provides nested test data.
548    *
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()
554    */
555   public function nestedDataProvider() {
556     return [
557       [
558         [
559           'a' => [
560             'd' => 1,
561           ],
562           'b' => [
563             'e' => 2,
564           ],
565           'c' => [
566             'f' => 3,
567           ],
568         ],
569       ],
570     ];
571   }
572
573   /**
574    * Asserts all config data equals $data provided.
575    *
576    * @param array $data
577    *   Config data to be checked.
578    */
579   public function assertConfigDataEquals($data) {
580     foreach ($data as $key => $value) {
581       $this->assertEquals($value, $this->config->get($key));
582     }
583   }
584
585   /**
586    * Asserts all original config data equals $data provided.
587    *
588    * @param array $data
589    *   Config data to be checked.
590    * @param bool $apply_overrides
591    *   Apply any overrides to the original data.
592    */
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);
597     }
598   }
599
600   /**
601    * @covers ::setData
602    * @covers ::set
603    * @covers ::initWithData
604    */
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'));
612
613     // Safe strings are cast when using ::setData().
614     $this->config->setData(['bar' => $safe_string]);
615     $this->assertSame('bar', $this->config->get('bar'));
616
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'));
620   }
621
622   /**
623    * Asserts that the correct keys are overridden.
624    *
625    * @param array $data
626    *   The original data.
627    * @param array $overridden_data
628    *   The overridden data.
629    */
630   protected function assertOverriddenKeys(array $data, array $overridden_data) {
631     if (empty($overridden_data)) {
632       $this->assertFalse($this->config->hasOverrides());
633     }
634     else {
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)) {
639           $nested_key = $key;
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);
645           }
646         }
647         $this->assertTrue($this->config->hasOverrides($key));
648       }
649     }
650
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);
662         }
663       }
664     }
665   }
666
667 }