-
-
Notifications
You must be signed in to change notification settings - Fork 863
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add assertions for testing response against JSON Schema from API resource #3003
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,16 +25,19 @@ | |
*/ | ||
final class MatchesJsonSchema extends Constraint | ||
{ | ||
/** | ||
* @var object|array | ||
*/ | ||
private $schema; | ||
private $checkMode; | ||
|
||
/** | ||
* @param array|string $schema | ||
* @param object|array|string $schema | ||
*/ | ||
public function __construct($schema, ?int $checkMode = null) | ||
{ | ||
$this->schema = \is_string($schema) ? json_decode($schema) : $schema; | ||
$this->checkMode = $checkMode; | ||
$this->schema = \is_array($schema) ? (object) $schema : json_decode($schema); | ||
} | ||
|
||
/** | ||
|
@@ -46,15 +49,15 @@ public function toString(): string | |
} | ||
|
||
/** | ||
* @param array $other | ||
* {@inheritdoc} | ||
*/ | ||
protected function matches($other): bool | ||
{ | ||
if (!class_exists(Validator::class)) { | ||
throw new \RuntimeException('The "justinrainbow/json-schema" library must be installed to use "assertMatchesJsonSchema()". Try running "composer require --dev justinrainbow/json-schema".'); | ||
throw new \LogicException('The "justinrainbow/json-schema" library must be installed to use "assertMatchesJsonSchema()". Try running "composer require --dev justinrainbow/json-schema".'); | ||
} | ||
|
||
$other = (object) $other; | ||
$other = $this->normalizeJson($other); | ||
|
||
$validator = new Validator(); | ||
$validator->validate($other, $this->schema, $this->checkMode); | ||
|
@@ -63,14 +66,14 @@ protected function matches($other): bool | |
} | ||
|
||
/** | ||
* @param object $other | ||
* {@inheritdoc} | ||
*/ | ||
protected function additionalFailureDescription($other): string | ||
{ | ||
$other = (object) $other; | ||
$other = $this->normalizeJson($other); | ||
|
||
$validator = new Validator(); | ||
$validator->check($other, $this->schema); | ||
$validator->validate($other, $this->schema, $this->checkMode); | ||
|
||
$errors = []; | ||
foreach ($validator->getErrors() as $error) { | ||
|
@@ -80,4 +83,32 @@ protected function additionalFailureDescription($other): string | |
|
||
return implode("\n", $errors); | ||
} | ||
|
||
/** | ||
* Normalizes a JSON document. | ||
* | ||
* Specifically, we should ensure that: | ||
* 1. a JSON object is represented as a PHP object, not as an associative array. | ||
*/ | ||
private function normalizeJson($document) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We support validating any JSON document against a JSON Schema now. 🎉 |
||
{ | ||
if (is_scalar($document) || \is_object($document)) { | ||
return $document; | ||
} | ||
|
||
if (!\is_array($document)) { | ||
throw new \InvalidArgumentException('Document must be scalar, array or object.'); | ||
} | ||
|
||
$document = json_encode($document); | ||
if (!\is_string($document)) { | ||
throw new \UnexpectedValueException('JSON encode failed.'); | ||
} | ||
$document = json_decode($document); | ||
if (!\is_array($document) && !\is_object($document)) { | ||
throw new \UnexpectedValueException('JSON decode failed.'); | ||
} | ||
|
||
return $document; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,9 +47,9 @@ public function __construct(BaseSchemaFactory $schemaFactory) | |
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function buildSchema(string $resourceClass, string $format = 'jsonld', bool $output = true, ?string $operationType = null, ?string $operationName = null, ?Schema $schema = null, ?array $serializerContext = null, bool $forceCollection = false): Schema | ||
public function buildSchema(string $resourceClass, string $format = 'jsonld', string $type = Schema::TYPE_OUTPUT, ?string $operationType = null, ?string $operationName = null, ?Schema $schema = null, ?array $serializerContext = null, bool $forceCollection = false): Schema | ||
{ | ||
$schema = $this->schemaFactory->buildSchema($resourceClass, $format, $output, $operationType, $operationName, $schema, $serializerContext, $forceCollection); | ||
$schema = $this->schemaFactory->buildSchema($resourceClass, $format, $type, $operationType, $operationName, $schema, $serializerContext, $forceCollection); | ||
if ('jsonld' !== $format) { | ||
return $schema; | ||
} | ||
|
@@ -74,24 +74,29 @@ public function buildSchema(string $resourceClass, string $format = 'jsonld', bo | |
], | ||
'hydra:totalItems' => [ | ||
'type' => 'integer', | ||
'minimum' => 1, | ||
'minimum' => 0, | ||
], | ||
'hydra:view' => [ | ||
'type' => 'object', | ||
'properties' => [ | ||
'@id' => ['type' => 'string'], | ||
'@type' => ['type' => 'string'], | ||
'@id' => [ | ||
'type' => 'string', | ||
'format' => 'iri-reference', | ||
], | ||
'@type' => [ | ||
'type' => 'string', | ||
], | ||
'hydra:first' => [ | ||
'type' => 'integer', | ||
'minimum' => 1, | ||
'type' => 'string', | ||
'format' => 'iri-reference', | ||
], | ||
'hydra:last' => [ | ||
'type' => 'integer', | ||
'minimum' => 1, | ||
'type' => 'string', | ||
'format' => 'iri-reference', | ||
], | ||
'hydra:next' => [ | ||
'type' => 'integer', | ||
'minimum' => 1, | ||
'type' => 'string', | ||
'format' => 'iri-reference', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wasn't aware of the existence of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dunglas Do you have any in mind? (We could do it in another PR.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. he means in the rest of the core I guess (tests?), so def another pr! |
||
], | ||
], | ||
], | ||
|
@@ -116,6 +121,9 @@ public function buildSchema(string $resourceClass, string $format = 'jsonld', bo | |
], | ||
], | ||
]; | ||
$schema['required'] = [ | ||
'hydra:member', | ||
]; | ||
|
||
return $schema; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jsonrainbow/json-schema#378
jsonrainbow/json-schema#409