1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the JVal package. |
5
|
|
|
* |
6
|
|
|
* For the full copyright and license information, please view the LICENSE |
7
|
|
|
* file that was distributed with this source code. |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
namespace JVal; |
11
|
|
|
|
12
|
|
|
use JVal\Testing\BaseTestCase; |
13
|
|
|
use stdClass; |
14
|
|
|
|
15
|
|
|
class ResolverTest extends BaseTestCase |
16
|
|
|
{ |
17
|
|
|
/** |
18
|
|
|
* @var Resolver |
19
|
|
|
*/ |
20
|
|
|
private $resolver; |
21
|
|
|
|
22
|
|
|
protected function setUp() |
23
|
|
|
{ |
24
|
|
|
$this->resolver = new Resolver(); |
25
|
|
|
} |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @expectedException \JVal\Exception\Resolver\EmptyStackException |
29
|
|
|
*/ |
30
|
|
|
public function testGetCurrentSchemaThrowsIfStackIsEmpty() |
31
|
|
|
{ |
32
|
|
|
$this->resolver->getCurrentSchema(); |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @expectedException \JVal\Exception\Resolver\EmptyStackException |
37
|
|
|
*/ |
38
|
|
|
public function testGetCurrentUriThrowsIfStackIsEmpty() |
39
|
|
|
{ |
40
|
|
|
$this->resolver->getCurrentUri(); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @expectedException \JVal\Exception\Resolver\EmptyStackException |
45
|
|
|
*/ |
46
|
|
|
public function testLeaveThrowsIfStackIsEmpty() |
47
|
|
|
{ |
48
|
|
|
$this->resolver->leave(); |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @dataProvider rootRefProvider |
53
|
|
|
* |
54
|
|
|
* @param string $schemaName |
55
|
|
|
*/ |
56
|
|
|
public function testResolveLocalRoot($schemaName) |
57
|
|
|
{ |
58
|
|
|
$schema = $this->loadSchema($schemaName); |
59
|
|
|
$this->resolver->initialize($schema, new Uri('file:///foo/bar')); |
60
|
|
|
$resolved = $this->resolver->resolve($schema->foo->bar); |
61
|
|
|
$this->assertEquals($schema, $resolved[1]); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* @dataProvider chainProvider |
66
|
|
|
* |
67
|
|
|
* @param stdClass $schema |
68
|
|
|
* @param string $pointerUri |
69
|
|
|
* @param stdClass $resolved |
70
|
|
|
*/ |
71
|
|
View Code Duplication |
public function testResolveChain(stdClass $schema, $pointerUri, stdClass $resolved) |
|
|
|
|
72
|
|
|
{ |
73
|
|
|
$this->resolver->initialize($schema, new Uri('file:///foo/bar')); |
74
|
|
|
$reference = new stdClass(); |
75
|
|
|
$reference->{'$ref'} = $pointerUri; |
76
|
|
|
$actual = $this->resolver->resolve($reference); |
77
|
|
|
$this->assertSame($actual[1], $resolved); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @dataProvider unresolvablePointerPropertyProvider |
82
|
|
|
* @expectedException \JVal\Exception\Resolver\UnresolvedPointerPropertyException |
83
|
|
|
* |
84
|
|
|
* @param stdClass $schema |
85
|
|
|
* @param string $pointerUri |
86
|
|
|
*/ |
87
|
|
View Code Duplication |
public function testResolveThrowsOnUnresolvedPointerProperty(stdClass $schema, $pointerUri) |
|
|
|
|
88
|
|
|
{ |
89
|
|
|
$this->resolver->initialize($schema, new Uri('file:///foo/bar')); |
90
|
|
|
$reference = new stdClass(); |
91
|
|
|
$reference->{'$ref'} = $pointerUri; |
92
|
|
|
$this->resolver->resolve($reference); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @dataProvider invalidPointerIndexProvider |
97
|
|
|
* @expectedException \JVal\Exception\Resolver\InvalidPointerIndexException |
98
|
|
|
* |
99
|
|
|
* @param stdClass $schema |
100
|
|
|
* @param string $pointerUri |
101
|
|
|
*/ |
102
|
|
View Code Duplication |
public function testResolveThrowsOnInvalidPointerIndex(stdClass $schema, $pointerUri) |
|
|
|
|
103
|
|
|
{ |
104
|
|
|
$this->resolver->initialize($schema, new Uri('file:///foo/bar')); |
105
|
|
|
$reference = new stdClass(); |
106
|
|
|
$reference->{'$ref'} = $pointerUri; |
107
|
|
|
$this->resolver->resolve($reference); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* @dataProvider unresolvablePointerIndexProvider |
112
|
|
|
* @expectedException \JVal\Exception\Resolver\UnresolvedPointerIndexException |
113
|
|
|
* |
114
|
|
|
* @param stdClass $schema |
115
|
|
|
* @param string $pointerUri |
116
|
|
|
*/ |
117
|
|
View Code Duplication |
public function testResolveThrowsOnUnresolvedPointerIndex(stdClass $schema, $pointerUri) |
|
|
|
|
118
|
|
|
{ |
119
|
|
|
$this->resolver->initialize($schema, new Uri('file:///foo/bar')); |
120
|
|
|
$reference = new stdClass(); |
121
|
|
|
$reference->{'$ref'} = $pointerUri; |
122
|
|
|
$this->resolver->resolve($reference); |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* @dataProvider invalidPointerSegmentProvider |
127
|
|
|
* @expectedException \JVal\Exception\Resolver\InvalidSegmentTypeException |
128
|
|
|
* |
129
|
|
|
* @param stdClass $schema |
130
|
|
|
* @param string $pointerUri |
131
|
|
|
*/ |
132
|
|
View Code Duplication |
public function testResolveThrowsOnInvalidPointerSegment(stdClass $schema, $pointerUri) |
|
|
|
|
133
|
|
|
{ |
134
|
|
|
$this->resolver->initialize($schema, new Uri('file:///foo/bar')); |
135
|
|
|
$reference = new stdClass(); |
136
|
|
|
$reference->{'$ref'} = $pointerUri; |
137
|
|
|
$this->resolver->resolve($reference); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* @dataProvider invalidPointerTargetProvider |
142
|
|
|
* @expectedException \JVal\Exception\Resolver\InvalidPointerTargetException |
143
|
|
|
* |
144
|
|
|
* @param stdClass $schema |
145
|
|
|
* @param string $pointerUri |
146
|
|
|
*/ |
147
|
|
View Code Duplication |
public function testResolveThrowsOnInvalidPointerTarget(stdClass $schema, $pointerUri) |
|
|
|
|
148
|
|
|
{ |
149
|
|
|
$this->resolver->initialize($schema, new Uri('file:///foo/bar')); |
150
|
|
|
$reference = new stdClass(); |
151
|
|
|
$reference->{'$ref'} = $pointerUri; |
152
|
|
|
$this->resolver->resolve($reference); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* @dataProvider selfReferencingPointerProvider |
157
|
|
|
* @expectedException \JVal\Exception\Resolver\SelfReferencingPointerException |
158
|
|
|
* |
159
|
|
|
* @param stdClass $schema |
160
|
|
|
* @param stdClass $reference |
161
|
|
|
*/ |
162
|
|
|
public function testResolveThrowsOnSelfReferencingPointer(stdClass $schema, stdClass $reference) |
163
|
|
|
{ |
164
|
|
|
$this->resolver->initialize($schema, new Uri('file:///foo/bar')); |
165
|
|
|
$this->resolver->resolve($reference); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* @group network |
170
|
|
|
* @dataProvider unfetchableUriProvider |
171
|
|
|
* @expectedException \JVal\Exception\Resolver\UnfetchableUriException |
172
|
|
|
* |
173
|
|
|
* @param string $pointerUri |
174
|
|
|
*/ |
175
|
|
View Code Duplication |
public function testResolveThrowsOnUnfetchableUri($pointerUri) |
|
|
|
|
176
|
|
|
{ |
177
|
|
|
$this->resolver->initialize(new stdClass(), new Uri('file:///foo/bar')); |
178
|
|
|
$reference = new stdClass(); |
179
|
|
|
$reference->{'$ref'} = $pointerUri; |
180
|
|
|
$this->resolver->resolve($reference); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* @group network |
185
|
|
|
* @dataProvider remoteUriProvider |
186
|
|
|
* |
187
|
|
|
* @param string $pointerUri |
188
|
|
|
* @param stdClass $expectedSchema |
189
|
|
|
*/ |
190
|
|
View Code Duplication |
public function testResolveRemoteSchema($pointerUri, stdClass $expectedSchema) |
|
|
|
|
191
|
|
|
{ |
192
|
|
|
$this->resolver->initialize(new stdClass(), new Uri('file:///foo/bar')); |
193
|
|
|
$reference = new stdClass(); |
194
|
|
|
$reference->{'$ref'} = $pointerUri; |
195
|
|
|
$resolved = $this->resolver->resolve($reference); |
196
|
|
|
$this->assertEquals($resolved[1], $expectedSchema); |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* @expectedException \JVal\Exception\JsonDecodeException |
201
|
|
|
*/ |
202
|
|
View Code Duplication |
public function testResolveThrowsOnUndecodableRemoteSchema() |
|
|
|
|
203
|
|
|
{ |
204
|
|
|
$this->resolver->initialize(new stdClass(), new Uri('file:///foo/bar')); |
205
|
|
|
$schemaFile = __DIR__.'/Data/schemas/invalid/undecodable.json'; |
206
|
|
|
$reference = new stdClass(); |
207
|
|
|
$reference->{'$ref'} = $this->getLocalUri($schemaFile); |
208
|
|
|
$this->resolver->resolve($reference); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* @expectedException \JVal\Exception\Resolver\InvalidRemoteSchemaException |
213
|
|
|
*/ |
214
|
|
View Code Duplication |
public function testResolveThrowsOnInvalidRemoteSchema() |
|
|
|
|
215
|
|
|
{ |
216
|
|
|
$this->resolver->initialize(new stdClass(), new Uri('file:///foo/bar')); |
217
|
|
|
$schemaFile = __DIR__.'/Data/schemas/invalid/not-an-object.json'; |
218
|
|
|
$reference = new stdClass(); |
219
|
|
|
$reference->{'$ref'} = $this->getLocalUri($schemaFile); |
220
|
|
|
$this->resolver->resolve($reference); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
public function rootRefProvider() |
224
|
|
|
{ |
225
|
|
|
return [ |
226
|
|
|
['valid/root-reference-1'], |
227
|
|
|
['valid/root-reference-2'], |
228
|
|
|
['valid/root-reference-3'], |
229
|
|
|
]; |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
public function chainProvider() |
233
|
|
|
{ |
234
|
|
|
$schema = $this->loadSchema('valid/resolution-chains'); |
235
|
|
|
|
236
|
|
|
return [ |
237
|
|
|
[$schema, '#foo', $schema->foo], |
238
|
|
|
[$schema, '#/foo', $schema->foo], |
239
|
|
|
[$schema, '#/foo/baz', $schema->foo->baz], |
240
|
|
|
[$schema, '#/bar/baz', $schema->bar->baz], |
241
|
|
|
[$schema, '#/bar/baz/bat', $schema->bar->baz->bat], |
242
|
|
|
[$schema, '#/bar/baz/bat/', $schema->bar->baz->bat], |
243
|
|
|
[$schema, '#/bat/0', $schema->bat[0]], |
244
|
|
|
[$schema, '#/bat/1/quz/0', $schema->bat[1]->quz[0]], |
245
|
|
|
[$schema, '#/with%25percent', $schema->{'with%percent'}], |
246
|
|
|
[$schema, '#/bar/with~1slash', $schema->bar->{'with/slash'}], |
247
|
|
|
[$schema, '#/bar/with~1slash', $schema->bar->{'with/slash'}], |
248
|
|
|
[$schema, '#/bar/with~0tilde', $schema->bar->{'with~tilde'}], |
249
|
|
|
]; |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
public function unresolvablePointerPropertyProvider() |
253
|
|
|
{ |
254
|
|
|
$schema = $this->loadSchema('valid/resolution-chains'); |
255
|
|
|
|
256
|
|
|
return [ |
257
|
|
|
[$schema, '#nope'], |
258
|
|
|
[$schema, '#/foo/nope'], |
259
|
|
|
[$schema, '#bar/baz/nope'], |
260
|
|
|
]; |
261
|
|
|
} |
262
|
|
|
|
263
|
|
View Code Duplication |
public function invalidPointerIndexProvider() |
|
|
|
|
264
|
|
|
{ |
265
|
|
|
$schema = $this->loadSchema('valid/resolution-chains'); |
266
|
|
|
|
267
|
|
|
return [ |
268
|
|
|
[$schema, '#/bat/1/quz/bar'], |
269
|
|
|
[$schema, '#/bat/1/quz/0/bar/baz'], |
270
|
|
|
]; |
271
|
|
|
} |
272
|
|
|
|
273
|
|
View Code Duplication |
public function unresolvablePointerIndexProvider() |
|
|
|
|
274
|
|
|
{ |
275
|
|
|
$schema = $this->loadSchema('valid/resolution-chains'); |
276
|
|
|
|
277
|
|
|
return [ |
278
|
|
|
[$schema, '#/bat/4'], |
279
|
|
|
[$schema, '#/bat/7/quz/2/bar'], |
280
|
|
|
]; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
View Code Duplication |
public function invalidPointerSegmentProvider() |
|
|
|
|
284
|
|
|
{ |
285
|
|
|
$schema = $this->loadSchema('valid/resolution-chains'); |
286
|
|
|
|
287
|
|
|
return [ |
288
|
|
|
[$schema, '#/bat/2/bar'], |
289
|
|
|
[$schema, '#/bat/1/quz/1/foo'], |
290
|
|
|
]; |
291
|
|
|
} |
292
|
|
|
|
293
|
|
View Code Duplication |
public function invalidPointerTargetProvider() |
|
|
|
|
294
|
|
|
{ |
295
|
|
|
$schema = $this->loadSchema('valid/resolution-chains'); |
296
|
|
|
|
297
|
|
|
return [ |
298
|
|
|
[$schema, '#/foo/bat'], |
299
|
|
|
[$schema, '#bat'], |
300
|
|
|
]; |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
public function selfReferencingPointerProvider() |
304
|
|
|
{ |
305
|
|
|
$schema1 = $this->loadSchema('invalid/self-referencing-pointer-1'); |
306
|
|
|
$schema2 = $this->loadSchema('invalid/self-referencing-pointer-2'); |
307
|
|
|
|
308
|
|
|
return [ |
309
|
|
|
[$schema1, $schema1], |
310
|
|
|
[$schema2, $schema2->foo->bar], |
311
|
|
|
]; |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
public function unfetchableUriProvider() |
315
|
|
|
{ |
316
|
|
|
return [ |
317
|
|
|
['`malformed:/?u?r::l'], |
318
|
|
|
['unknown://scheme'], |
319
|
|
|
['http://non.existent/host'], |
320
|
|
|
['http://localhost/non/existent/resource'], |
321
|
|
|
['http://localhost/same#/with/pointer'], |
322
|
|
|
]; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
public function remoteUriProvider() |
326
|
|
|
{ |
327
|
|
|
$schemaDir = $this->getVendorDir().'/json-schema/json-schema'; |
328
|
|
|
$schemaFile = $schemaDir.'/draft-03/schema'; |
329
|
|
|
$schema3 = $this->loadJsonFromFile($schemaFile); |
330
|
|
|
|
331
|
|
|
return [ |
332
|
|
|
['http://json-schema.org/draft-03/schema#', $schema3], |
333
|
|
|
[$this->getLocalUri($schemaFile), $schema3], |
334
|
|
|
]; |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
private function getVendorDir() |
338
|
|
|
{ |
339
|
|
|
$local = __DIR__.'/../vendor'; |
340
|
|
|
$parent = __DIR__.'/../../../../vendor'; |
341
|
|
|
|
342
|
|
|
if (is_dir($local)) { |
343
|
|
|
return $local; |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
if (is_dir($parent)) { |
347
|
|
|
return $parent; |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
throw new \Exception('Cannot find vendor dir'); |
351
|
|
|
} |
352
|
|
|
} |
353
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.