jsi 0.2.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +36 -0
  4. data/LICENSE.md +613 -0
  5. data/README.md +153 -52
  6. data/lib/jsi/base.rb +485 -338
  7. data/lib/jsi/jsi_coder.rb +24 -18
  8. data/lib/jsi/metaschema.rb +7 -0
  9. data/lib/jsi/metaschema_node/bootstrap_schema.rb +100 -0
  10. data/lib/jsi/metaschema_node.rb +245 -0
  11. data/lib/jsi/pathed_node.rb +49 -46
  12. data/lib/jsi/ptr.rb +292 -0
  13. data/lib/jsi/schema/application/child_application/contains.rb +16 -0
  14. data/lib/jsi/schema/application/child_application/draft04.rb +22 -0
  15. data/lib/jsi/schema/application/child_application/draft06.rb +29 -0
  16. data/lib/jsi/schema/application/child_application/draft07.rb +29 -0
  17. data/lib/jsi/schema/application/child_application/items.rb +18 -0
  18. data/lib/jsi/schema/application/child_application/properties.rb +25 -0
  19. data/lib/jsi/schema/application/child_application.rb +40 -0
  20. data/lib/jsi/schema/application/draft04.rb +8 -0
  21. data/lib/jsi/schema/application/draft06.rb +8 -0
  22. data/lib/jsi/schema/application/draft07.rb +8 -0
  23. data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
  24. data/lib/jsi/schema/application/inplace_application/draft04.rb +26 -0
  25. data/lib/jsi/schema/application/inplace_application/draft06.rb +27 -0
  26. data/lib/jsi/schema/application/inplace_application/draft07.rb +33 -0
  27. data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
  28. data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
  29. data/lib/jsi/schema/application/inplace_application/someof.rb +29 -0
  30. data/lib/jsi/schema/application/inplace_application.rb +46 -0
  31. data/lib/jsi/schema/application.rb +12 -0
  32. data/lib/jsi/schema/draft04.rb +14 -0
  33. data/lib/jsi/schema/draft06.rb +14 -0
  34. data/lib/jsi/schema/draft07.rb +14 -0
  35. data/lib/jsi/schema/issue.rb +36 -0
  36. data/lib/jsi/schema/ref.rb +159 -0
  37. data/lib/jsi/schema/schema_ancestor_node.rb +119 -0
  38. data/lib/jsi/schema/validation/array.rb +69 -0
  39. data/lib/jsi/schema/validation/const.rb +20 -0
  40. data/lib/jsi/schema/validation/contains.rb +25 -0
  41. data/lib/jsi/schema/validation/core.rb +39 -0
  42. data/lib/jsi/schema/validation/dependencies.rb +49 -0
  43. data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
  44. data/lib/jsi/schema/validation/draft04.rb +112 -0
  45. data/lib/jsi/schema/validation/draft06.rb +122 -0
  46. data/lib/jsi/schema/validation/draft07.rb +159 -0
  47. data/lib/jsi/schema/validation/enum.rb +25 -0
  48. data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
  49. data/lib/jsi/schema/validation/items.rb +54 -0
  50. data/lib/jsi/schema/validation/not.rb +20 -0
  51. data/lib/jsi/schema/validation/numeric.rb +121 -0
  52. data/lib/jsi/schema/validation/object.rb +45 -0
  53. data/lib/jsi/schema/validation/pattern.rb +34 -0
  54. data/lib/jsi/schema/validation/properties.rb +101 -0
  55. data/lib/jsi/schema/validation/property_names.rb +32 -0
  56. data/lib/jsi/schema/validation/ref.rb +40 -0
  57. data/lib/jsi/schema/validation/required.rb +27 -0
  58. data/lib/jsi/schema/validation/someof.rb +90 -0
  59. data/lib/jsi/schema/validation/string.rb +47 -0
  60. data/lib/jsi/schema/validation/type.rb +49 -0
  61. data/lib/jsi/schema/validation.rb +51 -0
  62. data/lib/jsi/schema.rb +528 -233
  63. data/lib/jsi/schema_classes.rb +238 -51
  64. data/lib/jsi/schema_registry.rb +141 -0
  65. data/lib/jsi/schema_set.rb +141 -0
  66. data/lib/jsi/simple_wrap.rb +8 -3
  67. data/lib/jsi/typelike_modules.rb +75 -68
  68. data/lib/jsi/util/attr_struct.rb +106 -0
  69. data/lib/jsi/util.rb +167 -64
  70. data/lib/jsi/validation/error.rb +34 -0
  71. data/lib/jsi/validation/result.rb +210 -0
  72. data/lib/jsi/validation.rb +15 -0
  73. data/lib/jsi/version.rb +3 -1
  74. data/lib/jsi.rb +72 -9
  75. data/lib/schemas/json-schema.org/draft-04/schema.rb +12 -0
  76. data/lib/schemas/json-schema.org/draft-06/schema.rb +12 -0
  77. data/lib/schemas/json-schema.org/draft-07/schema.rb +12 -0
  78. data/readme.rb +138 -0
  79. data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
  80. data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
  81. data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
  82. metadata +80 -107
  83. data/.simplecov +0 -1
  84. data/LICENSE.txt +0 -21
  85. data/Rakefile.rb +0 -9
  86. data/jsi.gemspec +0 -31
  87. data/lib/jsi/base/to_rb.rb +0 -126
  88. data/lib/jsi/json/node.rb +0 -243
  89. data/lib/jsi/json/pointer.rb +0 -330
  90. data/lib/jsi/json-schema-fragments.rb +0 -59
  91. data/lib/jsi/json.rb +0 -8
  92. data/test/base_array_test.rb +0 -209
  93. data/test/base_hash_test.rb +0 -204
  94. data/test/base_test.rb +0 -422
  95. data/test/jsi_coder_test.rb +0 -85
  96. data/test/jsi_json_arraynode_test.rb +0 -150
  97. data/test/jsi_json_hashnode_test.rb +0 -132
  98. data/test/jsi_json_node_test.rb +0 -310
  99. data/test/jsi_json_pointer_test.rb +0 -106
  100. data/test/jsi_test.rb +0 -11
  101. data/test/jsi_typelike_as_json_test.rb +0 -53
  102. data/test/schema_test.rb +0 -196
  103. data/test/spreedly_openapi_test.rb +0 -8
  104. data/test/test_helper.rb +0 -63
  105. data/test/util_test.rb +0 -62
@@ -1,310 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- describe JSI::JSON::Node do
4
- let(:path) { [] }
5
- let(:pointer) { JSI::JSON::Pointer.new(path) }
6
- let(:node) { JSI::JSON::Node.new(document, pointer) }
7
-
8
- describe 'initialization' do
9
- it 'initializes' do
10
- node = JSI::JSON::Node.new({'a' => 'b'}, pointer)
11
- assert_equal({'a' => 'b'}, node.document)
12
- assert_equal(JSI::JSON::Pointer.new([]), node.pointer)
13
- end
14
- it 'initializes, pointer is not pointer' do
15
- err = assert_raises(TypeError) { JSI::JSON::Node.new({'a' => 'b'}, []) }
16
- assert_equal('pointer must be a JSI::JSON::Pointer. got: [] (Array)', err.message)
17
- end
18
- it 'initializes, document is another Node' do
19
- err = assert_raises(TypeError) { JSI::JSON::Node.new(JSI::JSON::Node.new({'a' => 'b'}, pointer), pointer) }
20
- assert_equal("document of a Node should not be another JSI::JSON::Node: #<JSI::JSON::Node fragment=\"#\" {\"a\"=>\"b\"}>", err.message)
21
- end
22
- end
23
- describe 'initialization by .new_by_type' do
24
- it 'initializes HashNode' do
25
- node = JSI::JSON::Node.new_doc({'a' => 'b'})
26
- assert_instance_of(JSI::JSON::HashNode, node)
27
- assert_equal({'a' => 'b'}, node.document)
28
- end
29
- it 'initializes ArrayNode' do
30
- node = JSI::JSON::Node.new_doc(['a', 'b'])
31
- assert_instance_of(JSI::JSON::ArrayNode, node)
32
- assert_equal(['a', 'b'], node.document)
33
- end
34
- it 'initializes Node' do
35
- object = Object.new
36
- node = JSI::JSON::Node.new_doc(object)
37
- assert_instance_of(JSI::JSON::Node, node)
38
- assert_equal(object, node.document)
39
- end
40
- end
41
- describe '#pointer' do
42
- it 'is a JSI::JSON::Pointer' do
43
- assert_instance_of(JSI::JSON::Pointer, JSI::JSON::Node.new({}, pointer).pointer)
44
- end
45
- end
46
- describe '#path' do
47
- it 'is an array of reference tokens' do
48
- assert_equal(['a'], JSI::JSON::Node.new({}, JSI::JSON::Pointer.new(['a'])).path)
49
- end
50
- end
51
- describe '#content' do
52
- it 'returns the content at the root' do
53
- assert_equal({'a' => 'b'}, JSI::JSON::Node.new({'a' => 'b'}, pointer).content)
54
- end
55
- it 'returns the content from the deep' do
56
- assert_equal('b', JSI::JSON::Node.new([0, {'x' => [{'a' => ['b']}]}], JSI::JSON::Pointer.new([1, 'x', 0, 'a', 0])).content)
57
- end
58
- end
59
- describe '#deref' do
60
- let(:document) do
61
- {
62
- 'foo' => {'bar' => ['baz']},
63
- 'a' => {'$ref' => '#/foo'},
64
- }
65
- end
66
- it 'follows a $ref' do
67
- assert_equal({'bar' => ['baz']}, node['a'].deref.content)
68
- end
69
- it 'returns the node when there is no $ref to follow' do
70
- assert_equal({'bar' => ['baz']}, node['foo'].deref.content)
71
- end
72
- describe "dealing with google's invalid $refs" do
73
- let(:document) do
74
- {
75
- 'schemas' => {'bar' => {'description' => ['baz']}},
76
- 'a' => {'$ref' => 'bar', 'foo' => 'bar'},
77
- }
78
- end
79
- it 'subscripts a node consisting of a $ref WITHOUT following' do
80
- subscripted = node['a']
81
- assert_equal({'$ref' => 'bar', 'foo' => 'bar'}, subscripted.content)
82
- assert_equal(JSI::JSON::Pointer.new(['a']), subscripted.pointer)
83
- end
84
- it 'looks for a node in #/schemas with the name of the $ref' do
85
- assert_equal({'description' => ['baz']}, node['a'].deref.content)
86
- end
87
- it 'follows a $ref when subscripting past it' do
88
- subscripted = node['a']['description']
89
- assert_equal(['baz'], subscripted.content)
90
- assert_equal(JSI::JSON::Pointer.new(['schemas', 'bar', 'description']), subscripted.pointer)
91
- end
92
- it 'does not follow a $ref when subscripting a key that is present' do
93
- subscripted = node['a']['foo']
94
- assert_equal('bar', subscripted)
95
- end
96
- end
97
- describe "dealing with whatever this is" do
98
- # I think google uses this style in some cases maybe. I don't remember.
99
- let(:document) do
100
- {
101
- 'schemas' => {'bar' => {'id' => 'BarID', 'description' => 'baz'}},
102
- 'a' => {'$ref' => 'BarID'},
103
- }
104
- end
105
- it 'looks for a node in #/schemas with the name of the $ref' do
106
- assert_equal({'id' => 'BarID', 'description' => 'baz'}, node['a'].deref.content)
107
- end
108
- end
109
- end
110
- describe '#[]' do
111
- describe 'without dereferencing' do
112
- let(:document) { [0, {'x' => [{'a' => ['b']}]}] }
113
- it 'subscripts arrays and hashes' do
114
- assert_equal('b', node[1]['x'][0]['a'][0])
115
- end
116
- it 'returns ArrayNode for an array' do
117
- subscripted = node[1]['x']
118
- assert_instance_of(JSI::JSON::ArrayNode, subscripted)
119
- assert_equal([{'a' => ['b']}], subscripted.content)
120
- assert_equal(JSI::JSON::Pointer.new([1, 'x']), subscripted.pointer)
121
- end
122
- it 'returns HashNode for a Hash' do
123
- subscripted = node[1]
124
- assert_instance_of(JSI::JSON::HashNode, subscripted)
125
- assert_equal({'x' => [{'a' => ['b']}]}, subscripted.content)
126
- assert_equal(JSI::JSON::Pointer.new([1]), subscripted.pointer)
127
- end
128
- describe 'content does not respond to []' do
129
- let(:document) { Object.new }
130
- it 'cannot subscript' do
131
- err = assert_raises(NoMethodError) { node['x'] }
132
- assert_equal("undefined method `[]`\nsubscripting with \"x\" (String) from Object. content is: #{document.pretty_inspect.chomp}", err.message)
133
- end
134
- end
135
- end
136
- describe 'with dereferencing' do
137
- let(:document) do
138
- {
139
- 'foo' => {'bar' => ['baz']},
140
- 'a' => {'$ref' => '#/foo', 'description' => 'hi'}, # not sure a description is actually allowed here, whatever
141
- }
142
- end
143
- it 'subscripts a node consisting of a $ref WITHOUT following' do
144
- subscripted = node['a']
145
- assert_equal({'$ref' => '#/foo', 'description' => 'hi'}, subscripted.content)
146
- assert_equal(JSI::JSON::Pointer.new(['a']), subscripted.pointer)
147
- end
148
- it 'follows a $ref when subscripting past it' do
149
- subscripted = node['a']['bar']
150
- assert_equal(['baz'], subscripted.content)
151
- assert_equal(JSI::JSON::Pointer.new(['foo', 'bar']), subscripted.pointer)
152
- end
153
- it 'does not follow a $ref when subscripting a key that is present' do
154
- subscripted = node['a']['description']
155
- assert_equal('hi', subscripted)
156
- end
157
- end
158
- end
159
- describe '#[]=' do
160
- let(:document) { [0, {'x' => [{'a' => ['b']}]}] }
161
- it 'assigns' do
162
- node[0] = 'abcdefg'
163
- assert_equal(['abcdefg', {'x' => [{'a' => ['b']}]}], document)
164
- string_node = JSI::JSON::Node.new(document, JSI::JSON::Pointer.new([0]))
165
- string_node[0..2] = '0'
166
- assert_equal(['0defg', {'x' => [{'a' => ['b']}]}], document)
167
- node[0] = node[1]
168
- assert_equal([{'x' => [{'a' => ['b']}]}, {'x' => [{'a' => ['b']}]}], document)
169
- end
170
- it 'assigns, deeper' do
171
- node[1]['y'] = node[1]['x'][0]
172
- assert_equal([0, {'x' => [{'a' => ['b']}], 'y' => {'a' => ['b']}}], document)
173
- end
174
- end
175
- describe '#document_node' do
176
- let(:document) { {'a' => {'b' => 3}} }
177
- it 'has content that is the document' do
178
- assert_equal({'a' => {'b' => 3}}, node['a'].document_node.content)
179
- end
180
- end
181
- describe '#parent_node' do
182
- let(:document) { {'a' => {'b' => []}} }
183
- it 'finds a parent' do
184
- sub = node['a']['b']
185
- assert_equal(JSI::JSON::Pointer.new(['a', 'b']), sub.pointer)
186
- parent = sub.parent_node
187
- assert_equal(JSI::JSON::Pointer.new(['a']), parent.pointer)
188
- assert_equal({'b' => []}, parent.content)
189
- assert_equal(node['a'], parent)
190
- root_from_sub = sub.parent_node.parent_node
191
- assert_equal(JSI::JSON::Pointer.new([]), root_from_sub.pointer)
192
- assert_equal({'a' => {'b' => []}}, root_from_sub.content)
193
- assert_equal(node, root_from_sub)
194
- err = assert_raises(JSI::JSON::Pointer::ReferenceError) do
195
- root_from_sub.parent_node
196
- end
197
- assert_match(/\Acannot access parent of root pointer: #<JSI::JSON::Pointer/, err.message)
198
- end
199
- end
200
- describe '#pointer_path' do
201
- let(:document) { {'a' => {'b' => 3}} }
202
- it 'is empty' do
203
- assert_equal('', node.pointer_path)
204
- end
205
- it 'is not empty' do
206
- assert_equal('/a', node['a'].pointer_path)
207
- end
208
- describe 'containing an empty string and some slashes and tildes that need escaping' do
209
- let(:document) { {'' => {'a/b~c!d#e[f]' => []}} }
210
- it 'matches' do
211
- assert_equal('//a~1b~0c!d#e[f]', node['']['a/b~c!d#e[f]'].pointer_path)
212
- end
213
- end
214
- end
215
- describe '#fragment' do
216
- let(:document) { {'a' => {'b' => 3}} }
217
- it 'is empty' do
218
- assert_equal('#', node.fragment)
219
- end
220
- it 'is not empty' do
221
- assert_equal('#/a', node['a'].fragment)
222
- end
223
- describe 'containing an empty string and some slashes and tildes that need escaping' do
224
- let(:document) { {'' => {'a/b~c!d#e[f]' => []}} }
225
- it 'matches' do
226
- assert_equal('#//a~1b~0c!d#e%5Bf%5D', node['']['a/b~c!d#e[f]'].fragment)
227
- end
228
- end
229
- end
230
- describe '#modified_copy' do
231
- let(:document) { [['b', 'q'], {'c' => ['d', 'e']}] }
232
- let(:path) { ['1', 'c'] }
233
- it 'returns a different object' do
234
- # simplest thing
235
- modified_dup = node.modified_copy(&:dup)
236
- # it is equal - being a dup
237
- assert_equal(modified_dup, node)
238
- # but different object
239
- refute_equal(node.object_id, modified_dup.object_id)
240
- # the parents, obviously, are different
241
- refute_equal(node.parent_node.content.object_id, modified_dup.parent_node.content.object_id)
242
- refute_equal(node.parent_node.parent_node.content.object_id, modified_dup.parent_node.parent_node.content.object_id)
243
- # but any untouched part(s) - in this case the ['b', 'q'] at document[0] - are untouched
244
- assert_equal(node.document_node[0].content.object_id, modified_dup.document_node[0].content.object_id)
245
- end
246
- it 'returns the same object' do
247
- unmodified_dup = node.modified_copy { |o| o }
248
- assert_equal(unmodified_dup, node)
249
- # same object, since the block just returned it
250
- refute_equal(node.object_id, unmodified_dup.object_id)
251
- # the parents are unchanged since the object is the same
252
- assert_equal(node.parent_node.content.object_id, unmodified_dup.parent_node.content.object_id)
253
- assert_equal(node.parent_node.parent_node.content.object_id, unmodified_dup.parent_node.parent_node.content.object_id)
254
- # same as the other: any untouched part(s) - in this case the ['b', 'q'] at document[0] - are untouched
255
- assert_equal(node.document_node[0].content.object_id, unmodified_dup.document_node[0].content.object_id)
256
- end
257
- it 'raises subscripting string from array' do
258
- err = assert_raises(TypeError) { JSI::JSON::Node.new(document, JSI::JSON::Pointer.new(['x'])).modified_copy(&:dup) }
259
- assert_match(%r(\Abad subscript "x" with remaining subpath: \[\] for array: \[.*\]\z)m, err.message)
260
- end
261
- it 'raises subscripting from invalid subpath' do
262
- err = assert_raises(TypeError) { JSI::JSON::Node.new(document, JSI::JSON::Pointer.new([0, 0, 'what'])).modified_copy(&:dup) }
263
- assert_match(%r(bad subscript: "what" with remaining subpath: \[\] for content: "b"\z)m, err.message)
264
- end
265
- end
266
- describe '#inspect' do
267
- let(:document) { {'a' => {'c' => ['d', 'e']}} }
268
- let(:path) { ['a'] }
269
- it 'inspects' do
270
- assert_equal(%Q(#<JSI::JSON::Node fragment="#/a" {"c"=>["d", "e"]}>), node.inspect)
271
- end
272
- end
273
- describe '#pretty_print' do
274
- let(:document) { {'a' => {'c' => ['d', 'e']}} }
275
- let(:path) { ['a'] }
276
- it 'pretty prints' do
277
- assert_equal(%Q(#<JSI::JSON::Node fragment="#/a" {"c"=>["d", "e"]}>), node.pretty_inspect.chomp)
278
- end
279
- end
280
- describe '#fingerprint' do
281
- let(:pointer) { JSI::JSON::Pointer.new([]) }
282
- it 'hashes consistently' do
283
- assert_equal('x', {JSI::JSON::Node.new([0], pointer) => 'x'}[JSI::JSON::Node.new([0], pointer)])
284
- end
285
- it 'hashes consistently regardless of the Node being decorated as a subclass' do
286
- assert_equal('x', {JSI::JSON::Node.new_doc([0]) => 'x'}[JSI::JSON::Node.new([0], pointer)])
287
- assert_equal('x', {JSI::JSON::Node.new([0], pointer) => 'x'}[JSI::JSON::Node.new_doc([0])])
288
- end
289
- it '==' do
290
- assert_equal(JSI::JSON::Node.new([0], pointer), JSI::JSON::Node.new([0], pointer))
291
- assert_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new([0], pointer))
292
- assert_equal(JSI::JSON::Node.new([0], pointer), JSI::JSON::Node.new_doc([0]))
293
- assert_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new_doc([0]))
294
- end
295
- it '!=' do
296
- refute_equal(JSI::JSON::Node.new([0], pointer), JSI::JSON::Node.new({}, pointer))
297
- refute_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new({}, pointer))
298
- refute_equal(JSI::JSON::Node.new([0], pointer), JSI::JSON::Node.new_doc({}))
299
- refute_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new_doc({}))
300
- refute_equal({}, JSI::JSON::Node.new_doc({}))
301
- refute_equal(JSI::JSON::Node.new_doc({}), {})
302
- end
303
- end
304
- describe '#as_json' do
305
- let(:document) { {'a' => 'b'} }
306
- it '#as_json' do
307
- assert_equal({'a' => 'b'}, node.as_json)
308
- end
309
- end
310
- end
@@ -1,106 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- describe JSI::JSON::Pointer do
4
- # For example, given the document
5
- let(:document) do
6
- {
7
- "foo" => ["bar", "baz"],
8
- "" => 0,
9
- "a/b" => 1,
10
- "c%d" => 2,
11
- "e^f" => 3,
12
- "g|h" => 4,
13
- "i\\j" => 5,
14
- "k\"l" => 6,
15
- " " => 7,
16
- "m~n" => 8,
17
- }
18
- end
19
-
20
- describe 'initialize from pointer' do
21
- it 'parses' do
22
- # The following strings evaluate to the accompanying values:
23
- evaluations = [
24
- "" , document,
25
- "/foo" , ["bar", "baz"],
26
- "/foo/0", "bar",
27
- "/" , 0,
28
- "/a~1b" , 1,
29
- "/c%d" , 2,
30
- "/e^f" , 3,
31
- "/g|h" , 4,
32
- "/i\\j" , 5,
33
- "/k\"l" , 6,
34
- "/ " , 7,
35
- "/m~0n" , 8,
36
- ]
37
- evaluations.each_slice(2) do |pointer, value|
38
- assert_equal(value, JSI::JSON::Pointer.from_pointer(pointer).evaluate(document))
39
- end
40
- end
41
-
42
- it 'raises for invalid syntax' do
43
- err = assert_raises(JSI::JSON::Pointer::PointerSyntaxError) do
44
- JSI::JSON::Pointer.from_pointer("this does not begin with slash").evaluate(document)
45
- end
46
- assert_equal("Invalid pointer syntax in \"this does not begin with slash\": pointer must begin with /", err.message)
47
- end
48
- end
49
- describe 'initialize from fragment' do
50
- # For example, given the document
51
- let(:document) do
52
- {
53
- "foo" => ["bar", "baz"],
54
- "" => 0,
55
- "a/b" => 1,
56
- "c%d" => 2,
57
- "e^f" => 3,
58
- "g|h" => 4,
59
- "i\\j" => 5,
60
- "k\"l" => 6,
61
- " " => 7,
62
- "m~n" => 8,
63
- }
64
- end
65
-
66
- it 'parses' do
67
- # the following URI fragment identifiers evaluate to the accompanying values:
68
- evaluations = [
69
- '#', document,
70
- '#/foo', ["bar", "baz"],
71
- '#/foo/0', "bar",
72
- '#/', 0,
73
- '#/a~1b', 1,
74
- '#/c%25d', 2,
75
- '#/e%5Ef', 3,
76
- '#/g%7Ch', 4,
77
- '#/i%5Cj', 5,
78
- '#/k%22l', 6,
79
- '#/%20', 7,
80
- '#/m~0n', 8,
81
- ]
82
- evaluations.each_slice(2) do |fragment, value|
83
- assert_equal(value, JSI::JSON::Pointer.from_fragment(fragment).evaluate(document))
84
- end
85
- end
86
-
87
- it 'raises for invalid syntax' do
88
- err = assert_raises(JSI::JSON::Pointer::PointerSyntaxError) do
89
- JSI::JSON::Pointer.from_fragment("this does not begin with #").evaluate(document)
90
- end
91
- assert_equal("Invalid fragment syntax in \"this does not begin with #\": fragment must begin with #", err.message)
92
- err = assert_raises(JSI::JSON::Pointer::PointerSyntaxError) do
93
- JSI::JSON::Pointer.from_fragment("#this does not begin with slash").evaluate(document)
94
- end
95
- assert_equal("Invalid pointer syntax in \"this does not begin with slash\": pointer must begin with /", err.message)
96
- end
97
- end
98
- describe 'initialize' do
99
- describe 'invalid reference_tokens' do
100
- it 'raises' do
101
- err = assert_raises(TypeError) { JSI::JSON::Pointer.new({}) }
102
- assert_equal("reference_tokens must be an array. got: {}", err.message)
103
- end
104
- end
105
- end
106
- end
data/test/jsi_test.rb DELETED
@@ -1,11 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class JSITest < Minitest::Test
4
- def test_that_it_has_a_version_number
5
- refute_nil ::JSI::VERSION
6
- end
7
-
8
- def test_it_does_something_useful
9
- assert true
10
- end
11
- end
@@ -1,53 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class JSONifiable
4
- def initialize(object)
5
- @object = object
6
- end
7
- def as_json
8
- @object
9
- end
10
- end
11
-
12
- describe JSI::Typelike do
13
- describe 'as_json' do
14
- it 'expresses as json' do
15
- assert_equal({}, JSI::Typelike.as_json({}))
16
- assert_equal([], JSI::Typelike.as_json([]))
17
-
18
- # symbols to string
19
- assert_equal(['a'], JSI::Typelike.as_json([:a]))
20
-
21
- # set
22
- assert_equal(['a'], JSI::Typelike.as_json(Set.new(['a'])))
23
-
24
- # responds to #to_hash / #to_ary but naught else
25
- assert_equal({'a' => 'b'}, JSI::Typelike.as_json(SortOfHash.new({'a' => 'b'})))
26
- assert_equal(['a'], JSI::Typelike.as_json(SortOfArray.new(['a'])))
27
-
28
- # symbol keys to string
29
- assert_equal({'a' => 'b'}, JSI::Typelike.as_json({a: 'b'}))
30
- # non string/symbol key
31
- err = assert_raises(TypeError) { JSI::Typelike.as_json({nil => 0}) }
32
- assert_equal('json object (hash) cannot be keyed with: nil', err.message)
33
-
34
- # schema
35
- schema = JSI::Schema.from_object({'type' => 'array'})
36
- assert_equal({'type' => 'array'}, JSI::Typelike.as_json(schema))
37
-
38
- # JSI
39
- assert_equal(['a'], JSI::Typelike.as_json(JSI.class_for_schema(schema).new(['a'])))
40
-
41
- # JSON::Node
42
- assert_equal(['a'], JSI::Typelike.as_json(JSI::JSON::Node.new_doc(['a'])))
43
-
44
- # #as_json
45
- assert_equal(['a'], JSI::Typelike.as_json(JSONifiable.new(['a'])))
46
-
47
- # not jsonifiable
48
- object = Object.new
49
- err = assert_raises(TypeError) { JSI::Typelike.as_json(object) }
50
- assert_equal("cannot express object as json: #{object.pretty_inspect.chomp}", err.message)
51
- end
52
- end
53
- end
data/test/schema_test.rb DELETED
@@ -1,196 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- SomeMetaschema = JSI.class_for_schema({id: 'https://schemas.jsi.unth.net/test/somemetaschema', type: 'object'})
4
-
5
- describe JSI::Schema do
6
- describe 'new' do
7
- it 'initializes from a hash' do
8
- schema = JSI::Schema.new({'type' => 'object'})
9
- assert_equal(JSI::JSON::Node.new_doc({'type' => 'object'}), schema.schema_node)
10
- end
11
- it 'initializes from a Node' do
12
- schema_node = JSI::JSON::Node.new_doc({'type' => 'object'})
13
- schema = JSI::Schema.new(schema_node)
14
- assert_equal(schema_node, schema.schema_node)
15
- assert_equal(schema_node, schema.schema_object)
16
- end
17
- it 'initializes from a JSI' do
18
- schema_jsi = SomeMetaschema.new('type' => 'object')
19
- schema = JSI::Schema.new(schema_jsi)
20
- assert_equal(schema_jsi, schema.schema_node)
21
- assert_equal(schema_jsi, schema.schema_object)
22
- end
23
- it 'cannot instantiate from some unknown object' do
24
- err = assert_raises(TypeError) { JSI::Schema.new(Object.new) }
25
- assert_match(/\Acannot instantiate Schema from: #<Object:.*>\z/m, err.message)
26
- end
27
- it 'makes no sense to instantiate schema from schema' do
28
- err = assert_raises(TypeError) { JSI::Schema.new(JSI::Schema.new({})) }
29
- assert_match(/\Awill not instantiate Schema from another Schema: #<JSI::Schema schema_id=.*>\z/m, err.message)
30
- end
31
- end
32
- describe 'as an instance of metaschema' do
33
- let(:default_metaschema) do
34
- validator = ::JSON::Validator.default_validator
35
- metaschema_file = validator.metaschema
36
- JSI::Schema.new(::JSON.parse(File.read(metaschema_file)))
37
- end
38
- let(:metaschema_jsi_class) { JSI.class_for_schema(default_metaschema) }
39
- let(:schema_object) { {'type' => 'array', 'items' => {'description' => 'items!'}} }
40
- let(:schema_jsi) { metaschema_jsi_class.new(schema_object) }
41
- let(:schema) { JSI::Schema.new(schema_jsi) }
42
- it '#[]' do
43
- schema_items = schema['items']
44
- assert_instance_of(metaschema_jsi_class, schema_items)
45
- assert_equal({'description' => 'items!'}, schema_items.as_json)
46
- end
47
- end
48
- describe '#schema_id' do
49
- it 'generates one' do
50
- assert_match(/\A[0-9a-f\-]+#\z/, JSI::Schema.new({}).schema_id)
51
- end
52
- it 'uses a given id with a fragment' do
53
- schema = JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/given_id#'})
54
- assert_equal('https://schemas.jsi.unth.net/test/given_id#', schema.schema_id)
55
- end
56
- it 'uses a given id (adding a fragment)' do
57
- schema = JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/given_id'})
58
- assert_equal('https://schemas.jsi.unth.net/test/given_id#', schema.schema_id)
59
- end
60
- it 'uses a pointer in the fragment' do
61
- schema_node = JSI::JSON::Node.new_doc({
62
- 'id' => 'https://schemas.jsi.unth.net/test/given_id#',
63
- 'properties' => {'foo' => {'type' => 'object'}},
64
- })
65
- schema = JSI::Schema.new(schema_node['properties']['foo'])
66
- assert_equal('https://schemas.jsi.unth.net/test/given_id#/properties/foo', schema.schema_id)
67
- end
68
- it 'uses a pointer in the fragment relative to the fragment of the root' do
69
- schema_node = JSI::JSON::Node.new_doc({
70
- 'id' => 'https://schemas.jsi.unth.net/test/given_id#/notroot',
71
- 'properties' => {'foo' => {'type' => 'object'}},
72
- })
73
- schema = JSI::Schema.new(schema_node['properties']['foo'])
74
- assert_equal('https://schemas.jsi.unth.net/test/given_id#/notroot/properties/foo', schema.schema_id)
75
- end
76
- end
77
- describe '#schema_class' do
78
- it 'returns the class for the schema' do
79
- schema_node = JSI::JSON::Node.new_doc({'id' => 'https://schemas.jsi.unth.net/test/schema_schema_class'})
80
- assert_equal(JSI.class_for_schema(schema_node), JSI::Schema.new(schema_node).schema_class)
81
- end
82
- end
83
- describe '#subschema_for_property' do
84
- let(:schema) do
85
- JSI::Schema.new({
86
- properties: {foo: {description: 'foo'}},
87
- patternProperties: {"^ba" => {description: 'ba*'}},
88
- additionalProperties: {description: 'whatever'},
89
- })
90
- end
91
- it 'has no subschema' do
92
- assert_equal(nil, JSI::Schema.new({}).subschema_for_property('no'))
93
- end
94
- it 'has a subschema by property' do
95
- subschema = schema.subschema_for_property('foo')
96
- assert_instance_of(JSI::Schema, subschema)
97
- assert_equal('foo', subschema['description'])
98
- end
99
- it 'has a subschema by pattern property' do
100
- subschema = schema.subschema_for_property('bar')
101
- assert_instance_of(JSI::Schema, subschema)
102
- assert_equal('ba*', subschema['description'])
103
- end
104
- it 'has a subschema by additional properties' do
105
- subschema = schema.subschema_for_property('anything')
106
- assert_instance_of(JSI::Schema, subschema)
107
- assert_equal('whatever', subschema['description'])
108
- end
109
- end
110
- describe '#subschema_for_index' do
111
- it 'has no subschema' do
112
- assert_equal(nil, JSI::Schema.new({}).subschema_for_index(0))
113
- end
114
- it 'has a subschema for items' do
115
- schema = JSI::Schema.new({
116
- items: {description: 'items!'}
117
- })
118
- first_subschema = schema.subschema_for_index(0)
119
- assert_instance_of(JSI::Schema, first_subschema)
120
- assert_equal('items!', first_subschema['description'])
121
- last_subschema = schema.subschema_for_index(1)
122
- assert_instance_of(JSI::Schema, last_subschema)
123
- assert_equal('items!', last_subschema['description'])
124
- end
125
- it 'has a subschema for each item by index' do
126
- schema = JSI::Schema.new({
127
- items: [{description: 'item one'}, {description: 'item two'}]
128
- })
129
- first_subschema = schema.subschema_for_index(0)
130
- assert_instance_of(JSI::Schema, first_subschema)
131
- assert_equal('item one', first_subschema['description'])
132
- last_subschema = schema.subschema_for_index(1)
133
- assert_instance_of(JSI::Schema, last_subschema)
134
- assert_equal('item two', last_subschema['description'])
135
- end
136
- it 'has a subschema by additional items' do
137
- schema = JSI::Schema.new({
138
- items: [{description: 'item one'}],
139
- additionalItems: {description: "mo' crap"},
140
- })
141
- first_subschema = schema.subschema_for_index(0)
142
- assert_instance_of(JSI::Schema, first_subschema)
143
- assert_equal('item one', first_subschema['description'])
144
- last_subschema = schema.subschema_for_index(1)
145
- assert_instance_of(JSI::Schema, last_subschema)
146
- assert_equal("mo' crap", last_subschema['description'])
147
- end
148
- end
149
- describe 'stringification' do
150
- let(:schema) do
151
- JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/stringification', type: 'object'})
152
- end
153
-
154
- it '#inspect' do
155
- assert_equal(%q(#<JSI::Schema schema_id=https://schemas.jsi.unth.net/test/stringification# #{<JSI::JSON::HashNode fragment="#"> "id" => "https://schemas.jsi.unth.net/test/stringification", "type" => "object"}>), schema.inspect)
156
- end
157
- it '#pretty_print' do
158
- assert_equal(%q(#<JSI::Schema schema_id=https://schemas.jsi.unth.net/test/stringification#
159
- #{<JSI::JSON::HashNode fragment="#">
160
- "id" => "https://schemas.jsi.unth.net/test/stringification",
161
- "type" => "object"
162
- }
163
- >).gsub(/^ /, ''), schema.pretty_inspect.chomp)
164
- end
165
- end
166
- describe 'validation' do
167
- let(:schema) { JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/validation', type: 'object'}) }
168
- describe 'without errors' do
169
- let(:instance) { {'foo' => 'bar'} }
170
- it '#fully_validate_instance' do
171
- assert_equal([], schema.fully_validate_instance(instance))
172
- end
173
- it '#validate_instance' do
174
- assert_equal(true, schema.validate_instance(instance))
175
- end
176
- it '#validate_instance!' do
177
- assert_equal(true, schema.validate_instance!(instance))
178
- end
179
- end
180
- describe 'with errors' do
181
- let(:instance) { ['no'] }
182
- it '#fully_validate_instance' do
183
- assert_equal(["The property '#/' of type array did not match the following type: object in schema https://schemas.jsi.unth.net/test/validation"], schema.fully_validate_instance(instance))
184
- end
185
- it '#validate_instance' do
186
- assert_equal(false, schema.validate_instance(instance))
187
- end
188
- it '#validate_instance!' do
189
- err = assert_raises(JSON::Schema::ValidationError) do
190
- schema.validate_instance!(instance)
191
- end
192
- assert_equal("The property '#/' of type array did not match the following type: object", err.message)
193
- end
194
- end
195
- end
196
- end