0371ebb3503d0d261e808c75baceec9759ad1a9c
[yaffs-website] / web / core / tests / Drupal / Tests / Component / Utility / NestedArrayTest.php
1 <?php
2
3 namespace Drupal\Tests\Component\Utility;
4
5 use Drupal\Component\Utility\NestedArray;
6 use Drupal\Tests\UnitTestCase;
7
8 /**
9  * @coversDefaultClass \Drupal\Component\Utility\NestedArray
10  * @group Utility
11  */
12 class NestedArrayTest extends UnitTestCase {
13
14   /**
15    * Form array to check.
16    *
17    * @var array
18    */
19   protected $form;
20
21   /**
22    * Array of parents for the nested element.
23    *
24    * @var array
25    */
26   protected $parents;
27
28   /**
29    * {@inheritdoc}
30    */
31   protected function setUp() {
32     parent::setUp();
33
34     // Create a form structure with a nested element.
35     $this->form['details']['element'] = [
36      '#value' => 'Nested element',
37     ];
38
39     // Set up parent array.
40     $this->parents = ['details', 'element'];
41   }
42
43   /**
44    * Tests getting nested array values.
45    *
46    * @covers ::getValue
47    */
48   public function testGetValue() {
49     // Verify getting a value of a nested element.
50     $value = NestedArray::getValue($this->form, $this->parents);
51     $this->assertSame('Nested element', $value['#value'], 'Nested element value found.');
52
53     // Verify changing a value of a nested element by reference.
54     $value = &NestedArray::getValue($this->form, $this->parents);
55     $value['#value'] = 'New value';
56     $value = NestedArray::getValue($this->form, $this->parents);
57     $this->assertSame('New value', $value['#value'], 'Nested element value was changed by reference.');
58     $this->assertSame('New value', $this->form['details']['element']['#value'], 'Nested element value was changed by reference.');
59
60     // Verify that an existing key is reported back.
61     $key_exists = NULL;
62     NestedArray::getValue($this->form, $this->parents, $key_exists);
63     $this->assertTrue($key_exists, 'Existing key found.');
64
65     // Verify that a non-existing key is reported back and throws no errors.
66     $key_exists = NULL;
67     $parents = $this->parents;
68     $parents[] = 'foo';
69     NestedArray::getValue($this->form, $parents, $key_exists);
70     $this->assertFalse($key_exists, 'Non-existing key not found.');
71   }
72
73   /**
74    * Tests setting nested array values.
75    *
76    * @covers ::setValue
77    */
78   public function testSetValue() {
79     $new_value = [
80       '#value' => 'New value',
81       '#required' => TRUE,
82     ];
83
84     // Verify setting the value of a nested element.
85     NestedArray::setValue($this->form, $this->parents, $new_value);
86     $this->assertSame('New value', $this->form['details']['element']['#value'], 'Changed nested element value found.');
87     $this->assertTrue($this->form['details']['element']['#required'], 'New nested element value found.');
88   }
89
90   /**
91    * Tests force-setting values.
92    *
93    * @covers ::setValue
94    */
95   public function testSetValueForce() {
96     $new_value = [
97       'one',
98     ];
99     $this->form['details']['non-array-parent'] = 'string';
100     $parents = ['details', 'non-array-parent', 'child'];
101     NestedArray::setValue($this->form, $parents, $new_value, TRUE);
102     $this->assertSame($new_value, $this->form['details']['non-array-parent']['child'], 'The nested element was not forced to the new value.');
103   }
104
105   /**
106    * Tests unsetting nested array values.
107    *
108    * @covers ::unsetValue
109    */
110   public function testUnsetValue() {
111     // Verify unsetting a non-existing nested element throws no errors and the
112     // non-existing key is properly reported.
113     $key_existed = NULL;
114     $parents = $this->parents;
115     $parents[] = 'foo';
116     NestedArray::unsetValue($this->form, $parents, $key_existed);
117     $this->assertTrue(isset($this->form['details']['element']['#value']), 'Outermost nested element key still exists.');
118     $this->assertFalse($key_existed, 'Non-existing key not found.');
119
120     // Verify unsetting a nested element.
121     $key_existed = NULL;
122     NestedArray::unsetValue($this->form, $this->parents, $key_existed);
123     $this->assertFalse(isset($this->form['details']['element']), 'Removed nested element not found.');
124     $this->assertTrue($key_existed, 'Existing key was found.');
125   }
126
127   /**
128    * Tests existence of array key.
129    */
130   public function testKeyExists() {
131     // Verify that existing key is found.
132     $this->assertTrue(NestedArray::keyExists($this->form, $this->parents), 'Nested key found.');
133
134     // Verify that non-existing keys are not found.
135     $parents = $this->parents;
136     $parents[] = 'foo';
137     $this->assertFalse(NestedArray::keyExists($this->form, $parents), 'Non-existing nested key not found.');
138   }
139
140   /**
141    * Tests NestedArray::mergeDeepArray().
142    *
143    * @covers ::mergeDeep
144    * @covers ::mergeDeepArray
145    */
146   public function testMergeDeepArray() {
147     $link_options_1 = [
148       'fragment' => 'x',
149       'attributes' => ['title' => 'X', 'class' => ['a', 'b']],
150       'language' => 'en',
151     ];
152     $link_options_2 = [
153       'fragment' => 'y',
154       'attributes' => ['title' => 'Y', 'class' => ['c', 'd']],
155       'absolute' => TRUE,
156     ];
157     $expected = [
158       'fragment' => 'y',
159       'attributes' => ['title' => 'Y', 'class' => ['a', 'b', 'c', 'd']],
160       'language' => 'en',
161       'absolute' => TRUE,
162     ];
163     $this->assertSame($expected, NestedArray::mergeDeepArray([$link_options_1, $link_options_2]), 'NestedArray::mergeDeepArray() returned a properly merged array.');
164     // Test wrapper function, NestedArray::mergeDeep().
165     $this->assertSame($expected, NestedArray::mergeDeep($link_options_1, $link_options_2), 'NestedArray::mergeDeep() returned a properly merged array.');
166   }
167
168   /**
169    * Tests that arrays with implicit keys are appended, not merged.
170    *
171    * @covers ::mergeDeepArray
172    */
173   public function testMergeImplicitKeys() {
174     $a = [
175       'subkey' => ['X', 'Y'],
176     ];
177     $b = [
178       'subkey' => ['X'],
179     ];
180
181     // Drupal core behavior.
182     $expected = [
183       'subkey' => ['X', 'Y', 'X'],
184     ];
185     $actual = NestedArray::mergeDeepArray([$a, $b]);
186     $this->assertSame($expected, $actual, 'drupal_array_merge_deep() creates new numeric keys in the implicit sequence.');
187   }
188
189   /**
190    * Tests that even with explicit keys, values are appended, not merged.
191    *
192    * @covers ::mergeDeepArray
193    */
194   public function testMergeExplicitKeys() {
195     $a = [
196       'subkey' => [
197         0 => 'A',
198         1 => 'B',
199       ],
200     ];
201     $b = [
202       'subkey' => [
203         0 => 'C',
204         1 => 'D',
205       ],
206     ];
207
208     // Drupal core behavior.
209     $expected = [
210       'subkey' => [
211         0 => 'A',
212         1 => 'B',
213         2 => 'C',
214         3 => 'D',
215       ],
216     ];
217     $actual = NestedArray::mergeDeepArray([$a, $b]);
218     $this->assertSame($expected, $actual, 'drupal_array_merge_deep() creates new numeric keys in the explicit sequence.');
219   }
220
221   /**
222    * Tests that array keys values on the first array are ignored when merging.
223    *
224    * Even if the initial ordering would place the data from the second array
225    * before those in the first one, they are still appended, and the keys on
226    * the first array are deleted and regenerated.
227    *
228    * @covers ::mergeDeepArray
229    */
230   public function testMergeOutOfSequenceKeys() {
231     $a = [
232       'subkey' => [
233         10 => 'A',
234         30 => 'B',
235       ],
236     ];
237     $b = [
238       'subkey' => [
239         20 => 'C',
240         0 => 'D',
241       ],
242     ];
243
244     // Drupal core behavior.
245     $expected = [
246       'subkey' => [
247         0 => 'A',
248         1 => 'B',
249         2 => 'C',
250         3 => 'D',
251       ],
252     ];
253     $actual = NestedArray::mergeDeepArray([$a, $b]);
254     $this->assertSame($expected, $actual, 'drupal_array_merge_deep() ignores numeric key order when merging.');
255   }
256
257   /**
258    * @covers ::filter
259    * @dataProvider providerTestFilter
260    */
261   public function testFilter($array, $callable, $expected) {
262     $this->assertEquals($expected, NestedArray::filter($array, $callable));
263   }
264
265   public function providerTestFilter() {
266     $data = [];
267     $data['1d-array'] = [
268       [0, 1, '', TRUE], NULL, [1 => 1, 3 => TRUE]
269     ];
270     $data['1d-array-callable'] = [
271       [0, 1, '', TRUE], function ($element) { return $element === ''; }, [2 => '']
272     ];
273     $data['2d-array'] = [
274       [[0, 1, '', TRUE], [0, 1, 2, 3]], NULL, [0 => [1 => 1, 3 => TRUE], 1 => [1 => 1, 2 => 2, 3 => 3]],
275     ];
276     $data['2d-array-callable'] = [
277       [[0, 1, '', TRUE], [0, 1, 2, 3]], function ($element) { return is_array($element) || $element === 3; }, [0 => [], 1 => [3 => 3]],
278     ];
279
280     return $data;
281   }
282
283 }