Skip to content

Commit

Permalink
Add support for indexed arrays to ArraySubset
Browse files Browse the repository at this point in the history
  • Loading branch information
pfrenssen authored and sebastianbergmann committed Jun 7, 2018
1 parent 9b263ed commit 0a25ecb
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 12 deletions.
93 changes: 85 additions & 8 deletions src/Framework/Constraint/ArraySubset.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,28 +59,105 @@ public function __construct(iterable $subset, bool $strict = false)
*/
public function evaluate($other, $description = '', $returnResult = false)
{
// Anonymous function that checks whether the given array is
// associative.
$is_associative = function (array $array): bool {
return \array_reduce(\array_keys($array), function (bool $carry, $key): bool {
return $carry || \is_string($key);
}, false);
};

// Anonymous function that compares the two given values using either
// strict or loose comparisons.
$strict = $this->strict;
$compare = function ($first, $second) use ($strict): bool {
return $strict ? $first === $second : $first == $second;
};

// Anonymous function that sorts the given multidimensional array.
$deep_sort = function (array &$array) use (&$deep_sort, $is_associative): void {
foreach ($array as &$value) {
if (\is_array($value)) {
$deep_sort($value);
}
}

if ($is_associative($array)) {
\ksort($array);
} else {
\sort($array);
}
};

$array_intersect_recursive = function (array $array, array $subset) use (&$array_intersect_recursive, $is_associative, $compare): array {
$intersect = [];

if ($is_associative($subset)) {
// If the subset is an associative array, get the intersection
// while preserving the keys.
foreach ($subset as $key => $subset_value) {
if (\array_key_exists($key, $array)) {
$array_value = $array[$key];

if (\is_array($subset_value) && \is_array($array_value)) {
$intersect[$key] = $array_intersect_recursive($array_value, $subset_value);
} elseif ($compare($subset_value, $array_value)) {
$intersect[$key] = $array_value;
}
}
}
} else {
// If the subset is an indexed array, loop over all entries in
// the haystack and check if they match the ones in the subset.
foreach ($array as $array_value) {
if (\is_array($array_value)) {
foreach ($subset as $key => $subset_value) {
if (\is_array($subset_value)) {
$recursed = $array_intersect_recursive($array_value, $subset_value);

if (!empty($recursed)) {
$intersect[$key] = $recursed;
}
}
}
} else {
foreach ($subset as $key => $subset_value) {
if (!\is_array($subset_value) && $compare(
$subset_value,
$array_value
)) {
$intersect[$key] = $array_value;

break;
}
}
}
}
}

return $intersect;
};

//type cast $other & $this->subset as an array to allow
//support in standard array functions.
$other = $this->toArray($other);
$this->subset = $this->toArray($this->subset);

$patched = \array_replace_recursive($other, $this->subset);
$intersect = $array_intersect_recursive($other, $this->subset);
$deep_sort($intersect);
$deep_sort($this->subset);

if ($this->strict) {
$result = $other === $patched;
} else {
$result = $other == $patched;
}
$result = $compare($intersect, $this->subset);

if ($returnResult) {
return $result;
}

if (!$result) {
$f = new ComparisonFailure(
$patched,
$this->subset,
$other,
\print_r($patched, true),
\print_r($this->subset, true),
\print_r($other, true)
);

Expand Down
8 changes: 4 additions & 4 deletions tests/Framework/Constraint/ArraySubsetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public static function evaluateDataProvider()
'10',
],
'other' => [
0 => '1',
0 => '1',
'a' => [
'aa' => '2',
'ab' => [5, 4, 3],
Expand All @@ -113,7 +113,7 @@ public static function evaluateDataProvider()
'10',
],
'other' => [
0 => '1',
0 => '1',
'a' => [
'aa' => '2',
'ab' => [5, 4, 3],
Expand All @@ -130,7 +130,7 @@ public static function evaluateDataProvider()
'10',
],
'other' => new \ArrayObject([
0 => '1',
0 => '1',
'a' => [
'aa' => '2',
'ab' => [5, 4, 3],
Expand All @@ -147,7 +147,7 @@ public static function evaluateDataProvider()
'10',
]),
'other' => [
0 => '1',
0 => '1',
'a' => [
'aa' => '2',
'ab' => [5, 4, 3],
Expand Down

0 comments on commit 0a25ecb

Please sign in to comment.