jsi 0.0.4 → 0.4.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/.simplecov +3 -1
- data/CHANGELOG.md +48 -0
- data/LICENSE.md +613 -0
- data/README.md +84 -45
- data/jsi.gemspec +11 -14
- data/lib/jsi.rb +31 -12
- data/lib/jsi/base.rb +310 -344
- data/lib/jsi/base/to_rb.rb +2 -0
- data/lib/jsi/jsi_coder.rb +91 -0
- data/lib/jsi/json-schema-fragments.rb +3 -135
- data/lib/jsi/json.rb +3 -0
- data/lib/jsi/json/node.rb +72 -197
- data/lib/jsi/json/pointer.rb +419 -0
- data/lib/jsi/metaschema.rb +7 -0
- data/lib/jsi/metaschema_node.rb +218 -0
- data/lib/jsi/pathed_node.rb +118 -0
- data/lib/jsi/schema.rb +168 -223
- data/lib/jsi/schema_classes.rb +158 -0
- data/lib/jsi/simple_wrap.rb +12 -0
- data/lib/jsi/typelike_modules.rb +71 -45
- data/lib/jsi/util.rb +47 -57
- data/lib/jsi/version.rb +1 -1
- data/lib/schemas/json-schema.org/draft-04/schema.rb +7 -0
- data/lib/schemas/json-schema.org/draft-06/schema.rb +7 -0
- data/resources/icons/AGPL-3.0.png +0 -0
- data/test/base_array_test.rb +210 -84
- data/test/base_hash_test.rb +201 -58
- data/test/base_test.rb +212 -121
- data/test/jsi_coder_test.rb +85 -0
- data/test/jsi_json_arraynode_test.rb +26 -25
- data/test/jsi_json_hashnode_test.rb +40 -39
- data/test/jsi_json_node_test.rb +95 -126
- data/test/jsi_json_pointer_test.rb +102 -0
- data/test/jsi_typelike_as_json_test.rb +53 -0
- data/test/metaschema_node_test.rb +19 -0
- data/test/schema_module_test.rb +21 -0
- data/test/schema_test.rb +109 -97
- data/test/spreedly_openapi_test.rb +8 -0
- data/test/test_helper.rb +42 -8
- data/test/util_test.rb +14 -14
- metadata +54 -25
- data/LICENSE.txt +0 -21
- data/lib/jsi/schema_instance_json_coder.rb +0 -83
- data/lib/jsi/struct_json_coder.rb +0 -30
- data/test/schema_instance_json_coder_test.rb +0 -121
- data/test/struct_json_coder_test.rb +0 -130
data/test/base_test.rb
CHANGED
@@ -1,57 +1,54 @@
|
|
1
1
|
require_relative 'test_helper'
|
2
2
|
|
3
|
-
NamedSchemaInstance = JSI.
|
3
|
+
NamedSchemaInstance = JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/base/named_schema'}).jsi_schema_class
|
4
|
+
|
5
|
+
# hitting .tap(&:name) causes JSI to assign a constant name from the ID,
|
6
|
+
# meaning the name NamedSchemaInstanceTwo is not known.
|
7
|
+
NamedSchemaInstanceTwo = JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/base/named_schema_two'}).jsi_schema_class.tap(&:name)
|
4
8
|
|
5
9
|
describe JSI::Base do
|
6
|
-
let(:document) { {} }
|
7
|
-
let(:path) { [] }
|
8
|
-
let(:instance) { JSI::JSON::Node.new_by_type(document, path) }
|
9
10
|
let(:schema_content) { {} }
|
10
11
|
let(:schema) { JSI::Schema.new(schema_content) }
|
11
|
-
let(:
|
12
|
-
|
12
|
+
let(:instance) { {} }
|
13
|
+
let(:subject) { schema.new_jsi(instance) }
|
14
|
+
describe 'class .inspect' do
|
13
15
|
it 'is the same as Class#inspect on the base' do
|
14
16
|
assert_equal('JSI::Base', JSI::Base.inspect)
|
15
|
-
assert_equal('JSI::Base', JSI::Base.to_s)
|
16
17
|
end
|
17
|
-
it 'is
|
18
|
-
|
19
|
-
assert_match(%r(\AJSI::SchemaClasses\["[a-f0-9\-]+#"\]\z), subject.class.to_s)
|
18
|
+
it 'is (JSI Schema Class) for generated subclass without id' do
|
19
|
+
assert_equal("(JSI Schema Class: #)", subject.class.inspect)
|
20
20
|
end
|
21
21
|
describe 'with schema id' do
|
22
22
|
let(:schema_content) { {'id' => 'https://jsi/foo'} }
|
23
|
-
it 'is
|
24
|
-
assert_equal(
|
25
|
-
assert_equal(%q(JSI::SchemaClasses["https://jsi/foo#"]), subject.class.to_s)
|
23
|
+
it 'is (JSI Schema Class: ...) for generated subclass with id' do
|
24
|
+
assert_equal("(JSI Schema Class: https://jsi/foo#)", subject.class.inspect)
|
26
25
|
end
|
27
26
|
end
|
28
|
-
it 'is the constant name
|
27
|
+
it 'is the constant name plus id for a class assigned to a constant' do
|
29
28
|
assert_equal(%q(NamedSchemaInstance (https://schemas.jsi.unth.net/test/base/named_schema#)), NamedSchemaInstance.inspect)
|
30
|
-
|
29
|
+
end
|
30
|
+
it 'is not the constant name when the constant name has been generated from the schema_id' do
|
31
|
+
assert_equal("JSI::SchemaClasses::Xhttps___schemas_jsi_unth_net_test_base_named_schema_two_", NamedSchemaInstanceTwo.name)
|
32
|
+
assert_equal("(JSI Schema Class: https://schemas.jsi.unth.net/test/base/named_schema_two#)", NamedSchemaInstanceTwo.inspect)
|
31
33
|
end
|
32
34
|
end
|
33
35
|
describe 'class name' do
|
34
36
|
let(:schema_content) { {'id' => 'https://jsi/BaseTest'} }
|
35
37
|
it 'generates a class name from schema_id' do
|
36
|
-
assert_equal('JSI::SchemaClasses::
|
38
|
+
assert_equal('JSI::SchemaClasses::Xhttps___jsi_BaseTest_', subject.class.name)
|
37
39
|
end
|
38
40
|
it 'uses an existing name' do
|
39
41
|
assert_equal('NamedSchemaInstance', NamedSchemaInstance.name)
|
40
42
|
end
|
41
43
|
end
|
42
|
-
describe 'class for schema .
|
43
|
-
it '.
|
44
|
-
assert_equal(schema,
|
45
|
-
end
|
46
|
-
end
|
47
|
-
describe 'class for schema .schema_id' do
|
48
|
-
it '.schema_id' do
|
49
|
-
assert_equal(schema.schema_id, JSI.class_for_schema(schema).schema_id)
|
44
|
+
describe 'class for schema .jsi_class_schemas' do
|
45
|
+
it '.jsi_class_schemas' do
|
46
|
+
assert_equal(Set.new << schema, schema.jsi_schema_class.jsi_class_schemas)
|
50
47
|
end
|
51
48
|
end
|
52
49
|
describe 'module for schema .inspect' do
|
53
50
|
it '.inspect' do
|
54
|
-
|
51
|
+
assert_equal("(JSI Schema Module: #)", JSI::SchemaClasses.module_for_schema(schema).inspect)
|
55
52
|
end
|
56
53
|
end
|
57
54
|
describe 'module for schema .schema' do
|
@@ -59,26 +56,15 @@ describe JSI::Base do
|
|
59
56
|
assert_equal(schema, JSI::SchemaClasses.module_for_schema(schema).schema)
|
60
57
|
end
|
61
58
|
end
|
62
|
-
describe '
|
63
|
-
it 'stores the class for the schema' do
|
64
|
-
assert_equal(JSI.class_for_schema(schema), JSI::SchemaClasses[schema.schema_id])
|
65
|
-
end
|
66
|
-
end
|
67
|
-
describe '.class_for_schema' do
|
59
|
+
describe '.class_for_schemas' do
|
68
60
|
it 'returns a class from a schema' do
|
69
|
-
class_for_schema = JSI.
|
61
|
+
class_for_schema = JSI.class_for_schemas([schema])
|
70
62
|
# same class every time
|
71
|
-
assert_equal(JSI.
|
63
|
+
assert_equal(JSI.class_for_schemas([schema]), class_for_schema)
|
72
64
|
assert_operator(class_for_schema, :<, JSI::Base)
|
73
65
|
end
|
74
|
-
it 'returns
|
75
|
-
assert_equal(JSI.
|
76
|
-
end
|
77
|
-
it 'returns a class from a schema node' do
|
78
|
-
assert_equal(JSI.class_for_schema(schema), JSI.class_for_schema(schema.schema_node))
|
79
|
-
end
|
80
|
-
it 'returns a class from a Base' do
|
81
|
-
assert_equal(JSI.class_for_schema(schema), JSI.class_for_schema(JSI.class_for_schema({}).new(schema.schema_node)))
|
66
|
+
it 'returns the same class from a hash' do
|
67
|
+
assert_equal(JSI.class_for_schemas([schema]), JSI.class_for_schemas([schema_content]))
|
82
68
|
end
|
83
69
|
end
|
84
70
|
describe 'JSI::SchemaClasses.module_for_schema' do
|
@@ -88,26 +74,20 @@ describe JSI::Base do
|
|
88
74
|
assert_equal(JSI::SchemaClasses.module_for_schema(schema), module_for_schema)
|
89
75
|
end
|
90
76
|
it 'returns a module from a hash' do
|
91
|
-
assert_equal(JSI::SchemaClasses.module_for_schema(schema), JSI::SchemaClasses.module_for_schema(schema.
|
92
|
-
end
|
93
|
-
it 'returns a module from a schema node' do
|
94
|
-
assert_equal(JSI::SchemaClasses.module_for_schema(schema), JSI::SchemaClasses.module_for_schema(schema.schema_node))
|
95
|
-
end
|
96
|
-
it 'returns a module from a Base' do
|
97
|
-
assert_equal(JSI::SchemaClasses.module_for_schema(schema), JSI::SchemaClasses.module_for_schema(JSI.class_for_schema({}).new(schema.schema_node)))
|
77
|
+
assert_equal(JSI::SchemaClasses.module_for_schema(schema), JSI::SchemaClasses.module_for_schema(schema.jsi_instance))
|
98
78
|
end
|
99
79
|
end
|
100
80
|
describe 'initialization' do
|
101
81
|
describe 'on Base' do
|
102
82
|
it 'errors' do
|
103
83
|
err = assert_raises(TypeError) { JSI::Base.new({}) }
|
104
|
-
assert_equal('cannot instantiate JSI::Base which has no method #
|
84
|
+
assert_equal('cannot instantiate JSI::Base which has no method #jsi_schemas. it is recommended to instantiate JSIs from a schema using JSI::Schema#new_jsi.', err.message)
|
105
85
|
end
|
106
86
|
end
|
107
87
|
describe 'nil' do
|
108
88
|
let(:instance) { nil }
|
109
89
|
it 'initializes with nil instance' do
|
110
|
-
assert_equal(
|
90
|
+
assert_equal(nil, subject.jsi_instance)
|
111
91
|
assert(!subject.respond_to?(:to_ary))
|
112
92
|
assert(!subject.respond_to?(:to_hash))
|
113
93
|
end
|
@@ -115,7 +95,7 @@ describe JSI::Base do
|
|
115
95
|
describe 'arbitrary instance' do
|
116
96
|
let(:instance) { Object.new }
|
117
97
|
it 'initializes' do
|
118
|
-
assert_equal(
|
98
|
+
assert_equal(instance, subject.jsi_instance)
|
119
99
|
assert(!subject.respond_to?(:to_ary))
|
120
100
|
assert(!subject.respond_to?(:to_hash))
|
121
101
|
end
|
@@ -124,16 +104,16 @@ describe JSI::Base do
|
|
124
104
|
let(:instance) { {'foo' => 'bar'} }
|
125
105
|
let(:schema_content) { {'type' => 'object'} }
|
126
106
|
it 'initializes' do
|
127
|
-
assert_equal(
|
107
|
+
assert_equal({'foo' => 'bar'}, subject.jsi_instance)
|
128
108
|
assert(!subject.respond_to?(:to_ary))
|
129
109
|
assert(subject.respond_to?(:to_hash))
|
130
110
|
end
|
131
111
|
end
|
132
|
-
describe 'JSI::JSON::
|
133
|
-
let(:
|
112
|
+
describe 'JSI::JSON::HashNode' do
|
113
|
+
let(:instance) { JSI::JSON::HashNode.new({'foo' => 'bar'}, JSI::JSON::Pointer.new([])) }
|
134
114
|
let(:schema_content) { {'type' => 'object'} }
|
135
115
|
it 'initializes' do
|
136
|
-
assert_equal(JSI::JSON::HashNode.new({'foo' => 'bar'}, []), subject.
|
116
|
+
assert_equal(JSI::JSON::HashNode.new({'foo' => 'bar'}, JSI::JSON::Pointer.new([])), subject.jsi_instance)
|
137
117
|
assert(!subject.respond_to?(:to_ary))
|
138
118
|
assert(subject.respond_to?(:to_hash))
|
139
119
|
end
|
@@ -142,69 +122,93 @@ describe JSI::Base do
|
|
142
122
|
let(:instance) { ['foo'] }
|
143
123
|
let(:schema_content) { {'type' => 'array'} }
|
144
124
|
it 'initializes' do
|
145
|
-
assert_equal(
|
125
|
+
assert_equal(['foo'], subject.jsi_instance)
|
146
126
|
assert(subject.respond_to?(:to_ary))
|
147
127
|
assert(!subject.respond_to?(:to_hash))
|
148
128
|
end
|
149
129
|
end
|
150
|
-
describe 'JSI::JSON::
|
151
|
-
let(:
|
130
|
+
describe 'JSI::JSON::ArrayNode' do
|
131
|
+
let(:instance) { JSI::JSON::ArrayNode.new(['foo'], JSI::JSON::Pointer.new([])) }
|
152
132
|
let(:schema_content) { {'type' => 'array'} }
|
153
133
|
it 'initializes' do
|
154
|
-
assert_equal(JSI::JSON::ArrayNode.new(['foo'], []), subject.
|
134
|
+
assert_equal(JSI::JSON::ArrayNode.new(['foo'], JSI::JSON::Pointer.new([])), subject.jsi_instance)
|
155
135
|
assert(subject.respond_to?(:to_ary))
|
156
136
|
assert(!subject.respond_to?(:to_hash))
|
157
137
|
end
|
158
138
|
end
|
159
|
-
describe 'another Base' do
|
139
|
+
describe 'another JSI::Base invalid' do
|
160
140
|
let(:schema_content) { {'type' => 'object'} }
|
161
|
-
let(:instance) {
|
162
|
-
it 'initializes with
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
141
|
+
let(:instance) { schema.new_jsi({'foo' => 'bar'}) }
|
142
|
+
it 'initializes with an error' do
|
143
|
+
err = assert_raises(TypeError) { subject }
|
144
|
+
assert_equal("assigning another JSI::Base instance to a (JSI Schema Class: #) instance is incorrect. received: \#{<JSI> \"foo\" => \"bar\"}", err.message)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
describe 'Schema invalid' do
|
148
|
+
let(:instance) { JSI::Schema.new({}) }
|
149
|
+
it 'initializes with an error' do
|
150
|
+
err = assert_raises(TypeError) { subject }
|
151
|
+
assert_equal("assigning a schema to a (JSI Schema Class: #) instance is incorrect. received: \#{<JSI (JSI::JSONSchemaOrgDraft06) Schema>}", err.message)
|
167
152
|
end
|
168
153
|
end
|
169
154
|
end
|
170
|
-
describe '#
|
155
|
+
describe '#parent_jsis, #parent_jsi' do
|
171
156
|
let(:schema_content) { {'properties' => {'foo' => {'properties' => {'bar' => {'properties' => {'baz' => {}}}}}}} }
|
172
|
-
let(:
|
173
|
-
describe 'no
|
157
|
+
let(:instance) { {'foo' => {'bar' => {'baz' => {}}}} }
|
158
|
+
describe 'no parent_jsis' do
|
174
159
|
it 'has none' do
|
175
160
|
assert_equal([], subject.parents)
|
161
|
+
assert_equal([], subject.parent_jsis)
|
176
162
|
assert_equal(nil, subject.parent)
|
163
|
+
assert_equal(nil, subject.parent_jsi)
|
177
164
|
end
|
178
165
|
end
|
179
|
-
describe 'one
|
166
|
+
describe 'one parent_jsi' do
|
180
167
|
it 'has one' do
|
181
168
|
assert_equal([subject], subject.foo.parents)
|
169
|
+
assert_equal([subject], subject.foo.parent_jsis)
|
182
170
|
assert_equal(subject, subject.foo.parent)
|
171
|
+
assert_equal(subject, subject.foo.parent_jsi)
|
183
172
|
end
|
184
173
|
end
|
185
|
-
describe 'more
|
174
|
+
describe 'more parent_jsis' do
|
186
175
|
it 'has more' do
|
187
176
|
assert_equal([subject.foo.bar, subject.foo, subject], subject.foo.bar.baz.parents)
|
177
|
+
assert_equal([subject.foo.bar, subject.foo, subject], subject.foo.bar.baz.parent_jsis)
|
188
178
|
assert_equal(subject.foo.bar, subject.foo.bar.baz.parent)
|
179
|
+
assert_equal(subject.foo.bar, subject.foo.bar.baz.parent_jsi)
|
189
180
|
end
|
190
181
|
end
|
191
182
|
end
|
192
183
|
describe '#each, Enumerable methods' do
|
193
|
-
let(:
|
184
|
+
let(:instance) { 'a string' }
|
194
185
|
it "raises NoMethodError calling each or Enumerable methods" do
|
195
186
|
assert_raises(NoMethodError) { subject.each { nil } }
|
196
187
|
assert_raises(NoMethodError) { subject.map { nil } }
|
197
188
|
end
|
198
189
|
end
|
199
190
|
describe '#modified_copy' do
|
191
|
+
describe 'with an instance that does not have #modified_copy' do
|
192
|
+
let(:instance) { Object.new }
|
193
|
+
it 'yields the instance to modify' do
|
194
|
+
new_instance = Object.new
|
195
|
+
modified = subject.modified_copy do |o|
|
196
|
+
assert_equal(instance, o)
|
197
|
+
new_instance
|
198
|
+
end
|
199
|
+
assert_equal(new_instance, modified.jsi_instance)
|
200
|
+
assert_equal(instance, subject.jsi_instance)
|
201
|
+
refute_equal(instance, modified)
|
202
|
+
end
|
203
|
+
end
|
200
204
|
describe 'with an instance that does have #modified_copy' do
|
201
205
|
it 'yields the instance to modify' do
|
202
206
|
modified = subject.modified_copy do |o|
|
203
207
|
assert_equal({}, o)
|
204
208
|
{'a' => 'b'}
|
205
209
|
end
|
206
|
-
assert_equal({'a' => 'b'}, modified.
|
207
|
-
assert_equal({}, subject.
|
210
|
+
assert_equal({'a' => 'b'}, modified.jsi_instance)
|
211
|
+
assert_equal({}, subject.jsi_instance)
|
208
212
|
refute_equal(instance, modified)
|
209
213
|
end
|
210
214
|
end
|
@@ -212,7 +216,7 @@ describe JSI::Base do
|
|
212
216
|
it 'yields the instance to modify' do
|
213
217
|
modified = subject.modified_copy { |o| o }
|
214
218
|
# this doesn't really need to be tested but ... whatever
|
215
|
-
assert_equal(subject.
|
219
|
+
assert_equal(subject.jsi_instance.object_id, modified.jsi_instance.object_id)
|
216
220
|
assert_equal(subject, modified)
|
217
221
|
refute_equal(subject.object_id, modified.object_id)
|
218
222
|
end
|
@@ -224,18 +228,15 @@ describe JSI::Base do
|
|
224
228
|
modified = subject.modified_copy do |o|
|
225
229
|
o.to_s
|
226
230
|
end
|
227
|
-
assert_equal('{}', modified.
|
228
|
-
assert_equal({}, subject.
|
231
|
+
assert_equal('{}', modified.jsi_instance)
|
232
|
+
assert_equal({}, subject.jsi_instance)
|
229
233
|
refute_equal(instance, modified)
|
230
234
|
# interesting side effect
|
231
235
|
assert(subject.respond_to?(:to_hash))
|
232
236
|
assert(!modified.respond_to?(:to_hash))
|
233
|
-
assert_equal(JSI::JSON::HashNode, subject.instance.class)
|
234
|
-
assert_equal(JSI::JSON::Node, modified.instance.class)
|
235
237
|
end
|
236
238
|
end
|
237
239
|
end
|
238
|
-
it('#fragment') { assert_equal('#', subject.fragment) }
|
239
240
|
describe 'validation' do
|
240
241
|
describe 'without errors' do
|
241
242
|
it '#fully_validate' do
|
@@ -248,6 +249,94 @@ describe JSI::Base do
|
|
248
249
|
assert_equal(true, subject.validate!)
|
249
250
|
end
|
250
251
|
end
|
252
|
+
describe 'with errors' do
|
253
|
+
let(:schema_content) {
|
254
|
+
{
|
255
|
+
'id' => 'https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors',
|
256
|
+
'type' => 'object',
|
257
|
+
'properties' => {
|
258
|
+
'some_number' => {
|
259
|
+
'type' => 'number'
|
260
|
+
},
|
261
|
+
'a_required_property' => {
|
262
|
+
'type' => 'string'
|
263
|
+
}
|
264
|
+
}
|
265
|
+
}
|
266
|
+
}
|
267
|
+
let(:instance) { "this is a string" }
|
268
|
+
|
269
|
+
it '#validate' do
|
270
|
+
assert_equal(false, subject.validate)
|
271
|
+
end
|
272
|
+
it '#validate!' do
|
273
|
+
assert_raises JSON::Schema::ValidationError do
|
274
|
+
subject.validate!
|
275
|
+
end
|
276
|
+
end
|
277
|
+
describe 'fully_validate' do
|
278
|
+
it '#fully_validate ' do
|
279
|
+
assert_equal(["The property '#/' of type string did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors"], subject.fully_validate)
|
280
|
+
end
|
281
|
+
it '#fully_validate :errors_as_objects' do
|
282
|
+
expected = [
|
283
|
+
{
|
284
|
+
:schema => Addressable::URI.parse('https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors'),
|
285
|
+
:fragment => "#/",
|
286
|
+
:message => "The property '#/' of type string did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors",
|
287
|
+
:failed_attribute=>"TypeV4"
|
288
|
+
}
|
289
|
+
]
|
290
|
+
assert_equal(expected, subject.fully_validate(:errors_as_objects => true))
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
describe 'at a depth' do
|
295
|
+
let(:schema_content) do
|
296
|
+
{
|
297
|
+
'id' => 'https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth',
|
298
|
+
'description' => 'hash schema',
|
299
|
+
'type' => 'object',
|
300
|
+
'properties' => {
|
301
|
+
'foo' => {'type' => 'object'},
|
302
|
+
'bar' => {},
|
303
|
+
'baz' => {'type' => 'array'},
|
304
|
+
},
|
305
|
+
'additionalProperties' => {'not' => {}},
|
306
|
+
}
|
307
|
+
end
|
308
|
+
|
309
|
+
describe 'without errors' do
|
310
|
+
let(:instance) { {'foo' => {'x' => 'y'}, 'bar' => [9], 'baz' => [true]} }
|
311
|
+
|
312
|
+
it '#fully_validate' do
|
313
|
+
assert_equal([], subject.foo.fully_validate)
|
314
|
+
assert_equal([], subject.bar.fully_validate)
|
315
|
+
end
|
316
|
+
it '#validate' do
|
317
|
+
assert_equal(true, subject.foo.validate)
|
318
|
+
assert_equal(true, subject.bar.validate)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
describe 'with errors' do
|
322
|
+
let(:instance) { {'foo' => [true], 'bar' => [9], 'baz' => {'x' => 'y'}, 'more' => {}} }
|
323
|
+
|
324
|
+
it '#fully_validate' do
|
325
|
+
assert_equal(["The property '#/' of type array did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject.foo.fully_validate)
|
326
|
+
assert_equal([], subject.bar.fully_validate)
|
327
|
+
assert_equal(["The property '#/' of type object did not match the following type: array in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject.baz.fully_validate)
|
328
|
+
assert_equal(["The property '#/' of type object matched the disallowed schema in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject['more'].fully_validate)
|
329
|
+
assert_equal(["The property '#/foo' of type array did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth", "The property '#/baz' of type object did not match the following type: array in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth", "The property '#/more' of type object matched the disallowed schema in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject.fully_validate)
|
330
|
+
end
|
331
|
+
it '#validate' do
|
332
|
+
assert_equal(false, subject.foo.validate)
|
333
|
+
assert_equal(true, subject.bar.validate)
|
334
|
+
assert_equal(false, subject.baz.validate)
|
335
|
+
assert_equal(false, subject['more'].validate)
|
336
|
+
assert_equal(false, subject.validate)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
251
340
|
end
|
252
341
|
describe 'property accessors' do
|
253
342
|
let(:schema_content) do
|
@@ -260,17 +349,17 @@ describe JSI::Base do
|
|
260
349
|
},
|
261
350
|
}
|
262
351
|
end
|
263
|
-
let(:
|
352
|
+
let(:instance) do
|
264
353
|
{'foo' => {'x' => 'y'}, 'bar' => [3.14159], 'baz' => true, 'qux' => []}
|
265
354
|
end
|
266
355
|
describe 'readers' do
|
267
356
|
it 'reads attributes described as properties' do
|
268
357
|
assert_equal({'x' => 'y'}, subject.foo.as_json)
|
269
|
-
|
358
|
+
assert_is_a(schema.properties['foo'].jsi_schema_module, subject.foo)
|
270
359
|
assert_respond_to(subject.foo, :to_hash)
|
271
360
|
refute_respond_to(subject.foo, :to_ary)
|
272
361
|
assert_equal([3.14159], subject.bar.as_json)
|
273
|
-
|
362
|
+
assert_is_a(schema.properties['bar'].jsi_schema_module, subject.bar)
|
274
363
|
refute_respond_to(subject.bar, :to_hash)
|
275
364
|
assert_respond_to(subject.bar, :to_ary)
|
276
365
|
assert_equal(true, subject.baz)
|
@@ -281,8 +370,8 @@ describe JSI::Base do
|
|
281
370
|
describe 'when the instance is not hashlike' do
|
282
371
|
let(:instance) { nil }
|
283
372
|
it 'errors' do
|
284
|
-
err = assert_raises(
|
285
|
-
|
373
|
+
err = assert_raises(JSI::Base::CannotSubscriptError) { subject.foo }
|
374
|
+
assert_equal(%q(cannot subcript (using token: "foo") from instance: nil), err.message)
|
286
375
|
end
|
287
376
|
end
|
288
377
|
describe 'properties with the same names as instance methods' do
|
@@ -295,14 +384,14 @@ describe JSI::Base do
|
|
295
384
|
'inspect' => {}, # Base
|
296
385
|
'pretty_inspect' => {}, # Kernel
|
297
386
|
'as_json' => {}, # Base::OverrideFromExtensions, extended on initialization
|
298
|
-
'each' => {}, #
|
387
|
+
'each' => {}, # PathedHashNode / PathedArrayNode
|
299
388
|
'instance_exec' => {}, # BasicObject
|
300
|
-
'
|
301
|
-
'
|
389
|
+
'jsi_instance' => {}, # Base
|
390
|
+
'jsi_schemas' => {}, # module_for_schema singleton definition
|
302
391
|
},
|
303
392
|
}
|
304
393
|
end
|
305
|
-
let(:
|
394
|
+
let(:instance) do
|
306
395
|
{
|
307
396
|
'foo' => 'bar',
|
308
397
|
'initialize' => 'hi',
|
@@ -311,24 +400,23 @@ describe JSI::Base do
|
|
311
400
|
'as_json' => 'hi',
|
312
401
|
'each' => 'hi',
|
313
402
|
'instance_exec' => 'hi',
|
314
|
-
'
|
315
|
-
'
|
403
|
+
'jsi_instance' => 'hi',
|
404
|
+
'jsi_schemas' => 'hi',
|
316
405
|
}
|
317
406
|
end
|
318
407
|
it 'does not define readers' do
|
319
|
-
assert_equal('bar', subject.foo)
|
320
|
-
assert_equal(JSI::SchemaClasses.module_for_schema(subject.schema), subject.method(:foo).owner)
|
408
|
+
assert_equal('bar', subject.foo) # this one is defined
|
321
409
|
|
322
410
|
assert_equal(JSI::Base, subject.method(:initialize).owner)
|
323
411
|
assert_equal('hi', subject['initialize'])
|
324
|
-
|
412
|
+
assert_equal(%q(#{<JSI> "foo" => "bar", "initialize" => "hi", "inspect" => "hi", "pretty_inspect" => "hi", "as_json" => "hi", "each" => "hi", "instance_exec" => "hi", "jsi_instance" => "hi", "jsi_schemas" => "hi"}), subject.inspect)
|
325
413
|
assert_equal('hi', subject['inspect'])
|
326
|
-
|
327
|
-
assert_equal(
|
414
|
+
assert_equal(%Q(\#{<JSI>\n "foo" => "bar",\n "initialize" => "hi",\n "inspect" => "hi",\n "pretty_inspect" => "hi",\n "as_json" => "hi",\n "each" => "hi",\n "instance_exec" => "hi",\n "jsi_instance" => "hi",\n "jsi_schemas" => "hi"\n}\n), subject.pretty_inspect)
|
415
|
+
assert_equal(instance, subject.as_json)
|
328
416
|
assert_equal(subject, subject.each { })
|
329
417
|
assert_equal(2, subject.instance_exec { 2 })
|
330
|
-
assert_equal(instance, subject.
|
331
|
-
assert_equal(schema, subject.
|
418
|
+
assert_equal(instance, subject.jsi_instance)
|
419
|
+
assert_equal(Set.new << schema, subject.jsi_schemas)
|
332
420
|
end
|
333
421
|
end
|
334
422
|
end
|
@@ -339,57 +427,60 @@ describe JSI::Base do
|
|
339
427
|
subject.foo = {'y' => 'z'}
|
340
428
|
|
341
429
|
assert_equal({'y' => 'z'}, subject.foo.as_json)
|
342
|
-
|
343
|
-
|
430
|
+
assert_is_a(schema.properties['foo'].jsi_schema_module, orig_foo)
|
431
|
+
assert_is_a(schema.properties['foo'].jsi_schema_module, subject.foo)
|
344
432
|
end
|
345
433
|
it 'modifies the instance, visible to other references to the same instance' do
|
346
|
-
orig_instance = subject.
|
434
|
+
orig_instance = subject.jsi_instance
|
347
435
|
|
348
436
|
subject.foo = {'y' => 'z'}
|
349
437
|
|
350
|
-
assert_equal(orig_instance, subject.
|
351
|
-
assert_equal({'y' => 'z'}, orig_instance['foo']
|
352
|
-
assert_equal({'y' => 'z'}, subject.
|
353
|
-
assert_equal(orig_instance.class, subject.
|
438
|
+
assert_equal(orig_instance, subject.jsi_instance)
|
439
|
+
assert_equal({'y' => 'z'}, orig_instance['foo'])
|
440
|
+
assert_equal({'y' => 'z'}, subject.jsi_instance['foo'])
|
441
|
+
assert_equal(orig_instance.class, subject.jsi_instance.class)
|
354
442
|
end
|
355
443
|
describe 'when the instance is not hashlike' do
|
356
444
|
let(:instance) { nil }
|
357
445
|
it 'errors' do
|
358
446
|
err = assert_raises(NoMethodError) { subject.foo = 0 }
|
359
|
-
|
447
|
+
assert_equal('cannot assign subcript (using token: "foo") to instance: nil', err.message)
|
360
448
|
end
|
361
449
|
end
|
362
450
|
end
|
363
451
|
end
|
364
452
|
describe '#inspect' do
|
365
453
|
# if the instance is hash-like, #inspect gets overridden
|
366
|
-
let(:
|
454
|
+
let(:instance) { Object.new }
|
367
455
|
it 'inspects' do
|
368
|
-
assert_match(%r(\A
|
456
|
+
assert_match(%r(\A\#<JSI\ \#<Object:[^<>]*>>\z), subject.inspect)
|
369
457
|
end
|
370
458
|
end
|
371
459
|
describe '#pretty_print' do
|
372
460
|
# if the instance is hash-like, #pretty_print gets overridden
|
373
|
-
let(:
|
461
|
+
let(:instance) { Object.new }
|
374
462
|
it 'pretty_prints' do
|
375
|
-
assert_match(%r(\A
|
463
|
+
assert_match(%r(\A\#<JSI\ \#<Object:[^<>]*>>\z), subject.pretty_inspect.chomp)
|
376
464
|
end
|
377
465
|
end
|
378
466
|
describe '#as_json' do
|
379
467
|
it '#as_json' do
|
380
|
-
assert_equal({'a' => 'b'}, JSI.
|
381
|
-
assert_equal({'a' => 'b'}, JSI.
|
382
|
-
assert_equal(
|
383
|
-
assert_equal(['a'], JSI.
|
468
|
+
assert_equal({'a' => 'b'}, JSI::Schema.new({}).new_jsi({'a' => 'b'}).as_json)
|
469
|
+
assert_equal({'a' => 'b'}, JSI::Schema.new({}).new_jsi(JSI::JSON::Node.new_doc({'a' => 'b'})).as_json)
|
470
|
+
assert_equal({'a' => 'b'}, JSI::Schema.new({'type' => 'object'}).new_jsi(JSI::JSON::Node.new_doc({'a' => 'b'})).as_json)
|
471
|
+
assert_equal(['a', 'b'], JSI::Schema.new({'type' => 'array'}).new_jsi(JSI::JSON::Node.new_doc(['a', 'b'])).as_json)
|
472
|
+
assert_equal(['a'], JSI::Schema.new({}).new_jsi(['a']).as_json(some_option: true))
|
384
473
|
end
|
385
474
|
end
|
386
|
-
describe '
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
475
|
+
describe 'equality between different classes of JSI::Base subclasses' do
|
476
|
+
let(:subject_subclass) { Class.new(schema.jsi_schema_class).new(instance) }
|
477
|
+
|
478
|
+
it 'considers a Base subclass (class_for_schema) and subsubclass to be equal with the same instance' do
|
479
|
+
assert_equal(subject.hash, subject_subclass.hash)
|
480
|
+
assert(subject == subject_subclass)
|
481
|
+
assert(subject_subclass == subject)
|
482
|
+
assert(subject.eql?(subject_subclass))
|
483
|
+
assert(subject_subclass.eql?(subject))
|
393
484
|
end
|
394
485
|
end
|
395
486
|
end
|