From 9db6594c36b868b57d948621394744c0e75c7d65 Mon Sep 17 00:00:00 2001 From: Martin Helmich Date: Tue, 17 Apr 2018 18:27:24 +0200 Subject: [PATCH 1/7] Add failing test cases --- tests/Constraints/ConstTest.php | 98 +++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 tests/Constraints/ConstTest.php diff --git a/tests/Constraints/ConstTest.php b/tests/Constraints/ConstTest.php new file mode 100644 index 00000000..cdd0409a --- /dev/null +++ b/tests/Constraints/ConstTest.php @@ -0,0 +1,98 @@ + Date: Tue, 17 Apr 2018 18:27:37 +0200 Subject: [PATCH 2/7] Implement ConstConstraint --- src/JsonSchema/ConstraintError.php | 2 + .../Constraints/ConstConstraint.php | 54 +++++++++++++++++++ src/JsonSchema/Constraints/Constraint.php | 16 ++++++ src/JsonSchema/Constraints/Factory.php | 1 + .../Constraints/UndefinedConstraint.php | 5 ++ 5 files changed, 78 insertions(+) create mode 100644 src/JsonSchema/Constraints/ConstConstraint.php diff --git a/src/JsonSchema/ConstraintError.php b/src/JsonSchema/ConstraintError.php index 45e9539a..b3dd9363 100644 --- a/src/JsonSchema/ConstraintError.php +++ b/src/JsonSchema/ConstraintError.php @@ -14,6 +14,7 @@ class ConstraintError extends Enum const DISALLOW = 'disallow'; const DIVISIBLE_BY = 'divisibleBy'; const ENUM = 'enum'; + const CONSTANT = 'const'; const EXCLUSIVE_MINIMUM = 'exclusiveMinimum'; const EXCLUSIVE_MAXIMUM = 'exclusiveMaximum'; const FORMAT_COLOR = 'colorFormat'; @@ -63,6 +64,7 @@ public function getMessage() self::DISALLOW => 'Disallowed value was matched', self::DIVISIBLE_BY => 'Is not divisible by %d', self::ENUM => 'Does not have a value in the enumeration %s', + self::CONSTANT => 'Does not have a value equal to %s', self::EXCLUSIVE_MINIMUM => 'Must have a minimum value greater than %d', self::EXCLUSIVE_MAXIMUM => 'Must have a maximum value less than %d', self::FORMAT_COLOR => 'Invalid color', diff --git a/src/JsonSchema/Constraints/ConstConstraint.php b/src/JsonSchema/Constraints/ConstConstraint.php new file mode 100644 index 00000000..a3ca1068 --- /dev/null +++ b/src/JsonSchema/Constraints/ConstConstraint.php @@ -0,0 +1,54 @@ + + */ +class ConstConstraint extends Constraint +{ + /** + * {@inheritdoc} + */ + public function check(&$element, $schema = null, JsonPointer $path = null, $i = null) + { + // Only validate const if the attribute exists + if ($element instanceof UndefinedConstraint && (!isset($schema->required) || !$schema->required)) { + return; + } + $const = $schema->const; + + $type = gettype($element); + $constType = gettype($const); + + if ($this->factory->getConfig(self::CHECK_MODE_TYPE_CAST) && $type == 'array' && $constType == 'object') { + if ((object) $element == $const) { + return; + } + } + + if ($type === gettype($const)) { + if ($type == 'object') { + if ($element == $const) { + return; + } + } elseif ($element === $const) { + return; + } + } + + $this->addError(ConstraintError::CONSTANT(), $path, array('const' => $schema->const)); + } +} diff --git a/src/JsonSchema/Constraints/Constraint.php b/src/JsonSchema/Constraints/Constraint.php index 51b5a98a..389e0f53 100644 --- a/src/JsonSchema/Constraints/Constraint.php +++ b/src/JsonSchema/Constraints/Constraint.php @@ -169,6 +169,22 @@ protected function checkEnum($value, $schema = null, JsonPointer $path = null, $ $this->addErrors($validator->getErrors()); } + /** + * Checks a const element + * + * @param mixed $value + * @param mixed $schema + * @param JsonPointer|null $path + * @param mixed $i + */ + protected function checkConst($value, $schema = null, JsonPointer $path = null, $i = null) + { + $validator = $this->factory->createInstanceFor('const'); + $validator->check($value, $schema, $path, $i); + + $this->addErrors($validator->getErrors()); + } + /** * Checks format of an element * diff --git a/src/JsonSchema/Constraints/Factory.php b/src/JsonSchema/Constraints/Factory.php index 4e771c19..9c0f4f21 100644 --- a/src/JsonSchema/Constraints/Factory.php +++ b/src/JsonSchema/Constraints/Factory.php @@ -58,6 +58,7 @@ class Factory 'string' => 'JsonSchema\Constraints\StringConstraint', 'number' => 'JsonSchema\Constraints\NumberConstraint', 'enum' => 'JsonSchema\Constraints\EnumConstraint', + 'const' => 'JsonSchema\Constraints\ConstConstraint', 'format' => 'JsonSchema\Constraints\FormatConstraint', 'schema' => 'JsonSchema\Constraints\SchemaConstraint', 'validator' => 'JsonSchema\Validator' diff --git a/src/JsonSchema/Constraints/UndefinedConstraint.php b/src/JsonSchema/Constraints/UndefinedConstraint.php index 3b0c8eb0..02f14c0b 100644 --- a/src/JsonSchema/Constraints/UndefinedConstraint.php +++ b/src/JsonSchema/Constraints/UndefinedConstraint.php @@ -96,6 +96,11 @@ public function validateTypes(&$value, $schema = null, JsonPointer $path, $i = n if (isset($schema->enum)) { $this->checkEnum($value, $schema, $path, $i); } + + // check const + if (isset($schema->const)) { + $this->checkConst($value, $schema, $path, $i); + } } /** From 789c97e305ab1ab92fbd4edc0c66890b88369cb3 Mon Sep 17 00:00:00 2001 From: Martin Helmich Date: Tue, 17 Apr 2018 21:24:22 +0200 Subject: [PATCH 3/7] Add test cases for coercive mode --- tests/Constraints/CoerciveTest.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/Constraints/CoerciveTest.php b/tests/Constraints/CoerciveTest.php index 8d58a58d..d09b33f7 100644 --- a/tests/Constraints/CoerciveTest.php +++ b/tests/Constraints/CoerciveTest.php @@ -130,7 +130,20 @@ public function dataCoerceCases() 'string', 'integer', 42, true ); - $tests = array(); + // #46 check coercion with "const" + $tests[] = array( + '{"properties":{"propertyOne":{"type":"string","const":"42"}}}', + '{"propertyOne":42}', + 'integer', 'string', "42", true + ); + + // #46 check coercion with "const" + $tests[] = array( + '{"properties":{"propertyOne":{"type":"number","const":42}}}', + '{"propertyOne":"42"}', + 'string', 'integer', 42, true + ); + foreach ($types as $toType => $testCases) { foreach ($testCases as $testCase) { $tests[] = array( From 1b94558b42402a51700b0ac7cf9a5e88f11fe6c5 Mon Sep 17 00:00:00 2001 From: Martin Helmich Date: Tue, 17 Apr 2018 21:28:55 +0200 Subject: [PATCH 4/7] Fix counting --- tests/Constraints/CoerciveTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Constraints/CoerciveTest.php b/tests/Constraints/CoerciveTest.php index d09b33f7..221d672c 100644 --- a/tests/Constraints/CoerciveTest.php +++ b/tests/Constraints/CoerciveTest.php @@ -137,7 +137,7 @@ public function dataCoerceCases() 'integer', 'string', "42", true ); - // #46 check coercion with "const" + // #47 check coercion with "const" $tests[] = array( '{"properties":{"propertyOne":{"type":"number","const":42}}}', '{"propertyOne":"42"}', From 8c3ee91d3fa0c5a0786b89cab5bc18d48be77dc7 Mon Sep 17 00:00:00 2001 From: Martin Helmich Date: Tue, 17 Apr 2018 21:30:47 +0200 Subject: [PATCH 5/7] Fix coding style --- tests/Constraints/CoerciveTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Constraints/CoerciveTest.php b/tests/Constraints/CoerciveTest.php index 221d672c..6920190e 100644 --- a/tests/Constraints/CoerciveTest.php +++ b/tests/Constraints/CoerciveTest.php @@ -134,7 +134,7 @@ public function dataCoerceCases() $tests[] = array( '{"properties":{"propertyOne":{"type":"string","const":"42"}}}', '{"propertyOne":42}', - 'integer', 'string', "42", true + 'integer', 'string', '42', true ); // #47 check coercion with "const" From 853eb09bdc350c02a4b69511f8c09745e13c4027 Mon Sep 17 00:00:00 2001 From: Martin Helmich Date: Tue, 17 Apr 2018 21:42:34 +0200 Subject: [PATCH 6/7] Add tests for boolean coercion --- tests/Constraints/CoerciveTest.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/Constraints/CoerciveTest.php b/tests/Constraints/CoerciveTest.php index 6920190e..004a4434 100644 --- a/tests/Constraints/CoerciveTest.php +++ b/tests/Constraints/CoerciveTest.php @@ -144,6 +144,27 @@ public function dataCoerceCases() 'string', 'integer', 42, true ); + // #48 check boolean coercion with "const" + $tests[] = array( + '{"properties":{"propertyOne":{"type":"boolean","const":false}}}', + '{"propertyOne":"false"}', + 'string', 'boolean', false, true + ); + + // #49 check boolean coercion with "const" + $tests[] = array( + '{"properties":{"propertyOne":{"type":"boolean","const":true}}}', + '{"propertyOne":"true"}', + 'string', 'boolean', true, true + ); + + // #50 check boolean coercion with "const" + $tests[] = array( + '{"properties":{"propertyOne":{"type":"boolean","const":true}}}', + '{"propertyOne":1}', + 'integer', 'boolean', true, true + ); + foreach ($types as $toType => $testCases) { foreach ($testCases as $testCase) { $tests[] = array( From 8a9cd120985686ea994a3dbb6d74a7967c99fa04 Mon Sep 17 00:00:00 2001 From: Martin Helmich Date: Tue, 17 Apr 2018 21:52:28 +0200 Subject: [PATCH 7/7] Tests all the things! --- tests/Constraints/CoerciveTest.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/Constraints/CoerciveTest.php b/tests/Constraints/CoerciveTest.php index 004a4434..587f1f99 100644 --- a/tests/Constraints/CoerciveTest.php +++ b/tests/Constraints/CoerciveTest.php @@ -165,6 +165,13 @@ public function dataCoerceCases() 'integer', 'boolean', true, true ); + // #51 check boolean coercion with "const" + $tests[] = array( + '{"properties":{"propertyOne":{"type":"boolean","const":false}}}', + '{"propertyOne":"false"}', + 'string', 'boolean', false, true + ); + foreach ($types as $toType => $testCases) { foreach ($testCases as $testCase) { $tests[] = array(