diff --git a/src/JsonSchema/Constraints/CollectionConstraint.php b/src/JsonSchema/Constraints/CollectionConstraint.php index 93e0ab7b..1b1554aa 100644 --- a/src/JsonSchema/Constraints/CollectionConstraint.php +++ b/src/JsonSchema/Constraints/CollectionConstraint.php @@ -9,6 +9,8 @@ namespace JsonSchema\Constraints; +use JsonSchema\Entity\JsonPointer; + /** * The CollectionConstraint Constraints, validates an array against a given schema * @@ -20,7 +22,7 @@ class CollectionConstraint extends Constraint /** * {@inheritDoc} */ - public function check($value, $schema = null, $path = null, $i = null) + public function check($value, $schema = null, JsonPointer $path = null, $i = null) { // Verify minItems if (isset($schema->minItems) && count($value) < $schema->minItems) { @@ -52,12 +54,12 @@ public function check($value, $schema = null, $path = null, $i = null) /** * Validates the items * - * @param array $value - * @param \stdClass $schema - * @param string $path - * @param string $i + * @param array $value + * @param \stdClass $schema + * @param JsonPointer|null $path + * @param string $i */ - protected function validateItems($value, $schema = null, $path = null, $i = null) + protected function validateItems($value, $schema = null, JsonPointer $path = null, $i = null) { if (is_object($schema->items)) { // just one type definition for the whole array diff --git a/src/JsonSchema/Constraints/Constraint.php b/src/JsonSchema/Constraints/Constraint.php index fbf7f6ae..a56acbb4 100644 --- a/src/JsonSchema/Constraints/Constraint.php +++ b/src/JsonSchema/Constraints/Constraint.php @@ -11,6 +11,7 @@ use JsonSchema\Uri\UriRetriever; use JsonSchema\Validator; +use JsonSchema\Entity\JsonPointer; /** * The Base Constraints, all Validators should extend this class @@ -80,10 +81,11 @@ public function setUriRetriever(UriRetriever $uriRetriever) /** * {@inheritDoc} */ - public function addError($path, $message, $constraint='', array $more=null) + public function addError(JsonPointer $path = null, $message, $constraint='', array $more=null) { $error = array( - 'property' => $path, + 'property' => $this->convertJsonPointerIntoPropertyPath($path ?: new JsonPointer('')), + 'pointer' => ltrim(strval($path ?: new JsonPointer('')), '#'), 'message' => $message, 'constraint' => $constraint, ); @@ -132,37 +134,32 @@ public function reset() /** * Bubble down the path * - * @param string $path Current path - * @param mixed $i What to append to the path + * @param JsonPointer|null $path Current path + * @param mixed $i What to append to the path * - * @return string + * @return JsonPointer; */ - protected function incrementPath($path, $i) + protected function incrementPath(JsonPointer $path = null, $i) { - if ($path !== '') { - if (is_int($i)) { - $path .= '[' . $i . ']'; - } elseif ($i == '') { - $path .= ''; - } else { - $path .= '.' . $i; - } - } else { - $path = $i; - } - + $path = $path ?: new JsonPointer(''); + $path = $path->withPropertyPaths( + array_merge( + $path->getPropertyPaths(), + array_filter(array($i), 'strlen') + ) + ); return $path; } /** * Validates an array * - * @param mixed $value - * @param mixed $schema - * @param mixed $path - * @param mixed $i + * @param mixed $value + * @param mixed $schema + * @param JsonPointer|null $path + * @param mixed $i */ - protected function checkArray($value, $schema = null, $path = null, $i = null) + protected function checkArray($value, $schema = null, JsonPointer $path = null, $i = null) { $validator = $this->getFactory()->createInstanceFor('collection'); $validator->check($value, $schema, $path, $i); @@ -173,13 +170,13 @@ protected function checkArray($value, $schema = null, $path = null, $i = null) /** * Validates an object * - * @param mixed $value - * @param mixed $schema - * @param mixed $path - * @param mixed $i - * @param mixed $patternProperties + * @param mixed $value + * @param mixed $schema + * @param JsonPointer|null $path + * @param mixed $i + * @param mixed $patternProperties */ - protected function checkObject($value, $schema = null, $path = null, $i = null, $patternProperties = null) + protected function checkObject($value, $schema = null, JsonPointer $path = null, $i = null, $patternProperties = null) { $validator = $this->getFactory()->createInstanceFor('object'); $validator->check($value, $schema, $path, $i, $patternProperties); @@ -190,12 +187,12 @@ protected function checkObject($value, $schema = null, $path = null, $i = null, /** * Validates the type of a property * - * @param mixed $value - * @param mixed $schema - * @param mixed $path - * @param mixed $i + * @param mixed $value + * @param mixed $schema + * @param JsonPointer|null $path + * @param mixed $i */ - protected function checkType($value, $schema = null, $path = null, $i = null) + protected function checkType($value, $schema = null, JsonPointer $path = null, $i = null) { $validator = $this->getFactory()->createInstanceFor('type'); $validator->check($value, $schema, $path, $i); @@ -206,12 +203,12 @@ protected function checkType($value, $schema = null, $path = null, $i = null) /** * Checks a undefined element * - * @param mixed $value - * @param mixed $schema - * @param mixed $path - * @param mixed $i + * @param mixed $value + * @param mixed $schema + * @param JsonPointer|null $path + * @param mixed $i */ - protected function checkUndefined($value, $schema = null, $path = null, $i = null) + protected function checkUndefined($value, $schema = null, JsonPointer $path = null, $i = null) { $validator = $this->getFactory()->createInstanceFor('undefined'); $validator->check($value, $schema, $path, $i); @@ -222,12 +219,12 @@ protected function checkUndefined($value, $schema = null, $path = null, $i = nul /** * Checks a string element * - * @param mixed $value - * @param mixed $schema - * @param mixed $path - * @param mixed $i + * @param mixed $value + * @param mixed $schema + * @param JsonPointer|null $path + * @param mixed $i */ - protected function checkString($value, $schema = null, $path = null, $i = null) + protected function checkString($value, $schema = null, JsonPointer $path = null, $i = null) { $validator = $this->getFactory()->createInstanceFor('string'); $validator->check($value, $schema, $path, $i); @@ -238,12 +235,12 @@ protected function checkString($value, $schema = null, $path = null, $i = null) /** * Checks a number element * - * @param mixed $value - * @param mixed $schema - * @param mixed $path - * @param mixed $i + * @param mixed $value + * @param mixed $schema + * @param JsonPointer $path + * @param mixed $i */ - protected function checkNumber($value, $schema = null, $path = null, $i = null) + protected function checkNumber($value, $schema = null, JsonPointer $path = null, $i = null) { $validator = $this->getFactory()->createInstanceFor('number'); $validator->check($value, $schema, $path, $i); @@ -254,12 +251,12 @@ protected function checkNumber($value, $schema = null, $path = null, $i = null) /** * Checks a enum element * - * @param mixed $value - * @param mixed $schema - * @param mixed $path - * @param mixed $i + * @param mixed $value + * @param mixed $schema + * @param JsonPointer|null $path + * @param mixed $i */ - protected function checkEnum($value, $schema = null, $path = null, $i = null) + protected function checkEnum($value, $schema = null, JsonPointer $path = null, $i = null) { $validator = $this->getFactory()->createInstanceFor('enum'); $validator->check($value, $schema, $path, $i); @@ -267,7 +264,15 @@ protected function checkEnum($value, $schema = null, $path = null, $i = null) $this->addErrors($validator->getErrors()); } - protected function checkFormat($value, $schema = null, $path = null, $i = null) + /** + * Checks format of an element + * + * @param mixed $value + * @param mixed $schema + * @param JsonPointer|null $path + * @param mixed $i + */ + protected function checkFormat($value, $schema = null, JsonPointer $path = null, $i = null) { $validator = $this->getFactory()->createInstanceFor('format'); $validator->check($value, $schema, $path, $i); @@ -298,4 +303,19 @@ protected function getTypeCheck() { return $this->getFactory()->getTypeCheck(); } + + /** + * @param JsonPointer $pointer + * @return string property path + */ + protected function convertJsonPointerIntoPropertyPath(JsonPointer $pointer) + { + $result = array_map( + function($path) { + return sprintf(is_numeric($path) ? '[%d]' : '.%s', $path); + }, + $pointer->getPropertyPaths() + ); + return trim(implode('', $result), '.'); + } } diff --git a/src/JsonSchema/Constraints/ConstraintInterface.php b/src/JsonSchema/Constraints/ConstraintInterface.php index d89a46e5..ca123639 100644 --- a/src/JsonSchema/Constraints/ConstraintInterface.php +++ b/src/JsonSchema/Constraints/ConstraintInterface.php @@ -9,6 +9,8 @@ namespace JsonSchema\Constraints; +use JsonSchema\Entity\JsonPointer; + /** * The Constraints Interface * @@ -33,12 +35,12 @@ public function addErrors(array $errors); /** * adds an error * - * @param string $path - * @param string $message - * @param string $constraint the constraint/rule that is broken, e.g.: 'minLength' - * @param array $more more array elements to add to the error + * @param JsonPointer|null $path + * @param string $message + * @param string $constraint the constraint/rule that is broken, e.g.: 'minLength' + * @param array $more more array elements to add to the error */ - public function addError($path, $message, $constraint='', array $more=null); + public function addError(JsonPointer $path = null, $message, $constraint='', array $more=null); /** * checks if the validator has not raised errors @@ -51,11 +53,11 @@ public function isValid(); * invokes the validation of an element * * @abstract - * @param mixed $value - * @param mixed $schema - * @param mixed $path - * @param mixed $i + * @param mixed $value + * @param mixed $schema + * @param JsonPointer|null $path + * @param mixed $i * @throws \JsonSchema\Exception\ExceptionInterface */ - public function check($value, $schema = null, $path = null, $i = null); + public function check($value, $schema = null, JsonPointer $path = null, $i = null); } \ No newline at end of file diff --git a/src/JsonSchema/Constraints/EnumConstraint.php b/src/JsonSchema/Constraints/EnumConstraint.php index 79ce3db3..69fd0308 100644 --- a/src/JsonSchema/Constraints/EnumConstraint.php +++ b/src/JsonSchema/Constraints/EnumConstraint.php @@ -9,6 +9,7 @@ namespace JsonSchema\Constraints; use JsonSchema\Validator; +use JsonSchema\Entity\JsonPointer; /** * The EnumConstraint Constraints, validates an element against a given set of possibilities @@ -21,7 +22,7 @@ class EnumConstraint extends Constraint /** * {@inheritDoc} */ - public function check($element, $schema = null, $path = null, $i = null) + public function check($element, $schema = null, JsonPointer $path = null, $i = null) { // Only validate enum if the attribute exists if ($element instanceof UndefinedConstraint && (!isset($schema->required) || !$schema->required)) { diff --git a/src/JsonSchema/Constraints/FormatConstraint.php b/src/JsonSchema/Constraints/FormatConstraint.php index 8843dd61..05d6de99 100644 --- a/src/JsonSchema/Constraints/FormatConstraint.php +++ b/src/JsonSchema/Constraints/FormatConstraint.php @@ -8,7 +8,9 @@ */ namespace JsonSchema\Constraints; + use JsonSchema\Rfc3339; +use JsonSchema\Entity\JsonPointer; /** * Validates against the "format" property @@ -21,7 +23,7 @@ class FormatConstraint extends Constraint /** * {@inheritDoc} */ - public function check($element, $schema = null, $path = null, $i = null) + public function check($element, $schema = null, JsonPointer $path = null, $i = null) { if (!isset($schema->format)) { return; diff --git a/src/JsonSchema/Constraints/NumberConstraint.php b/src/JsonSchema/Constraints/NumberConstraint.php index 7b359921..601b86a0 100644 --- a/src/JsonSchema/Constraints/NumberConstraint.php +++ b/src/JsonSchema/Constraints/NumberConstraint.php @@ -9,6 +9,8 @@ namespace JsonSchema\Constraints; +use JsonSchema\Entity\JsonPointer; + /** * The NumberConstraint Constraints, validates an number against a given schema * @@ -20,7 +22,7 @@ class NumberConstraint extends Constraint /** * {@inheritDoc} */ - public function check($element, $schema = null, $path = null, $i = null) + public function check($element, $schema = null, JsonPointer $path = null, $i = null) { // Verify minimum if (isset($schema->exclusiveMinimum)) { diff --git a/src/JsonSchema/Constraints/ObjectConstraint.php b/src/JsonSchema/Constraints/ObjectConstraint.php index 73af5177..f9733971 100644 --- a/src/JsonSchema/Constraints/ObjectConstraint.php +++ b/src/JsonSchema/Constraints/ObjectConstraint.php @@ -9,6 +9,8 @@ namespace JsonSchema\Constraints; +use JsonSchema\Entity\JsonPointer; + /** * The ObjectConstraint Constraints, validates an object against a given schema * @@ -20,7 +22,7 @@ class ObjectConstraint extends Constraint /** * {@inheritDoc} */ - public function check($element, $definition = null, $path = null, $additionalProp = null, $patternProperties = null) + public function check($element, $definition = null, JsonPointer $path = null, $additionalProp = null, $patternProperties = null) { if ($element instanceof UndefinedConstraint) { return; @@ -40,7 +42,7 @@ public function check($element, $definition = null, $path = null, $additionalPro $this->validateElement($element, $matches, $definition, $path, $additionalProp); } - public function validatePatternProperties($element, $path, $patternProperties) + public function validatePatternProperties($element, JsonPointer $path = null, $patternProperties) { $try = array('/','#','+','~','%'); $matches = array(); @@ -71,13 +73,13 @@ public function validatePatternProperties($element, $path, $patternProperties) /** * Validates the element properties * - * @param \stdClass $element Element to validate - * @param array $matches Matches from patternProperties (if any) - * @param \stdClass $objectDefinition ObjectConstraint definition - * @param string $path Path to test? - * @param mixed $additionalProp Additional properties + * @param \stdClass $element Element to validate + * @param array $matches Matches from patternProperties (if any) + * @param \stdClass $objectDefinition ObjectConstraint definition + * @param JsonPointer|null $path Path to test? + * @param mixed $additionalProp Additional properties */ - public function validateElement($element, $matches, $objectDefinition = null, $path = null, $additionalProp = null) + public function validateElement($element, $matches, $objectDefinition = null, JsonPointer $path = null, $additionalProp = null) { $this->validateMinMaxConstraint($element, $objectDefinition, $path); foreach ($element as $i => $value) { @@ -118,11 +120,11 @@ public function validateElement($element, $matches, $objectDefinition = null, $p /** * Validates the definition properties * - * @param \stdClass $element Element to validate - * @param \stdClass $objectDefinition ObjectConstraint definition - * @param string $path Path? + * @param \stdClass $element Element to validate + * @param \stdClass $objectDefinition ObjectConstraint definition + * @param JsoinPointer|null $path Path? */ - public function validateDefinition($element, $objectDefinition = null, $path = null) + public function validateDefinition($element, $objectDefinition = null, JsonPointer $path = null) { foreach ($objectDefinition as $i => $value) { $property = $this->getProperty($element, $i, new UndefinedConstraint()); @@ -154,11 +156,11 @@ protected function getProperty($element, $property, $fallback = null) /** * validating minimum and maximum property constraints (if present) against an element * - * @param \stdClass $element Element to validate - * @param \stdClass $objectDefinition ObjectConstraint definition - * @param string $path Path to test? + * @param \stdClass $element Element to validate + * @param \stdClass $objectDefinition ObjectConstraint definition + * @param JsonPointer|null $path Path to test? */ - protected function validateMinMaxConstraint($element, $objectDefinition, $path) { + protected function validateMinMaxConstraint($element, $objectDefinition, JsonPointer $path = null) { // Verify minimum number of properties if (isset($objectDefinition->minProperties) && !is_object($objectDefinition->minProperties)) { if ($this->getTypeCheck()->propertyCount($element) < $objectDefinition->minProperties) { diff --git a/src/JsonSchema/Constraints/SchemaConstraint.php b/src/JsonSchema/Constraints/SchemaConstraint.php index ffd4757b..071cd123 100644 --- a/src/JsonSchema/Constraints/SchemaConstraint.php +++ b/src/JsonSchema/Constraints/SchemaConstraint.php @@ -10,6 +10,7 @@ namespace JsonSchema\Constraints; use JsonSchema\Exception\InvalidArgumentException; +use JsonSchema\Entity\JsonPointer; /** * The SchemaConstraint Constraints, validates an element against a given schema @@ -22,19 +23,18 @@ class SchemaConstraint extends Constraint /** * {@inheritDoc} */ - public function check($element, $schema = null, $path = null, $i = null) + public function check($element, $schema = null, JsonPointer $path = null, $i = null) { if ($schema !== null) { // passed schema - $this->checkUndefined($element, $schema, '', ''); + $this->checkUndefined($element, $schema, $path, $i); } elseif ($this->getTypeCheck()->propertyExists($element, $this->inlineSchemaProperty)) { $inlineSchema = $this->getTypeCheck()->propertyGet($element, $this->inlineSchemaProperty); if (is_array($inlineSchema)) { $inlineSchema = json_decode(json_encode($inlineSchema)); } - // inline schema - $this->checkUndefined($element, $inlineSchema, '', ''); + $this->checkUndefined($element, $inlineSchema, $path, $i); } else { throw new InvalidArgumentException('no schema found to verify against'); } diff --git a/src/JsonSchema/Constraints/StringConstraint.php b/src/JsonSchema/Constraints/StringConstraint.php index f57f64c9..44313cb2 100644 --- a/src/JsonSchema/Constraints/StringConstraint.php +++ b/src/JsonSchema/Constraints/StringConstraint.php @@ -9,6 +9,8 @@ namespace JsonSchema\Constraints; +use JsonSchema\Entity\JsonPointer; + /** * The StringConstraint Constraints, validates an string against a given schema * @@ -20,7 +22,7 @@ class StringConstraint extends Constraint /** * {@inheritDoc} */ - public function check($element, $schema = null, $path = null, $i = null) + public function check($element, $schema = null, JsonPointer $path = null, $i = null) { // Verify maxLength if (isset($schema->maxLength) && $this->strlen($element) > $schema->maxLength) { diff --git a/src/JsonSchema/Constraints/TypeConstraint.php b/src/JsonSchema/Constraints/TypeConstraint.php index a7af5748..3e0ac4e1 100644 --- a/src/JsonSchema/Constraints/TypeConstraint.php +++ b/src/JsonSchema/Constraints/TypeConstraint.php @@ -10,6 +10,7 @@ namespace JsonSchema\Constraints; use JsonSchema\Exception\InvalidArgumentException; +use JsonSchema\Entity\JsonPointer; use UnexpectedValueException as StandardUnexpectedValueException; /** @@ -38,7 +39,7 @@ class TypeConstraint extends Constraint /** * {@inheritDoc} */ - public function check($value = null, $schema = null, $path = null, $i = null) + public function check($value = null, $schema = null, JsonPointer $path = null, $i = null) { $type = isset($schema->type) ? $schema->type : null; $isValid = true; diff --git a/src/JsonSchema/Constraints/UndefinedConstraint.php b/src/JsonSchema/Constraints/UndefinedConstraint.php index 63947199..7815e241 100644 --- a/src/JsonSchema/Constraints/UndefinedConstraint.php +++ b/src/JsonSchema/Constraints/UndefinedConstraint.php @@ -10,6 +10,7 @@ namespace JsonSchema\Constraints; use JsonSchema\Uri\UriResolver; +use JsonSchema\Entity\JsonPointer; /** * The UndefinedConstraint Constraints @@ -22,14 +23,13 @@ class UndefinedConstraint extends Constraint /** * {@inheritDoc} */ - public function check($value, $schema = null, $path = null, $i = null) + public function check($value, $schema = null, JsonPointer $path = null, $i = null) { if (is_null($schema) || !is_object($schema)) { return; } - $i = is_null($i) ? "" : $i; - $path = $this->incrementPath($path, $i); + $path = $this->incrementPath($path ?: new JsonPointer(''), $i); // check special properties $this->validateCommonProperties($value, $schema, $path); @@ -44,12 +44,12 @@ public function check($value, $schema = null, $path = null, $i = null) /** * Validates the value against the types * - * @param mixed $value - * @param mixed $schema - * @param string $path - * @param string $i + * @param mixed $value + * @param mixed $schema + * @param JsonPointer $path + * @param string $i */ - public function validateTypes($value, $schema = null, $path = null, $i = null) + public function validateTypes($value, $schema = null, JsonPointer $path, $i = null) { // check array if ($this->getTypeCheck()->isArray($value)) { @@ -86,12 +86,12 @@ public function validateTypes($value, $schema = null, $path = null, $i = null) /** * Validates common properties * - * @param mixed $value - * @param mixed $schema - * @param string $path - * @param string $i + * @param mixed $value + * @param mixed $schema + * @param JsonPointer $path + * @param string $i */ - protected function validateCommonProperties($value, $schema = null, $path = null, $i = "") + protected function validateCommonProperties($value, $schema = null, JsonPointer $path, $i = "") { // if it extends another schema, it must pass that schema as well if (isset($schema->extends)) { @@ -113,7 +113,11 @@ protected function validateCommonProperties($value, $schema = null, $path = null // Draft 4 - Required is an array of strings - e.g. "required": ["foo", ...] foreach ($schema->required as $required) { if (!$this->getTypeCheck()->propertyExists($value, $required)) { - $this->addError((!$path) ? $required : "$path.$required", "The property " . $required . " is required", 'required'); + $this->addError( + $this->incrementPath($path ?: new JsonPointer(''), $required), + "The property " . $required . " is required", + 'required' + ); } } } elseif (isset($schema->required) && !is_array($schema->required)) { @@ -166,12 +170,12 @@ protected function validateCommonProperties($value, $schema = null, $path = null /** * Validate allOf, anyOf, and oneOf properties * - * @param mixed $value - * @param mixed $schema - * @param string $path - * @param string $i + * @param mixed $value + * @param mixed $schema + * @param JsonPointer $path + * @param string $i */ - protected function validateOfProperties($value, $schema, $path, $i = "") + protected function validateOfProperties($value, $schema, JsonPointer $path, $i = "") { // Verify type if ($value instanceof UndefinedConstraint) { @@ -220,17 +224,8 @@ protected function validateOfProperties($value, $schema, $path, $i = "") $allErrors = array_merge($allErrors, array_values($this->getErrors())); } if ($matchedSchemas !== 1) { - $this->addErrors( - array_merge( - $allErrors, - array(array( - 'property' => $path, - 'message' => "Failed to match exactly one schema", - 'constraint' => 'oneOf', - ),), - $startErrors - ) - ); + $this->addErrors(array_merge($allErrors, $startErrors)); + $this->addError($path, "Failed to match exactly one schema", 'oneOf'); } else { $this->errors = $startErrors; } @@ -240,12 +235,12 @@ protected function validateOfProperties($value, $schema, $path, $i = "") /** * Validate dependencies * - * @param mixed $value - * @param mixed $dependencies - * @param string $path - * @param string $i + * @param mixed $value + * @param mixed $dependencies + * @param JsonPointer $path + * @param string $i */ - protected function validateDependencies($value, $dependencies, $path, $i = "") + protected function validateDependencies($value, $dependencies, JsonPointer $path, $i = "") { foreach ($dependencies as $key => $dependency) { if ($this->getTypeCheck()->propertyExists($value, $key)) { diff --git a/src/JsonSchema/Entity/JsonPointer.php b/src/JsonSchema/Entity/JsonPointer.php index ff841de0..00e14e09 100644 --- a/src/JsonSchema/Entity/JsonPointer.php +++ b/src/JsonSchema/Entity/JsonPointer.php @@ -100,6 +100,17 @@ public function getPropertyPaths() return $this->propertyPaths; } + /** + * @param array $propertyPaths + * @return JsonPointer + */ + public function withPropertyPaths(array $propertyPaths) + { + $new = clone $this; + $new->propertyPaths = $propertyPaths; + return $new; + } + /** * @return string */ diff --git a/src/JsonSchema/Validator.php b/src/JsonSchema/Validator.php index 14dbb609..b627d785 100644 --- a/src/JsonSchema/Validator.php +++ b/src/JsonSchema/Validator.php @@ -11,6 +11,7 @@ use JsonSchema\Constraints\SchemaConstraint; use JsonSchema\Constraints\Constraint; +use JsonSchema\Entity\JsonPointer; /** * A JsonSchema Constraint @@ -30,7 +31,7 @@ class Validator extends Constraint * * {@inheritDoc} */ - public function check($value, $schema = null, $path = null, $i = null) + public function check($value, $schema = null, JsonPointer $path = null, $i = null) { $validator = $this->getFactory()->createInstanceFor('schema'); $validator->check($value, $schema); diff --git a/tests/Constraints/AdditionalPropertiesTest.php b/tests/Constraints/AdditionalPropertiesTest.php index 24254d0b..4d68654b 100644 --- a/tests/Constraints/AdditionalPropertiesTest.php +++ b/tests/Constraints/AdditionalPropertiesTest.php @@ -34,6 +34,7 @@ public function getInvalidTests() array( array( 'property' => '', + 'pointer' => '', 'message' => 'The property additionalProp is not defined and the definition does not allow additional properties', 'constraint' => 'additionalProp', ) diff --git a/tests/Constraints/FactoryTest.php b/tests/Constraints/FactoryTest.php index e3a2acab..50a2d69a 100644 --- a/tests/Constraints/FactoryTest.php +++ b/tests/Constraints/FactoryTest.php @@ -11,6 +11,7 @@ use JsonSchema\Constraints\Constraint; use JsonSchema\Constraints\Factory; +use JsonSchema\Entity\JsonPointer; use PHPUnit_Framework_TestCase as TestCase; @@ -25,7 +26,7 @@ class MyBadConstraint {} * @package JsonSchema\Tests\Constraints */ class MyStringConstraint extends Constraint { - public function check($value, $schema = null, $path = null, $i = null){} + public function check($value, $schema = null, JsonPointer $path = null, $i = null){} } class FactoryTest extends TestCase diff --git a/tests/Constraints/OfPropertiesTest.php b/tests/Constraints/OfPropertiesTest.php index 34c8cbff..5255fc6e 100644 --- a/tests/Constraints/OfPropertiesTest.php +++ b/tests/Constraints/OfPropertiesTest.php @@ -73,16 +73,19 @@ public function getInvalidTests() array( array( "property" => "prop2", + "pointer" => "/prop2", "message" => "Array value found, but a string is required", "constraint" => "type", ), array( "property" => "prop2", + "pointer" => "/prop2", "message" => "Array value found, but a number is required", "constraint" => "type", ), array( "property" => "prop2", + "pointer" => "/prop2", "message" => "Failed to match exactly one schema", "constraint" => "oneOf", ), diff --git a/tests/Constraints/PointerTest.php b/tests/Constraints/PointerTest.php new file mode 100644 index 00000000..a48eae0d --- /dev/null +++ b/tests/Constraints/PointerTest.php @@ -0,0 +1,114 @@ + 'object', + 'required' => array('prop1', 'prop2', 'prop3', 'prop4'), + 'properties' => array( + 'prop1' => array( + 'type' => 'string' + ), + 'prop2' => array( + 'type' => 'object', + 'required' => array('prop2.1'), + 'properties' => array( + 'prop2.1' => array( + 'type' => 'string' + ) + ) + ), + 'prop3' => array( + 'type' => 'object', + 'required' => array('prop3/1'), + 'properties' => array( + 'prop3/1' => array( + 'type' => 'object', + 'required' => array('prop3/1.1'), + 'properties' => array( + 'prop3/1.1' => array( + 'type' => 'string' + ) + ) + ) + ) + ), + 'prop4' => array( + 'type' => 'array', + 'minItems' => 1, + 'items' => array( + 'type' => 'object', + 'required' => array('prop4-child'), + 'properties' => array( + 'prop4-child' => array( + 'type' => 'string' + ) + ) + ) + ) + ) + ); + + $value = array( + 'prop2' => array( + 'foo' => 'bar' + ), + 'prop3' => array( + 'prop3/1' => array( + 'foo' => 'bar' + ) + ), + 'prop4' => array( + array( + 'foo' => 'bar' + ) + ) + ); + + $validator = new Validator(); + $validator->check(json_decode(json_encode($value)), json_decode(json_encode($schema))); + + $this->assertEquals( + array( + array( + 'property' => 'prop1', + 'pointer' => '/prop1', + 'message' => 'The property prop1 is required', + 'constraint' => 'required' + ), + array( + 'property' => 'prop2.prop2.1', + 'pointer' => '/prop2/prop2.1', + 'message' => 'The property prop2.1 is required', + 'constraint' => 'required' + ), + array( + 'property' => 'prop3.prop3/1.prop3/1.1', + 'pointer' => '/prop3/prop3~11/prop3~11.1', + 'message' => 'The property prop3/1.1 is required', + 'constraint' => 'required' + ), + array( + 'property' => 'prop4[0].prop4-child', + 'pointer' => '/prop4/0/prop4-child', + 'message' => 'The property prop4-child is required', + 'constraint' => 'required' + ) + ), + $validator->getErrors() + ); + } +} diff --git a/tests/Entity/JsonPointerTest.php b/tests/Entity/JsonPointerTest.php index c7a49d22..1cc8c0bf 100644 --- a/tests/Entity/JsonPointerTest.php +++ b/tests/Entity/JsonPointerTest.php @@ -92,4 +92,22 @@ public function getTestData() ); } + + public function testJsonPointerWithPropertyPaths() + { + $initial = new JsonPointer('#/definitions/date'); + + $this->assertEquals(array('definitions', 'date'), $initial->getPropertyPaths()); + $this->assertEquals('#/definitions/date', $initial->getPropertyPathAsString()); + + $modified = $initial->withPropertyPaths(array('~definitions/general', '%custom%')); + + $this->assertNotSame($initial, $modified); + + $this->assertEquals(array('definitions', 'date'), $initial->getPropertyPaths()); + $this->assertEquals('#/definitions/date', $initial->getPropertyPathAsString()); + + $this->assertEquals(array('~definitions/general', '%custom%'), $modified->getPropertyPaths()); + $this->assertEquals('#/~0definitions~1general/%25custom%25', $modified->getPropertyPathAsString()); + } }