annotate core/tests/Drupal/Tests/Component/Utility/NestedArrayTest.php @ 19:fa3358dc1485 tip

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