Skip to content

BREAKING CHANGE: Upgrade libraries, changing interfaces and introduci… #19

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

Merged
merged 2 commits into from
Oct 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 58 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class MyTestCase extends \PHPUnit_Framework_TestCase

$json = json_decode('{"foo":1}');

$this->assertJsonMatchesSchema('./my-schema.json', $json);
$this->assertJsonMatchesSchema($json, './my-schema.json');
$this->assertJsonValueEquals(1, '* | [0]', $json);
}
}
Expand Down Expand Up @@ -115,7 +115,63 @@ class MyTestCase extends \PHPUnit_Framework_TestCase

$json = json_decode('{"foo":1}');

JsonAssert::assertJsonMatchesSchema('./my-schema.json', $json);
JsonAssert::assertJsonMatchesSchema($json, './my-schema.json');
JsonAssert::assertJsonValueEquals(1, '* | [0]', $json);
}
}
```

## Schema storage

The [schema storage](https://github.com/justinrainbow/json-schema/blob/master/src/JsonSchema/SchemaStorage.php) of `justinrainbow/json-schema` allows to register schemas which will effectively override the actual schema location.

Example:
```json
{"$ref" : "https://iglu.foobar.com/myschema.json#/definitions/positiveInteger"}
```

The resolver will fetch the schema from this endpoint and match the JSON document against it. Using schema storage you're able to override this behaviour.

```php
$schemastorage->addSchema('https://iglu.foobar.com/myschema.json', (object)['type' => 'string']);
```

With this in place the resolver will take the schema that is already in place without downloading it again.

```php
<?php

namespace EnricoStahn\JsonAssert\Tests;

use EnricoStahn\JsonAssert\AssertClass as JsonAssert;

class MyTestCase extends \PHPUnit_Framework_TestCase
{
public function setUp()
{
self::$schemaStorage = new SchemaStorage();

self::$schemaStorage->addSchema('<id>', obj);
...
}

public function testJsonDocumentIsValid()
{
// my-schema.json
//
// {
// "type" : "object",
// "properties" : {
// "foo" : {
// "type" : "integer"
// }
// },
// "required" : [ "foo" ]
// }

$json = json_decode('{"foo":1}');

JsonAssert::assertJsonMatchesSchema($json, './my-schema.json');
JsonAssert::assertJsonValueEquals(1, '* | [0]', $json);
}
}
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"minimum-stability": "stable",
"require": {
"php": "^7.0",
"justinrainbow/json-schema": "^2.0",
"justinrainbow/json-schema": "^5.0",
"mtdowling/jmespath.php": "^2.3"
},
"require-dev": {
Expand Down
58 changes: 45 additions & 13 deletions src/Assert.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@

namespace EnricoStahn\JsonAssert;

use JsonSchema\RefResolver;
use JsonSchema\Uri\UriResolver;
use JsonSchema\Uri\UriRetriever;
use JsonSchema\Constraints\Factory;
use JsonSchema\SchemaStorage;
use JsonSchema\Validator;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;

/**
* Asserts to validate JSON data.
Expand All @@ -25,25 +25,40 @@
*/
trait Assert
{
/**
* @var SchemaStorage
*/
private static $schemaStorage = null;

/**
* Asserts that json content is valid according to the provided schema file.
*
* Example:
*
* static::assertJsonMatchesSchema('./schema.json', json_decode('{"foo":1}'))
* static::assertJsonMatchesSchema(json_decode('{"foo":1}'), './schema.json')
*
* @param string $schema Path to the schema file
* @param string|null $schema Path to the schema file
* @param array|object $content JSON array or object
*/
public static function assertJsonMatchesSchema($schema, $content)
public static function assertJsonMatchesSchema($content, $schema = null)
{
// Assume references are relative to the current file
// Create an issue or pull request if you need more complex use cases
$refResolver = new RefResolver(new UriRetriever(), new UriResolver());
$schemaObj = $refResolver->resolve('file://'.realpath($schema));
if (self::$schemaStorage === null) {
self::$schemaStorage = new SchemaStorage();
}

if ($schema !== null && !file_exists($schema)) {
throw new FileNotFoundException($schema);
}

$schemaObject = null;

$validator = new Validator();
$validator->check($content, $schemaObj);
if ($schema !== null) {
$schemaObject = json_decode(file_get_contents($schema));
self::$schemaStorage->addSchema('file://'.$schema, $schemaObject);
}

$validator = new Validator(new Factory(self::$schemaStorage));
$validator->validate($content, $schemaObject);

$message = '- Property: %s, Contraint: %s, Message: %s';
$messages = array_map(function ($exception) use ($message) {
Expand All @@ -54,6 +69,23 @@ public static function assertJsonMatchesSchema($schema, $content)
\PHPUnit\Framework\Assert::assertTrue($validator->isValid(), implode("\n", $messages));
}

/**
* Asserts that json content is valid according to the provided schema file.
*
* Example:
*
* static::assertJsonMatchesSchema(json_decode('{"foo":1}'), './schema.json')
*
* @param string|null $schema Path to the schema file
* @param array|object $content JSON array or object
*
* @deprecated This will be removed in the next major version (4.x).
*/
public static function assertJsonMatchesSchemaDepr($schema, $content)
{
self::assertJsonMatchesSchema($content, $schema);
}

/**
* Asserts that json content is valid according to the provided schema string.
*
Expand All @@ -65,7 +97,7 @@ public static function assertJsonMatchesSchemaString($schema, $content)
$file = tempnam(sys_get_temp_dir(), 'json-schema-');
file_put_contents($file, $schema);

self::assertJsonMatchesSchema($file, $content);
self::assertJsonMatchesSchema($content, $file);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Extension/Symfony.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ trait Symfony
*/
public static function assertJsonMatchesSchema($schema, Response $response)
{
Assert::assertJsonMatchesSchema($schema, json_decode($response->getContent()));
Assert::assertJsonMatchesSchemaDepr($schema, json_decode($response->getContent()));
}

/**
Expand Down
19 changes: 19 additions & 0 deletions tests/AssertTraitImpl.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,28 @@
namespace EnricoStahn\JsonAssert\Tests;

use EnricoStahn\JsonAssert\Assert as JsonAssert;
use JsonSchema\SchemaStorage;
use PHPUnit\Framework\TestCase;

class AssertTraitImpl extends TestCase
{
use JsonAssert;

public function setUp()
{
self::$schemaStorage = new SchemaStorage();
}

/**
* @param string $id
* @param string $schema
*
* @return SchemaStorage
*/
public function testWithSchemaStore($id, $schema)
{
self::$schemaStorage->addSchema($id, $schema);

return self::$schemaStorage;
}
}
23 changes: 17 additions & 6 deletions tests/AssertTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ public function testAssertJsonMatchesSchemaSimple()
{
$content = json_decode(file_get_contents(Utils::getJsonPath('assertJsonMatchesSchema_simple.json')));

AssertTraitImpl::assertJsonMatchesSchema(Utils::getSchemaPath('assertJsonMatchesSchema_simple.schema.json'), $content);
AssertTraitImpl::assertJsonMatchesSchemaDepr(Utils::getSchemaPath('assertJsonMatchesSchema_simple.schema.json'), $content);
}

public function testAssertJsonMatchesSchema()
{
$content = json_decode('{"foo":123}');

AssertTraitImpl::assertJsonMatchesSchema(Utils::getSchemaPath('test.schema.json'), $content);
AssertTraitImpl::assertJsonMatchesSchemaDepr(Utils::getSchemaPath('test.schema.json'), $content);
}

/**
Expand All @@ -42,7 +42,7 @@ public function testAssertJsonMatchesSchemaFail()
{
$content = json_decode('{"foo":"123"}');

AssertTraitImpl::assertJsonMatchesSchema(Utils::getSchemaPath('test.schema.json'), $content);
AssertTraitImpl::assertJsonMatchesSchemaDepr(Utils::getSchemaPath('test.schema.json'), $content);
}

public function testAssertJsonMatchesSchemaFailMessage()
Expand All @@ -52,7 +52,7 @@ public function testAssertJsonMatchesSchemaFailMessage()
$exception = null;

try {
AssertTraitImpl::assertJsonMatchesSchema(Utils::getSchemaPath('test.schema.json'), $content);
AssertTraitImpl::assertJsonMatchesSchemaDepr(Utils::getSchemaPath('test.schema.json'), $content);
} catch (ExpectationFailedException $exception) {
self::assertContains('- Property: foo, Contraint: type, Message: String value found, but an integer is required', $exception->getMessage());
self::assertContains('- Response: {"foo":"123"}', $exception->getMessage());
Expand All @@ -68,7 +68,7 @@ public function testAssertJsonMatchesSchemaWithRefs()
{
$content = json_decode('{"code":123, "message":"Nothing works."}');

AssertTraitImpl::assertJsonMatchesSchema(Utils::getSchemaPath('error.schema.json'), $content);
AssertTraitImpl::assertJsonMatchesSchemaDepr(Utils::getSchemaPath('error.schema.json'), $content);
}

/**
Expand All @@ -78,7 +78,7 @@ public function testAssertJsonMatchesSchemaWithRefsFails()
{
$content = json_decode('{"code":"123", "message":"Nothing works."}');

AssertTraitImpl::assertJsonMatchesSchema(Utils::getSchemaPath('error.schema.json'), $content);
AssertTraitImpl::assertJsonMatchesSchemaDepr(Utils::getSchemaPath('error.schema.json'), $content);
}

public function testAssertJsonMatchesSchemaString()
Expand All @@ -104,6 +104,17 @@ public function testAssertJsonValueEquals($expression, $value)
AssertTraitImpl::assertJsonValueEquals($value, $expression, $content);
}

public function testAssertWithSchemaStore()
{
$obj = new AssertTraitImpl();
$obj->setUp();

$schemastore = $obj->testWithSchemaStore('foobar', (object) ['type' => 'string']);

self::assertInstanceOf('JsonSchema\SchemaStorage', $schemastore);
self::assertEquals($schemastore->getSchema('foobar'), (object) ['type' => 'string']);
}

public function assertJsonValueEqualsProvider()
{
return [
Expand Down