Chris@0: form['details']['element'] = [ Chris@0: '#value' => 'Nested element', Chris@0: ]; Chris@0: Chris@0: // Set up parent array. Chris@0: $this->parents = ['details', 'element']; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests getting nested array values. Chris@0: * Chris@0: * @covers ::getValue Chris@0: */ Chris@0: public function testGetValue() { Chris@0: // Verify getting a value of a nested element. Chris@0: $value = NestedArray::getValue($this->form, $this->parents); Chris@0: $this->assertSame('Nested element', $value['#value'], 'Nested element value found.'); Chris@0: Chris@0: // Verify changing a value of a nested element by reference. Chris@0: $value = &NestedArray::getValue($this->form, $this->parents); Chris@0: $value['#value'] = 'New value'; Chris@0: $value = NestedArray::getValue($this->form, $this->parents); Chris@0: $this->assertSame('New value', $value['#value'], 'Nested element value was changed by reference.'); Chris@0: $this->assertSame('New value', $this->form['details']['element']['#value'], 'Nested element value was changed by reference.'); Chris@0: Chris@0: // Verify that an existing key is reported back. Chris@0: $key_exists = NULL; Chris@0: NestedArray::getValue($this->form, $this->parents, $key_exists); Chris@0: $this->assertTrue($key_exists, 'Existing key found.'); Chris@0: Chris@0: // Verify that a non-existing key is reported back and throws no errors. Chris@0: $key_exists = NULL; Chris@0: $parents = $this->parents; Chris@0: $parents[] = 'foo'; Chris@0: NestedArray::getValue($this->form, $parents, $key_exists); Chris@0: $this->assertFalse($key_exists, 'Non-existing key not found.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests setting nested array values. Chris@0: * Chris@0: * @covers ::setValue Chris@0: */ Chris@0: public function testSetValue() { Chris@0: $new_value = [ Chris@0: '#value' => 'New value', Chris@0: '#required' => TRUE, Chris@0: ]; Chris@0: Chris@0: // Verify setting the value of a nested element. Chris@0: NestedArray::setValue($this->form, $this->parents, $new_value); Chris@0: $this->assertSame('New value', $this->form['details']['element']['#value'], 'Changed nested element value found.'); Chris@0: $this->assertTrue($this->form['details']['element']['#required'], 'New nested element value found.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests force-setting values. Chris@0: * Chris@0: * @covers ::setValue Chris@0: */ Chris@0: public function testSetValueForce() { Chris@0: $new_value = [ Chris@0: 'one', Chris@0: ]; Chris@0: $this->form['details']['non-array-parent'] = 'string'; Chris@0: $parents = ['details', 'non-array-parent', 'child']; Chris@0: NestedArray::setValue($this->form, $parents, $new_value, TRUE); Chris@0: $this->assertSame($new_value, $this->form['details']['non-array-parent']['child'], 'The nested element was not forced to the new value.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests unsetting nested array values. Chris@0: * Chris@0: * @covers ::unsetValue Chris@0: */ Chris@0: public function testUnsetValue() { Chris@0: // Verify unsetting a non-existing nested element throws no errors and the Chris@0: // non-existing key is properly reported. Chris@0: $key_existed = NULL; Chris@0: $parents = $this->parents; Chris@0: $parents[] = 'foo'; Chris@0: NestedArray::unsetValue($this->form, $parents, $key_existed); Chris@0: $this->assertTrue(isset($this->form['details']['element']['#value']), 'Outermost nested element key still exists.'); Chris@0: $this->assertFalse($key_existed, 'Non-existing key not found.'); Chris@0: Chris@0: // Verify unsetting a nested element. Chris@0: $key_existed = NULL; Chris@0: NestedArray::unsetValue($this->form, $this->parents, $key_existed); Chris@0: $this->assertFalse(isset($this->form['details']['element']), 'Removed nested element not found.'); Chris@0: $this->assertTrue($key_existed, 'Existing key was found.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests existence of array key. Chris@0: */ Chris@0: public function testKeyExists() { Chris@0: // Verify that existing key is found. Chris@0: $this->assertTrue(NestedArray::keyExists($this->form, $this->parents), 'Nested key found.'); Chris@0: Chris@0: // Verify that non-existing keys are not found. Chris@0: $parents = $this->parents; Chris@0: $parents[] = 'foo'; Chris@0: $this->assertFalse(NestedArray::keyExists($this->form, $parents), 'Non-existing nested key not found.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests NestedArray::mergeDeepArray(). Chris@0: * Chris@0: * @covers ::mergeDeep Chris@0: * @covers ::mergeDeepArray Chris@0: */ Chris@0: public function testMergeDeepArray() { Chris@0: $link_options_1 = [ Chris@0: 'fragment' => 'x', Chris@0: 'attributes' => ['title' => 'X', 'class' => ['a', 'b']], Chris@0: 'language' => 'en', Chris@0: ]; Chris@0: $link_options_2 = [ Chris@0: 'fragment' => 'y', Chris@0: 'attributes' => ['title' => 'Y', 'class' => ['c', 'd']], Chris@0: 'absolute' => TRUE, Chris@0: ]; Chris@0: $expected = [ Chris@0: 'fragment' => 'y', Chris@0: 'attributes' => ['title' => 'Y', 'class' => ['a', 'b', 'c', 'd']], Chris@0: 'language' => 'en', Chris@0: 'absolute' => TRUE, Chris@0: ]; Chris@0: $this->assertSame($expected, NestedArray::mergeDeepArray([$link_options_1, $link_options_2]), 'NestedArray::mergeDeepArray() returned a properly merged array.'); Chris@0: // Test wrapper function, NestedArray::mergeDeep(). Chris@0: $this->assertSame($expected, NestedArray::mergeDeep($link_options_1, $link_options_2), 'NestedArray::mergeDeep() returned a properly merged array.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that arrays with implicit keys are appended, not merged. Chris@0: * Chris@0: * @covers ::mergeDeepArray Chris@0: */ Chris@0: public function testMergeImplicitKeys() { Chris@0: $a = [ Chris@0: 'subkey' => ['X', 'Y'], Chris@0: ]; Chris@0: $b = [ Chris@0: 'subkey' => ['X'], Chris@0: ]; Chris@0: Chris@0: // Drupal core behavior. Chris@0: $expected = [ Chris@0: 'subkey' => ['X', 'Y', 'X'], Chris@0: ]; Chris@0: $actual = NestedArray::mergeDeepArray([$a, $b]); Chris@0: $this->assertSame($expected, $actual, 'drupal_array_merge_deep() creates new numeric keys in the implicit sequence.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that even with explicit keys, values are appended, not merged. Chris@0: * Chris@0: * @covers ::mergeDeepArray Chris@0: */ Chris@0: public function testMergeExplicitKeys() { Chris@0: $a = [ Chris@0: 'subkey' => [ Chris@0: 0 => 'A', Chris@0: 1 => 'B', Chris@0: ], Chris@0: ]; Chris@0: $b = [ Chris@0: 'subkey' => [ Chris@0: 0 => 'C', Chris@0: 1 => 'D', Chris@0: ], Chris@0: ]; Chris@0: Chris@0: // Drupal core behavior. Chris@0: $expected = [ Chris@0: 'subkey' => [ Chris@0: 0 => 'A', Chris@0: 1 => 'B', Chris@0: 2 => 'C', Chris@0: 3 => 'D', Chris@0: ], Chris@0: ]; Chris@0: $actual = NestedArray::mergeDeepArray([$a, $b]); Chris@0: $this->assertSame($expected, $actual, 'drupal_array_merge_deep() creates new numeric keys in the explicit sequence.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests that array keys values on the first array are ignored when merging. Chris@0: * Chris@0: * Even if the initial ordering would place the data from the second array Chris@0: * before those in the first one, they are still appended, and the keys on Chris@0: * the first array are deleted and regenerated. Chris@0: * Chris@0: * @covers ::mergeDeepArray Chris@0: */ Chris@0: public function testMergeOutOfSequenceKeys() { Chris@0: $a = [ Chris@0: 'subkey' => [ Chris@0: 10 => 'A', Chris@0: 30 => 'B', Chris@0: ], Chris@0: ]; Chris@0: $b = [ Chris@0: 'subkey' => [ Chris@0: 20 => 'C', Chris@0: 0 => 'D', Chris@0: ], Chris@0: ]; Chris@0: Chris@0: // Drupal core behavior. Chris@0: $expected = [ Chris@0: 'subkey' => [ Chris@0: 0 => 'A', Chris@0: 1 => 'B', Chris@0: 2 => 'C', Chris@0: 3 => 'D', Chris@0: ], Chris@0: ]; Chris@0: $actual = NestedArray::mergeDeepArray([$a, $b]); Chris@0: $this->assertSame($expected, $actual, 'drupal_array_merge_deep() ignores numeric key order when merging.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * @covers ::filter Chris@0: * @dataProvider providerTestFilter Chris@0: */ Chris@0: public function testFilter($array, $callable, $expected) { Chris@0: $this->assertEquals($expected, NestedArray::filter($array, $callable)); Chris@0: } Chris@0: Chris@0: public function providerTestFilter() { Chris@0: $data = []; Chris@0: $data['1d-array'] = [ Chris@17: [0, 1, '', TRUE], NULL, [1 => 1, 3 => TRUE], Chris@0: ]; Chris@0: $data['1d-array-callable'] = [ Chris@0: [0, 1, '', TRUE], Chris@0: function ($element) { Chris@0: return $element === ''; Chris@0: }, Chris@0: [2 => ''], Chris@0: ]; Chris@0: $data['2d-array'] = [ Chris@0: [[0, 1, '', TRUE], [0, 1, 2, 3]], NULL, [0 => [1 => 1, 3 => TRUE], 1 => [1 => 1, 2 => 2, 3 => 3]], Chris@0: ]; Chris@0: $data['2d-array-callable'] = [ Chris@0: [[0, 1, '', TRUE], [0, 1, 2, 3]], Chris@0: function ($element) { Chris@0: return is_array($element) || $element === 3; Chris@0: }, Chris@0: [0 => [], 1 => [3 => 3]], Chris@0: ]; Chris@0: Chris@0: return $data; Chris@0: } Chris@0: Chris@0: }