diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -499,6 +499,7 @@ 'array_mergev' => 'utils/utils.php', 'array_select_keys' => 'utils/utils.php', 'assert_instances_of' => 'utils/utils.php', + 'assert_same_keys' => 'utils/utils.php', 'assert_stringlike' => 'utils/utils.php', 'coalesce' => 'utils/utils.php', 'csprintf' => 'xsprintf/csprintf.php', diff --git a/src/utils/__tests__/PhutilUtilsTestCase.php b/src/utils/__tests__/PhutilUtilsTestCase.php --- a/src/utils/__tests__/PhutilUtilsTestCase.php +++ b/src/utils/__tests__/PhutilUtilsTestCase.php @@ -231,6 +231,37 @@ 'InvalidArgumentException'); } + public function testAssertSameKeys() { + $cases = array( + array(true, array(), array()), + array(true, array(0), array(1)), + + array(false, array(0), array()), + array(false, array(), array(0)), + + array(false, array('a' => 1), array('b' => 1)), + + // Make sure "null" values survive "isset()" tests. + array(true, array('a' => 1), array('a' => null)), + + // Key order should not matter. + array(true, array('a' => 1, 'b' => 1), array('b' => 1, 'a' => 1)), + ); + + foreach ($cases as $case) { + list($same_keys, $expect, $input) = $case; + + $caught = null; + try { + assert_same_keys($expect, $input); + } catch (InvalidArgumentException $ex) { + $caught = $ex; + } + + $this->assertEqual($same_keys, ($caught === null)); + } + } + public function testAssertStringLike() { $this->assertEqual( null, diff --git a/src/utils/utils.php b/src/utils/utils.php --- a/src/utils/utils.php +++ b/src/utils/utils.php @@ -629,6 +629,38 @@ return $arr; } +/** + * Assert that two arrays have the exact same keys, in any order. + * + * @param map Array with expected keys. + * @param map Array with actual keys. + * @return void + */ +function assert_same_keys(array $expect, array $actual) { + foreach ($expect as $key => $value) { + if (isset($actual[$key]) || array_key_exists($key, $actual)) { + continue; + } + + throw new InvalidArgumentException( + pht( + 'Expected to find key "%s", but it is not present.', + $key)); + + } + + foreach ($actual as $key => $value) { + if (isset($expect[$key]) || array_key_exists($key, $expect)) { + continue; + } + + throw new InvalidArgumentException( + pht( + 'Found unexpected surplus key "%s" where no such key was expected.', + $key)); + } +} + /** * Assert that passed data can be converted to string. *