From 0d46d205ae77a6a5b9da958418ebe1c38defbdb1 Mon Sep 17 00:00:00 2001 From: Erayd Date: Sat, 18 Mar 2017 08:33:38 +1300 Subject: [PATCH] Don't throw exceptions until after checking anyOf / oneOf Fixes #393 --- .../Constraints/UndefinedConstraint.php | 27 ++++++++---- tests/Constraints/OfPropertiesTest.php | 43 +++++++++++++++++++ 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/JsonSchema/Constraints/UndefinedConstraint.php b/src/JsonSchema/Constraints/UndefinedConstraint.php index 264a8d36..a03291da 100644 --- a/src/JsonSchema/Constraints/UndefinedConstraint.php +++ b/src/JsonSchema/Constraints/UndefinedConstraint.php @@ -12,6 +12,7 @@ use JsonSchema\ConstraintError; use JsonSchema\Constraints\TypeCheck\LooseTypeCheck; use JsonSchema\Entity\JsonPointer; +use JsonSchema\Exception\ValidationException; use JsonSchema\Uri\UriResolver; /** @@ -245,11 +246,16 @@ protected function validateOfProperties(&$value, $schema, JsonPointer $path, $i if (isset($schema->anyOf)) { $isValid = false; $startErrors = $this->getErrors(); + $caughtException = null; foreach ($schema->anyOf as $anyOf) { $initErrors = $this->getErrors(); - $this->checkUndefined($value, $anyOf, $path, $i); - if ($isValid = (count($this->getErrors()) == count($initErrors))) { - break; + try { + $this->checkUndefined($value, $anyOf, $path, $i); + if ($isValid = (count($this->getErrors()) == count($initErrors))) { + break; + } + } catch (ValidationException $e) { + $isValid = false; } } if (!$isValid) { @@ -264,12 +270,17 @@ protected function validateOfProperties(&$value, $schema, JsonPointer $path, $i $matchedSchemas = 0; $startErrors = $this->getErrors(); foreach ($schema->oneOf as $oneOf) { - $this->errors = array(); - $this->checkUndefined($value, $oneOf, $path, $i); - if (count($this->getErrors()) == 0) { - $matchedSchemas++; + try { + $this->errors = array(); + $this->checkUndefined($value, $oneOf, $path, $i); + if (count($this->getErrors()) == 0) { + $matchedSchemas++; + } + $allErrors = array_merge($allErrors, array_values($this->getErrors())); + } catch (ValidationException $e) { + // deliberately do nothing here - validation failed, but we want to check + // other schema options in the OneOf field. } - $allErrors = array_merge($allErrors, array_values($this->getErrors())); } if ($matchedSchemas !== 1) { $this->addErrors(array_merge($allErrors, $startErrors)); diff --git a/tests/Constraints/OfPropertiesTest.php b/tests/Constraints/OfPropertiesTest.php index 721195f5..f4fb8968 100644 --- a/tests/Constraints/OfPropertiesTest.php +++ b/tests/Constraints/OfPropertiesTest.php @@ -8,6 +8,9 @@ namespace JsonSchema\Tests\Constraints; +use JsonSchema\Constraints\Constraint; +use JsonSchema\Validator; + /** * Class OfPropertiesTest */ @@ -223,4 +226,44 @@ public function getInvalidTests() ) ); } + + public function testNoPrematureAnyOfException() + { + $schema = json_decode('{ + "type": "object", + "properties": { + "propertyOne": { + "anyOf": [ + {"type": "number"}, + {"type": "string"} + ] + } + } + }'); + $data = json_decode('{"propertyOne":"ABC"}'); + + $v = new Validator(); + $v->validate($data, $schema, Constraint::CHECK_MODE_EXCEPTIONS); + $this->assertTrue($v->isValid()); + } + + public function testNoPrematureOneOfException() + { + $schema = json_decode('{ + "type": "object", + "properties": { + "propertyOne": { + "oneOf": [ + {"type": "number"}, + {"type": "string"} + ] + } + } + }'); + $data = json_decode('{"propertyOne":"ABC"}'); + + $v = new Validator(); + $v->validate($data, $schema, Constraint::CHECK_MODE_EXCEPTIONS); + $this->assertTrue($v->isValid()); + } }