Skip to content

Commit db5449f

Browse files
committed
spec tests fixed again! 🎉
1 parent c307c99 commit db5449f

File tree

5 files changed

+181
-32
lines changed

5 files changed

+181
-32
lines changed

src/Constraint/Ref.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
namespace Swaggest\JsonSchema\Constraint;
44

5-
use Swaggest\JsonSchema\RefResolver;
6-
75
class Ref implements Constraint
86
{
7+
public $resolutionScope;
8+
99
public $ref;
1010
public function __construct($ref, $data = null)
1111
{

src/RefResolver.php

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
namespace Swaggest\JsonSchema;
44

5+
use PhpLang\ScopeExit;
56
use Swaggest\JsonSchema\Constraint\Ref;
67
use Swaggest\JsonSchema\RemoteRef\BasicFetcher;
78

89
class RefResolver
910
{
10-
private $resolutionScope = '';
11-
private $url;
11+
public $resolutionScope = '';
12+
public $url;
1213
/** @var RefResolver */
1314
private $rootResolver;
1415

@@ -24,6 +25,16 @@ public function setResolutionScope($resolutionScope)
2425
return $prev;
2526
}
2627

28+
/**
29+
* @return string
30+
*/
31+
public function getResolutionScope()
32+
{
33+
$rootResolver = $this->rootResolver ? $this->rootResolver : $this;
34+
return $rootResolver->resolutionScope;
35+
}
36+
37+
2738
public function updateResolutionScope($id)
2839
{
2940
$rootResolver = $this->rootResolver ? $this->rootResolver : $this;
@@ -43,7 +54,7 @@ public function setupResolutionScope($id, $data)
4354

4455
$prev = $this->updateResolutionScope($id);
4556

46-
$refParts = explode('#', $this->resolutionScope, 2);
57+
$refParts = explode('#', $rootResolver->resolutionScope, 2);
4758
if ($refParts[0] && empty($refParts[1])) {
4859
if (!isset($rootResolver->remoteRefResolvers[$refParts[0]])) {
4960
$resolver = new RefResolver($data);
@@ -118,12 +129,25 @@ public function resolveReference($referencePath)
118129
if (null === $ref) {
119130
if ($referencePath[0] === '#') {
120131
if ($referencePath === '#') {
121-
$ref = new Ref($referencePath, $this->rootData);
132+
$ref = new Ref($referencePath, $refResolver->rootData);
133+
$ref->resolutionScope = $this->getResolutionScope();
122134
} else {
123135
$ref = new Ref($referencePath);
124136
$path = explode('/', trim($referencePath, '#/'));
125-
$branch = &$this->rootData;
137+
138+
$prevResScope = $refResolver->getResolutionScope();
139+
/** @noinspection PhpUnusedLocalVariableInspection */
140+
$defer = new ScopeExit(function () use ($prevResScope, $refResolver) {
141+
$refResolver->setResolutionScope($prevResScope);
142+
});
143+
144+
/** @var JsonSchema $branch */
145+
$branch = &$refResolver->rootData;
126146
while (!empty($path)) {
147+
if (isset($branch->id)) {
148+
$refResolver->updateResolutionScope($branch->id);
149+
}
150+
127151
$folder = array_shift($path);
128152

129153
// unescaping special characters
@@ -140,6 +164,7 @@ public function resolveReference($referencePath)
140164
}
141165
}
142166
$ref->setData($branch);
167+
$ref->resolutionScope = $refResolver->getResolutionScope();
143168
}
144169
} else {
145170
if ($url !== $this->url) {
@@ -151,19 +176,14 @@ public function resolveReference($referencePath)
151176
$refResolver->rootResolver = $rootResolver;
152177
$refResolver->refProvider = $this->refProvider;
153178
$refResolver->url = $url;
179+
$rootResolver->setResolutionScope($url);
154180
}
155181
}
156182

157183
$ref = $refResolver->resolveReference($refLocalPath);
158184
}
159185
}
160186

161-
$refData = $ref->getData();
162-
// we need to go deeper
163-
if (isset($refData->{'$ref'})) {
164-
return $refResolver->resolveReference($refData->{'$ref'});
165-
}
166-
167187
return $ref;
168188
}
169189

src/Schema.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,9 @@ public function export($data, ProcessingOptions $options = null)
180180
return $this->process($data, $options);
181181
}
182182

183-
public function process($data, ProcessingOptions $options, $path = '#')
183+
public function process($data, ProcessingOptions $options, $path = '#', $result = null)
184184
{
185+
185186
$import = $options->import;
186187
//$pathTrace = explode('->', $path);
187188

@@ -196,7 +197,9 @@ public function process($data, ProcessingOptions $options, $path = '#')
196197
$data = $options->dataPreProcessor->process($data, $this, $import);
197198
}
198199

199-
$result = $data;
200+
if ($result === null) {
201+
$result = $data;
202+
}
200203

201204
if ($this->type !== null) {
202205
if (!Type::isValid($this->type, $data)) {
@@ -382,10 +385,17 @@ public function process($data, ProcessingOptions $options, $path = '#')
382385
$data = $ref->getData();
383386
if ($result instanceof Schema) {
384387
$result->fromRef = $refString;
385-
386388
}
387389
$ref->setImported($result);
388-
$path .= '->$ref:' . $refString;
390+
if ($ref->resolutionScope !== $options->refResolver->resolutionScope) {
391+
$parentRefScope = $options->refResolver->updateResolutionScope($ref->resolutionScope);
392+
/** @noinspection PhpUnusedLocalVariableInspection */
393+
$deferRef = new ScopeExit(function () use ($parentRefScope, $options) {
394+
$options->refResolver->setResolutionScope($parentRefScope);
395+
});
396+
}
397+
398+
return $this->process($data, $options, $path . '->ref:' . $refString, $result);
389399
}
390400
} catch (InvalidValue $exception) {
391401
$this->fail($exception, $path);

tests/src/PHPUnit/RefTest.php

Lines changed: 119 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Swaggest\JsonSchema\ProcessingOptions;
1212
use Swaggest\JsonSchema\RefResolver;
1313
use Swaggest\JsonSchema\RemoteRef\Preloaded;
14+
use Swaggest\JsonSchema\Tests\PHPUnit\Spec\SpecTest;
1415

1516
class RefTest extends \PHPUnit_Framework_TestCase
1617
{
@@ -307,15 +308,129 @@ public function testScopeChange()
307308
);
308309

309310
$options = new ProcessingOptions();
310-
$options->remoteRefProvider = (new Preloaded())
311-
->setSchemaData('http://localhost:1234/folder/folderInteger.json', json_decode(file_get_contents(
312-
__DIR__ . '/../../../spec/JSON-Schema-Test-Suite/remotes/folder/folderInteger.json'
313-
)));
311+
$options->remoteRefProvider = SpecTest::getProvider();
314312
$schema = JsonSchema::importToSchema($testData->schema, $options);
315313

316314
$schema->import($testData->tests[0]->data);
317315
$this->setExpectedException(get_class(new InvalidValue()));
318316
$schema->import($testData->tests[1]->data);
319317
}
320318

319+
320+
public function testScopeChangeSubschema()
321+
{
322+
$testData = json_decode(<<<'JSON'
323+
{
324+
"description": "base URI change - change folder in subschema",
325+
"schema": {
326+
"id": "http://localhost:1234/scope_change_defs2.json",
327+
"type" : "object",
328+
"properties": {
329+
"list": {"$ref": "#/definitions/baz/definitions/bar"}
330+
},
331+
"definitions": {
332+
"baz": {
333+
"id": "folder/",
334+
"definitions": {
335+
"bar": {
336+
"type": "array",
337+
"items": {"$ref": "folderInteger.json"}
338+
}
339+
}
340+
}
341+
}
342+
},
343+
"tests": [
344+
{
345+
"description": "number is valid",
346+
"data": {"list": [1]},
347+
"valid": true
348+
},
349+
{
350+
"description": "string is invalid",
351+
"data": {"list": ["a"]},
352+
"valid": false
353+
}
354+
]
355+
}
356+
JSON
357+
);
358+
$options = new ProcessingOptions();
359+
$options->remoteRefProvider = SpecTest::getProvider();
360+
$schema = JsonSchema::importToSchema($testData->schema, $options);
361+
362+
$schema->import($testData->tests[0]->data);
363+
$this->setExpectedException(get_class(new InvalidValue()));
364+
$schema->import($testData->tests[1]->data);
365+
366+
367+
}
368+
369+
370+
public function testExtRef()
371+
{
372+
$testData = json_decode(<<<'JSON'
373+
{
374+
"description": "external ref within remote ref",
375+
"schema": {
376+
"$ref": "http://localhost:1234/subSchemas.json#/refToExternalInteger"
377+
},
378+
"tests": [
379+
{
380+
"description": "external ref within ref valid",
381+
"data": 1,
382+
"valid": true
383+
},
384+
{
385+
"description": "external ref within ref invalid",
386+
"data": "a",
387+
"valid": false
388+
}
389+
]
390+
}
391+
JSON
392+
);
393+
394+
$schema = JsonSchema::importToSchema($testData->schema, new ProcessingOptions(
395+
SpecTest::getProvider())
396+
);
397+
$schema->import($testData->tests[0]->data);
398+
$this->setExpectedException(get_class(new InvalidValue()));
399+
$schema->import($testData->tests[1]->data);
400+
401+
}
402+
403+
404+
public function testRefWithinRef()
405+
{
406+
$testData = json_decode(<<<'JSON'
407+
{
408+
"description": "ref within remote ref",
409+
"schema": {
410+
"$ref": "http://localhost:1234/subSchemas.json#/refToInteger"
411+
},
412+
"tests": [
413+
{
414+
"description": "ref within ref valid",
415+
"data": 1,
416+
"valid": true
417+
},
418+
{
419+
"description": "ref within ref invalid",
420+
"data": "a",
421+
"valid": false
422+
}
423+
]
424+
}
425+
JSON
426+
);
427+
$schema = JsonSchema::importToSchema($testData->schema, new ProcessingOptions(
428+
SpecTest::getProvider())
429+
);
430+
$schema->import($testData->tests[0]->data);
431+
$this->setExpectedException(get_class(new InvalidValue()));
432+
$schema->import($testData->tests[1]->data);
433+
434+
}
435+
321436
}

tests/src/PHPUnit/Spec/SpecTest.php

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,11 @@
55
use Swaggest\JsonSchema\InvalidValue;
66
use Swaggest\JsonSchema\JsonSchema;
77
use Swaggest\JsonSchema\ProcessingOptions;
8-
use Swaggest\JsonSchema\RefResolver;
98
use Swaggest\JsonSchema\RemoteRef\Preloaded;
10-
use Swaggest\JsonSchema\Schema;
11-
use Swaggest\JsonSchema\SchemaLoader;
129

1310
class SpecTest extends \PHPUnit_Framework_TestCase
1411
{
15-
/**
16-
* @dataProvider provider
17-
* @param $schemaData
18-
* @param $data
19-
* @param $isValid
20-
* @throws InvalidValue
21-
*/
22-
public function testSpecDraft4($schemaData, $data, $isValid)
12+
public static function getProvider()
2313
{
2414
static $refProvider = null;
2515

@@ -44,6 +34,20 @@ public function testSpecDraft4($schemaData, $data, $isValid)
4434
. '/../../../../spec/JSON-Schema-Test-Suite/remotes/folder/folderInteger.json')));
4535
}
4636

37+
return $refProvider;
38+
}
39+
40+
/**
41+
* @dataProvider provider
42+
* @param $schemaData
43+
* @param $data
44+
* @param $isValid
45+
* @throws InvalidValue
46+
*/
47+
public function testSpecDraft4($schemaData, $data, $isValid)
48+
{
49+
$refProvider = self::getProvider();
50+
4751
$actualValid = true;
4852
$error = '';
4953
try {

0 commit comments

Comments
 (0)