Skip to content

Commit 1310fcb

Browse files
committed
Add support for draft 6
- updates json library dependency version for draft 6 support - adds assertions for some draft 6 scenarios
1 parent 54fb7c9 commit 1310fcb

6 files changed

+256
-8
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class MyTestCase extends \PHPUnit_Framework_TestCase
8686

8787
### Class
8888

89-
In case you don't want to use the `trait` you can use the provided class wich extends from `\PHPUnit_Framework_TestCase`.
89+
In case you don't want to use the `trait` you can use the provided class which extends from `\PHPUnit_Framework_TestCase`.
9090
You can either extend your test case or use the static methods like below.
9191

9292
```php

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"minimum-stability": "stable",
1515
"require": {
1616
"php": "^7.4|^8.0",
17-
"justinrainbow/json-schema": "^5.0",
17+
"justinrainbow/json-schema": "^6.0",
1818
"mtdowling/jmespath.php": "^2.3",
1919
"ext-json": "*"
2020
},

src/Assert.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public static function assertJsonMatchesSchema($content, ?string $schema = null)
6363

6464
$message = '- Property: %s, Constraint: %s, Message: %s';
6565
$messages = array_map(function ($exception) use ($message) {
66-
return sprintf($message, $exception['property'], $exception['constraint'], $exception['message']);
66+
return sprintf($message, $exception['property'], $exception['constraint']['name'], $exception['message']);
6767
}, $validator->getErrors());
6868
$messages[] = '- Response: '.json_encode($content);
6969

tests/AssertTraitTest.php

+161-5
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,164 @@ class AssertTraitTest extends TestCase
2222
*
2323
* @see https://github.com/estahn/phpunit-json-assertions/wiki/assertJsonMatchesSchema
2424
*/
25+
public function testAssertJsonMatchesSchemaSimpleDraft6()
26+
{
27+
$content = json_decode(file_get_contents(Utils::getJsonPath('assertJsonMatchesSchema_simple_draft6.json')));
28+
29+
AssertTraitImpl::assertJsonMatchesSchema(
30+
$content,
31+
Utils::getSchemaPath('assertJsonMatchesSchema_draft6.schema.json')
32+
);
33+
}
34+
35+
/**
36+
* @testWith
37+
* ["{\"created_at\": \"2016-01-01T12:00:00Z\"}", true]
38+
* ["{\"created_at\": \"2016/01/01\"}", false]
39+
*/
40+
public function testAssertJsonMatchesSchemaDraft6DateTime($json, $pass)
41+
{
42+
if (!$pass) {
43+
$this->expectException(ExpectationFailedException::class);
44+
}
45+
46+
$content = json_decode($json);
47+
48+
AssertTraitImpl::assertJsonMatchesSchema(
49+
$content,
50+
Utils::getSchemaPath('assertJsonMatchesSchema_draft6.schema.json')
51+
);
52+
}
53+
54+
/**
55+
* @testWith
56+
* ["{\"status\": \"active\", \"created_at\": \"2016-01-01T12:00:00Z\"}", true]
57+
* ["{\"status\": \"completed\", \"created_at\": \"2016-01-01T12:00:00Z\"}", true]
58+
* ["{\"status\": \"deleted\", \"created_at\": \"2016-01-01T12:00:00Z\"}", false]
59+
*/
60+
public function testAssertJsonMatchesSchemaDraft6EnumAndNot($json, $pass)
61+
{
62+
if (!$pass) {
63+
$this->expectException(ExpectationFailedException::class);
64+
}
65+
66+
$content = json_decode($json);
67+
68+
AssertTraitImpl::assertJsonMatchesSchema(
69+
$content,
70+
Utils::getSchemaPath('assertJsonMatchesSchema_draft6.schema.json')
71+
);
72+
}
73+
74+
/**
75+
* @testWith
76+
* ["{\"status\": \"active\", \"created_at\": \"2016-01-01T12:00:00Z\"}", true]
77+
* ["{\"status\": \"active\"}", false]
78+
*/
79+
public function testAssertJsonMatchesSchemaDraft6Dependency($json, $pass)
80+
{
81+
if (!$pass) {
82+
$this->expectException(ExpectationFailedException::class);
83+
}
84+
85+
$content = json_decode($json);
86+
87+
AssertTraitImpl::assertJsonMatchesSchema(
88+
$content,
89+
Utils::getSchemaPath('assertJsonMatchesSchema_draft6.schema.json')
90+
);
91+
}
92+
93+
/**
94+
* @testWith
95+
* ["{\"id\": 2}", true]
96+
* ["{\"id\": 1}", false]
97+
* ["{\"id\": 0}", false]
98+
*/
99+
public function testAssertJsonMatchesSchemaDraft6ExclusiveMinimum($json, $pass)
100+
{
101+
if (!$pass) {
102+
$this->expectException(ExpectationFailedException::class);
103+
}
104+
105+
$content = json_decode($json);
106+
107+
AssertTraitImpl::assertJsonMatchesSchema(
108+
$content,
109+
Utils::getSchemaPath('assertJsonMatchesSchema_draft6.schema.json')
110+
);
111+
}
112+
113+
/**
114+
* @testWith
115+
* ["{\"title\": \"A brief description\"}", true]
116+
* ["{\"title\": \"A description that is too long\"}", false]
117+
* ["{\"title\": \"A\"}", false]
118+
*/
119+
public function testAssertJsonMatchesSchemaDraft6MaxMinLength($json, $pass)
120+
{
121+
if (!$pass) {
122+
$this->expectException(ExpectationFailedException::class);
123+
}
124+
125+
$content = json_decode($json);
126+
127+
AssertTraitImpl::assertJsonMatchesSchema(
128+
$content,
129+
Utils::getSchemaPath('assertJsonMatchesSchema_draft6.schema.json')
130+
);
131+
}
132+
133+
/**
134+
* @testWith
135+
* ["{\"invalid_name\": \"value\"}", false]
136+
*/
137+
public function testAssertJsonMatchesSchemaDraft6AdditionalProperties($json, $pass)
138+
{
139+
if (!$pass) {
140+
$this->expectException(ExpectationFailedException::class);
141+
}
142+
143+
$content = json_decode($json);
144+
145+
AssertTraitImpl::assertJsonMatchesSchema(
146+
$content,
147+
Utils::getSchemaPath('assertJsonMatchesSchema_draft6.schema.json')
148+
);
149+
}
150+
151+
/**
152+
* @testWith
153+
* ["{\"status\": \"completed\", \"completed_at\": \"2020-01-01T12:00:00Z\", \"created_at\": \"2020-01-01T12:00:00Z\"}", true]
154+
* ["{\"status\": \"completed\", \"created_at\": \"2020-01-01T12:00:00Z\"}", false]
155+
* ["{\"status\": \"pending\", \"expected_completion\": \"2020-01-01T12:00:00Z\", \"created_at\": \"2020-01-01T12:00:00Z\"}", true]
156+
* ["{\"status\": \"pending\", \"created_at\": \"2020-01-01T12:00:00Z\"}", false]
157+
* ["{\"status\": \"active\", \"created_at\": \"2020-01-01T12:00:00Z\"}", true]
158+
*/
159+
public function testAssertJsonMatchesSchemaDraft6Conditional($json, $pass)
160+
{
161+
$this->markTestSkipped('Conditional validation is not supported by the current implementation.');
162+
163+
if (!$pass) {
164+
$this->expectException(ExpectationFailedException::class);
165+
}
166+
167+
$content = json_decode($json);
168+
169+
AssertTraitImpl::assertJsonMatchesSchema(
170+
$content,
171+
Utils::getSchemaPath('assertJsonMatchesSchema_draft6.schema.json')
172+
);
173+
}
174+
25175
public function testAssertJsonMatchesSchemaSimple()
26176
{
27177
$content = json_decode(file_get_contents(Utils::getJsonPath('assertJsonMatchesSchema_simple.json')));
28178

29-
AssertTraitImpl::assertJsonMatchesSchema($content, Utils::getSchemaPath('assertJsonMatchesSchema_simple.schema.json'));
179+
AssertTraitImpl::assertJsonMatchesSchema(
180+
$content,
181+
Utils::getSchemaPath('assertJsonMatchesSchema_simple.schema.json')
182+
);
30183
}
31184

32185
public function testAssertJsonMatchesSchema()
@@ -61,7 +214,10 @@ public function testAssertJsonMatchesSchemaFailMessage()
61214
try {
62215
AssertTraitImpl::assertJsonMatchesSchema($content, Utils::getSchemaPath('test.schema.json'));
63216
} catch (ExpectationFailedException $exception) {
64-
self::assertStringContainsString('- Property: foo, Constraint: type, Message: String value found, but an integer is required', $exception->getMessage());
217+
self::assertStringContainsString(
218+
'- Property: foo, Constraint: type, Message: String value found, but an integer is required',
219+
$exception->getMessage()
220+
);
65221
self::assertStringContainsString('- Response: {"foo":"123"}', $exception->getMessage());
66222
}
67223

@@ -100,7 +256,7 @@ public function testAssertJsonMatchesSchemaString()
100256
* @dataProvider assertJsonValueEqualsProvider
101257
*
102258
* @param string $expression
103-
* @param mixed $value
259+
* @param mixed $value
104260
*/
105261
public function testAssertJsonValueEquals(string $expression, $value)
106262
{
@@ -114,10 +270,10 @@ public function testAssertWithSchemaStore()
114270
$obj = new AssertTraitImpl();
115271
$obj->setUp();
116272

117-
$schemaStore = $obj->testWithSchemaStore('foobar', (object) ['type' => 'string']);
273+
$schemaStore = $obj->testWithSchemaStore('foobar', (object)['type' => 'string']);
118274

119275
self::assertInstanceOf('JsonSchema\SchemaStorage', $schemaStore);
120-
self::assertEquals($schemaStore->getSchema('foobar'), (object) ['type' => 'string']);
276+
self::assertEquals($schemaStore->getSchema('foobar'), (object)['type' => 'string']);
121277
}
122278

123279
public function assertJsonValueEqualsProvider(): array
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"id": 33,
3+
"title": "Sample Title",
4+
"status": "active",
5+
"created_at": "2009-03-24T16:24:32Z",
6+
"tags": [
7+
"foo",
8+
"bar"
9+
],
10+
"meta_description": "A brief description."
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-06/schema#",
3+
"type": "object",
4+
"additionalProperties": false,
5+
"minProperties": 1,
6+
"maxProperties": 7,
7+
"properties": {
8+
"id": {
9+
"type": "integer",
10+
"minimum": 1,
11+
"exclusiveMinimum": 1,
12+
"multipleOf": 1
13+
},
14+
"title": {
15+
"type": "string",
16+
"examples": ["Sample Title", "Another Title"],
17+
"minLength": 2,
18+
"maxLength": 20
19+
},
20+
"status": {
21+
"type": "string",
22+
"enum": ["active", "pending", "completed"],
23+
"not": {
24+
"enum": ["inactive", "deleted"]
25+
}
26+
},
27+
"created_at": {
28+
"type": "string",
29+
"format": "date-time"
30+
},
31+
"completed_at": {
32+
"type": "string",
33+
"format": "date-time"
34+
},
35+
"expected_completion": {
36+
"type": "string",
37+
"format": "date-time"
38+
},
39+
"tags": {
40+
"type": "array",
41+
"minItems": 1,
42+
"maxItems": 10,
43+
"items": {
44+
"type": "string"
45+
},
46+
"uniqueItems": true,
47+
"contains": { "const": "foo" }
48+
},
49+
"meta_description": {
50+
"type": "string"
51+
}
52+
},
53+
"dependencies": {
54+
"status": ["created_at"]
55+
},
56+
"patternProperties": {
57+
"^meta_": {
58+
"type": "string",
59+
"minLength": 5
60+
}
61+
},
62+
"propertyNames": {
63+
"pattern": "^[a-z][a-z0-9_]*$",
64+
"maxLength": 10
65+
},
66+
67+
"if": {
68+
"properties": { "status": { "const": "completed" } }
69+
},
70+
"then": {
71+
"required": ["completed_at"]
72+
},
73+
"else": {
74+
"if": {
75+
"properties": { "status": { "const": "pending" } }
76+
},
77+
"then": {
78+
"required": ["expected_completion"]
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)