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