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.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/CHANGELOG.md +36 -0
- data/LICENSE.md +613 -0
- data/README.md +153 -52
- data/lib/jsi/base.rb +485 -338
- data/lib/jsi/jsi_coder.rb +24 -18
- data/lib/jsi/metaschema.rb +7 -0
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +100 -0
- data/lib/jsi/metaschema_node.rb +245 -0
- data/lib/jsi/pathed_node.rb +49 -46
- data/lib/jsi/ptr.rb +292 -0
- data/lib/jsi/schema/application/child_application/contains.rb +16 -0
- data/lib/jsi/schema/application/child_application/draft04.rb +22 -0
- data/lib/jsi/schema/application/child_application/draft06.rb +29 -0
- data/lib/jsi/schema/application/child_application/draft07.rb +29 -0
- data/lib/jsi/schema/application/child_application/items.rb +18 -0
- data/lib/jsi/schema/application/child_application/properties.rb +25 -0
- data/lib/jsi/schema/application/child_application.rb +40 -0
- data/lib/jsi/schema/application/draft04.rb +8 -0
- data/lib/jsi/schema/application/draft06.rb +8 -0
- data/lib/jsi/schema/application/draft07.rb +8 -0
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
- data/lib/jsi/schema/application/inplace_application/draft04.rb +26 -0
- data/lib/jsi/schema/application/inplace_application/draft06.rb +27 -0
- data/lib/jsi/schema/application/inplace_application/draft07.rb +33 -0
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
- data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
- data/lib/jsi/schema/application/inplace_application/someof.rb +29 -0
- data/lib/jsi/schema/application/inplace_application.rb +46 -0
- data/lib/jsi/schema/application.rb +12 -0
- data/lib/jsi/schema/draft04.rb +14 -0
- data/lib/jsi/schema/draft06.rb +14 -0
- data/lib/jsi/schema/draft07.rb +14 -0
- data/lib/jsi/schema/issue.rb +36 -0
- data/lib/jsi/schema/ref.rb +159 -0
- data/lib/jsi/schema/schema_ancestor_node.rb +119 -0
- data/lib/jsi/schema/validation/array.rb +69 -0
- data/lib/jsi/schema/validation/const.rb +20 -0
- data/lib/jsi/schema/validation/contains.rb +25 -0
- data/lib/jsi/schema/validation/core.rb +39 -0
- data/lib/jsi/schema/validation/dependencies.rb +49 -0
- data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
- data/lib/jsi/schema/validation/draft04.rb +112 -0
- data/lib/jsi/schema/validation/draft06.rb +122 -0
- data/lib/jsi/schema/validation/draft07.rb +159 -0
- data/lib/jsi/schema/validation/enum.rb +25 -0
- data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
- data/lib/jsi/schema/validation/items.rb +54 -0
- data/lib/jsi/schema/validation/not.rb +20 -0
- data/lib/jsi/schema/validation/numeric.rb +121 -0
- data/lib/jsi/schema/validation/object.rb +45 -0
- data/lib/jsi/schema/validation/pattern.rb +34 -0
- data/lib/jsi/schema/validation/properties.rb +101 -0
- data/lib/jsi/schema/validation/property_names.rb +32 -0
- data/lib/jsi/schema/validation/ref.rb +40 -0
- data/lib/jsi/schema/validation/required.rb +27 -0
- data/lib/jsi/schema/validation/someof.rb +90 -0
- data/lib/jsi/schema/validation/string.rb +47 -0
- data/lib/jsi/schema/validation/type.rb +49 -0
- data/lib/jsi/schema/validation.rb +51 -0
- data/lib/jsi/schema.rb +528 -233
- data/lib/jsi/schema_classes.rb +238 -51
- data/lib/jsi/schema_registry.rb +141 -0
- data/lib/jsi/schema_set.rb +141 -0
- data/lib/jsi/simple_wrap.rb +8 -3
- data/lib/jsi/typelike_modules.rb +75 -68
- data/lib/jsi/util/attr_struct.rb +106 -0
- data/lib/jsi/util.rb +167 -64
- data/lib/jsi/validation/error.rb +34 -0
- data/lib/jsi/validation/result.rb +210 -0
- data/lib/jsi/validation.rb +15 -0
- data/lib/jsi/version.rb +3 -1
- data/lib/jsi.rb +72 -9
- data/lib/schemas/json-schema.org/draft-04/schema.rb +12 -0
- data/lib/schemas/json-schema.org/draft-06/schema.rb +12 -0
- data/lib/schemas/json-schema.org/draft-07/schema.rb +12 -0
- data/readme.rb +138 -0
- data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
- data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
- data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
- metadata +80 -107
- data/.simplecov +0 -1
- data/LICENSE.txt +0 -21
- data/Rakefile.rb +0 -9
- data/jsi.gemspec +0 -31
- data/lib/jsi/base/to_rb.rb +0 -126
- data/lib/jsi/json/node.rb +0 -243
- data/lib/jsi/json/pointer.rb +0 -330
- data/lib/jsi/json-schema-fragments.rb +0 -59
- data/lib/jsi/json.rb +0 -8
- data/test/base_array_test.rb +0 -209
- data/test/base_hash_test.rb +0 -204
- data/test/base_test.rb +0 -422
- data/test/jsi_coder_test.rb +0 -85
- data/test/jsi_json_arraynode_test.rb +0 -150
- data/test/jsi_json_hashnode_test.rb +0 -132
- data/test/jsi_json_node_test.rb +0 -310
- data/test/jsi_json_pointer_test.rb +0 -106
- data/test/jsi_test.rb +0 -11
- data/test/jsi_typelike_as_json_test.rb +0 -53
- data/test/schema_test.rb +0 -196
- data/test/spreedly_openapi_test.rb +0 -8
- data/test/test_helper.rb +0 -63
- data/test/util_test.rb +0 -62
data/test/jsi_json_node_test.rb
DELETED
|
@@ -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,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
|