From 5a63b4db3083c8216fbf3e3397cdfc130f90ba9d Mon Sep 17 00:00:00 2001 From: Danny van der Sluijs Date: Fri, 7 Mar 2025 15:15:08 +0100 Subject: [PATCH 1/3] refactor: replace icecase/parity with custom deep comparator https://github.com/jsonrainbow/json-schema/issues/753 --- composer.json | 3 +- .../Constraints/ConstConstraint.php | 8 +- src/JsonSchema/Constraints/EnumConstraint.php | 9 +- src/JsonSchema/Tool/DeepComparer.php | 53 +++++++++++ tests/Tool/DeepComparerTest.php | 95 +++++++++++++++++++ 5 files changed, 158 insertions(+), 10 deletions(-) create mode 100644 src/JsonSchema/Tool/DeepComparer.php create mode 100644 tests/Tool/DeepComparerTest.php diff --git a/composer.json b/composer.json index 0befa020..8229d635 100644 --- a/composer.json +++ b/composer.json @@ -29,8 +29,7 @@ "require": { "php": "^7.2 || ^8.0", "ext-json": "*", - "marc-mabe/php-enum":"^4.0", - "icecave/parity": "^3.0" + "marc-mabe/php-enum":"^4.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "3.3.0", diff --git a/src/JsonSchema/Constraints/ConstConstraint.php b/src/JsonSchema/Constraints/ConstConstraint.php index 6e3a14bc..b9bb1f48 100644 --- a/src/JsonSchema/Constraints/ConstConstraint.php +++ b/src/JsonSchema/Constraints/ConstConstraint.php @@ -11,9 +11,9 @@ namespace JsonSchema\Constraints; -use Icecave\Parity\Parity; use JsonSchema\ConstraintError; use JsonSchema\Entity\JsonPointer; +use JsonSchema\Tool\DeepComparer; /** * The ConstConstraint Constraints, validates an element against a constant value @@ -36,13 +36,13 @@ public function check(&$element, $schema = null, ?JsonPointer $path = null, $i = $type = gettype($element); $constType = gettype($const); - if ($this->factory->getConfig(self::CHECK_MODE_TYPE_CAST) && $type == 'array' && $constType == 'object') { - if (Parity::isEqualTo((object) $element, $const)) { + if ($this->factory->getConfig(self::CHECK_MODE_TYPE_CAST) && $type === 'array' && $constType === 'object') { + if (DeepComparer::isEqual((object) $element, $const)) { return; } } - if (Parity::isEqualTo($element, $const)) { + if (DeepComparer::isEqual($element, $const)) { return; } diff --git a/src/JsonSchema/Constraints/EnumConstraint.php b/src/JsonSchema/Constraints/EnumConstraint.php index 1f30fadf..ce3853d6 100644 --- a/src/JsonSchema/Constraints/EnumConstraint.php +++ b/src/JsonSchema/Constraints/EnumConstraint.php @@ -11,9 +11,9 @@ namespace JsonSchema\Constraints; -use Icecave\Parity\Parity; use JsonSchema\ConstraintError; use JsonSchema\Entity\JsonPointer; +use JsonSchema\Tool\DeepComparer; /** * The EnumConstraint Constraints, validates an element against a given set of possibilities @@ -36,14 +36,15 @@ public function check(&$element, $schema = null, ?JsonPointer $path = null, $i = foreach ($schema->enum as $enum) { $enumType = gettype($enum); - if ($this->factory->getConfig(self::CHECK_MODE_TYPE_CAST) && $type == 'array' && $enumType == 'object') { - if (Parity::isEqualTo((object) $element, $enum)) { + + if ($this->factory->getConfig(self::CHECK_MODE_TYPE_CAST) && $type === 'array' && $enumType === 'object') { + if (DeepComparer::isEqual((object) $element, $enum)) { return; } } if ($type === gettype($enum)) { - if (Parity::isEqualTo($element, $enum)) { + if (DeepComparer::isEqual($element, $enum)) { return; } } diff --git a/src/JsonSchema/Tool/DeepComparer.php b/src/JsonSchema/Tool/DeepComparer.php new file mode 100644 index 00000000..3965af48 --- /dev/null +++ b/src/JsonSchema/Tool/DeepComparer.php @@ -0,0 +1,53 @@ + $value) { + if (!array_key_exists($key, $right)) { + return false; + } + + if (!self::isEqual($value, $right[$key])) { + return false; + } + } + + return true; + } + +} diff --git a/tests/Tool/DeepComparerTest.php b/tests/Tool/DeepComparerTest.php new file mode 100644 index 00000000..1299fc63 --- /dev/null +++ b/tests/Tool/DeepComparerTest.php @@ -0,0 +1,95 @@ + [true, true]; + yield 'Boolean false' => [false, false]; + + yield 'Integer one' => [1, 1]; + yield 'Integer INT MIN' => [PHP_INT_MIN, PHP_INT_MIN]; + yield 'Integer INT MAX' => [PHP_INT_MAX, PHP_INT_MAX]; + + yield 'Float PI' => [M_PI, M_PI]; + + yield 'String' => ['hello world!', 'hello world!']; + + yield 'array of integer' => [[1, 2, 3], [1, 2, 3]]; + yield 'object of integer' => [(object) [1, 2, 3], (object) [1, 2, 3]]; + + yield 'nested objects of integers' => [ + (object) [1 => (object) range(1, 10), 2 => (object) range(50, 60)], + (object) [1 => (object) range(1, 10), 2 => (object) range(50, 60)], + ]; + } + + public function notEqualDataProvider(): \Generator + { + yield 'Boolean true/false' => [true, false]; + + yield 'Integer one/two' => [1, 2]; + yield 'Integer INT MIN/MAX' => [PHP_INT_MIN, PHP_INT_MAX]; + + yield 'Float PI/' => [M_PI, M_E]; + + yield 'String' => ['hello world!', 'hell0 w0rld!']; + + yield 'array of integer with smaller left side' => [[1, 3], [1, 2, 3]]; + yield 'array of integer with smaller right side' => [[1, 2, 3], [1, 3]]; + yield 'object of integer with smaller left side' => [(object) [1, 3], (object) [1, 2, 3]]; + yield 'object of integer with smaller right side' => [(object) [1, 2, 3], (object) [1, 3]]; + + yield 'nested objects of integers with different left hand side' => [ + (object) [1 => (object) range(1, 10), 2 => (object) range(50, 60, 2)], + (object) [1 => (object) range(1, 10), 2 => (object) range(50, 60)], + ]; + yield 'nested objects of integers with different right hand side' => [ + (object) [1 => (object) range(1, 10), 2 => (object) range(50, 60)], + (object) [1 => (object) range(1, 10), 2 => (object) range(50, 60, 2)], + ]; + + $options = [ + 'boolean' => true, + 'integer' => 42, + 'float' => M_PI, + 'string' => 'hello world!', + 'array' => [1, 2, 3], + 'object' => (object) [1, 2, 3], + ]; + + foreach ($options as $leftType => $leftValue) { + foreach ($options as $rightType => $rightValue) { + if ($leftType === $rightType) { + continue; + } + + yield sprintf('%s vs. %s', $leftType, $rightType) => [$leftValue, $rightValue]; + } + } + } + +} From 0a8408661b5293726d63e3fbaef695cae5712396 Mon Sep 17 00:00:00 2001 From: Danny van der Sluijs Date: Fri, 7 Mar 2025 15:20:10 +0100 Subject: [PATCH 2/3] style: correct code style violations --- src/JsonSchema/Tool/DeepComparer.php | 11 ++++++++--- tests/Tool/DeepComparerTest.php | 1 - 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/JsonSchema/Tool/DeepComparer.php b/src/JsonSchema/Tool/DeepComparer.php index 3965af48..70b16ef0 100644 --- a/src/JsonSchema/Tool/DeepComparer.php +++ b/src/JsonSchema/Tool/DeepComparer.php @@ -4,10 +4,12 @@ namespace JsonSchema\Tool; -use phpDocumentor\Reflection\Types\True_; - class DeepComparer { + /** + * @param mixed $left + * @param mixed $right + */ public static function isEqual($left, $right): bool { $isLeftScalar = is_scalar($left); @@ -32,6 +34,10 @@ public static function isEqual($left, $right): bool return false; } + /** + * @param array $left + * @param array $right + */ private static function isArrayEqual(array $left, array $right): bool { if (count($left) !== count($right)) { @@ -49,5 +55,4 @@ private static function isArrayEqual(array $left, array $right): bool return true; } - } diff --git a/tests/Tool/DeepComparerTest.php b/tests/Tool/DeepComparerTest.php index 1299fc63..112ace66 100644 --- a/tests/Tool/DeepComparerTest.php +++ b/tests/Tool/DeepComparerTest.php @@ -91,5 +91,4 @@ public function notEqualDataProvider(): \Generator } } } - } From 09e34b739fceb7f6432fea62f6c4dd8e38066bf7 Mon Sep 17 00:00:00 2001 From: Danny van der Sluijs Date: Fri, 14 Mar 2025 12:49:53 +0100 Subject: [PATCH 3/3] docs: add changelog entry --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 031eb1df..fdc62e5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - only check minProperties or maxProperties on objects ([#802](https://github.com/jsonrainbow/json-schema/pull/802)) - replace filter_var for uri and uri-reference to userland code to be RFC 3986 compliant ([#800](https://github.com/jsonrainbow/json-schema/pull/800)) +## Changed +- replace icecave/parity with custom deep comparator ([#803](https://github.com/jsonrainbow/json-schema/pull/803)) +- ## [6.2.1] - 2025-03-06 ### Fixed - allow items: true to pass validation ([#801](https://github.com/jsonrainbow/json-schema/pull/801))