0

Some of my PHPUnit tests call the Facebook "php-business-sdk" so that I can be confident that Facebook's API is continuing to operate as I expect. E.g. getInsights() within FacebookAds\Object\Ad.

And those PHPUnit tests have been using assertEqualsCanonicalizing.

However, the tests are still brittle; Facebook's API often changes not just the order of the top-level array in the result (an array of associative arrays) but also the order of the keys inside the associative arrays.

So what I really need is a version of assertEqualsCanonicalizing that is recursive and agnostic to the sorting of the keys of the associative arrays within that top-level array too.

I'd rather not code my own if such a function already exists (maybe in PHP, PHPUnit, Laravel, or elsewhere). Does it?

P.S. Here is a simplified example of a result:

[
  {
    "Spend": "$3,009",
    "Campaign ID": 3335626793661,
    "Reach": 37640,
    "Unique Inline Link Clicks": 2368
  },
  {
    "Spend": "$1,030",
    "Campaign ID": 3335626793662,
    "Reach": 1620,
    "Unique Inline Link Clicks": 231
  }
]

(Imagine next time the API returns the same data but with "Reach" being written before "Spend", and the order of the objects can change too.)

P.S. This is not a duplicate of the linked question because I'm specifically asking how to be agnostic of the sorting order of the inner array keys.

2
  • Possible duplicate of PHPUnit: assert two arrays are equal, but order of elements not important Commented Jul 12, 2019 at 14:34
  • @MohammedYassineCHABLI I updated my question to show how it's not a duplicate, and I also provided an answer. How can I now remove the warning about it being a possible duplicate? Or can you change your vote? Commented Jul 12, 2019 at 22:06

2 Answers 2

1

There isn't a native method for in_array which works recursively.

But many people have solved this issue with a helper like this one:

    private function in_array_recursive($needle, $haystack, $strict = true)
    {
        foreach ($haystack as $value) {
            if (($strict ? $value === $needle : $value == $needle) || (is_array($value) && $this->in_array_recursive($needle, $value, $strict))) {
                return true;
            }
        }
        return false;
    }
Sign up to request clarification or add additional context in comments.

Comments

0

Until someone shows an existing native function or something better than this, this is what seems to work for my purposes:

/**
 * @see https://stackoverflow.com/q/57008999/470749
 *
 * @param array $expected
 * @param array $actual
 */
public function assertEqualsCanonicalizingInner($expected, $actual) {
    try {
        $this->assertEqualsCanonicalizing(AT::sortInnerArrays($expected), AT::sortInnerArrays($actual));
    } catch (\Exception $e) {
        $expectedSortedJson = json_encode(AT::sortInnerArrays($expected));
        $actualSortedJson = json_encode(AT::sortInnerArrays($actual));
        $this->assertTrue(false, __FUNCTION__ . ' failed: ' . PHP_EOL . $expectedSortedJson . PHP_EOL . ' vs ' . PHP_EOL . $actualSortedJson);
    }
}

/**
 * @see https://stackoverflow.com/q/57008999/470749
 * 
 * @param array $arr
 * @return array
 */
public static function sortInnerArrays($arr) {
    $resultingOuterArr = [];
    foreach ($arr as $k => $v) {
        if (is_array($v)) {
            foreach ($v as $kInner => $vInner) {
                if (is_array($vInner)) {
                    $v[$kInner] = self::sortInnerArrays($vInner);
                }
            }
            ksort($v);
        }
        $resultingOuterArr[$k] = $v;
    }
    sort($resultingOuterArr);
    return $resultingOuterArr;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.